From e89f8f2fe7d26174195c3ab7a427c419e35165eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=AE=E7=94=9F=E8=8B=A5=E6=A2=A6?= <1070753498@qq.com> Date: Thu, 24 Aug 2023 18:59:47 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BB=BB=E5=8A=A1=E9=98=9F?= =?UTF-8?q?=E5=88=97=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ffmpeg/CMakeLists.txt | 2 + ffmpeg/audiodecoder.cpp | 25 ++++----- ffmpeg/audiodecoder.h | 4 +- ffmpeg/decoder.h | 40 ++++++-------- ffmpeg/decoderaudioframe.cpp | 89 +++++++++++++++--------------- ffmpeg/decoderaudioframe.h | 5 +- ffmpeg/decodersubtitleframe.cc | 27 ++------- ffmpeg/decodersubtitleframe.hpp | 3 +- ffmpeg/decodervideoframe.cpp | 25 ++------- ffmpeg/decodervideoframe.h | 3 +- ffmpeg/event.cc | 38 +++++++++++++ ffmpeg/event.hpp | 39 +++++++++++++ ffmpeg/ffmpeg.pro | 2 + ffmpeg/frame.hpp | 3 + ffmpeg/packet.h | 2 + ffmpeg/player.cpp | 35 +++++------- ffmpeg/subtitle.h | 2 + ffmpeg/subtitledecoder.cpp | 27 ++++----- ffmpeg/subtitledecoder.h | 4 +- ffmpeg/videodecoder.cpp | 25 ++++----- ffmpeg/videodecoder.h | 4 +- utils/CMakeLists.txt | 2 +- utils/boundedblockingqueue.hpp | 97 +++++++++++++++++++++++++++++++++ utils/taskqueue.h | 96 -------------------------------- utils/utils.pro | 2 +- 25 files changed, 321 insertions(+), 280 deletions(-) create mode 100644 ffmpeg/event.cc create mode 100644 ffmpeg/event.hpp create mode 100644 utils/boundedblockingqueue.hpp delete mode 100644 utils/taskqueue.h diff --git a/ffmpeg/CMakeLists.txt b/ffmpeg/CMakeLists.txt index 1786ee4..49ea8dc 100644 --- a/ffmpeg/CMakeLists.txt +++ b/ffmpeg/CMakeLists.txt @@ -48,6 +48,8 @@ set(PROJECT_SOURCES decodersubtitleframe.hpp decodervideoframe.cpp decodervideoframe.h + event.cc + event.hpp ffmepg_global.h ffmpegutils.cc ffmpegutils.hpp diff --git a/ffmpeg/audiodecoder.cpp b/ffmpeg/audiodecoder.cpp index 622292b..ffe0de3 100644 --- a/ffmpeg/audiodecoder.cpp +++ b/ffmpeg/audiodecoder.cpp @@ -21,7 +21,7 @@ class AudioDecoder::AudioDecoderPrivate }; AudioDecoder::AudioDecoder(QObject *parent) - : Decoder(parent) + : Decoder(parent) , d_ptr(new AudioDecoderPrivate(this)) { connect(d_ptr->decoderAudioFrame, @@ -30,7 +30,13 @@ AudioDecoder::AudioDecoder(QObject *parent) &AudioDecoder::positionChanged); } -AudioDecoder::~AudioDecoder() {} +AudioDecoder::~AudioDecoder() = default; + +void AudioDecoder::seek(qint64 seekTime) +{ + Decoder::seek(seekTime); + d_ptr->decoderAudioFrame->seek(seekTime); +} void AudioDecoder::pause(bool state) { @@ -52,25 +58,14 @@ void AudioDecoder::runDecoder() d_ptr->decoderAudioFrame->startDecoder(m_formatContext, m_contextInfo); while (m_runing) { - if (m_seek) { - clear(); - d_ptr->decoderAudioFrame->seek(m_seekTime, m_latchPtr.lock()); - seekFinish(); - } - - QScopedPointer packetPtr(m_queue.dequeue()); + auto packetPtr(m_queue.take()); if (packetPtr.isNull()) { - msleep(Sleep_Queue_Empty_Milliseconds); continue; } auto frames(m_contextInfo->decodeFrame(packetPtr.data())); for (auto frame : frames) { Ffmpeg::calculateTime(frame, m_contextInfo, m_formatContext); - d_ptr->decoderAudioFrame->append(frame); - } - - while (m_runing && d_ptr->decoderAudioFrame->size() > Max_Frame_Size && !m_seek) { - msleep(Sleep_Queue_Full_Milliseconds); + d_ptr->decoderAudioFrame->append(FramePtr(frame)); } } while (m_runing && d_ptr->decoderAudioFrame->size() != 0) { diff --git a/ffmpeg/audiodecoder.h b/ffmpeg/audiodecoder.h index 88de209..a99bedb 100644 --- a/ffmpeg/audiodecoder.h +++ b/ffmpeg/audiodecoder.h @@ -6,13 +6,15 @@ namespace Ffmpeg { -class AudioDecoder : public Decoder +class AudioDecoder : public Decoder { Q_OBJECT public: explicit AudioDecoder(QObject *parent = nullptr); ~AudioDecoder() override; + void seek(qint64 seekTime) override; + void pause(bool state) override; void setVolume(qreal volume); diff --git a/ffmpeg/decoder.h b/ffmpeg/decoder.h index e404c86..9234fe3 100644 --- a/ffmpeg/decoder.h +++ b/ffmpeg/decoder.h @@ -4,21 +4,20 @@ #include #include -#include -#include +#include #include "avcontextinfo.h" #include "codeccontext.h" #include "formatcontext.h" #define Sleep_Queue_Full_Milliseconds 50 -#define Sleep_Queue_Empty_Milliseconds 10 -#define Max_Frame_Size 25 #define UnWait_Microseconds (50 * 1000) #define Drop_Microseconds (-100 * 1000) namespace Ffmpeg { +static const auto g_frameQueueSize = 25; + void calculateTime(Frame *frame, AVContextInfo *contextInfo, FormatContext *formatContext); void calculateTime(Packet *packet, AVContextInfo *contextInfo); @@ -34,6 +33,7 @@ class Decoder : public QThread public: explicit Decoder(QObject *parent = nullptr) : QThread(parent) + , m_queue(g_frameQueueSize) {} ~Decoder() override { stopDecoder(); } @@ -49,37 +49,37 @@ class Decoder : public QThread virtual void stopDecoder() { m_runing = false; + clear(); + wakeup(); if (isRunning()) { quit(); wait(); } - clear(); m_seekTime = 0; } - void append(const T &t) { m_queue.enqueue(t); } + void append(const T &t) { m_queue.put(t); } + void append(const T &&t) { m_queue.put(t); } - auto size() -> int { return m_queue.size(); } + auto size() -> size_t { return m_queue.size(); } - void clear() { m_queue.clearPoints(); } + void clear() { m_queue.clear(); } + + void wakeup() { m_queue.put(T()); } virtual void pause(bool state) = 0; - void seek(qint64 seekTime, QSharedPointer latchPtr) // microsecond + virtual void seek(qint64 seekTime) // microsecond { + clear(); + m_seekTime = seekTime; assertVaild(); if (!m_contextInfo->isIndexVaild()) { - latchPtr->countDown(); return; } - m_seek = true; - m_seekTime = seekTime; - m_latchPtr = latchPtr; pause(false); } - auto isSeek() -> bool { return m_seek; } - protected: virtual void runDecoder() = 0; @@ -92,21 +92,17 @@ class Decoder : public QThread runDecoder(); } - void seekFinish() { m_seek = false; } - void assertVaild() { Q_ASSERT(m_formatContext != nullptr); Q_ASSERT(m_contextInfo != nullptr); } - Utils::Queue m_queue; + Utils::BoundedBlockingQueue m_queue; AVContextInfo *m_contextInfo = nullptr; FormatContext *m_formatContext = nullptr; - volatile bool m_runing = true; - volatile bool m_seek = false; - qint64 m_seekTime = 0; // seconds - QWeakPointer m_latchPtr; + std::atomic_bool m_runing = true; + qint64 m_seekTime = 0; // microsecond }; } // namespace Ffmpeg diff --git a/ffmpeg/decoderaudioframe.cpp b/ffmpeg/decoderaudioframe.cpp index 9de85ce..62d16ad 100644 --- a/ffmpeg/decoderaudioframe.cpp +++ b/ffmpeg/decoderaudioframe.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include namespace Ffmpeg { @@ -25,21 +26,22 @@ class DecoderAudioFrame::DecoderAudioFramePrivate QIODevice *audioDevice = nullptr; qreal volume = 0.5; - volatile bool pause = false; + std::atomic_bool pause = false; double speed = 0; + qint64 pauseTime; QMutex mutex; QWaitCondition waitCondition; qint64 seekTime = 0; // milliseconds - volatile bool firstSeekFrame = false; + std::atomic_bool firstSeekFrame = false; QScopedPointer mediaDevicesPtr; - volatile bool audioOutputsChanged = false; - volatile bool isLocalFile = true; + std::atomic_bool audioOutputsChanged = false; + std::atomic_bool isLocalFile = true; }; DecoderAudioFrame::DecoderAudioFrame(QObject *parent) - : Decoder(parent) + : Decoder(parent) , d_ptr(new DecoderAudioFramePrivate(this)) { buildConnect(); @@ -50,7 +52,15 @@ DecoderAudioFrame::~DecoderAudioFrame() = default; void DecoderAudioFrame::stopDecoder() { pause(false); - Decoder::stopDecoder(); + Decoder::stopDecoder(); +} + +void DecoderAudioFrame::seek(qint64 seekTime) +{ + Decoder::seek(seekTime); + setMediaClock(m_seekTime); + d_ptr->firstSeekFrame = true; + d_ptr->pauseTime = 0; } void DecoderAudioFrame::pause(bool state) @@ -112,22 +122,21 @@ void DecoderAudioFrame::onAudioOutputsChanged() void DecoderAudioFrame::runDecoder() { + quint64 dropNum = 0; QAudioDevice audioDevice(QMediaDevices::defaultAudioOutput()); auto format = resetAudioOutput(); d_ptr->seekTime = 0; + d_ptr->pauseTime = 0; AudioFrameConverter audioConverter(m_contextInfo->codecCtx(), format); QElapsedTimer timer; if (d_ptr->isLocalFile) { // 音频播放依赖外部时钟,适用于本地文件播放 - qint64 pauseTime = 0; while (m_runing) { checkDefaultAudioOutput(audioDevice); - checkPause(pauseTime); - checkSeek(pauseTime); - checkSpeed(timer, pauseTime); + checkPause(d_ptr->pauseTime); + checkSpeed(timer, d_ptr->pauseTime); - QScopedPointer framePtr(m_queue.dequeue()); + auto framePtr(m_queue.take()); if (framePtr.isNull()) { - msleep(Sleep_Queue_Empty_Milliseconds); continue; } if (!timer.isValid()) { @@ -144,17 +153,24 @@ void DecoderAudioFrame::runDecoder() } auto audioBuf = audioConverter.convert(framePtr.data()); - auto diff = pts - d_ptr->seekTime - (timer.elapsed() - pauseTime) * d_ptr->speed * 1000; + auto diff = pts - d_ptr->seekTime + - (timer.elapsed() - d_ptr->pauseTime) * d_ptr->speed * 1000; + // qDebug() << "PTS:" + // << QTime::fromMSecsSinceStartOfDay(pts / 1000).toString("hh:mm:ss.zzz") + // << "SeekTime:" + // << QTime::fromMSecsSinceStartOfDay(d_ptr->seekTime / 1000) + // .toString("hh:mm:ss.zzz") + // << "Diff:" << diff; { auto cleanup = qScopeGuard([&] { setMediaClock(pts); emit positionChanged(pts); }); - if (qAbs(diff) > UnWait_Microseconds && !m_seek && !d_ptr->pause) { + if (qAbs(diff) > UnWait_Microseconds && !d_ptr->pause) { QMutexLocker locker(&d_ptr->mutex); - d_ptr->waitCondition.wait(&d_ptr->mutex, diff / 1000); - //msleep(diff); + d_ptr->waitCondition.wait(&d_ptr->mutex, qAbs(diff) / 1000); } else if (d_ptr->speed > 1.0) { + dropNum++; continue; // speed > 1.0 drop } } @@ -165,25 +181,28 @@ void DecoderAudioFrame::runDecoder() qint64 lastPts = 0; while (m_runing) { checkDefaultAudioOutput(audioDevice); - qint64 pauseTime = 0; - checkPause(pauseTime); - checkSeek(lastPts); + checkPause(d_ptr->pauseTime); checkSpeed(timer, lastPts); - QScopedPointer framePtr(m_queue.dequeue()); + auto framePtr(m_queue.take()); if (framePtr.isNull()) { - msleep(Sleep_Queue_Empty_Milliseconds); continue; } auto pts = framePtr->pts(); if (m_seekTime > pts) { continue; } + if (d_ptr->firstSeekFrame) { + d_ptr->seekTime = pts; + d_ptr->firstSeekFrame = false; + lastPts = 0; + } - QByteArray audioBuf = audioConverter.convert(framePtr.data()); + auto audioBuf = audioConverter.convert(framePtr.data()); double diff = 0; if (lastPts > 0) { - diff = pts - lastPts - (durationTimer.elapsed() - pauseTime) * d_ptr->speed * 1000; + diff = pts - lastPts + - (durationTimer.elapsed() - d_ptr->pauseTime) * d_ptr->speed * 1000; } lastPts = pts; { @@ -192,11 +211,11 @@ void DecoderAudioFrame::runDecoder() setMediaClock(pts); emit positionChanged(pts); }); - if (diff > 0 && !m_seek && !d_ptr->pause) { + if (diff > 0 && !d_ptr->pause) { QMutexLocker locker(&d_ptr->mutex); d_ptr->waitCondition.wait(&d_ptr->mutex, diff / 1000); - //msleep(diff); } else if (d_ptr->speed > 1.0) { + dropNum++; continue; // speed > 1.0 drop } } @@ -204,6 +223,7 @@ void DecoderAudioFrame::runDecoder() } } d_ptr->audioSinkPtr.reset(); + qInfo() << "Audio Drop Num:" << dropNum; } void DecoderAudioFrame::buildConnect() @@ -245,23 +265,6 @@ void DecoderAudioFrame::checkPause(qint64 &pauseTime) } } -void DecoderAudioFrame::checkSeek(qint64 &pauseTime) -{ - if (!m_seek) { - return; - } - clear(); - pauseTime = 0; - setMediaClock(m_seekTime); - d_ptr->seekTime = m_seekTime * 1000; - auto latchPtr = m_latchPtr.lock(); - if (latchPtr) { - latchPtr->countDown(); - } - seekFinish(); - d_ptr->firstSeekFrame = true; -} - void DecoderAudioFrame::checkSpeed(QElapsedTimer &timer, qint64 &pauseTime) { auto speed = mediaSpeed(); @@ -279,7 +282,7 @@ void DecoderAudioFrame::writeToDevice(QByteArray &audioBuf) if (!d_ptr->audioDevice) { return; } - while (audioBuf.size() > 0 && !m_seek && !d_ptr->pause) { + while (audioBuf.size() > 0 && !d_ptr->pause) { int byteFree = d_ptr->audioSinkPtr->bytesFree(); if (byteFree > 0 && byteFree < audioBuf.size()) { d_ptr->audioDevice->write(audioBuf.data(), byteFree); // Memory leak diff --git a/ffmpeg/decoderaudioframe.h b/ffmpeg/decoderaudioframe.h index 950d963..b7d85d6 100644 --- a/ffmpeg/decoderaudioframe.h +++ b/ffmpeg/decoderaudioframe.h @@ -11,7 +11,7 @@ class QAudioDevice; namespace Ffmpeg { -class DecoderAudioFrame : public Decoder +class DecoderAudioFrame : public Decoder { Q_OBJECT public: @@ -20,6 +20,8 @@ class DecoderAudioFrame : public Decoder void stopDecoder() override; + void seek(qint64 seekTime) override; + void pause(bool state) override; auto isPause() -> bool; @@ -42,7 +44,6 @@ private slots: void checkDefaultAudioOutput(QAudioDevice &audioDevice); void checkPause(qint64 &pauseTime); - void checkSeek(qint64 &pauseTime); void checkSpeed(QElapsedTimer &timer, qint64 &pauseTime); void writeToDevice(QByteArray &audioBuf); diff --git a/ffmpeg/decodersubtitleframe.cc b/ffmpeg/decodersubtitleframe.cc index 23df52d..aa82595 100644 --- a/ffmpeg/decodersubtitleframe.cc +++ b/ffmpeg/decodersubtitleframe.cc @@ -34,7 +34,7 @@ class DecoderSubtitleFrame::DecoderSubtitleFramePrivate }; DecoderSubtitleFrame::DecoderSubtitleFrame(QObject *parent) - : Decoder(parent) + : Decoder(parent) , d_ptr(new DecoderSubtitleFramePrivate(this)) {} @@ -43,7 +43,7 @@ DecoderSubtitleFrame::~DecoderSubtitleFrame() = default; void DecoderSubtitleFrame::stopDecoder() { pause(false); - Decoder::stopDecoder(); + Decoder::stopDecoder(); } void DecoderSubtitleFrame::pause(bool state) @@ -83,11 +83,9 @@ void DecoderSubtitleFrame::runDecoder() quint64 dropNum = 0; while (m_runing) { checkPause(); - checkSeek(assPtr.data()); - QSharedPointer subtitlePtr(m_queue.dequeue()); + auto subtitlePtr(m_queue.take()); if (subtitlePtr.isNull()) { - msleep(Sleep_Queue_Empty_Milliseconds); continue; } subtitlePtr->setVideoResolutionRatio(d_ptr->videoResolutionRatio); @@ -95,6 +93,7 @@ void DecoderSubtitleFrame::runDecoder() auto pts = subtitlePtr->pts(); auto duration = subtitlePtr->duration(); if (m_seekTime > (pts + duration)) { + assPtr->flushASSEvents(); continue; } if (subtitlePtr->type() == Subtitle::Type::ASS) { @@ -107,7 +106,7 @@ void DecoderSubtitleFrame::runDecoder() || (mediaSpeed() > 1.0 && qAbs(difDuration) > UnWait_Microseconds)) { dropNum++; continue; - } else if (diffPts > UnWait_Microseconds && !m_seek && !d_ptr->pause) { + } else if (diffPts > UnWait_Microseconds && !d_ptr->pause) { QMutexLocker locker(&d_ptr->mutex); d_ptr->waitCondition.wait(&d_ptr->mutex, diffPts / 1000); } @@ -115,7 +114,7 @@ void DecoderSubtitleFrame::runDecoder() renderFrame(subtitlePtr); } sws_freeContext(swsContext); - qInfo() << dropNum; + qInfo() << "Subtitle Drop Num:" << dropNum; } void DecoderSubtitleFrame::checkPause() @@ -126,20 +125,6 @@ void DecoderSubtitleFrame::checkPause() } } -void DecoderSubtitleFrame::checkSeek(Ass *ass) -{ - if (!m_seek) { - return; - } - clear(); - ass->flushASSEvents(); - auto latchPtr = m_latchPtr.lock(); - if (latchPtr) { - latchPtr->countDown(); - } - seekFinish(); -} - void DecoderSubtitleFrame::renderFrame(const QSharedPointer &subtitlePtr) { QMutexLocker locker(&d_ptr->mutex_render); diff --git a/ffmpeg/decodersubtitleframe.hpp b/ffmpeg/decodersubtitleframe.hpp index ebdca33..e46933b 100644 --- a/ffmpeg/decodersubtitleframe.hpp +++ b/ffmpeg/decodersubtitleframe.hpp @@ -9,7 +9,7 @@ namespace Ffmpeg { class VideoRender; class Ass; -class DecoderSubtitleFrame : public Decoder +class DecoderSubtitleFrame : public Decoder { public: explicit DecoderSubtitleFrame(QObject *parent = nullptr); @@ -28,7 +28,6 @@ class DecoderSubtitleFrame : public Decoder private: void checkPause(); - void checkSeek(Ass *ass); void renderFrame(const QSharedPointer &subtitlePtr); class DecoderSubtitleFramePrivate; diff --git a/ffmpeg/decodervideoframe.cpp b/ffmpeg/decodervideoframe.cpp index 0345239..8f2a20a 100644 --- a/ffmpeg/decodervideoframe.cpp +++ b/ffmpeg/decodervideoframe.cpp @@ -25,7 +25,7 @@ class DecoderVideoFrame::DecoderVideoFramePrivate }; DecoderVideoFrame::DecoderVideoFrame(QObject *parent) - : Decoder(parent) + : Decoder(parent) , d_ptr(new DecoderVideoFramePrivate(this)) {} @@ -34,7 +34,7 @@ DecoderVideoFrame::~DecoderVideoFrame() {} void DecoderVideoFrame::stopDecoder() { pause(false); - Decoder::stopDecoder(); + Decoder::stopDecoder(); } void DecoderVideoFrame::pause(bool state) @@ -63,11 +63,9 @@ void DecoderVideoFrame::runDecoder() quint64 dropNum = 0; while (m_runing) { checkPause(); - checkSeek(); - QSharedPointer framePtr(m_queue.dequeue()); + auto framePtr(m_queue.take()); if (framePtr.isNull()) { - msleep(Sleep_Queue_Empty_Milliseconds); continue; } auto pts = framePtr->pts(); @@ -78,14 +76,14 @@ void DecoderVideoFrame::runDecoder() if (diff < Drop_Microseconds || (mediaSpeed() > 1.0 && qAbs(diff) > UnWait_Microseconds)) { dropNum++; continue; - } else if (diff > UnWait_Microseconds && !m_seek && !d_ptr->pause) { + } else if (diff > UnWait_Microseconds && !d_ptr->pause) { QMutexLocker locker(&d_ptr->mutex); d_ptr->waitCondition.wait(&d_ptr->mutex, diff / 1000); } // 略慢于音频 renderFrame(framePtr); } - qInfo() << dropNum; + qInfo() << "Video Drop Num:" << dropNum; } void DecoderVideoFrame::checkPause() @@ -96,19 +94,6 @@ void DecoderVideoFrame::checkPause() } } -void DecoderVideoFrame::checkSeek() -{ - if (!m_seek) { - return; - } - clear(); - auto latchPtr = m_latchPtr.lock(); - if (latchPtr) { - latchPtr->countDown(); - } - seekFinish(); -} - void DecoderVideoFrame::renderFrame(const QSharedPointer &framePtr) { QMutexLocker locker(&d_ptr->mutex_render); diff --git a/ffmpeg/decodervideoframe.h b/ffmpeg/decodervideoframe.h index 1cf437e..3693ddb 100644 --- a/ffmpeg/decodervideoframe.h +++ b/ffmpeg/decodervideoframe.h @@ -8,7 +8,7 @@ namespace Ffmpeg { class VideoRender; -class DecoderVideoFrame : public Decoder +class DecoderVideoFrame : public Decoder { public: explicit DecoderVideoFrame(QObject *parent = nullptr); @@ -25,7 +25,6 @@ class DecoderVideoFrame : public Decoder private: void checkPause(); - void checkSeek(); void renderFrame(const QSharedPointer &framePtr); class DecoderVideoFramePrivate; diff --git a/ffmpeg/event.cc b/ffmpeg/event.cc new file mode 100644 index 0000000..96a8bc0 --- /dev/null +++ b/ffmpeg/event.cc @@ -0,0 +1,38 @@ +#include "event.hpp" + +namespace Ffmpeg { + +class Event::EventPrivate +{ +public: + explicit EventPrivate(Event *q) + : q_ptr(q) + {} + + Event *q_ptr; + + EventType type; + QVariantList args; +}; + +Event::Event(EventType type, const QVariantList &args, QObject *parent) + : QObject(parent) + , d_ptr(new EventPrivate(this)) +{ + d_ptr->type = type; + d_ptr->args = std::move(args); +} + +Event::~Event() = default; + +auto Event::type() const -> EventType +{ + return d_ptr->type; +} + +auto Event::args() const -> QVariantList +{ + return d_ptr->args; +} + +} // namespace Ffmpeg diff --git a/ffmpeg/event.hpp b/ffmpeg/event.hpp new file mode 100644 index 0000000..516b34e --- /dev/null +++ b/ffmpeg/event.hpp @@ -0,0 +1,39 @@ +#pragma once + +#include +#include + +namespace Ffmpeg { + +class Event : public QObject +{ +public: + enum EventType { + None, + OpenMedia, + Seek, + Pause, + Stop, + Volume, + Speed, + AudioTrack, + SubtitleTrack, + VideoRenders, + UseGpuDecode, + }; + Q_ENUM(EventType); + + explicit Event(EventType type, const QVariantList &args = {}, QObject *parent = nullptr); + ~Event() override; + + [[nodiscard]] auto type() const -> EventType; + [[nodiscard]] auto args() const -> QVariantList; + +private: + class EventPrivate; + QScopedPointer d_ptr; +}; + +using EventPtr = QSharedPointer; + +} // namespace Ffmpeg diff --git a/ffmpeg/ffmpeg.pro b/ffmpeg/ffmpeg.pro index 2ad8716..acc70bd 100644 --- a/ffmpeg/ffmpeg.pro +++ b/ffmpeg/ffmpeg.pro @@ -24,6 +24,7 @@ SOURCES += \ decoderaudioframe.cpp \ decodersubtitleframe.cc \ decodervideoframe.cpp \ + event.cc \ ffmpegutils.cc \ formatcontext.cpp \ frame.cc \ @@ -49,6 +50,7 @@ HEADERS += \ decoderaudioframe.h \ decodersubtitleframe.hpp \ decodervideoframe.h \ + event.hpp \ ffmepg_global.h \ ffmpegutils.hpp \ formatcontext.h \ diff --git a/ffmpeg/frame.hpp b/ffmpeg/frame.hpp index 057ce67..aa8b62d 100644 --- a/ffmpeg/frame.hpp +++ b/ffmpeg/frame.hpp @@ -3,6 +3,7 @@ #include "ffmepg_global.h" #include +#include extern "C" { #include @@ -57,4 +58,6 @@ class FFMPEG_EXPORT Frame QScopedPointer d_ptr; }; +using FramePtr = QSharedPointer; + } // namespace Ffmpeg diff --git a/ffmpeg/packet.h b/ffmpeg/packet.h index acc5551..f357bce 100644 --- a/ffmpeg/packet.h +++ b/ffmpeg/packet.h @@ -45,6 +45,8 @@ class FFMPEG_EXPORT Packet QScopedPointer d_ptr; }; +using PacketPtr = QSharedPointer; + } // namespace Ffmpeg #endif // PACKET_H diff --git a/ffmpeg/player.cpp b/ffmpeg/player.cpp index 9867876..253b6b3 100644 --- a/ffmpeg/player.cpp +++ b/ffmpeg/player.cpp @@ -49,13 +49,13 @@ class Player::PlayerPrivate SubtitleDecoder *subtitleDecoder; QString filepath; - volatile bool isopen = true; - volatile bool runing = true; - volatile bool seek = false; + std::atomic_bool isopen = true; + std::atomic_bool runing = true; + std::atomic_bool seek = false; qint64 seekTime = 0; // seconds bool gpuDecode = false; - volatile Player::MediaState mediaState = Player::MediaState::StoppedState; + std::atomic mediaState = Player::MediaState::StoppedState; QVector videoRenders = {}; }; @@ -302,30 +302,25 @@ void Player::playVideo() while (d_ptr->runing) { checkSeek(); - std::unique_ptr packetPtr(new Packet); - if (!d_ptr->formatCtx->readFrame(packetPtr.get())) { + PacketPtr packetPtr(new Packet); + if (!d_ptr->formatCtx->readFrame(packetPtr.data())) { break; } calculateSpeed(elapsedTimer, readSize, packetPtr->avPacket()->size); auto stream_index = packetPtr->streamIndex(); - if (!d_ptr->formatCtx->checkPktPlayRange(packetPtr.get())) { + if (!d_ptr->formatCtx->checkPktPlayRange(packetPtr.data())) { } else if (d_ptr->audioInfo->isIndexVaild() && stream_index == d_ptr->audioInfo->index()) { // 如果是音频数据 - d_ptr->audioDecoder->append(packetPtr.release()); + d_ptr->audioDecoder->append(packetPtr); } else if (d_ptr->videoInfo->isIndexVaild() && stream_index == d_ptr->videoInfo->index() && !(d_ptr->videoInfo->stream()->disposition & AV_DISPOSITION_ATTACHED_PIC)) { // 如果是视频数据 - d_ptr->videoDecoder->append(packetPtr.release()); + d_ptr->videoDecoder->append(packetPtr); } else if (d_ptr->subtitleInfo->isIndexVaild() - && stream_index == d_ptr->subtitleInfo->index()) { - d_ptr->subtitleDecoder->append(packetPtr.release()); - } - while (d_ptr->runing && !d_ptr->seek - && (d_ptr->videoDecoder->size() > Max_Frame_Size - || d_ptr->audioDecoder->size() > Max_Frame_Size)) { - msleep(Sleep_Queue_Full_Milliseconds); + && stream_index == d_ptr->subtitleInfo->index()) { // 如果是字幕数据 + d_ptr->subtitleDecoder->append(packetPtr); } } while (d_ptr->runing && (d_ptr->videoDecoder->size() > 0 || d_ptr->audioDecoder->size() > 0)) { @@ -346,11 +341,9 @@ void Player::checkSeek() QElapsedTimer timer; timer.start(); - QSharedPointer latchPtr(new Utils::CountDownLatch(3)); - d_ptr->videoDecoder->seek(d_ptr->seekTime, latchPtr); - d_ptr->audioDecoder->seek(d_ptr->seekTime, latchPtr); - d_ptr->subtitleDecoder->seek(d_ptr->seekTime, latchPtr); - latchPtr->wait(); + d_ptr->videoDecoder->seek(d_ptr->seekTime); + d_ptr->audioDecoder->seek(d_ptr->seekTime); + d_ptr->subtitleDecoder->seek(d_ptr->seekTime); d_ptr->formatCtx->seek(d_ptr->seekTime); if (d_ptr->videoInfo->isIndexVaild()) { d_ptr->videoInfo->codecCtx()->flush(); diff --git a/ffmpeg/subtitle.h b/ffmpeg/subtitle.h index 9165a3c..9babf24 100644 --- a/ffmpeg/subtitle.h +++ b/ffmpeg/subtitle.h @@ -49,6 +49,8 @@ class FFMPEG_EXPORT Subtitle : public QObject QScopedPointer d_ptr; }; +using SubtitlePtr = QSharedPointer; + } // namespace Ffmpeg #endif // SUBTITLE_H diff --git a/ffmpeg/subtitledecoder.cpp b/ffmpeg/subtitledecoder.cpp index f28d354..b5474a3 100644 --- a/ffmpeg/subtitledecoder.cpp +++ b/ffmpeg/subtitledecoder.cpp @@ -23,12 +23,18 @@ class SubtitleDecoder::SubtitleDecoderPrivate }; SubtitleDecoder::SubtitleDecoder(QObject *parent) - : Decoder(parent) + : Decoder(parent) , d_ptr(new SubtitleDecoderPrivate(this)) {} SubtitleDecoder::~SubtitleDecoder() = default; +void SubtitleDecoder::seek(qint64 seekTime) +{ + Decoder::seek(seekTime); + d_ptr->decoderSubtitleFrame->seek(seekTime); +} + void SubtitleDecoder::pause(bool state) { d_ptr->decoderSubtitleFrame->pause(state); @@ -49,20 +55,13 @@ void SubtitleDecoder::runDecoder() d_ptr->decoderSubtitleFrame->startDecoder(m_formatContext, m_contextInfo); while (m_runing) { - if (m_seek) { - clear(); - d_ptr->decoderSubtitleFrame->seek(m_seekTime, m_latchPtr.lock()); - seekFinish(); - } - - QScopedPointer packetPtr(m_queue.dequeue()); + auto packetPtr(m_queue.take()); if (packetPtr.isNull()) { - msleep(Sleep_Queue_Empty_Milliseconds); continue; } //qDebug() << "packet ass :" << QString::fromUtf8(packetPtr->avPacket()->data); - std::unique_ptr subtitlePtr(new Subtitle); - if (!m_contextInfo->decodeSubtitle2(subtitlePtr.get(), packetPtr.data())) { + QSharedPointer subtitlePtr(new Subtitle); + if (!m_contextInfo->decodeSubtitle2(subtitlePtr.data(), packetPtr.data())) { continue; } @@ -71,11 +70,7 @@ void SubtitleDecoder::runDecoder() packetPtr->duration(), (const char *) packetPtr->avPacket()->data); - d_ptr->decoderSubtitleFrame->append(subtitlePtr.release()); - - while (m_runing && d_ptr->decoderSubtitleFrame->size() > Max_Frame_Size && !m_seek) { - msleep(Sleep_Queue_Full_Milliseconds); - } + d_ptr->decoderSubtitleFrame->append(subtitlePtr); } while (m_runing && d_ptr->decoderSubtitleFrame->size() != 0) { msleep(Sleep_Queue_Full_Milliseconds); diff --git a/ffmpeg/subtitledecoder.h b/ffmpeg/subtitledecoder.h index 02e41cf..8b9f582 100644 --- a/ffmpeg/subtitledecoder.h +++ b/ffmpeg/subtitledecoder.h @@ -8,12 +8,14 @@ namespace Ffmpeg { class VideoRender; -class SubtitleDecoder : public Decoder +class SubtitleDecoder : public Decoder { public: explicit SubtitleDecoder(QObject *parent = nullptr); ~SubtitleDecoder(); + void seek(qint64 seekTime) override; + void pause(bool state) override; void setVideoResolutionRatio(const QSize &size); diff --git a/ffmpeg/videodecoder.cpp b/ffmpeg/videodecoder.cpp index 5a70c89..3cda88c 100644 --- a/ffmpeg/videodecoder.cpp +++ b/ffmpeg/videodecoder.cpp @@ -22,11 +22,17 @@ class VideoDecoder::VideoDecoderPrivate }; VideoDecoder::VideoDecoder(QObject *parent) - : Decoder(parent) + : Decoder(parent) , d_ptr(new VideoDecoderPrivate(this)) {} -VideoDecoder::~VideoDecoder() {} +VideoDecoder::~VideoDecoder() = default; + +void VideoDecoder::seek(qint64 seekTime) +{ + Decoder::seek(seekTime); + d_ptr->decoderVideoFrame->seek(seekTime); +} void VideoDecoder::pause(bool state) { @@ -43,25 +49,14 @@ void VideoDecoder::runDecoder() d_ptr->decoderVideoFrame->startDecoder(m_formatContext, m_contextInfo); while (m_runing) { - if (m_seek) { - clear(); - d_ptr->decoderVideoFrame->seek(m_seekTime, m_latchPtr.lock()); - seekFinish(); - } - - QScopedPointer packetPtr(m_queue.dequeue()); + auto packetPtr(m_queue.take()); if (packetPtr.isNull()) { - msleep(Sleep_Queue_Empty_Milliseconds); continue; } auto frames(m_contextInfo->decodeFrame(packetPtr.data())); for (auto frame : frames) { Ffmpeg::calculateTime(frame, m_contextInfo, m_formatContext); - d_ptr->decoderVideoFrame->append(frame); - } - - while (m_runing && d_ptr->decoderVideoFrame->size() > Max_Frame_Size && !m_seek) { - msleep(Sleep_Queue_Full_Milliseconds); + d_ptr->decoderVideoFrame->append(FramePtr(frame)); } } while (m_runing && d_ptr->decoderVideoFrame->size() != 0) { diff --git a/ffmpeg/videodecoder.h b/ffmpeg/videodecoder.h index f624bfe..5c7601d 100644 --- a/ffmpeg/videodecoder.h +++ b/ffmpeg/videodecoder.h @@ -8,12 +8,14 @@ namespace Ffmpeg { class VideoRender; -class VideoDecoder : public Decoder +class VideoDecoder : public Decoder { public: explicit VideoDecoder(QObject *parent = nullptr); ~VideoDecoder(); + void seek(qint64 seekTime) override; + void pause(bool state) override; void setVideoRenders(QVector videoRenders); diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt index bf24cb2..1458132 100644 --- a/utils/CMakeLists.txt +++ b/utils/CMakeLists.txt @@ -1,4 +1,5 @@ set(PROJECT_SOURCES + boundedblockingqueue.hpp countdownlatch.cc countdownlatch.hpp fps.cc @@ -9,7 +10,6 @@ set(PROJECT_SOURCES logasync.h osspecificaspects.h singleton.hpp - taskqueue.h utils_global.h utils.cpp utils.h) diff --git a/utils/boundedblockingqueue.hpp b/utils/boundedblockingqueue.hpp new file mode 100644 index 0000000..0687392 --- /dev/null +++ b/utils/boundedblockingqueue.hpp @@ -0,0 +1,97 @@ +#pragma once + +#include +#include +#include + +namespace Utils { + +template +class BoundedBlockingQueue +{ + Q_DISABLE_COPY_MOVE(BoundedBlockingQueue); + +public: + using ClearCallback = std::function; + + explicit BoundedBlockingQueue(int maxSize) + : m_maxSize(maxSize) + {} + + void put(const T &x) + { + QMutexLocker locker(&m_mutex); + while (m_queue.size() >= m_maxSize) { + m_notFull.wait(&m_mutex); + } + m_queue.push(x); + m_notEmpty.wakeOne(); + } + + void put(T &&x) + { + QMutexLocker locker(&m_mutex); + while (m_queue.size() >= m_maxSize) { + m_notFull.wait(&m_mutex); + } + m_queue.push(std::move(x)); + m_notEmpty.wakeOne(); + } + + auto take() -> T + { + QMutexLocker locker(&m_mutex); + while (m_queue.empty()) { + m_notEmpty.wait(&m_mutex); + } + T front(std::move(m_queue.front())); + m_queue.pop(); + m_notFull.wakeOne(); + return front; + } + + void clear(ClearCallback callback = nullptr) + { + QMutexLocker locker(&m_mutex); + while (!m_queue.empty()) { + if (callback != nullptr) { + callback(m_queue.front()); + } + m_queue.pop(); + } + m_notFull.wakeAll(); + } + + [[nodiscard]] auto empty() const -> bool + { + QMutexLocker locker(&m_mutex); + return m_queue.empty(); + } + + [[nodiscard]] auto full() const -> bool + { + QMutexLocker locker(&m_mutex); + return m_queue.size() >= m_maxSize; + } + + [[nodiscard]] size_t size() const + { + QMutexLocker locker(&m_mutex); + return m_queue.size(); + } + + [[nodiscard]] size_t maxSize() const + { + QMutexLocker locker(&m_mutex); + return m_maxSize; + } + +private: + mutable QMutex m_mutex; + QWaitCondition m_notEmpty; + QWaitCondition m_notFull; + std::queue m_queue; + int m_maxSize; +}; + +} // namespace Utils diff --git a/utils/taskqueue.h b/utils/taskqueue.h deleted file mode 100644 index c16aa41..0000000 --- a/utils/taskqueue.h +++ /dev/null @@ -1,96 +0,0 @@ -#ifndef TASKQUEUE_H -#define TASKQUEUE_H - -#include -#include - -namespace Utils { - -/*----------------------------------------------------------------------------/ -/ 线程安全的有界队列 模板 / -/----------------------------------------------------------------------------*/ - -template -class Queue -{ -public: - Queue() - : m_T() - , m_mutex() - , m_maxSize(100) - {} - ~Queue() {} - - auto enqueue(const T &t) -> bool - { - QMutexLocker locker(&m_mutex); - if (m_T.size() >= m_maxSize) { - return false; - } - m_T.enqueue(t); - return true; - } - - auto enqueue(T &&t) -> bool - { - QMutexLocker locker(&m_mutex); - if (m_T.size() >= m_maxSize) { - return false; - } - m_T.enqueue(t); - return true; - } - - auto dequeue() -> T - { - QMutexLocker locker(&m_mutex); - if (!m_T.isEmpty()) { - return m_T.dequeue(); - } - return nullptr; - } - - auto isEmpty() -> bool - { - QMutexLocker locker(&m_mutex); - if (m_T.isEmpty()) { - return true; - } - return false; - } - - void clearPoints() - { - QMutexLocker locker(&m_mutex); - if (m_T.isEmpty()) { - return; - } - qDeleteAll(m_T); - m_T.clear(); - } - - void clear() { m_T.clear(); } - - [[nodiscard]] auto size() const -> int - { - QMutexLocker locker(&m_mutex); - return m_T.size(); - } - - void setMaxSize(const int maxSize) - { - QMutexLocker locker(&m_mutex); - m_maxSize = maxSize; - } - -private: - Q_DISABLE_COPY(Queue) - - QQueue m_T; - mutable QMutex m_mutex; - int m_maxSize; -}; - -} // namespace Utils - -#endif // TASKQUEUE_H diff --git a/utils/utils.pro b/utils/utils.pro index ad1440e..fd1bc3c 100644 --- a/utils/utils.pro +++ b/utils/utils.pro @@ -17,12 +17,12 @@ SOURCES += \ utils.cpp HEADERS += \ + boundedblockingqueue.hpp \ countdownlatch.hpp \ fps.hpp \ hostosinfo.h \ logasync.h \ osspecificaspects.h \ singleton.hpp \ - taskqueue.h \ utils_global.h \ utils.h