zhuizhu 8 bulan lalu
induk
melakukan
2ed12b191c

+ 2 - 0
AvPlayer2/AvPlayer2.pri

@@ -22,6 +22,7 @@ HEADERS += \
     $$PWD/start_play_thread.h \
     $$PWD/stopplay_waiting_thread.h \
     $$PWD/subtitle_decode_thread.h \
+    $$PWD/thread_manager.h \
     $$PWD/version.h \
     $$PWD/video_decode_thread.h \
     $$PWD/video_play_thread.h \
@@ -49,6 +50,7 @@ SOURCES += \
     $$PWD/start_play_thread.cpp \
     $$PWD/stopplay_waiting_thread.cpp \
     $$PWD/subtitle_decode_thread.cpp \
+    $$PWD/thread_manager.cpp \
     $$PWD/video_decode_thread.cpp \
     $$PWD/video_play_thread.cpp \
     $$PWD/video_state.cpp

+ 20 - 13
AvPlayer2/audio_decode_thread.cpp

@@ -8,12 +8,18 @@
 
 #include "audio_decode_thread.h"
 #include "AVPlayer2/playercontroller.h"
+#include <QLoggingCategory>
+Q_LOGGING_CATEGORY(playerControllerAudioDecodeThread, "player.controller.AudioDecodeThread")
 
 AudioDecodeThread::AudioDecodeThread(VideoState* pState)
     : m_pState(pState)
 {}
 
