diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index fffa255..0b85bcf 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -357,7 +357,14 @@ void MainWindow::openSavedVideoDirSlot() {
ui->videoControlWidget->updateVideoSlider(
currentTime, duration);
});
- int i = 0;
+
+ connect(ui->videoControlWidget,
+ &VideoControl::seekToVideoSignal, ui->videoWidget,
+ &VideoWidget::seekToVideo, Qt::UniqueConnection);
+
+ connect(ui->videoControlWidget,
+ &VideoControl::changePlaySpeedSignal, ui->videoWidget,
+ &VideoWidget::setPlaySpeed, Qt::UniqueConnection);
}
}
}
@@ -477,6 +484,8 @@ void MainWindow::closeVideoSlot() {
ui->videoWidget3->stopPlay();
ui->videoWidget4->stopPlay();
+ ui->videoControlWidget->resetVideoSlider();
+
emit sendErrorMessage("视频流已关闭!", NotifyType::SUCCESS);
}
diff --git a/src/resources/Qss/dark-style.qss b/src/resources/Qss/dark-style.qss
index 09f32ab..8db97de 100644
--- a/src/resources/Qss/dark-style.qss
+++ b/src/resources/Qss/dark-style.qss
@@ -157,4 +157,4 @@ QWidget#clock-widget {
color: #FEFEFE;
font-weight: bold;
background-color: transparent;
-}
\ No newline at end of file
+}
diff --git a/src/resources/images/play0.5X.png b/src/resources/images/play0.5X.png
new file mode 100644
index 0000000..1ec75a5
Binary files /dev/null and b/src/resources/images/play0.5X.png differ
diff --git a/src/resources/images/play0.75X.png b/src/resources/images/play0.75X.png
new file mode 100644
index 0000000..7845acb
Binary files /dev/null and b/src/resources/images/play0.75X.png differ
diff --git a/src/resources/images/play1.25X.png b/src/resources/images/play1.25X.png
new file mode 100644
index 0000000..8c0bff4
Binary files /dev/null and b/src/resources/images/play1.25X.png differ
diff --git a/src/resources/images/play1.5X.png b/src/resources/images/play1.5X.png
new file mode 100644
index 0000000..8c70347
Binary files /dev/null and b/src/resources/images/play1.5X.png differ
diff --git a/src/resources/images/play1.75X.png b/src/resources/images/play1.75X.png
new file mode 100644
index 0000000..5d1a725
Binary files /dev/null and b/src/resources/images/play1.75X.png differ
diff --git a/src/resources/images/play1X.png b/src/resources/images/play1X.png
new file mode 100644
index 0000000..b83bb2a
Binary files /dev/null and b/src/resources/images/play1X.png differ
diff --git a/src/resources/images/play2X.png b/src/resources/images/play2X.png
new file mode 100644
index 0000000..d7fa465
Binary files /dev/null and b/src/resources/images/play2X.png differ
diff --git a/src/resources/res.qrc b/src/resources/res.qrc
index 3e25fdb..424cc77 100644
--- a/src/resources/res.qrc
+++ b/src/resources/res.qrc
@@ -30,5 +30,12 @@
images/playFast.png
images/playSlow.png
images/map3D.png
+ images/play0.5X.png
+ images/play0.75X.png
+ images/play1.5X.png
+ images/play1.25X.png
+ images/play1.75X.png
+ images/play1X.png
+ images/play2X.png
diff --git a/src/video/avpacketqueuemanager.cpp b/src/video/avpacketqueuemanager.cpp
index 1e19234..b899e1e 100644
--- a/src/video/avpacketqueuemanager.cpp
+++ b/src/video/avpacketqueuemanager.cpp
@@ -24,6 +24,11 @@ void AVPacketQueueManager::enqueuePushPacket(AVPacket *pkt) {
if (clonedPacket) m_pushQueue.enqueue(clonedPacket);
}
+void AVPacketQueueManager::enqueueSeekTime(int64_t time) {
+ QMutexLocker locker(&m_seekMutex);
+ m_seekQueue.enqueue(time);
+}
+
AVPacket *AVPacketQueueManager::dequeueDecodePacket() {
QMutexLocker locker(&m_decodeMutex);
if (!m_decodeQueue.isEmpty()) {
@@ -51,6 +56,11 @@ AVPacket *AVPacketQueueManager::dequeuePushPacket() {
return nullptr;
}
+int64_t AVPacketQueueManager::dequeueSeekTime() {
+ QMutexLocker locker(&m_seekMutex);
+ return m_seekQueue.dequeue();
+}
+
void AVPacketQueueManager::clearDecodeQueue() {
QMutexLocker locker(&m_decodeMutex);
m_decodeQueue.clear();
@@ -66,6 +76,11 @@ void AVPacketQueueManager::clearPushQueue() {
m_pushQueue.clear();
}
+void AVPacketQueueManager::clearSeekQueue() {
+ QMutexLocker locker(&m_seekMutex);
+ m_seekQueue.clear();
+}
+
bool AVPacketQueueManager::isEmptyDecodeQueue() {
QMutexLocker locker(&m_decodeMutex);
return m_decodeQueue.isEmpty();
@@ -75,3 +90,8 @@ bool AVPacketQueueManager::isEmptySaveQueue() {
QMutexLocker locker(&m_saveMutex);
return m_saveQueue.isEmpty();
}
+
+bool AVPacketQueueManager::isEmptySeekQueue() {
+ QMutexLocker locker(&m_seekMutex);
+ return m_seekQueue.isEmpty();
+}
diff --git a/src/video/avpacketqueuemanager.h b/src/video/avpacketqueuemanager.h
index 3e3372a..240b2c1 100644
--- a/src/video/avpacketqueuemanager.h
+++ b/src/video/avpacketqueuemanager.h
@@ -13,26 +13,37 @@ public:
void enqueueDecodePacket(AVPacket* pkt);
void enqueueSavePacket(AVPacket* pkt);
void enqueuePushPacket(AVPacket* pkt);
+ void enqueueSeekTime(int64_t time);
AVPacket* dequeueDecodePacket();
AVPacket* dequeueSavePacket();
AVPacket* dequeuePushPacket();
+ int64_t dequeueSeekTime();
void clearDecodeQueue();
void clearSaveQueue();
void clearPushQueue();
+ void clearSeekQueue();
bool isEmptyDecodeQueue();
bool isEmptySaveQueue();
+ bool isEmptySeekQueue();
+
+public:
+ std::atomic m_isSeeking{false}; // 是否正在跳转
+ std::atomic m_isReadEnd{false};
+ std::atomic m_isDecodeEnd{false};
private:
int QUEUECAPACITY = 100;
QQueue m_decodeQueue;
QQueue m_saveQueue;
QQueue m_pushQueue;
- QMutex m_decodeMutex; // 共享的互斥锁
- QMutex m_saveMutex; // 共享的互斥锁
- QMutex m_pushMutex; // 共享的互斥锁
+ QQueue m_seekQueue; // 存储目标时间戳
+ QMutex m_decodeMutex; // 共享的互斥锁
+ QMutex m_saveMutex; // 共享的互斥锁
+ QMutex m_pushMutex; // 共享的互斥锁
+ QMutex m_seekMutex; // 共享的互斥锁
};
#endif // AVPACKETQUEUEMANAGER_H
diff --git a/src/video/decodestream.cpp b/src/video/decodestream.cpp
index 5a72f2b..1d1caff 100644
--- a/src/video/decodestream.cpp
+++ b/src/video/decodestream.cpp
@@ -1,6 +1,6 @@
#include "decodestream.h"
-DecodeStream::DecodeStream(QObject *parent) : QObject{parent} {}
+DecodeStream::DecodeStream(QObject *parent) : QObject{parent}, m_playSpeed{1} {}
bool DecodeStream::init(AVPacketQueueManager *queueManager,
AVFormatContext *formatContext, int videoIndex) {
@@ -17,6 +17,12 @@ bool DecodeStream::init(AVPacketQueueManager *queueManager,
} else {
m_isFile = true;
}
+
+ m_fps = av_q2d(formatContext->streams[videoIndex]->avg_frame_rate);
+ if (m_fps <= 0) {
+ m_fps = 30.0; // 默认帧率
+ }
+
return initDecoder(formatContext, videoIndex);
}
@@ -34,31 +40,98 @@ void DecodeStream::startDecode() {
return;
}
bool isPlayEnd = false;
+ // m_firstFramePTS = AV_NOPTS_VALUE;
+ // m_startDecodeTime = AV_NOPTS_VALUE;
+ int64_t lastPts = AV_NOPTS_VALUE;
+ auto lastDisplayTime =
+ std::chrono::high_resolution_clock::now(); // 记录上一帧的显示时间
+ m_queueManager->m_isDecodeEnd = false;
+
+ double startTime = m_startTime / static_cast(AV_TIME_BASE);
+ int64_t duration = static_cast(m_duration / AV_TIME_BASE);
+
while (m_start) {
try {
+ // 检查跳转状态
+ if (m_queueManager->m_isSeeking) {
+ m_queueManager->clearDecodeQueue();
+ // 清空解码器缓冲区
+ avcodec_flush_buffers(m_codecContext);
+ continue;
+ }
+
AVPacket *inputPacket = m_queueManager->dequeueDecodePacket();
if (inputPacket) {
AVFrame *frame = decodePacket(inputPacket);
- // 更新当前播放时间进度
- if (frame && m_isFile) {
- double currentTime = frame->best_effort_timestamp *
- av_q2d(m_outStreamTimeBase);
- double startTime =
- m_startTime / static_cast(AV_TIME_BASE);
- int64_t duration =
- static_cast(m_duration / AV_TIME_BASE);
- qDebug() << currentTime - startTime;
- int64_t currentTime1 =
- static_cast(currentTime - startTime);
- emit updateVideoCurrentTime(currentTime1, duration);
- if (m_queueManager->isEmptyDecodeQueue()) isPlayEnd = true;
+
+ if (frame) {
+ // 播放本地视频
+ if (m_isFile) {
+ // 计算帧间隔
+ if (lastPts != AV_NOPTS_VALUE &&
+ frame->pts != AV_NOPTS_VALUE) {
+ int64_t ptsDiff = frame->pts - lastPts;
+ if (ptsDiff < 0) {
+ // 如果 ptsDiff 为负数,说明 pts
+ // 不连续,跳过该帧
+ continue;
+ }
+ double frameDuration = av_q2d(m_outStreamTimeBase) *
+ ptsDiff; // 转换为秒
+ // 根据播放速度调整
+ double adjustedDuration =
+ frameDuration / m_playSpeed;
+
+ // 计算实际延迟
+ auto now =
+ std::chrono::high_resolution_clock::now();
+ auto elapsed = std::chrono::duration_cast<
+ std::chrono::milliseconds>(
+ now - lastDisplayTime)
+ .count() /
+ 1000.0;
+ double sleepTime = adjustedDuration - elapsed;
+
+ if (sleepTime > 0) {
+ std::this_thread::sleep_for(
+ std::chrono::microseconds(
+ static_cast(
+ sleepTime *
+ 1000000))); // 微秒级延迟
+ }
+ // qDebug() << "delay:" << sleepTime * 1000;
+ }
+
+ lastPts = frame->pts;
+ lastDisplayTime = std::chrono::high_resolution_clock::
+ now(); // 更新上一帧的显示时间
+
+ // qDebug() << frame->best_effort_timestamp;
+ // int64_t aaa = frame->best_effort_timestamp;
+ // 更新当前播放时间进度
+ double currentTime = frame->best_effort_timestamp *
+ av_q2d(m_outStreamTimeBase);
+
+ // qDebug() << currentTime - startTime;
+ int64_t currentTime1 =
+ static_cast(currentTime - startTime);
+ emit updateVideoCurrentTime(currentTime1, duration);
+ if (m_queueManager->isEmptyDecodeQueue() &&
+ m_queueManager->m_isReadEnd) {
+ isPlayEnd = true;
+ }
+ }
+
+ emit repaintSignal(frame);
}
- emit repaintSignal(frame);
av_packet_unref(inputPacket);
av_packet_free(&inputPacket);
inputPacket = nullptr;
- if (isPlayEnd && m_isFile) break;
+ if (isPlayEnd && m_isFile && !m_queueManager->m_isSeeking) {
+ m_queueManager->m_isDecodeEnd = true;
+ break;
+ }
} else {
// QThread::usleep(1000);
// av_usleep(1000);
@@ -70,9 +143,15 @@ void DecodeStream::startDecode() {
free();
qDebug() << "Decoding Thread End!";
+ emit decodeEndSignal();
emit sendErrorMessageSignal("视频解码结束!", 1);
}
+void DecodeStream::changePlaySpeedSlot(double speed) {
+ m_playSpeed = speed;
+ qDebug() << "receive changePlaySpeedSlot:" << m_playSpeed;
+}
+
void DecodeStream::close() {
m_start = false;
qDebug() << "decode Stream close!" << m_start;
diff --git a/src/video/decodestream.h b/src/video/decodestream.h
index 700d16c..c57b0d1 100644
--- a/src/video/decodestream.h
+++ b/src/video/decodestream.h
@@ -7,6 +7,7 @@
#include
#include
#include
+#include
#include "avpacketqueuemanager.h"
#include "ffmpeginclude.h"
@@ -23,12 +24,13 @@ public:
AVCodecParserContext *getParserContext();
public slots:
void startDecode();
-
+ void changePlaySpeedSlot(double speed);
signals:
void repaintSignal(AVFrame *frame); // 重绘
void startDecodeSignal();
void sendErrorMessageSignal(QString message, int type);
void updateVideoCurrentTime(int currentTime, int duration);
+ void decodeEndSignal();
private:
bool initObject(); // 初始化对象
@@ -54,6 +56,11 @@ private:
int64_t m_startTime;
int64_t m_duration;
bool m_isFile = false;
+ int m_fps;
+ std::atomic m_playSpeed;
+
+ int64_t m_firstFramePTS;
+ int64_t m_startDecodeTime;
AVCodecParserContext *m_parser = nullptr;
};
diff --git a/src/video/readstream.cpp b/src/video/readstream.cpp
index 68e5e6c..9a3162f 100644
--- a/src/video/readstream.cpp
+++ b/src/video/readstream.cpp
@@ -92,7 +92,10 @@ bool ReadStream::openFile(const QString &url) {
m_videoDuration = -1;
}
- m_startTime = -1;
+ m_startTime = m_formatContext->start_time;
+ m_inStreamTimeBase = m_formatContext->streams[m_videoIndex]->time_base;
+
+ // m_startTime = -1;
m_pullURL = url;
return initObject();
}
@@ -216,6 +219,20 @@ double ReadStream::getVideoDuration() {
return m_videoDuration;
}
+void ReadStream::seekToVideo(int64_t targetTimestamp) {
+ qDebug() << "Receive targetTimeStamp!**************";
+ if (m_formatContext) {
+ // double starttime = m_startTime / static_cast(AV_TIME_BASE);
+ int64_t aaa =
+ targetTimestamp * static_cast(AV_TIME_BASE) + m_startTime;
+ int64_t bbb = av_rescale_q(aaa, AV_TIME_BASE_Q, m_inStreamTimeBase);
+ // double tmp = (targetTimestamp + starttime) /
+ // av_q2d(m_inStreamTimeBase);
+ qDebug() << "tmp:" << bbb;
+ m_queueManager.enqueueSeekTime(bbb);
+ };
+}
+
void ReadStream::startPullStream() {
// 如果没有打开则返回
if (!m_formatContext) {
@@ -282,6 +299,93 @@ void ReadStream::startPullStream() {
qDebug() << "read Stream End!";
}
+void ReadStream::startReadFileStream() {
+ // 如果没有打开则返回
+ if (!m_formatContext) {
+ return;
+ }
+ qDebug() << "readStreamThreadID:" << QThread::currentThreadId();
+
+ m_start = true;
+ int readRet;
+ // 读取数据包
+ while (m_start) {
+ // 检查跳转请求
+ if (!m_queueManager.isEmptySeekQueue()) {
+ int64_t targetTimestamp = m_queueManager.dequeueSeekTime();
+ // 设置跳转状态
+ m_queueManager.m_isSeeking = true;
+ // 尝试跳转
+ // ;
+ // av_seek_frame(m_formatContext, -1, targetTimestamp,
+ // AVSEEK_FLAG_ANY);
+ if (avformat_seek_file(m_formatContext, m_videoIndex, INT64_MIN,
+ targetTimestamp, INT64_MAX,
+ AVSEEK_FLAG_ANY) >= 0) {
+ m_queueManager.clearDecodeQueue();
+ m_queueManager.m_isReadEnd = false;
+ } else {
+ }
+
+ // 恢复读取
+ m_queueManager.m_isSeeking = false;
+ }
+
+ readRet = av_read_frame(m_formatContext, m_inputPacket);
+ if (readRet == AVERROR(EAGAIN)) { // 暂时没有数据流
+ qDebug() << "No Stream Data";
+ av_packet_unref(m_inputPacket);
+ av_usleep(30000); // 等待 30 毫秒
+ continue;
+ } else if (readRet == AVERROR_EOF) { // 流文件结束
+ av_packet_unref(m_inputPacket);
+ m_queueManager.m_isReadEnd = true;
+ if (m_queueManager.m_isDecodeEnd) {
+ qDebug() << "Stream End";
+ close();
+ break;
+ } else {
+ av_usleep(2000);
+ continue;
+ }
+ } else if (readRet < 0) { // 发生错误
+ qDebug() << "Stream Error" << readRet;
+ if (m_streamDecoder) {
+ m_streamDecoder->close();
+ }
+
+ if (m_streamPusher) {
+ m_streamPusher->close();
+ }
+ m_queueManager.m_isReadEnd = true;
+ break;
+ }
+
+ if (m_inputPacket->stream_index == m_videoIndex &&
+ readRet != AVERROR_EOF) {
+ if (isValidAVPacket(m_inputPacket)) {
+ // if (test) {
+ // qDebug() << m_inputPacket->pts;
+ // int i = 0;
+ // }
+ if (m_decodeStreamFlag) {
+ m_queueManager.enqueueDecodePacket(m_inputPacket);
+ }
+
+ if (m_pushStreamFlag) {
+ m_queueManager.enqueuePushPacket(m_inputPacket);
+ }
+ }
+ }
+ av_packet_unref(m_inputPacket);
+ // QThread::usleep(2000); // 等待 2 毫秒
+ av_usleep(1000);
+ }
+ clear();
+ free();
+ qDebug() << "read Stream End!";
+}
+
void ReadStream::startPullUDPStream() {
initObject();
// parser = av_parser_init(AV_CODEC_ID_H264);
diff --git a/src/video/readstream.h b/src/video/readstream.h
index e9b67a2..dd4a465 100644
--- a/src/video/readstream.h
+++ b/src/video/readstream.h
@@ -34,8 +34,11 @@ public:
bool initSavedRawFile(QString fileDir = "./dat", QString uavName = "fp98");
double getVideoDuration();
+
+ void seekToVideo(int64_t targetTimestamp);
public slots:
void startPullStream();
+ void startReadFileStream();
void startPullUDPStream();
void closeUDPConnectionSLot();
signals:
@@ -76,12 +79,11 @@ private:
qreal m_frameRate = 0; // 视频帧率
QSize m_size; // 视频分辨率大小
uchar *m_buffer = nullptr;
- bool m_start = true;
- bool m_end = false;
- int64_t m_startTime;
+ std::atomic m_start{true};
+ std::atomic m_end{false};
+ // int64_t m_startTime;
AVFormatContext *m_formatContext = nullptr; // 解封装上下文
- AVCodecContext *m_codecContext = nullptr; // 解码器上下文
// SwsContext* m_swsContext = nullptr; // 图像转换上下文
AVPacket *m_inputPacket = nullptr; // 数据包
int m_videoIndex = 0; // 视频流索引
@@ -94,6 +96,11 @@ private:
// QMutex m_mutex;
AVPacketQueueManager m_queueManager;
+ AVRational m_inStreamTimeBase;
+ int64_t m_startTime;
+
+ bool test = false;
+
private:
QFile m_saveFile;
QUdpSocket *udpSocket = nullptr;
diff --git a/src/video/videowidget.cpp b/src/video/videowidget.cpp
index b7fb315..aa20bef 100644
--- a/src/video/videowidget.cpp
+++ b/src/video/videowidget.cpp
@@ -52,6 +52,11 @@ VideoWidget::~VideoWidget() {
}
bool VideoWidget::play(const QString &url, bool bSave) {
+ if (this->getPlayStatus()) {
+ emit sendErrorMessageSignal("视频窗口已占用!", 2);
+ return false;
+ }
+
if (url.isEmpty()) return false;
if (!m_pullFlag) {
m_pullFlag = pullStream(url, bSave);
@@ -73,7 +78,13 @@ bool VideoWidget::play(const QString &url, bool bSave) {
if (!bSave) {
connect(decodeStreamer, &DecodeStream::updateVideoCurrentTime, this,
- &VideoWidget::receiveVideoCurrentTime);
+ &VideoWidget::receiveVideoCurrentTime, Qt::UniqueConnection);
+
+ connect(this, &VideoWidget::changePlaySpeedSignal, decodeStreamer,
+ &DecodeStream::changePlaySpeedSlot, Qt::UniqueConnection);
+
+ connect(decodeStreamer, &DecodeStream::decodeEndSignal, this,
+ &VideoWidget::stopPlay, Qt::UniqueConnection);
}
decodeStreamer->moveToThread(&decodeStreamThread);
@@ -92,6 +103,11 @@ bool VideoWidget::play(const QString &url, bool bSave) {
}
bool VideoWidget::udpPlay(QString ip, int port) {
+ if (this->getPlayStatus()) {
+ emit sendErrorMessageSignal("视频窗口已占用!", 2);
+ return false;
+ }
+
if (!m_pullFlag) {
m_pullFlag = pullUDPStream(ip, port);
if (!m_pullFlag) {
@@ -229,6 +245,20 @@ double VideoWidget::getVideoDuration() {
return -1;
}
+bool VideoWidget::seekToVideo(int64_t targetTime) {
+ if (readStreamer) {
+ readStreamer->seekToVideo(targetTime);
+ }
+ return true;
+}
+
+void VideoWidget::setPlaySpeed(double speed) {
+ if (decodeStreamer) {
+ decodeStreamer->changePlaySpeedSlot(speed);
+ }
+ emit changePlaySpeedSignal(speed);
+}
+
void VideoWidget::repaint(AVFrame *frame) {
try {
QMutexLocker locker(&m_mutex);
@@ -585,8 +615,16 @@ bool VideoWidget::pullStream(const QString &url, bool bSave) {
if (url.isEmpty()) return false;
if (!readStreamer) {
readStreamer = new ReadStream;
- connect(readStreamer, &ReadStream::startPullStreamSignal, readStreamer,
- &ReadStream::startPullStream, Qt::UniqueConnection);
+ if (bSave) {
+ connect(readStreamer, &ReadStream::startPullStreamSignal,
+ readStreamer, &ReadStream::startPullStream,
+ Qt::UniqueConnection);
+ } else {
+ connect(readStreamer, &ReadStream::startPullStreamSignal,
+ readStreamer, &ReadStream::startReadFileStream,
+ Qt::UniqueConnection);
+ }
+
connect(readStreamer, &ReadStream::sendErrorMessageSignal, this,
&VideoWidget::receiveErrorMessage, Qt::UniqueConnection);
// connect(this, &VideoWidget::startPullSignal, readStreamer,
@@ -662,7 +700,8 @@ void VideoWidget::receiveErrorMessage(QString message, int type) {
emit sendErrorMessageSignal(message, type);
}
-void VideoWidget::receiveVideoCurrentTime(int currentTime, int duration) {
+void VideoWidget::receiveVideoCurrentTime(int64_t currentTime,
+ int64_t duration) {
emit updateVideoCurrentTimeSignal(currentTime, duration);
}
diff --git a/src/video/videowidget.h b/src/video/videowidget.h
index e5e007b..a915172 100644
--- a/src/video/videowidget.h
+++ b/src/video/videowidget.h
@@ -54,6 +54,9 @@ public:
bool getPlayStatus();
double getVideoDuration();
+ bool seekToVideo(int64_t targetTime);
+ void setPlaySpeed(double speed);
+
protected:
void initializeGL() override; // 初始化gl
void resizeGL(int w, int h) override; // 窗口尺寸变化
@@ -91,7 +94,7 @@ private:
bool pullStream(const QString &url, bool bSave = true);
bool pullUDPStream(QString ip, int port);
void receiveErrorMessage(QString message, int type);
- void receiveVideoCurrentTime(int currentTime, int duration);
+ void receiveVideoCurrentTime(int64_t currentTime, int64_t duration);
private:
QString m_pullURL;
@@ -121,7 +124,8 @@ signals:
void startPullSignal();
void sendErrorMessageSignal(QString message, int type);
void closeUDPConnectionSignal();
- void updateVideoCurrentTimeSignal(int currentTime, int duration);
+ void updateVideoCurrentTimeSignal(int64_t currentTime, int64_t duration);
+ void changePlaySpeedSignal(double speed);
public:
QSizeF getCurImgSize();
diff --git a/src/videoControl.cpp b/src/videoControl.cpp
index 826cead..3046dc0 100644
--- a/src/videoControl.cpp
+++ b/src/videoControl.cpp
@@ -2,11 +2,13 @@
#include "ui_videoControl.h"
-VideoControl::VideoControl(QWidget *parent)
+VideoControl::VideoControl(QWidget* parent)
: QWidget(parent), ui(new Ui::VideoControl) {
ui->setupUi(this);
// 其他初始化代码...
initIconButton();
+
+ m_playSpeed = 1.0;
}
VideoControl::~VideoControl() {
@@ -27,6 +29,12 @@ void VideoControl::updateVideoSlider(int currentTime, int duration) {
ui->videoSlider->setValue(currentTime);
}
+void VideoControl::resetVideoSlider() {
+ ui->label->setText("00:00:00");
+ ui->durationLabel->setText("00:00:00");
+ ui->videoSlider->setValue(0);
+}
+
void VideoControl::initIconButton() {
ui->pbPlayer->setIcon(QIcon(":/images/playMedio.png"));
ui->pbPlayer->setIconSize(QSize(32, 32));
@@ -148,3 +156,65 @@ void VideoControl::on_pbStop_clicked() {
emit stopVideoSignal();
ui->pbStop->setDisabled(false);
}
+
+void VideoControl::on_videoSlider_sliderReleased() {
+ m_bSliderPressed = false;
+ int currentValue = ui->videoSlider->value();
+ if (currentValue != m_sliderPressedValue) {
+ emit seekToVideoSignal(currentValue);
+ }
+}
+
+void VideoControl::on_videoSlider_sliderPressed() {
+ m_bSliderPressed = true;
+ m_sliderPressedValue = ui->videoSlider->value();
+}
+
+void VideoControl::on_videoSlider_actionTriggered(int action) {
+ onSliderPressed();
+ if (m_bSliderPressed) {
+ } else {
+ qDebug() << "actionTriggered Value:" << ui->videoSlider->value();
+ emit seekToVideoSignal(ui->videoSlider->value());
+ }
+}
+
+void VideoControl::onSliderPressed() {
+ QSlider* slider = ui->videoSlider;
+ // 获取鼠标位置
+ QPoint pos = slider->mapFromGlobal(QCursor::pos());
+ // 计算点击位置对应的值
+ int value = slider->minimum() + (slider->maximum() - slider->minimum()) *
+ pos.x() / slider->width();
+ slider->setValue(value);
+}
+
+void VideoControl::on_pbFast_clicked() {
+ ui->pbSlow->setIcon(QIcon(":/images/playSlow.png"));
+ if (m_playSpeed <= 1.0) {
+ ui->pbFast->setIcon(QIcon(":/images/play1.5X.png"));
+ m_playSpeed = 1.5;
+ } else if (m_playSpeed == 1.5) {
+ ui->pbFast->setIcon(QIcon(":/images/play2X.png"));
+ m_playSpeed = 2.0;
+ } else if (m_playSpeed == 2.0) {
+ ui->pbFast->setIcon(QIcon(":/images/playFast.png"));
+ m_playSpeed = 1.0;
+ }
+ emit changePlaySpeedSignal(m_playSpeed);
+}
+
+void VideoControl::on_pbSlow_clicked() {
+ ui->pbFast->setIcon(QIcon(":/images/playFast.png"));
+ if (m_playSpeed >= 1.0) {
+ ui->pbSlow->setIcon(QIcon(":/images/play0.75X.png"));
+ m_playSpeed = 0.75;
+ } else if (m_playSpeed == 0.75) {
+ ui->pbSlow->setIcon(QIcon(":/images/play0.5X.png"));
+ m_playSpeed = 0.5;
+ } else if (m_playSpeed == 0.5) {
+ ui->pbSlow->setIcon(QIcon(":/images/playSlow.png"));
+ m_playSpeed = 1.0;
+ }
+ emit changePlaySpeedSignal(m_playSpeed);
+}
diff --git a/src/videoControl.h b/src/videoControl.h
index 24d9fea..06b695c 100644
--- a/src/videoControl.h
+++ b/src/videoControl.h
@@ -19,9 +19,12 @@ public:
void updateVideoDuration(int duration);
void updateVideoSlider(int currentTime, int duration);
+ void resetVideoSlider();
+
private:
void initIconButton();
QString secondsToHMS(int totalSeconds);
+ void onSliderPressed();
signals:
void startConnectionSignal(QString ip, int port);
void stopConnectionSignal();
@@ -29,6 +32,8 @@ signals:
void changeVideoLayout(int index);
void stopVideoSignal();
+ void seekToVideoSignal(int64_t targetTime);
+ void changePlaySpeedSignal(double speed);
private slots:
void receiveMessageSlots(QString message, int type);
@@ -40,11 +45,26 @@ private slots:
void on_pbStop_clicked();
+ void on_videoSlider_sliderReleased();
+
+ void on_videoSlider_sliderPressed();
+
+ void on_videoSlider_actionTriggered(int action);
+
+ void on_pbFast_clicked();
+
+ void on_pbSlow_clicked();
+
private:
Ui::VideoControl *ui;
QString m_remoteIP;
int m_remotePort;
+
+ bool m_bSliderPressed = false;
+ int m_sliderPressedValue;
+
+ double m_playSpeed;
};
#endif // VIDEOCONTROL_H