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