-AudioDecodeThread::~AudioDecodeThread() {}
+AudioDecodeThread::~AudioDecodeThread()
+{
+    qCDebug(playerControllerAudioDecodeThread)
+        << "[AudioDecodeThread] ~AudioDecodeThread, m_pState:" << (void*) m_pState;
+}
 
 void AudioDecodeThread::stop()
 {
@@ -23,10 +29,10 @@ void AudioDecodeThread::stop()
 
 void AudioDecodeThread::run()
 {
-    qCDebug(playerControllerLog) << "[AudioDecodeThread] run start, m_pState:" << (void*) m_pState;
+    qCDebug(playerControllerAudioDecodeThread) << "[AudioDecodeThread] run start, m_pState:" << (void*) m_pState;
     assert(m_pState);
     VideoState* is = m_pState;
-    qCDebug(playerControllerLog) << "[AudioDecodeThread] VideoState* is:" << (void*) is
+    qCDebug(playerControllerAudioDecodeThread) << "[AudioDecodeThread] VideoState* is:" << (void*) is
                                  << ", abort_request:" << is->abort_request;
     AVFrame* frame = av_frame_alloc();
     Frame* af;
@@ -40,29 +46,29 @@ void AudioDecodeThread::run()
     int ret = 0;
 
     if (!frame) {
-        qCWarning(playerControllerLog) << "[AudioDecodeThread] av_frame_alloc failed!";
+        qCWarning(playerControllerAudioDecodeThread) << "[AudioDecodeThread] av_frame_alloc failed!";
         return;
     }
 
     do {
         if (is->abort_request) {
-            qCDebug(playerControllerLog) << "[AudioDecodeThread] abort_request set, exit.";
+            qCDebug(playerControllerAudioDecodeThread) << "[AudioDecodeThread] abort_request set, exit.";
             break;
         }
-        if (m_exit) {
-            qCDebug(playerControllerLog) << "[AudioDecodeThread] m_exit set, exit.";
+        if (m_exit && *m_exit) {
+            qCDebug(playerControllerAudioDecodeThread) << "[AudioDecodeThread] m_exit set, exit.";
             break;
         }
-        qCDebug(playerControllerLog)
+        qCDebug(playerControllerAudioDecodeThread)
             << "[AudioDecodeThread] call decoder_decode_frame, auddec.avctx:"
             << (void*) is->auddec.avctx;
         if ((got_frame = decoder_decode_frame(&is->auddec, frame, nullptr)) < 0) {
-            qCWarning(playerControllerLog)
+            qCWarning(playerControllerAudioDecodeThread)
                 << "[AudioDecodeThread] decoder_decode_frame failed, ret:" << got_frame;
             goto the_end;
         }
         if (got_frame) {
-            qCDebug(playerControllerLog)
+            qCDebug(playerControllerAudioDecodeThread)
                 << "[AudioDecodeThread] got audio frame, pts:" << frame->pts
                 << ", sample_rate:" << frame->sample_rate << ", nb_samples:" << frame->nb_samples;
             tb = AVRational{1, frame->sample_rate};
@@ -139,7 +145,7 @@ void AudioDecodeThread::run()
                 is->auddec.finished = is->auddec.pkt_serial;
 #endif
         } else {
-            qCDebug(playerControllerLog) << "[AudioDecodeThread] no frame decoded, continue.";
+            qCDebug(playerControllerAudioDecodeThread) << "[AudioDecodeThread] no frame decoded, continue.";
         }
     } while (got_frame);
 
@@ -155,7 +161,8 @@ the_end:
 
     av_frame_free(&frame);
     // 可加日志输出
-    qCDebug(playerControllerLog) << "[AudioDecodeThread] run end, abort_request:"
-                                 << is->abort_request << ", m_exit:" << m_exit;
+    qCDebug(playerControllerAudioDecodeThread) << "[AudioDecodeThread] run end, abort_request:"
+                                 << is->abort_request
+                                 << ", m_exit:" << (m_exit ? m_exit->load() : -1);
     return;
 }

+ 22 - 14
AvPlayer2/audio_play_thread.cpp

@@ -9,6 +9,8 @@
 #include "audio_play_thread.h"
 #include "AVPlayer2/playercontroller.h"
 #include <utility>
+#include <QLoggingCategory>
+Q_LOGGING_CATEGORY(playerControllerAudioPlayThread, "player.controller.AudioPlayThread")
 
 #if !NDEBUG
 #define DEBUG_PLAYFILTER 0
@@ -31,10 +33,9 @@ AudioPlayThread::AudioPlayThread(VideoState* pState)
 
 AudioPlayThread::~AudioPlayThread()
 {
+    stop();
     stop_device();
     final_resample_param();
-    stop();
-    join();
 }
 
 void AudioPlayThread::print_device() const
@@ -155,32 +156,36 @@ void AudioPlayThread::play_buf(const uint8_t* buf, int datasize)
 
 void AudioPlayThread::run()
 {
-    qCDebug(playerControllerLog) << "[AudioPlayThread] run start, m_pState:" << (void*)m_pState;
+    qCDebug(playerControllerAudioPlayThread) << "[AudioPlayThread] run start, m_pState:" << (void*) m_pState;
     assert(m_pState);
     VideoState* is = m_pState;
-    qCDebug(playerControllerLog) << "[AudioPlayThread] VideoState* is:" << (void*)is << ", abort_request:" << is->abort_request;
+    qCDebug(playerControllerAudioPlayThread) << "[AudioPlayThread] VideoState* is:" << (void*) is
+                                 << ", abort_request:" << is->abort_request;
     int audio_size;
     int loop_count = 0;
     for (;;) {
-        if (m_exit) {
-            qCDebug(playerControllerLog) << "[AudioPlayThread] m_exit set, exit.";
+        if (m_exit && *m_exit) {
+            qCDebug(playerControllerAudioPlayThread) << "[AudioPlayThread] m_exit set, exit.";
             break;
         }
         if (is->abort_request) {
-            qCDebug(playerControllerLog) << "[AudioPlayThread] abort_request set, exit.";
+            qCDebug(playerControllerAudioPlayThread) << "[AudioPlayThread] abort_request set, exit.";
             break;
         }
         if (is->paused) {
-            qCDebug(playerControllerLog) << "[AudioPlayThread] paused, wait.";
+            qCDebug(playerControllerAudioPlayThread) << "[AudioPlayThread] paused, wait.";
             std::unique_lock<std::mutex> lock(m_mutex);
             m_cv.wait_for(lock, std::chrono::milliseconds(10), [this] { return m_exit && *m_exit; });
             continue;
         }
-        qCDebug(playerControllerLog) << "[AudioPlayThread] call audio_decode_frame, loop:" << loop_count << ", sampq size:" << (is ? is->sampq.size : -1);
+        qCDebug(playerControllerAudioPlayThread)
+            << "[AudioPlayThread] call audio_decode_frame, loop:" << loop_count
+            << ", sampq size:" << (is ? is->sampq.size : -1);
         audio_size = audio_decode_frame(is);
-        qCDebug(playerControllerLog) << "[AudioPlayThread] audio_decode_frame ret:" << audio_size << ", loop:" << loop_count++;
+        qCDebug(playerControllerAudioPlayThread) << "[AudioPlayThread] audio_decode_frame ret:" << audio_size
+                                     << ", loop:" << loop_count++;
         if (audio_size < 0) {
-            qCWarning(playerControllerLog) << "[AudioPlayThread] audio_decode_frame failed, exit.";
+            qCWarning(playerControllerAudioPlayThread) << "[AudioPlayThread] audio_decode_frame failed, exit.";
             break;
         }
         if (!isnan(is->audio_clock)) {
@@ -200,7 +205,8 @@ void AudioPlayThread::run()
             }
         }
     }
-    qCDebug(playerControllerLog) << "[AudioPlayThread] run end, abort_request:" << is->abort_request << ", m_exit:" << m_exit;
+    qCDebug(playerControllerAudioPlayThread) << "[AudioPlayThread] run end, abort_request:" << is->abort_request
+                                 << ", m_exit:" << (m_exit ? m_exit->load() : -1);
 }
 
 int AudioPlayThread::audio_decode_frame(VideoState* is)
@@ -280,7 +286,8 @@ int AudioPlayThread::audio_decode_frame(VideoState* is)
         int len = std::min(data_size, BUFFER_LEN);
         memcpy(data.buffer, buffer_audio, len);
         data.len = len;
-        if (m_onDataVisualReady) m_onDataVisualReady(data);
+        if (m_onDataVisualReady)
+            m_onDataVisualReady(data);
     }
 
     play_buf(buffer_audio, data_size);
@@ -322,7 +329,8 @@ int AudioPlayThread::audio_decode_frame(VideoState* is)
     }
     is->audio_clock_serial = af->serial;
 
-    if (m_onUpdatePlayTime) m_onUpdatePlayTime();
+    if (m_onUpdatePlayTime)
+        m_onUpdatePlayTime();
 
 #if (!NDEBUG && PRINT_PACKETQUEUE_AUDIO_INFO)
     {

+ 4 - 1
AvPlayer2/packets_sync.cpp

@@ -427,7 +427,10 @@ void decoder_abort(Decoder* d, FrameQueue* fq)
     frame_queue_signal(fq);
     // SDL_WaitThread(d->decoder_tid, nullptr);
     // TODO: //
-    // ((ThreadBase*) (d->decoder_tid))->join();
+    ThreadBase* thread = (ThreadBase*) (d->decoder_tid);
+    if (thread && thread->isRunning()) {
+        thread->join();
+    }
     d->decoder_tid = nullptr;
     packet_queue_flush(d->queue);
 }

+ 8 - 11
AvPlayer2/playercontroller.h

@@ -8,14 +8,14 @@
 #include <QObject>
 #include <QThread>
 
-#include <memory>
-#include <thread>
 #include <atomic>
 #include <condition_variable>
 #include <functional>
+#include <memory>
+#include <thread>
 
-#include "AVPlayer2/audio_play_thread.h"
 #include <QLoggingCategory>
+#include "AVPlayer2/audio_play_thread.h"
 Q_DECLARE_LOGGING_CATEGORY(playerControllerLog)
 
 class ReadThread;
@@ -37,12 +37,7 @@ class PlayerController : public QObject
     Q_OBJECT
 
 public:
-    enum class PlayerState {
-        Idle,
-        Initializing,
-        Playing,
-        Stopping
-    };
+    enum class PlayerState { Idle, Initializing, Playing, Stopping };
 
     explicit PlayerController(QWidget* parent = nullptr);
     ~PlayerController();
@@ -101,8 +96,8 @@ signals:
     void waitStopAudioPlayThread();
     void waitStopVideoPlayThread();
 
-    void audioStopped(); // 音频结束
-    void videoStopped(); // 视频结束
+    void audioStopped();     // 音频结束
+    void videoStopped();     // 视频结束
     void playbackFinished(); // 新增:播放自然结束
 
     // 多媒体数据处理
@@ -179,6 +174,8 @@ private:
     std::unique_ptr<StartPlayThread> m_beforePlayThread;
     std::unique_ptr<StopWaitingThread> m_stopPlayWaitingThread;
 
+    std::thread m_eventThread;
+
     QString m_currentFile; // 更清晰的命名
     void checkAndResetState();
 };

+ 40 - 24
AvPlayer2/read_thread.cpp

@@ -8,6 +8,8 @@
 
 #include "read_thread.h"
 #include "AVPlayer2/playercontroller.h"
+#include <QLoggingCategory>
+Q_LOGGING_CATEGORY(playerControllerReadThread, "player.controller.ReadThread")
 
 extern int infinite_buffer;
 extern int64_t start_time;
@@ -16,12 +18,12 @@ static int64_t duration = AV_NOPTS_VALUE;
 ReadThread::ReadThread(VideoState* pState)
     : m_pPlayData(pState)
 {
-    qCDebug(playerControllerLog) << "[ReadThread] constructed, pState:" << (void*)pState;
+    qCDebug(playerControllerReadThread) << "[ReadThread] constructed, pState:" << (void*) pState;
 }
 
 ReadThread::~ReadThread()
 {
-    qCDebug(playerControllerLog) << "[ReadThread] destructed.";
+    qCDebug(playerControllerReadThread) << "[ReadThread] destructed.";
     stop();
     join();
 }
@@ -53,21 +55,22 @@ int ReadThread::loop_read()
     if (!pkt) {
         av_log(nullptr, AV_LOG_FATAL, "Could not allocate packet.\n");
         ret = AVERROR(ENOMEM);
-        qCWarning(playerControllerLog) << "[ReadThread] av_packet_alloc failed!";
+        qCWarning(playerControllerReadThread) << "[ReadThread] av_packet_alloc failed!";
         return ret;
     }
-    qCDebug(playerControllerLog) << "[ReadThread] loop_read start, file:" << (is && is->ic ? is->ic->url : "null");
+    qCDebug(playerControllerReadThread) << "[ReadThread] loop_read start, file:"
+                                 << (is && is->ic ? is->ic->url : "null");
 
     is->read_thread_exit = 0;
 
     for (;;) {
-        if (m_exit) {
-            qCDebug(playerControllerLog) << "[ReadThread] m_exit set, break.";
+        if (m_exit && *m_exit) {
+            qCDebug(playerControllerReadThread) << "[ReadThread] m_exit set, break.";
             break;
         }
 
         if (is->abort_request) {
-            qCDebug(playerControllerLog) << "[ReadThread] abort_request set, break.";
+            qCDebug(playerControllerReadThread) << "[ReadThread] abort_request set, break.";
             break;
         }
 
@@ -80,7 +83,9 @@ int ReadThread::loop_read()
         }
 
         if (is->seek_req) {
-            qCDebug(playerControllerLog) << "[ReadThread] seek_req, seek_pos:" << is->seek_pos << ", seek_rel:" << is->seek_rel << ", seek_flags:" << is->seek_flags;
+            qCDebug(playerControllerReadThread)
+                << "[ReadThread] seek_req, seek_pos:" << is->seek_pos
+                << ", seek_rel:" << is->seek_rel << ", seek_flags:" << is->seek_flags;
             int64_t seek_target = is->seek_pos;
             int64_t seek_min = is->seek_rel > 0 ? seek_target - is->seek_rel + 2 : INT64_MIN;
             int64_t seek_max = is->seek_rel < 0 ? seek_target - is->seek_rel - 2 : INT64_MAX;
@@ -88,9 +93,11 @@ int ReadThread::loop_read()
             ret = avformat_seek_file(is->ic, -1, seek_min, seek_target, seek_max, is->seek_flags);
             if (ret < 0) {
                 av_log(nullptr, AV_LOG_ERROR, "%s: error while seeking\n", is->ic->url);
-                qCWarning(playerControllerLog) << "[ReadThread] avformat_seek_file failed, ret:" << ret;
+                qCWarning(playerControllerReadThread)
+                    << "[ReadThread] avformat_seek_file failed, ret:" << ret;
             } else {
-                qCDebug(playerControllerLog) << "[ReadThread] avformat_seek_file success, flush queues.";
+                qCDebug(playerControllerReadThread)
+                    << "[ReadThread] avformat_seek_file success, flush queues.";
                 if (is->audio_stream >= 0)
                     packet_queue_flush(&is->audioq);
                 if (is->subtitle_stream >= 0)
@@ -111,7 +118,8 @@ int ReadThread::loop_read()
         }
 
         if (is->queue_attachments_req) {
-            qCDebug(playerControllerLog) << "[ReadThread] queue_attachments_req, video_st:" << (void*)is->video_st;
+            qCDebug(playerControllerReadThread)
+                << "[ReadThread] queue_attachments_req, video_st:" << (void*) is->video_st;
             if (is->video_st && is->video_st->disposition & AV_DISPOSITION_ATTACHED_PIC) {
                 ret = av_packet_ref(pkt, &is->video_st->attached_pic);
                 if (ret < 0)
@@ -130,7 +138,7 @@ int ReadThread::loop_read()
                     && stream_has_enough_packets(is->subtitle_st,
                                                  is->subtitle_stream,
                                                  &is->subtitleq)))) {
-            qCDebug(playerControllerLog)
+            qCDebug(playerControllerReadThread)
                 << "[ReadThread] queues full, waiting... audioq:" << is->audioq.size
                 << ", videoq:" << is->videoq.size << ", subtitleq:" << is->subtitleq.size;
             std::unique_lock<std::mutex> lock(m_mutex);
@@ -140,9 +148,11 @@ int ReadThread::loop_read()
 
         ret = av_read_frame(is->ic, pkt);
         if (ret < 0) {
-            qCWarning(playerControllerLog) << "[ReadThread] av_read_frame failed, ret:" << ret << ", eof:" << is->eof << ", pb_error:" << (is->ic->pb ? is->ic->pb->error : 0);
+            qCWarning(playerControllerReadThread)
+                << "[ReadThread] av_read_frame failed, ret:" << ret << ", eof:" << is->eof
+                << ", pb_error:" << (is->ic->pb ? is->ic->pb->error : 0);
             if ((ret == AVERROR_EOF || avio_feof(is->ic->pb)) && !is->eof) {
-                qCDebug(playerControllerLog) << "[ReadThread] EOF reached, send null packets.";
+                qCDebug(playerControllerReadThread) << "[ReadThread] EOF reached, send null packets.";
                 if (is->video_stream >= 0)
                     packet_queue_put_nullpacket(&is->videoq, pkt, is->video_stream);
                 if (is->audio_stream >= 0)
@@ -158,7 +168,7 @@ int ReadThread::loop_read()
                 }
             }
             if (is->ic->pb && is->ic->pb->error) {
-                qCWarning(playerControllerLog) << "[ReadThread] IO error detected.";
+                qCWarning(playerControllerReadThread) << "[ReadThread] IO error detected.";
                 break;
             }
 
@@ -167,7 +177,9 @@ int ReadThread::loop_read()
             continue;
         } else {
             is->eof = 0;
-            qCDebug(playerControllerLog) << "[ReadThread] av_read_frame success, stream_index:" << pkt->stream_index << ", pts:" << pkt->pts;
+            qCDebug(playerControllerReadThread)
+                << "[ReadThread] av_read_frame success, stream_index:" << pkt->stream_index
+                << ", pts:" << pkt->pts;
         }
 
         /* check if packet is in play range specified by user, then queue, otherwise
@@ -182,23 +194,27 @@ int ReadThread::loop_read()
                                              / 1000000
                                    <= ((double) duration / 1000000);
         if (pkt->stream_index == is->audio_stream && pkt_in_play_range) {
-            qCDebug(playerControllerLog) << "[ReadThread] put audio packet, pts:" << pkt->pts;
+            qCDebug(playerControllerReadThread) << "[ReadThread] put audio packet, pts:" << pkt->pts;
             packet_queue_put(&is->audioq, pkt);
         } else if (pkt->stream_index == is->video_stream && pkt_in_play_range
                    && !(is->video_st->disposition & AV_DISPOSITION_ATTACHED_PIC)) {
-            qCDebug(playerControllerLog) << "[ReadThread] put video packet, pts:" << pkt->pts;
+            qCDebug(playerControllerReadThread) << "[ReadThread] put video packet, pts:" << pkt->pts;
             packet_queue_put(&is->videoq, pkt);
         } else if (pkt->stream_index == is->subtitle_stream && pkt_in_play_range) {
-            qCDebug(playerControllerLog) << "[ReadThread] put subtitle packet, pts:" << pkt->pts;
+            qCDebug(playerControllerReadThread) << "[ReadThread] put subtitle packet, pts:" << pkt->pts;
             packet_queue_put(&is->subtitleq, pkt);
         } else {
-            qCDebug(playerControllerLog)
+            qCDebug(playerControllerReadThread)
                 << "[ReadThread] drop packet, stream_index:" << pkt->stream_index;
             av_packet_unref(pkt);
         }
     }
-    qCWarning(playerControllerLog) << "[ReadThread] loop_read about to exit, eof:" << is->eof << ", audioq.size:" << is->audioq.size << ", videoq.size:" << is->videoq.size << ", subtitleq.size:" << is->subtitleq.size << ", abort_request:" << is->abort_request << ", m_exit:" << m_exit;
-    qCDebug(playerControllerLog) << "[ReadThread] loop_read exit, set read_thread_exit = -1";
+    qCWarning(playerControllerReadThread)
+        << "[ReadThread] loop_read about to exit, eof:" << is->eof
+        << ", audioq.size:" << is->audioq.size << ", videoq.size:" << is->videoq.size
+        << ", subtitleq.size:" << is->subtitleq.size << ", abort_request:" << is->abort_request
+        << ", m_exit:" << (m_exit ? m_exit->load() : -1);
+    qCDebug(playerControllerReadThread) << "[ReadThread] loop_read exit, set read_thread_exit = -1";
     is->read_thread_exit = -1;
     av_packet_free(&pkt);
     return 0;
@@ -206,8 +222,8 @@ int ReadThread::loop_read()
 
 void ReadThread::run()
 {
-    qCDebug(playerControllerLog) << "[ReadThread] run start";
+    qCDebug(playerControllerReadThread) << "[ReadThread] run start";
     int ret = loop_read();
-    qCDebug(playerControllerLog) << "[ReadThread] run end, loop_read ret:" << ret;
+    qCDebug(playerControllerReadThread) << "[ReadThread] run end, loop_read ret:" << ret;
     // 可加日志输出
 }

+ 0 - 2
AvPlayer2/read_thread.h

@@ -20,8 +20,6 @@ public:
     void stop() override;
 
 protected:
-    int stream_component_open(int stream_index);
-    void stream_component_close(VideoState* is, int stream_index);
     int loop_read();
     void run() override;
 

+ 4 - 2
AvPlayer2/start_play_thread.cpp

@@ -10,6 +10,8 @@
 #include "start_play_thread.h"
 #include "AVPlayer2/video_state.h"
 #include "playercontroller.h"
+#include <QLoggingCategory>
+Q_LOGGING_CATEGORY(playerControllerStartPlayThread, "player.controller.StartPlayThread")
 
 StartPlayThread::StartPlayThread(PlayerController* playerController)
     : m_playerController(playerController)
@@ -26,7 +28,7 @@ void StartPlayThread::stop()
 void StartPlayThread::run()
 {
     assert(m_playerController);
-    if (m_exit) return;
+    if (m_exit && *m_exit) return;
     bool ret = false;
 
     float vol = 1.0;
@@ -50,5 +52,5 @@ void StartPlayThread::run()
         }
     }
     // 可加回调或日志
-    qCDebug(playerControllerLog) << "[StartPlayThread] run finished, ret=" << ret;
+    qCDebug(playerControllerStartPlayThread) << "[StartPlayThread] run finished, ret=" << ret;
 }

+ 3 - 1
AvPlayer2/stopplay_waiting_thread.cpp

@@ -7,6 +7,8 @@
 // ***********************************************************/
 #include "stopplay_waiting_thread.h"
 #include "playercontroller.h"
+#include <QLoggingCategory>
+Q_LOGGING_CATEGORY(playerControllerStopWaitingThread, "player.controller.StopWaitingThread")
 
 StopWaitingThread::StopWaitingThread(PlayerController* parent, const std::string& file)
     : m_file(file), m_parent(parent)
@@ -26,7 +28,7 @@ void StopWaitingThread::run()
     if (!m_parent) return;
     m_parent->stopPlay();
     while (m_parent->isPlaying()) {
-        if (m_exit) break;
+        if (m_exit && *m_exit) break;
         std::this_thread::sleep_for(std::chrono::milliseconds(2));
     }
     if (!m_exit) {

+ 3 - 1
AvPlayer2/subtitle_decode_thread.cpp

@@ -7,6 +7,8 @@
 // ***********************************************************/
 
 #include "subtitle_decode_thread.h"
+#include <QLoggingCategory>
+Q_LOGGING_CATEGORY(playerControllerSubtitleDecodeThread, "player.controller.SubtitleDecodeThread")
 
 SubtitleDecodeThread::SubtitleDecodeThread(VideoState* pState)
     : m_pState(pState)
@@ -33,7 +35,7 @@ void SubtitleDecodeThread::run()
 
     for (;;)
     {
-        if (m_exit)
+        if (m_exit && *m_exit)
             break;
         if (!(sp = frame_queue_peek_writable(&is->subpq)))
             return;

+ 34 - 14
AvPlayer2/video_decode_thread.cpp

@@ -8,11 +8,13 @@
 // ***********************************************************/
 
 #include "video_decode_thread.h"
-#include "AVPlayer2/playercontroller.h"
+
+#include <QLoggingCategory>
+Q_LOGGING_CATEGORY(playerControllerVideoDecodeThread, "player.controller.VideoDecodeThread")
 
 VideoDecodeThread::VideoDecodeThread(VideoState* pState)
     : m_pState(pState)
-    {}
+{}
 
 VideoDecodeThread::~VideoDecodeThread() {}
 
@@ -24,10 +26,13 @@ void VideoDecodeThread::stop()
 
 void VideoDecodeThread::run()
 {
-    qCDebug(playerControllerLog) << "[VideoDecodeThread] run start, m_pState:" << (void*)m_pState;
+    qCDebug(playerControllerVideoDecodeThread)
+        << "[VideoDecodeThread] run start, m_pState:" << (void*) m_pState;
     assert(m_pState);
     VideoState* is = m_pState;
-    qCDebug(playerControllerLog) << "[VideoDecodeThread] VideoState* is:" << (void*)is << ", abort_request:" << is->abort_request;
+    qCDebug(playerControllerVideoDecodeThread)
+        << "[VideoDecodeThread] VideoState* is:" << (void*) is
+        << ", abort_request:" << is->abort_request;
     AVFrame* frame = av_frame_alloc();
     AVFrame* sw_frame = av_frame_alloc();
     AVFrame* tmp_frame = nullptr;
@@ -37,31 +42,44 @@ void VideoDecodeThread::run()
     AVRational tb = is->video_st->time_base;
     AVRational frame_rate = av_guess_frame_rate(is->ic, is->video_st, nullptr);
     if (!frame) {
-        qCWarning(playerControllerLog) << "[VideoDecodeThread] av_frame_alloc failed!";
+        qCWarning(playerControllerVideoDecodeThread)
+            << "[VideoDecodeThread] av_frame_alloc failed!";
         return;
     }
     int loop_count = 0;
     for (;;) {
-        if (m_exit) {
-            qCDebug(playerControllerLog) << "[VideoDecodeThread] m_exit set, exit.";
+        qCDebug(playerControllerVideoDecodeThread)
+            << "[VideoDecodeThread] loop start, loop_count:" << loop_count
+            << ", m_exit:" << (m_exit ? m_exit->load() : -1)
+            << ", abort_request:" << is->abort_request;
+        if (m_exit && *m_exit) {
+            qCDebug(playerControllerVideoDecodeThread) << "[VideoDecodeThread] m_exit set, exit.";
             break;
         }
         if (is->abort_request) {
-            qCDebug(playerControllerLog) << "[VideoDecodeThread] abort_request set, exit.";
+            qCDebug(playerControllerVideoDecodeThread)
+                << "[VideoDecodeThread] abort_request set, exit.";
             break;
         }
-        qCDebug(playerControllerLog) << "[VideoDecodeThread] call get_video_frame, loop:" << loop_count;
+        qCDebug(playerControllerVideoDecodeThread)
+            << "[VideoDecodeThread] call get_video_frame, loop:" << loop_count;
         ret = get_video_frame(is, frame);
-        qCDebug(playerControllerLog) << "[VideoDecodeThread] get_video_frame ret:" << ret << ", loop:" << loop_count++;
+        qCDebug(playerControllerVideoDecodeThread)
+            << "[VideoDecodeThread] get_video_frame ret:" << ret << ", loop:" << loop_count++
+            << ", m_exit:" << (m_exit ? m_exit->load() : -1)
+            << ", abort_request:" << is->abort_request;
         if (ret < 0) {
-            qCWarning(playerControllerLog) << "[VideoDecodeThread] get_video_frame failed, exit.";
+            qCWarning(playerControllerVideoDecodeThread)
+                << "[VideoDecodeThread] get_video_frame failed, exit.";
             goto the_end;
         }
         if (!ret) {
-            qCDebug(playerControllerLog) << "[VideoDecodeThread] no frame, continue.";
+            qCDebug(playerControllerVideoDecodeThread) << "[VideoDecodeThread] no frame, continue. m_exit:" << (m_exit ? m_exit->load() : -1) << ", abort_request:" << is->abort_request;
             continue;
         }
-        qCDebug(playerControllerLog) << "[VideoDecodeThread] got video frame, pts:" << frame->pts << ", width:" << frame->width << ", height:" << frame->height;
+        qCDebug(playerControllerVideoDecodeThread)
+            << "[VideoDecodeThread] got video frame, pts:" << frame->pts
+            << ", width:" << frame->width << ", height:" << frame->height;
 
 #if USE_AVFILTER_VIDEO
         if (last_w != frame->width || last_h != frame->height || last_format != frame->format
@@ -175,6 +193,8 @@ the_end:
     av_frame_free(&frame);
     av_frame_free(&sw_frame);
     // 可加日志输出
-    qCDebug(playerControllerLog) << "[VideoDecodeThread] run end, abort_request:" << is->abort_request << ", m_exit:" << m_exit;
+    qCDebug(playerControllerVideoDecodeThread)
+        << "[VideoDecodeThread] run end, abort_request:" << is->abort_request
+        << ", m_exit:" << (m_exit ? m_exit->load() : -1);
     return;
 }

+ 0 - 1
AvPlayer2/video_decode_thread.h

@@ -5,7 +5,6 @@
 
 #include "ThreadBase.h"
 #include "packets_sync.h"
-#include <atomic>
 
 class VideoDecodeThread : public ThreadBase
 {

+ 23 - 9
AvPlayer2/video_play_thread.cpp

@@ -10,6 +10,9 @@
 
 #include "video_play_thread.h"
 #include "AVPlayer2/playercontroller.h"
+#include <QLoggingCategory>
+
+Q_LOGGING_CATEGORY(playerControllerVideoPlayThread, "player.controller.VideoPlayThread")
 
 extern int framedrop;
 
@@ -37,37 +40,42 @@ void VideoPlayThread::stop()
 
 void VideoPlayThread::run()
 {
-    qCDebug(playerControllerLog) << "[VideoPlayThread] run start, m_pState:" << (void*)m_pState;
+    qCDebug(playerControllerVideoPlayThread) << "[VideoPlayThread] run start, m_pState:" << (void*)m_pState;
     assert(m_pState);
     VideoState* is = m_pState;
-    qCDebug(playerControllerLog) << "[VideoPlayThread] VideoState* is:" << (void*)is << ", abort_request:" << is->abort_request;
+    qCDebug(playerControllerVideoPlayThread) << "[VideoPlayThread] VideoState* is:" << (void*)is << ", abort_request:" << is->abort_request;
     double remaining_time = 0.0;
     int loop_count = 0;
     for (;;) {
-        if (m_exit) {
-            qCDebug(playerControllerLog) << "[VideoPlayThread] m_exit set, exit.";
+        if (m_exit && *m_exit) {
+            qCDebug(playerControllerVideoPlayThread) << "[VideoPlayThread] m_exit set, exit.";
             break;
         }
         if (is->abort_request) {
-            qCDebug(playerControllerLog) << "[VideoPlayThread] abort_request set, exit.";
+            qCDebug(playerControllerVideoPlayThread) << "[VideoPlayThread] abort_request set, exit.";
             break;
         }
+        if (is->eof && frame_queue_nb_remaining(&is->pictq) == 0) {
+            qCDebug(playerControllerVideoPlayThread) << "[VideoPlayThread] eof且队列空,退出线程";
+            break; // 线程退出
+        }
         if (is->paused) {
-            qCDebug(playerControllerLog) << "[VideoPlayThread] paused, wait.";
+            qCDebug(playerControllerVideoPlayThread) << "[VideoPlayThread] paused, wait.";
             std::unique_lock<std::mutex> lock(m_mutex);
             m_cv.wait_for(lock, std::chrono::milliseconds(10), [this] { return m_exit && *m_exit; });
             continue;
         }
-        qCDebug(playerControllerLog) << "[VideoPlayThread] call video_refresh, loop:" << loop_count << ", pictq size:" << (is ? is->pictq.size : -1) << ", remaining_time:" << remaining_time;
+        qCDebug(playerControllerVideoPlayThread) << "[VideoPlayThread] call video_refresh, loop:" << loop_count << ", pictq size:" << (is ? is->pictq.size : -1) << ", remaining_time:" << remaining_time;
         if (remaining_time > 0.0)
             av_usleep((int64_t) (remaining_time * 1000000.0));
         remaining_time = REFRESH_RATE;
         if ((!is->paused || is->force_refresh)) {
-            qCDebug(playerControllerLog) << "[VideoPlayThread] call video_refresh, loop:" << loop_count++;
+            qCDebug(playerControllerVideoPlayThread) << "[VideoPlayThread] call video_refresh, loop:" << loop_count++;
             video_refresh(is, &remaining_time);
         }
     }
-    qCDebug(playerControllerLog) << "[VideoPlayThread] run end, abort_request:" << is->abort_request << ", m_exit:" << m_exit;
+    qCDebug(playerControllerVideoPlayThread) << "[VideoPlayThread] run end, abort_request:" << is->abort_request
+                                 << ", m_exit:" << (m_exit ? m_exit->load() : -1);
 }
 
 void VideoPlayThread::video_refresh(VideoState* is, double* remaining_time)
@@ -80,6 +88,12 @@ void VideoPlayThread::video_refresh(VideoState* is, double* remaining_time)
 
     if (is->video_st) {
     retry:
+        // ffplay方案:eof且只剩最后一帧时,消耗掉最后一帧
+        if (is->eof && frame_queue_nb_remaining(&is->pictq) == 1) {
+            frame_queue_next(&is->pictq);
+            // 这里可以考虑发信号通知播放结束
+            return;
+        }
         if (frame_queue_nb_remaining(&is->pictq) == 0) {
             // nothing to do, no picture to display in the queue
             *remaining_time = REFRESH_RATE;

+ 13 - 23
AvPlayer2/video_state.cpp

@@ -330,30 +330,20 @@ void VideoStateData::threads_exit_wait(VideoState* is)
     if (!is)
         return;
 
-    if (is->threads.video_play_tid) {
-        is->threads.video_play_tid->join();
-        is->threads.video_play_tid = nullptr;
-    }
-
-    if (is->threads.audio_play_tid) {
-        is->threads.audio_play_tid->join();
-        is->threads.audio_play_tid = nullptr;
-    }
-
-    if (is->threads.video_decode_tid) {
-        is->threads.video_decode_tid->join();
-        is->threads.video_decode_tid = nullptr;
-    }
-
-    if (is->threads.audio_decode_tid) {
-        is->threads.audio_decode_tid->join();
-        is->threads.audio_decode_tid = nullptr;
-    }
+    auto try_join_and_delete = [](ThreadBase*& t) {
+        if (t) {
+            t->stop(); // 通知线程退出
+            t->join(); // 等待线程结束
+            delete t;  // 释放内存
+            t = nullptr;
+        }
+    };
 
-    if (is->threads.subtitle_decode_tid) {
-        is->threads.subtitle_decode_tid->join();
-        is->threads.subtitle_decode_tid = nullptr;
-    }
+    try_join_and_delete(is->threads.video_play_tid);
+    try_join_and_delete(is->threads.audio_play_tid);
+    try_join_and_delete(is->threads.video_decode_tid);
+    try_join_and_delete(is->threads.audio_decode_tid);
+    try_join_and_delete(is->threads.subtitle_decode_tid);
 }
 
 void VideoStateData::stream_close(VideoState* is)

+ 8 - 1
main.cpp

@@ -52,7 +52,14 @@ void myMessageHandler(QtMsgType type, const QMessageLogContext &context, const Q
 namespace avrecorder::video { void InitWinRTCapture(); }
 int main(int argc, char* argv[])
 {
-    QLoggingCategory::setFilterRules(QStringLiteral("player.controller.debug=true\n"));
+    // QLoggingCategory::setFilterRules(QStringLiteral("player.controller.debug=true\n"));
+    QLoggingCategory::setFilterRules("*.debug=false\n"
+                                     "*.info=false\n"
+                                     "*.warning=false\n"
+                                     "*.critical=false\n"
+                                     "player.controller.PlayerController.debug=true\n"
+                                     "player.controller.VideoDecodeThread.debug=true\n");
+
     // 打开日志文件(覆盖模式)
     g_logFile.setFileName("log.txt");
     g_logFile.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate);