zhuizhu 8 mesi fa
parent
commit
3b2bf28f6d

+ 4 - 0
AvPlayer2/PlayWidget.h

@@ -1,3 +1,5 @@
+#ifndef AVPLAYER2_PLAYWIDGET_H
+#define AVPLAYER2_PLAYWIDGET_H
 #pragma once
 #include <QComboBox>
 #include <QHBoxLayout>
@@ -43,3 +45,5 @@ private slots:
     void onSpeedChanged(int index);
     void onVolumeChanged(int value);
 };
+
+#endif // AVPLAYER2_PLAYWIDGET_H

+ 5 - 0
AvPlayer2/app_settings.h

@@ -1,3 +1,6 @@
+#ifndef AVPLAYER2_APP_SETTINGS_H
+#define AVPLAYER2_APP_SETTINGS_H
+
 #pragma once
 
 #include <QSettings>
@@ -52,3 +55,5 @@ private:
     std::unique_ptr<QSettings> m_pSettings;
     static const Section m_sections[];
 };
+
+#endif // AVPLAYER2_APP_SETTINGS_H

+ 29 - 8
AvPlayer2/audio_decode_thread.cpp

@@ -7,6 +7,7 @@
 // ***********************************************************/
 
 #include "audio_decode_thread.h"
+#include "AVPlayer2/playercontroller.h"
 
 AudioDecodeThread::AudioDecodeThread(VideoState* pState)
     : m_pState(pState)
@@ -16,14 +17,17 @@ AudioDecodeThread::~AudioDecodeThread() {}
 
 void AudioDecodeThread::stop()
 {
-    m_exit = true;
+    *m_exit = true;
     m_cv.notify_all();
 }
 
 void AudioDecodeThread::run()
 {
+    qCDebug(playerControllerLog) << "[AudioDecodeThread] run start, m_pState:" << (void*) m_pState;
     assert(m_pState);
     VideoState* is = m_pState;
+    qCDebug(playerControllerLog) << "[AudioDecodeThread] VideoState* is:" << (void*) is
+                                 << ", abort_request:" << is->abort_request;
     AVFrame* frame = av_frame_alloc();
     Frame* af;
 #if USE_AVFILTER_AUDIO
@@ -35,19 +39,32 @@ void AudioDecodeThread::run()
     AVRational tb;
     int ret = 0;
 
-    if (!frame)
+    if (!frame) {
+        qCWarning(playerControllerLog) << "[AudioDecodeThread] av_frame_alloc failed!";
         return;
+    }
 
     do {
-        if (is->abort_request)
+        if (is->abort_request) {
+            qCDebug(playerControllerLog) << "[AudioDecodeThread] abort_request set, exit.";
             break;
-        if (m_exit)
+        }
+        if (m_exit) {
+            qCDebug(playerControllerLog) << "[AudioDecodeThread] m_exit set, exit.";
             break;
-
-        if ((got_frame = decoder_decode_frame(&is->auddec, frame, nullptr)) < 0)
+        }
+        qCDebug(playerControllerLog)
+            << "[AudioDecodeThread] call decoder_decode_frame, auddec.avctx:"
+            << (void*) is->auddec.avctx;
+        if ((got_frame = decoder_decode_frame(&is->auddec, frame, nullptr)) < 0) {
+            qCWarning(playerControllerLog)
+                << "[AudioDecodeThread] decoder_decode_frame failed, ret:" << got_frame;
             goto the_end;
-
+        }
         if (got_frame) {
+            qCDebug(playerControllerLog)
+                << "[AudioDecodeThread] got audio frame, pts:" << frame->pts
+                << ", sample_rate:" << frame->sample_rate << ", nb_samples:" << frame->nb_samples;
             tb = AVRational{1, frame->sample_rate};
 
 #if USE_AVFILTER_AUDIO
@@ -121,8 +138,10 @@ void AudioDecodeThread::run()
             if (ret == AVERROR_EOF)
                 is->auddec.finished = is->auddec.pkt_serial;
 #endif
+        } else {
+            qCDebug(playerControllerLog) << "[AudioDecodeThread] no frame decoded, continue.";
         }
-    } while (ret >= 0 || ret == AVERROR(EAGAIN) || ret == AVERROR_EOF);
+    } while (got_frame);
 
 the_end:
 
@@ -136,5 +155,7 @@ the_end:
 
     av_frame_free(&frame);
     // 可加日志输出
+    qCDebug(playerControllerLog) << "[AudioDecodeThread] run end, abort_request:"
+                                 << is->abort_request << ", m_exit:" << m_exit;
     return;
 }

+ 9 - 0
AvPlayer2/audio_decode_thread.h

@@ -1,3 +1,6 @@
+#ifndef AVPLAYER2_AUDIO_DECODE_THREAD_H
+#define AVPLAYER2_AUDIO_DECODE_THREAD_H
+
 #pragma once
 
 #include "ThreadBase.h"
@@ -7,6 +10,10 @@
 class AudioDecodeThread : public ThreadBase
 {
 public:
+    AudioDecodeThread(const AudioDecodeThread&) = delete;
+    AudioDecodeThread& operator=(const AudioDecodeThread&) = delete;
+    AudioDecodeThread(AudioDecodeThread&&) = delete;
+    AudioDecodeThread& operator=(AudioDecodeThread&&) = delete;
     explicit AudioDecodeThread(VideoState* pState = nullptr);
     ~AudioDecodeThread();
 
@@ -18,3 +25,5 @@ protected:
 private:
     VideoState* m_pState;
 };
+
+#endif // AVPLAYER2_AUDIO_DECODE_THREAD_H

+ 7 - 2
AvPlayer2/audio_effect_gl.h

@@ -1,9 +1,12 @@
+#ifndef AVPLAYER2_AUDIO_EFFECT_GL_H
+#define AVPLAYER2_AUDIO_EFFECT_GL_H
+
 #pragma once
 
 #include <QImage>
 #include <QKeyEvent>
-// #include <QtOpenGLWidgets>
 #include <QOpenGLWidget>
+
 #include "audio_effect_helper.h"
 #include "audio_play_thread.h"
 
@@ -21,7 +24,7 @@ public:
     {
         m_data.len = 0;
         repaint();
-    };
+    }
     void set_draw_fmt(const BarHelper::VisualFormat& fmt) { m_helper.set_draw_fmt(fmt); }
 signals:
     void hiden(bool bSend = false);
@@ -36,3 +39,5 @@ private:
     BarHelper m_helper;
     AudioData m_data;
 };
+
+#endif // AVPLAYER2_AUDIO_EFFECT_GL_H

+ 3 - 0
AvPlayer2/audio_effect_helper.h

@@ -1,3 +1,5 @@
+#ifndef AVPLAYER2_AUDIO_EFFECT_HELPER_H
+#define AVPLAYER2_AUDIO_EFFECT_HELPER_H
 #pragma once
 #include <QBrush>
 #include <QFont>
@@ -56,3 +58,4 @@ private:
     AudioFrameFmt m_datafmt;
     VisualFormat m_visualFmt;
 };
+#endif // AVPLAYER2_AUDIO_EFFECT_HELPER_H

+ 27 - 19
AvPlayer2/audio_play_thread.cpp

@@ -7,6 +7,7 @@
 // ***********************************************************/
 
 #include "audio_play_thread.h"
+#include "AVPlayer2/playercontroller.h"
 #include <utility>
 
 #if !NDEBUG
@@ -21,12 +22,10 @@
 #include <fstream>
 #endif
 
-AudioPlayThread::AudioPlayThread(QObject* parent, VideoState* pState)
-    : QThread(parent)
-    , m_pOutput(nullptr)
+AudioPlayThread::AudioPlayThread(VideoState* pState)
+    : m_pOutput(nullptr)
     , m_pState(pState)
 {
-    // print_device();
     qRegisterMetaType<AudioData>("AudioData");
 }
 
@@ -34,6 +33,8 @@ AudioPlayThread::~AudioPlayThread()
 {
     stop_device();
     final_resample_param();
+    stop();
+    join();
 }
 
 void AudioPlayThread::print_device() const
@@ -94,7 +95,7 @@ bool AudioPlayThread::init_device(int sample_rate,
     }
 
     // m_pOutput = std::make_unique<QAudioOutput>(deviceInfo, format);
-    m_pOutput = new QAudioOutput(deviceInfo, format, this); // this 为 parent
+    m_pOutput = new QAudioOutput(deviceInfo, format); // this 为 parent
     // 析构时 Qt 自动 delete
 
     set_device_volume(default_vol);
@@ -154,26 +155,34 @@ void AudioPlayThread::play_buf(const uint8_t* buf, int datasize)
 
 void AudioPlayThread::run()
 {
+    qCDebug(playerControllerLog) << "[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;
     int audio_size;
-
+    int loop_count = 0;
     for (;;) {
-        if (m_bExitThread)
+        if (m_exit) {
+            qCDebug(playerControllerLog) << "[AudioPlayThread] m_exit set, exit.";
             break;
-
-        if (is->abort_request)
+        }
+        if (is->abort_request) {
+            qCDebug(playerControllerLog) << "[AudioPlayThread] abort_request set, exit.";
             break;
-
+        }
         if (is->paused) {
-            msleep(10);
+            qCDebug(playerControllerLog) << "[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);
         audio_size = audio_decode_frame(is);
-        if (audio_size < 0)
+        qCDebug(playerControllerLog) << "[AudioPlayThread] audio_decode_frame ret:" << audio_size << ", loop:" << loop_count++;
+        if (audio_size < 0) {
+            qCWarning(playerControllerLog) << "[AudioPlayThread] audio_decode_frame failed, exit.";
             break;
-
+        }
         if (!isnan(is->audio_clock)) {
             AVCodecContext* pAudioCodex = is->auddec.avctx;
             if (pAudioCodex) {
@@ -191,8 +200,7 @@ void AudioPlayThread::run()
             }
         }
     }
-
-    qDebug("-------- Audio play thread exit.");
+    qCDebug(playerControllerLog) << "[AudioPlayThread] run end, abort_request:" << is->abort_request << ", m_exit:" << m_exit;
 }
 
 int AudioPlayThread::audio_decode_frame(VideoState* is)
@@ -272,7 +280,7 @@ int AudioPlayThread::audio_decode_frame(VideoState* is)
         int len = std::min(data_size, BUFFER_LEN);
         memcpy(data.buffer, buffer_audio, len);
         data.len = len;
-        emit data_visual_ready(data);
+        if (m_onDataVisualReady) m_onDataVisualReady(data);
     }
 
     play_buf(buffer_audio, data_size);
@@ -314,7 +322,7 @@ int AudioPlayThread::audio_decode_frame(VideoState* is)
     }
     is->audio_clock_serial = af->serial;
 
-    emit update_play_time();
+    if (m_onUpdatePlayTime) m_onUpdatePlayTime();
 
 #if (!NDEBUG && PRINT_PACKETQUEUE_AUDIO_INFO)
     {
@@ -387,6 +395,6 @@ void AudioPlayThread::final_resample_param()
 
 void AudioPlayThread::stop_thread()
 {
-    m_bExitThread = true;
+    *m_exit = true;
     // 如有条件变量/阻塞等待,这里唤醒
 }

+ 20 - 16
AvPlayer2/audio_play_thread.h

@@ -1,3 +1,6 @@
+#ifndef AVPLAYER2_AUDIO_PLAY_THREAD_H
+#define AVPLAYER2_AUDIO_PLAY_THREAD_H
+
 #pragma once
 
 #include <QAudio>
@@ -7,13 +10,13 @@
 #include <QFile>
 #include <QIODevice>
 #include <QQueue>
-#include <QThread>
 #include <QWaitCondition>
 
 #include <memory>
 #include <atomic>
 
 #include "packets_sync.h"
+#include "ThreadBase.h"
 
 #define BUFFER_LEN 8192 // 1024
 
@@ -32,12 +35,15 @@ typedef struct AudioFrameFmt
     int sample_type; // QAudioFormat::SignedInt
 } AudioFrameFmt;
 
-class AudioPlayThread : public QThread
+class AudioPlayThread : public ThreadBase
 {
-    Q_OBJECT
 public:
-    explicit AudioPlayThread(QObject* parent = nullptr, VideoState* pState = nullptr);
+    explicit AudioPlayThread(VideoState* pState = nullptr);
     virtual ~AudioPlayThread();
+    AudioPlayThread(const AudioPlayThread&) = delete;
+    AudioPlayThread& operator=(const AudioPlayThread&) = delete;
+    AudioPlayThread(AudioPlayThread&&) = delete;
+    AudioPlayThread& operator=(AudioPlayThread&&) = delete;
 
 public:
     void print_device() const;
@@ -50,11 +56,13 @@ public:
     float get_device_volume() const;
     void set_device_volume(float volume);
     void send_visual_open(bool bSend = true) { m_bSendToVisual = bSend; };
-signals:
-    void update_play_time();
-    void data_visual_ready(const AudioData& data);
-public slots:
     void stop_thread();
+    void setOnUpdatePlayTime(std::function<void()> cb) { m_onUpdatePlayTime = std::move(cb); }
+    void setOnDataVisualReady(std::function<void(const AudioData&)> cb) { m_onDataVisualReady = std::move(cb); }
+
+    // signals:
+    //     void update_play_time();
+    //     void data_visual_ready(const AudioData& data);
 
 protected:
     void run() override;
@@ -65,14 +73,7 @@ private:
 private:
     typedef struct Audio_Resample
     {
-        // AVFrame* pFrame;
-        // uint8_t* buffer;
         struct SwrContext* swrCtx{nullptr};
-
-        // uint64_t channel_layout;	// out
-        // AVChannelLayout channel_layout;
-        // AVSampleFormat sample_fmt;
-        // int sample_rate;
     } Audio_Resample;
 
 private:
@@ -80,6 +81,9 @@ private:
     QIODevice* m_audioDevice{nullptr};
     VideoState* m_pState{nullptr};
     Audio_Resample m_audioResample;
-    std::atomic<bool> m_bExitThread{false}; // 统一为原子变量
     bool m_bSendToVisual{false};
+    std::function<void()> m_onUpdatePlayTime;
+    std::function<void(const AudioData&)> m_onDataVisualReady;
 };
+
+#endif // AVPLAYER2_AUDIO_PLAY_THREAD_H

+ 5 - 0
AvPlayer2/ffmpeg_init.h

@@ -1,3 +1,6 @@
+#ifndef AVPLAYER2_FFMPEG_INIT_H
+#define AVPLAYER2_FFMPEG_INIT_H
+
 #pragma once
 
 #include <QDebug>
@@ -24,3 +27,5 @@ QString dump_metadata(const AVDictionary* m, const char* indent = "  ");
 QString dump_stream_format(const AVFormatContext* ic, int i, int index, int is_output);
 QString print_fps(double d, const char* postfix);
 QString dump_sidedata(const AVStream* st, const char* indent);
+
+#endif // AVPLAYER2_FFMPEG_INIT_H

+ 3 - 0
AvPlayer2/log.h

@@ -1,3 +1,5 @@
+#ifndef AVPLAYER2_LOG_H
+#define AVPLAYER2_LOG_H
 #pragma once
 #include <QFile>
 #include <QFileInfo>
@@ -27,3 +29,4 @@ private:
     std::unique_ptr<QFile> m_logfile;
     std::unique_ptr<QTextStream> m_ts;
 };
+#endif // AVPLAYER2_LOG_H

+ 5 - 0
AvPlayer2/mainwindowa.h

@@ -1,3 +1,6 @@
+#ifndef AVPLAYER2_MAINWINDOWA_H
+#define AVPLAYER2_MAINWINDOWA_H
+
 #pragma once
 
 #include <QActionGroup>
@@ -257,3 +260,5 @@ private:
     std::unique_ptr<QAction> m_savedPlaylists[MaxPlaylist];
     std::unique_ptr<QAction> m_PlaylistsClear;
 };
+
+#endif // AVPLAYER2_MAINWINDOWA_H

+ 269 - 293
AvPlayer2/packets_sync.cpp

@@ -21,14 +21,12 @@ int packet_queue_init(PacketQueue* q)
     if (!q->pkt_list)
         return AVERROR(ENOMEM);
     q->mutex = new QMutex();
-    if (!q->mutex)
-    {
+    if (!q->mutex) {
         av_log(nullptr, AV_LOG_FATAL, "new QMutex() error.\n");
         return AVERROR(ENOMEM);
     }
     q->cond = new QWaitCondition();
-    if (!q->cond)
-    {
+    if (!q->cond) {
         av_log(nullptr, AV_LOG_FATAL, "new QWaitCondition() error.\n");
         return AVERROR(ENOMEM);
     }
@@ -85,16 +83,13 @@ int packet_queue_get(PacketQueue* q, AVPacket* pkt, int block, int* serial)
 
     q->mutex->lock();
 
-    for (;;)
-    {
-        if (q->abort_request)
-        {
+    for (;;) {
+        if (q->abort_request) {
             ret = -1;
             break;
         }
 
-        if (av_fifo_read(q->pkt_list, &pkt1, 1) >= 0)
-        {
+        if (av_fifo_read(q->pkt_list, &pkt1, 1) >= 0) {
             q->nb_packets--;
             q->size -= pkt1.pkt->size + sizeof(pkt1);
             q->duration -= pkt1.pkt->duration;
@@ -104,14 +99,10 @@ int packet_queue_get(PacketQueue* q, AVPacket* pkt, int block, int* serial)
             av_packet_free(&pkt1.pkt);
             ret = 1;
             break;
-        }
-        else if (!block)
-        {
+        } else if (!block) {
             ret = 0;
             break;
-        }
-        else
-        {
+        } else {
             q->cond->wait(q->mutex);
         }
     }
@@ -123,9 +114,18 @@ void packet_queue_print(const PacketQueue* q, const AVPacket* pkt, const QString
 {
     qDebug("[%s]Queue:[%p](nb_packets:%d, size:%d, dur:%d, serial:%d), "
            "pkt(pts:%lld,dts:%lld,size:%d,s_index:%d,dur:%lld,pos:%lld).",
-           qUtf8Printable(prefix), q, q->nb_packets, q->size, q->duration,
-           q->serial, pkt->pts, pkt->dts, pkt->size, pkt->stream_index,
-           pkt->duration, pkt->pos);
+           qUtf8Printable(prefix),
+           q,
+           q->nb_packets,
+           q->size,
+           q->duration,
+           q->serial,
+           pkt->pts,
+           pkt->dts,
+           pkt->size,
+           pkt->stream_index,
+           pkt->duration,
+           pkt->pos);
 }
 
 int packet_queue_put(PacketQueue* q, AVPacket* pkt)
@@ -134,8 +134,7 @@ int packet_queue_put(PacketQueue* q, AVPacket* pkt)
     int ret = -1;
 
     pkt1 = av_packet_alloc();
-    if (!pkt1)
-    {
+    if (!pkt1) {
         av_packet_unref(pkt);
         return ret;
     }
@@ -149,7 +148,7 @@ int packet_queue_put(PacketQueue* q, AVPacket* pkt)
         av_packet_free(&pkt1);
 
 #if PRINT_PACKETQUEUE_INFO
-        // packet_queue_print(q, pkt, "packet_queue_put");
+    // packet_queue_print(q, pkt, "packet_queue_put");
 #endif
     return ret;
 }
@@ -186,13 +185,11 @@ int frame_queue_init(FrameQueue* f, PacketQueue* pktq, int max_size, int keep_la
 {
     int i;
     memset(f, 0, sizeof(FrameQueue));
-    if (!(f->mutex = new QMutex()))
-    {
+    if (!(f->mutex = new QMutex())) {
         av_log(nullptr, AV_LOG_FATAL, "new QMutex() error!\n");
         return AVERROR(ENOMEM);
     }
-    if (!(f->cond = new QWaitCondition()))
-    {
+    if (!(f->cond = new QWaitCondition())) {
         av_log(nullptr, AV_LOG_FATAL, "new QWaitCondition() error\n");
         return AVERROR(ENOMEM);
     }
@@ -208,8 +205,7 @@ int frame_queue_init(FrameQueue* f, PacketQueue* pktq, int max_size, int keep_la
 void frame_queue_destory(FrameQueue* f)
 {
     int i;
-    for (i = 0; i < f->max_size; i++)
-    {
+    for (i = 0; i < f->max_size; i++) {
         Frame* vp = &f->queue[i];
         frame_queue_unref_item(vp);
         av_frame_free(&vp->frame);
@@ -242,14 +238,16 @@ Frame* frame_queue_peek_next(FrameQueue* f)
     return &f->queue[(f->rindex + f->rindex_shown + 1) % f->max_size];
 }
 
-Frame* frame_queue_peek_last(FrameQueue* f) { return &f->queue[f->rindex]; }
+Frame* frame_queue_peek_last(FrameQueue* f)
+{
+    return &f->queue[f->rindex];
+}
 
 Frame* frame_queue_peek_writable(FrameQueue* f)
 {
     /* wait until we have space to put a new frame */
     f->mutex->lock();
-    while (f->size >= f->max_size && !f->pktq->abort_request)
-    {
+    while (f->size >= f->max_size && !f->pktq->abort_request) {
         f->cond->wait(f->mutex);
     }
     f->mutex->unlock();
@@ -264,8 +262,7 @@ Frame* frame_queue_peek_readable(FrameQueue* f)
 {
     /* wait until we have a readable a new frame */
     f->mutex->lock();
-    while (f->size - f->rindex_shown <= 0 && !f->pktq->abort_request)
-    {
+    while (f->size - f->rindex_shown <= 0 && !f->pktq->abort_request) {
         f->cond->wait(f->mutex);
     }
     f->mutex->unlock();
@@ -288,8 +285,7 @@ void frame_queue_push(FrameQueue* f)
 
 void frame_queue_next(FrameQueue* f)
 {
-    if (f->keep_last && !f->rindex_shown)
-    {
+    if (f->keep_last && !f->rindex_shown) {
         f->rindex_shown = 1;
         return;
     }
@@ -318,17 +314,24 @@ int64_t frame_queue_last_pos(FrameQueue* f)
         return -1;
 }
 
-int queue_picture(VideoState* is, AVFrame* src_frame, double pts, double duration, int64_t pos, int serial)
+int queue_picture(
+    VideoState* is, AVFrame* src_frame, double pts, double duration, int64_t pos, int serial)
 {
 #if PRINT_PACKETQUEUE_INFO
     // int64 lld, double lf
     qDebug("queue picture, w:%d, h:%d, nb:%d, ft:%d(%s), kf:%d, pic_t:%d(%c), "
            "pts:%lf, duration:%lf, pos:%lld, serial:%d",
-           src_frame->width, src_frame->height, src_frame->nb_samples,
+           src_frame->width,
+           src_frame->height,
+           src_frame->nb_samples,
            src_frame->format,
            av_get_sample_fmt_name(AVSampleFormat(src_frame->format)),
-           src_frame->key_frame, src_frame->pict_type,
-           av_get_picture_type_char(src_frame->pict_type), pts, duration, pos,
+           src_frame->key_frame,
+           src_frame->pict_type,
+           av_get_picture_type_char(src_frame->pict_type),
+           pts,
+           duration,
+           pos,
            serial);
 #endif
 
@@ -361,27 +364,20 @@ int get_video_frame(VideoState* is, AVFrame* frame)
     if ((got_picture = decoder_decode_frame(&is->viddec, frame, nullptr)) < 0)
         return -1;
 
-    if (got_picture)
-    {
+    if (got_picture) {
         double dpts = NAN;
 
         if (frame->pts != AV_NOPTS_VALUE)
             dpts = av_q2d(is->video_st->time_base) * frame->pts;
 
-        frame->sample_aspect_ratio =
-            av_guess_sample_aspect_ratio(is->ic, is->video_st, frame);
+        frame->sample_aspect_ratio = av_guess_sample_aspect_ratio(is->ic, is->video_st, frame);
 
-        if (framedrop > 0 ||
-            (framedrop && get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER))
-        {
-            if (frame->pts != AV_NOPTS_VALUE)
-            {
+        if (framedrop > 0 || (framedrop && get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER)) {
+            if (frame->pts != AV_NOPTS_VALUE) {
                 double diff = dpts - get_master_clock(is);
-                if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD &&
-                    diff - is->frame_last_filter_delay < 0 &&
-                    is->viddec.pkt_serial == is->vidclk.serial &&
-                    is->videoq.nb_packets)
-                {
+                if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD
+                    && diff - is->frame_last_filter_delay < 0
+                    && is->viddec.pkt_serial == is->vidclk.serial && is->videoq.nb_packets) {
                     is->frame_drops_early++;
                     av_frame_unref(frame);
                     got_picture = 0;
@@ -393,7 +389,10 @@ int get_video_frame(VideoState* is, AVFrame* frame)
     return got_picture;
 }
 
-int decoder_init(Decoder* d, AVCodecContext* avctx, PacketQueue* queue, QWaitCondition* empty_queue_cond)
+int decoder_init(Decoder* d,
+                 AVCodecContext* avctx,
+                 PacketQueue* queue,
+                 QWaitCondition* empty_queue_cond)
 {
     memset(d, 0, sizeof(Decoder));
     d->pkt = av_packet_alloc();
@@ -427,7 +426,8 @@ void decoder_abort(Decoder* d, FrameQueue* fq)
     packet_queue_abort(d->queue);
     frame_queue_signal(fq);
     // SDL_WaitThread(d->decoder_tid, nullptr);
-    ((QThread*)(d->decoder_tid))->wait();
+    // TODO: //
+    // ((ThreadBase*) (d->decoder_tid))->join();
     d->decoder_tid = nullptr;
     packet_queue_flush(d->queue);
 }
@@ -436,50 +436,39 @@ int decoder_decode_frame(Decoder* d, AVFrame* frame, AVSubtitle* sub)
 {
     int ret = AVERROR(EAGAIN);
     int decoder_reorder_pts = -1;
-    for (;;)
-    {
-        if (d->queue->serial == d->pkt_serial)
-        {
-            do
-            {
+    for (;;) {
+        if (d->queue->serial == d->pkt_serial) {
+            do {
                 if (d->queue->abort_request)
                     return -1;
 
-                switch (d->avctx->codec_type)
-                {
-                    case AVMEDIA_TYPE_VIDEO:
-                        ret = avcodec_receive_frame(d->avctx, frame);
-                        if (ret >= 0)
-                        {
-                            if (decoder_reorder_pts == -1)
-                            {
-                                frame->pts = frame->best_effort_timestamp;
-                            }
-                            else if (!decoder_reorder_pts)
-                            {
-                                frame->pts = frame->pkt_dts;
-                            }
+                switch (d->avctx->codec_type) {
+                case AVMEDIA_TYPE_VIDEO:
+                    ret = avcodec_receive_frame(d->avctx, frame);
+                    if (ret >= 0) {
+                        if (decoder_reorder_pts == -1) {
+                            frame->pts = frame->best_effort_timestamp;
+                        } else if (!decoder_reorder_pts) {
+                            frame->pts = frame->pkt_dts;
                         }
-                        break;
-                    case AVMEDIA_TYPE_AUDIO:
-                        ret = avcodec_receive_frame(d->avctx, frame);
-                        if (ret >= 0)
-                        {
-                            AVRational tb = AVRational{1, frame->sample_rate};
-                            if (frame->pts != AV_NOPTS_VALUE)
-                                frame->pts = av_rescale_q(frame->pts, d->avctx->pkt_timebase, tb);
-                            else if (d->next_pts != AV_NOPTS_VALUE)
-                                frame->pts = av_rescale_q(d->next_pts, d->next_pts_tb, tb);
-                            if (frame->pts != AV_NOPTS_VALUE)
-                            {
-                                d->next_pts = frame->pts + frame->nb_samples;
-                                d->next_pts_tb = tb;
-                            }
+                    }
+                    break;
+                case AVMEDIA_TYPE_AUDIO:
+                    ret = avcodec_receive_frame(d->avctx, frame);
+                    if (ret >= 0) {
+                        AVRational tb = AVRational{1, frame->sample_rate};
+                        if (frame->pts != AV_NOPTS_VALUE)
+                            frame->pts = av_rescale_q(frame->pts, d->avctx->pkt_timebase, tb);
+                        else if (d->next_pts != AV_NOPTS_VALUE)
+                            frame->pts = av_rescale_q(d->next_pts, d->next_pts_tb, tb);
+                        if (frame->pts != AV_NOPTS_VALUE) {
+                            d->next_pts = frame->pts + frame->nb_samples;
+                            d->next_pts_tb = tb;
                         }
-                        break;
+                    }
+                    break;
                 }
-                if (ret == AVERROR_EOF)
-                {
+                if (ret == AVERROR_EOF) {
                     d->finished = d->pkt_serial;
                     avcodec_flush_buffers(d->avctx);
                     return 0;
@@ -489,22 +478,17 @@ int decoder_decode_frame(Decoder* d, AVFrame* frame, AVSubtitle* sub)
             } while (ret != AVERROR(EAGAIN));
         }
 
-        do
-        {
+        do {
             if (d->queue->nb_packets == 0)
                 d->empty_queue_cond->wakeAll();
 
-            if (d->packet_pending)
-            {
+            if (d->packet_pending) {
                 d->packet_pending = 0;
-            }
-            else
-            {
+            } else {
                 int old_serial = d->pkt_serial;
                 if (packet_queue_get(d->queue, d->pkt, 1, &d->pkt_serial) < 0)
                     return -1;
-                if (old_serial != d->pkt_serial)
-                {
+                if (old_serial != d->pkt_serial) {
                     avcodec_flush_buffers(d->avctx);
                     d->finished = 0;
                     d->next_pts = d->start_pts;
@@ -516,35 +500,26 @@ int decoder_decode_frame(Decoder* d, AVFrame* frame, AVSubtitle* sub)
             av_packet_unref(d->pkt);
         } while (1);
 
-        if (d->avctx->codec_type == AVMEDIA_TYPE_SUBTITLE)
-        {
+        if (d->avctx->codec_type == AVMEDIA_TYPE_SUBTITLE) {
             int got_frame = 0;
             ret = avcodec_decode_subtitle2(d->avctx, sub, &got_frame, d->pkt);
-            if (ret < 0)
-            {
+            if (ret < 0) {
                 ret = AVERROR(EAGAIN);
-            }
-            else
-            {
-                if (got_frame && !d->pkt->data)
-                {
+            } else {
+                if (got_frame && !d->pkt->data) {
                     d->packet_pending = 1;
                 }
                 ret = got_frame ? 0 : (d->pkt->data ? AVERROR(EAGAIN) : AVERROR_EOF);
             }
             av_packet_unref(d->pkt);
-        }
-        else
-        {
-            if (avcodec_send_packet(d->avctx, d->pkt) == AVERROR(EAGAIN))
-            {
-                av_log(d->avctx, AV_LOG_ERROR,
+        } else {
+            if (avcodec_send_packet(d->avctx, d->pkt) == AVERROR(EAGAIN)) {
+                av_log(d->avctx,
+                       AV_LOG_ERROR,
                        "Receive_frame and send_packet both returned EAGAIN, which is "
                        "an API violation.\n");
                 d->packet_pending = 1;
-            }
-            else
-            {
+            } else {
                 av_packet_unref(d->pkt);
             }
         }
@@ -554,8 +529,7 @@ int decoder_decode_frame(Decoder* d, AVFrame* frame, AVSubtitle* sub)
 void get_file_info(const char* filename, int64_t& duration)
 {
     AVFormatContext* pFormatCtx = avformat_alloc_context();
-    if (avformat_open_input(&pFormatCtx, filename, NULL, NULL) == 0)
-    {
+    if (avformat_open_input(&pFormatCtx, filename, NULL, NULL) == 0) {
         if (pFormatCtx->duration < 0)
             avformat_find_stream_info(pFormatCtx, NULL);
         duration = pFormatCtx->duration;
@@ -565,7 +539,8 @@ void get_file_info(const char* filename, int64_t& duration)
     avformat_free_context(pFormatCtx);
 }
 
-void get_duration_time(const int64_t duration_us, int64_t& hours, int64_t& mins, int64_t& secs, int64_t& us)
+void get_duration_time(
+    const int64_t duration_us, int64_t& hours, int64_t& mins, int64_t& secs, int64_t& us)
 {
     int64_t duration = duration_us + (duration_us <= INT64_MAX - 5000 ? 5000 : 0);
     duration = duration < 0 ? 0 : duration;
@@ -582,12 +557,9 @@ double get_clock(Clock* c)
 {
     if (*c->queue_serial != c->serial)
         return NAN;
-    if (c->paused)
-    {
+    if (c->paused) {
         return c->pts;
-    }
-    else
-    {
+    } else {
         double time = av_gettime_relative() / 1000000.0;
         return c->pts_drift + time - (time - c->last_updated) * (1.0 - c->speed);
     }
@@ -625,24 +597,21 @@ void sync_clock_to_slave(Clock* c, Clock* slave)
 {
     double clock = get_clock(c);
     double slave_clock = get_clock(slave);
-    if (!isnan(slave_clock) &&
-        (isnan(clock) || fabs(clock - slave_clock) > AV_NOSYNC_THRESHOLD))
+    if (!isnan(slave_clock) && (isnan(clock) || fabs(clock - slave_clock) > AV_NOSYNC_THRESHOLD))
         set_clock(c, slave_clock, slave->serial);
 }
 
 int stream_has_enough_packets(AVStream* st, int stream_id, PacketQueue* queue)
 {
-    return stream_id < 0 || queue->abort_request ||
-           (st->disposition & AV_DISPOSITION_ATTACHED_PIC) ||
-           queue->nb_packets > MIN_FRAMES &&
-               (!queue->duration ||
-                av_q2d(st->time_base) * queue->duration > 1.0);
+    return stream_id < 0 || queue->abort_request || (st->disposition & AV_DISPOSITION_ATTACHED_PIC)
+           || queue->nb_packets > MIN_FRAMES
+                  && (!queue->duration || av_q2d(st->time_base) * queue->duration > 1.0);
 }
 
 int is_realtime(AVFormatContext* s)
 {
-    if (!strcmp(s->iformat->name, "rtp") || !strcmp(s->iformat->name, "rtsp") ||
-        !strcmp(s->iformat->name, "sdp"))
+    if (!strcmp(s->iformat->name, "rtp") || !strcmp(s->iformat->name, "rtsp")
+        || !strcmp(s->iformat->name, "sdp"))
         return 1;
 
     if (s->pb && (!strncmp(s->url, "rtp:", 4) || !strncmp(s->url, "udp:", 4)))
@@ -652,22 +621,17 @@ int is_realtime(AVFormatContext* s)
 
 int get_master_sync_type(VideoState* is)
 {
-    if (is->av_sync_type == AV_SYNC_VIDEO_MASTER)
-    {
+    if (is->av_sync_type == AV_SYNC_VIDEO_MASTER) {
         if (is->video_st)
             return AV_SYNC_VIDEO_MASTER;
         else
             return AV_SYNC_AUDIO_MASTER;
-    }
-    else if (is->av_sync_type == AV_SYNC_AUDIO_MASTER)
-    {
+    } else if (is->av_sync_type == AV_SYNC_AUDIO_MASTER) {
         if (is->audio_st)
             return AV_SYNC_AUDIO_MASTER;
         else
             return AV_SYNC_EXTERNAL_CLOCK;
-    }
-    else
-    {
+    } else {
         return AV_SYNC_EXTERNAL_CLOCK;
     }
 }
@@ -677,56 +641,44 @@ double get_master_clock(VideoState* is)
 {
     double val;
 
-    switch (get_master_sync_type(is))
-    {
-        case AV_SYNC_VIDEO_MASTER:
-            val = get_clock(&is->vidclk);
-            break;
-        case AV_SYNC_AUDIO_MASTER:
-            val = get_clock(&is->audclk);
-            break;
-        default:
-            val = get_clock(&is->extclk);
-            break;
+    switch (get_master_sync_type(is)) {
+    case AV_SYNC_VIDEO_MASTER:
+        val = get_clock(&is->vidclk);
+        break;
+    case AV_SYNC_AUDIO_MASTER:
+        val = get_clock(&is->audclk);
+        break;
+    default:
+        val = get_clock(&is->extclk);
+        break;
     }
     return val;
 }
 
 void check_external_clock_speed(VideoState* is)
 {
-    if ((is->video_stream >= 0 &&
-         is->videoq.nb_packets <= EXTERNAL_CLOCK_MIN_FRAMES) ||
-        (is->audio_stream >= 0 &&
-         is->audioq.nb_packets <= EXTERNAL_CLOCK_MIN_FRAMES))
-    {
+    if ((is->video_stream >= 0 && is->videoq.nb_packets <= EXTERNAL_CLOCK_MIN_FRAMES)
+        || (is->audio_stream >= 0 && is->audioq.nb_packets <= EXTERNAL_CLOCK_MIN_FRAMES)) {
         set_clock_speed(&is->extclk,
                         FFMAX(EXTERNAL_CLOCK_SPEED_MIN,
                               is->extclk.speed - EXTERNAL_CLOCK_SPEED_STEP));
-    }
-    else if ((is->video_stream < 0 ||
-              is->videoq.nb_packets > EXTERNAL_CLOCK_MAX_FRAMES) &&
-             (is->audio_stream < 0 ||
-              is->audioq.nb_packets > EXTERNAL_CLOCK_MAX_FRAMES))
-    {
+    } else if ((is->video_stream < 0 || is->videoq.nb_packets > EXTERNAL_CLOCK_MAX_FRAMES)
+               && (is->audio_stream < 0 || is->audioq.nb_packets > EXTERNAL_CLOCK_MAX_FRAMES)) {
         set_clock_speed(&is->extclk,
                         FFMIN(EXTERNAL_CLOCK_SPEED_MAX,
                               is->extclk.speed + EXTERNAL_CLOCK_SPEED_STEP));
-    }
-    else
-    {
+    } else {
         double speed = is->extclk.speed;
         if (speed != 1.0)
-            set_clock_speed(&is->extclk, speed + EXTERNAL_CLOCK_SPEED_STEP *
-                                                     (1.0 - speed) /
-                                                     fabs(1.0 - speed));
+            set_clock_speed(&is->extclk,
+                            speed + EXTERNAL_CLOCK_SPEED_STEP * (1.0 - speed) / fabs(1.0 - speed));
     }
 }
 
 /* seek in the stream */
 void stream_seek(VideoState* is, int64_t pos, int64_t rel, int seek_by_bytes)
 {
-    if (!is->seek_req)
-    {
+    if (!is->seek_req) {
         is->seek_pos = pos;
         is->seek_rel = rel;
         is->seek_flags &= ~AVSEEK_FLAG_BYTE;
@@ -756,42 +708,36 @@ void stream_seek(VideoState* is, int64_t pos, int64_t rel, int seek_by_bytes)
 
 void toggle_pause(VideoState* is, bool pause)
 {
-    if (is->paused)
-    {
-        is->frame_timer +=
-            av_gettime_relative() / 1000000.0 - is->vidclk.last_updated;
-        if (is->read_pause_return != AVERROR(ENOSYS))
-        {
+    if (is->paused) {
+        is->frame_timer += av_gettime_relative() / 1000000.0 - is->vidclk.last_updated;
+        if (is->read_pause_return != AVERROR(ENOSYS)) {
             is->vidclk.paused = 0;
         }
         set_clock(&is->vidclk, get_clock(&is->vidclk), is->vidclk.serial);
     }
     set_clock(&is->extclk, get_clock(&is->extclk), is->extclk.serial);
-    is->paused = is->audclk.paused = is->vidclk.paused = is->extclk.paused =
-        pause; // !is->paused;
+    is->paused = is->audclk.paused = is->vidclk.paused = is->extclk.paused = pause; // !is->paused;
     is->step = 0;
 }
 
 void toggle_mute(VideoState* is, bool mute)
 {
     bool muted = !!is->muted;
-    if (muted != mute)
-    {
+    if (muted != mute) {
         is->muted = mute;
     }
 }
 
 void update_volume(VideoState* is, int sign, double step)
 {
-    double volume_level =
-        is->audio_volume
-            ? (20 * log(is->audio_volume / (double)SDL_MIX_MAXVOLUME) / log(10))
-            : -1000.0;
-    int new_volume =
-        lrint(SDL_MIX_MAXVOLUME * pow(10.0, (volume_level + sign * step) / 20.0));
-    is->audio_volume = av_clip(
-        is->audio_volume == new_volume ? (is->audio_volume + sign) : new_volume,
-        0, SDL_MIX_MAXVOLUME);
+    double volume_level = is->audio_volume
+                              ? (20 * log(is->audio_volume / (double) SDL_MIX_MAXVOLUME) / log(10))
+                              : -1000.0;
+    int new_volume = lrint(SDL_MIX_MAXVOLUME * pow(10.0, (volume_level + sign * step) / 20.0));
+    is->audio_volume = av_clip(is->audio_volume == new_volume ? (is->audio_volume + sign)
+                                                              : new_volume,
+                               0,
+                               SDL_MIX_MAXVOLUME);
 }
 
 void step_to_next_frame(VideoState* is)
@@ -807,8 +753,7 @@ double compute_target_delay(double delay, VideoState* is)
     double sync_threshold, diff = 0;
 
     /* update delay to follow master synchronisation source */
-    if (get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER)
-    {
+    if (get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER) {
         /* if video is slave, we try to correct big delays by
        duplicating or deleting a frame */
         diff = get_clock(&is->vidclk) - get_master_clock(is);
@@ -816,10 +761,8 @@ double compute_target_delay(double delay, VideoState* is)
         /* skip or repeat frame. We take into account the
        delay to compute the threshold. I still don't know
        if it is the best guess */
-        sync_threshold =
-            FFMAX(AV_SYNC_THRESHOLD_MIN, FFMIN(AV_SYNC_THRESHOLD_MAX, delay));
-        if (!isnan(diff) && fabs(diff) < is->max_frame_duration)
-        {
+        sync_threshold = FFMAX(AV_SYNC_THRESHOLD_MIN, FFMIN(AV_SYNC_THRESHOLD_MAX, delay));
+        if (!isnan(diff) && fabs(diff) < is->max_frame_duration) {
             if (diff <= -sync_threshold)
                 delay = FFMAX(0, delay + diff);
             else if (diff >= sync_threshold && delay > AV_SYNC_FRAMEDUP_THRESHOLD)
@@ -835,8 +778,7 @@ double compute_target_delay(double delay, VideoState* is)
 
 double vp_duration(VideoState* is, Frame* vp, Frame* nextvp)
 {
-    if (vp->serial == nextvp->serial)
-    {
+    if (vp->serial == nextvp->serial) {
         double duration = nextvp->pts - vp->pts;
         if (isnan(duration) || duration <= 0 || duration > is->max_frame_duration)
             return vp->duration;
@@ -857,25 +799,36 @@ void update_video_pts(VideoState* is, double pts, int64_t pos, int serial)
 #if PRINT_PACKETQUEUE_INFO
 void print_state_info(VideoState* is)
 {
-    if (is)
-    {
+    if (is) {
         PacketQueue* pPacket = &is->videoq;
         qDebug("[VideoState] V PacketQueue[%p](nb_packets:%d,size:%d,dur:%lld, "
                "abort:%d, serial:%d)",
-               pPacket, pPacket->nb_packets, pPacket->size, pPacket->duration,
-               pPacket->abort_request, pPacket->serial);
+               pPacket,
+               pPacket->nb_packets,
+               pPacket->size,
+               pPacket->duration,
+               pPacket->abort_request,
+               pPacket->serial);
 
         pPacket = &is->audioq;
         qDebug("[VideoState] A PacketQueue[%p](nb_packets:%d,size:%d,dur:%lld, "
                "abort:%d, serial:%d)",
-               pPacket, pPacket->nb_packets, pPacket->size, pPacket->duration,
-               pPacket->abort_request, pPacket->serial);
+               pPacket,
+               pPacket->nb_packets,
+               pPacket->size,
+               pPacket->duration,
+               pPacket->abort_request,
+               pPacket->serial);
 
         pPacket = &is->subtitleq;
         qDebug("[VideoState] S PacketQueue[%p](nb_packets:%d,size:%d,dur:%lld, "
                "abort:%d, serial:%d)",
-               pPacket, pPacket->nb_packets, pPacket->size, pPacket->duration,
-               pPacket->abort_request, pPacket->serial);
+               pPacket,
+               pPacket->nb_packets,
+               pPacket->size,
+               pPacket->duration,
+               pPacket->abort_request,
+               pPacket->serial);
 
         /*qDebug("[VideoState]FrameQueue(v:%p,a:%p,s:%p)",
             &is->pictq, &is->sampq, &is->subpq);
@@ -900,23 +853,18 @@ void set_audio_playspeed(VideoState* is, double value)
 
     const size_t len = 32;
     if (!is->afilters)
-        is->afilters = (char*)av_malloc(len);
+        is->afilters = (char*) av_malloc(len);
 
-    if (value <= 0.5)
-    {
+    if (value <= 0.5) {
         snprintf(is->afilters, len, "atempo=0.5,");
         char tmp[128];
         snprintf(tmp, sizeof(tmp), "atempo=%lf", value / 0.5);
 
         // strncat(is->afilters, tmp, len - strlen(is->afilters) - 1);
         strncat_s(is->afilters, len, tmp, len - strlen(is->afilters) - 1);
-    }
-    else if (value <= 2.0)
-    {
+    } else if (value <= 2.0) {
         snprintf(is->afilters, len, "atempo=%lf", value);
-    }
-    else
-    {
+    } else {
         snprintf(is->afilters, len, "atempo=2.0,");
         char tmp[128];
         snprintf(tmp, sizeof(tmp), "atempo=%lf", value / 2.0);
@@ -940,7 +888,7 @@ void set_video_playspeed(VideoState* is)
 
     size_t len = 32;
     if (!is->vfilters)
-        is->vfilters = (char*)av_malloc(len);
+        is->vfilters = (char*) av_malloc(len);
 
     snprintf(is->vfilters, len, "setpts=%.4lf*PTS", 1.0 / speed);
 
@@ -949,8 +897,10 @@ void set_video_playspeed(VideoState* is)
     qDebug("changing video filters to :%s", is->vfilters);
 }
 
-int cmp_audio_fmts(enum AVSampleFormat fmt1, int64_t channel_count1,
-                   enum AVSampleFormat fmt2, int64_t channel_count2)
+int cmp_audio_fmts(enum AVSampleFormat fmt1,
+                   int64_t channel_count1,
+                   enum AVSampleFormat fmt2,
+                   int64_t channel_count2)
 {
     /* If channel count == 1, planar and non-planar formats are the same */
     if (channel_count1 == 1 && channel_count2 == 1)
@@ -965,18 +915,19 @@ int cmp_audio_fmts(enum AVSampleFormat fmt1, int64_t channel_count1,
 //== channels) 		return channel_layout; 	else 		return 0;
 //}
 
-int configure_filtergraph(AVFilterGraph* graph, const char* filtergraph, AVFilterContext* source_ctx, AVFilterContext* sink_ctx)
+int configure_filtergraph(AVFilterGraph* graph,
+                          const char* filtergraph,
+                          AVFilterContext* source_ctx,
+                          AVFilterContext* sink_ctx)
 {
     int ret;
     int nb_filters = graph->nb_filters;
     AVFilterInOut *outputs = nullptr, *inputs = nullptr;
 
-    if (filtergraph)
-    {
+    if (filtergraph) {
         outputs = avfilter_inout_alloc();
         inputs = avfilter_inout_alloc();
-        if (!outputs || !inputs)
-        {
+        if (!outputs || !inputs) {
             ret = AVERROR(ENOMEM);
             goto fail;
         }
@@ -991,12 +942,9 @@ int configure_filtergraph(AVFilterGraph* graph, const char* filtergraph, AVFilte
         inputs->pad_idx = 0;
         inputs->next = nullptr;
 
-        if ((ret = avfilter_graph_parse_ptr(graph, filtergraph, &inputs, &outputs,
-                                            nullptr)) < 0)
+        if ((ret = avfilter_graph_parse_ptr(graph, filtergraph, &inputs, &outputs, nullptr)) < 0)
             goto fail;
-    }
-    else
-    {
+    } else {
         if ((ret = avfilter_link(source_ctx, 0, sink_ctx, 0)) < 0)
             goto fail;
     }
@@ -1004,8 +952,7 @@ int configure_filtergraph(AVFilterGraph* graph, const char* filtergraph, AVFilte
     /* Reorder the filters to ensure that inputs of the custom filters are merged
    * first */
     for (unsigned int i = 0; i < graph->nb_filters - nb_filters; i++)
-        FFSWAP(AVFilterContext*, graph->filters[i],
-               graph->filters[i + nb_filters]);
+        FFSWAP(AVFilterContext*, graph->filters[i], graph->filters[i + nb_filters]);
 
     ret = avfilter_graph_config(graph, nullptr);
 fail:
@@ -1016,8 +963,7 @@ fail:
 
 int configure_audio_filters(VideoState* is, const char* afilters, int force_output_format)
 {
-    static const enum AVSampleFormat sample_fmts[] = {AV_SAMPLE_FMT_S16,
-                                                      AV_SAMPLE_FMT_NONE};
+    static const enum AVSampleFormat sample_fmts[] = {AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE};
     int sample_rates[2] = {0, -1};
     // int64_t channel_layouts[2] = { 0, -1 };
     // AVChannelLayout channel_layouts[2] = {};
@@ -1043,55 +989,66 @@ int configure_audio_filters(VideoState* is, const char* afilters, int force_outp
     av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC);
     av_channel_layout_describe_bprint(&is->audio_filter_src.ch_layout, &bp);
 
-    snprintf(asrc_args, sizeof(asrc_args),
+    snprintf(asrc_args,
+             sizeof(asrc_args),
              "sample_rate=%d:sample_fmt=%s:time_base=%d/%d:channel_layout=%s",
              is->audio_filter_src.freq,
-             av_get_sample_fmt_name(is->audio_filter_src.fmt), 1,
-             is->audio_filter_src.freq, bp.str);
-
-    ret = avfilter_graph_create_filter(
-        &filt_asrc, avfilter_get_by_name("abuffer"), "ffplay_abuffer", asrc_args,
-        nullptr, is->agraph);
+             av_get_sample_fmt_name(is->audio_filter_src.fmt),
+             1,
+             is->audio_filter_src.freq,
+             bp.str);
+
+    ret = avfilter_graph_create_filter(&filt_asrc,
+                                       avfilter_get_by_name("abuffer"),
+                                       "ffplay_abuffer",
+                                       asrc_args,
+                                       nullptr,
+                                       is->agraph);
     if (ret < 0)
         goto end;
 
-    ret = avfilter_graph_create_filter(
-        &filt_asink, avfilter_get_by_name("abuffersink"), "ffplay_abuffersink",
-        nullptr, nullptr, is->agraph);
+    ret = avfilter_graph_create_filter(&filt_asink,
+                                       avfilter_get_by_name("abuffersink"),
+                                       "ffplay_abuffersink",
+                                       nullptr,
+                                       nullptr,
+                                       is->agraph);
     if (ret < 0)
         goto end;
 
-    if ((ret = av_opt_set_int_list(filt_asink, "sample_fmts", sample_fmts,
-                                   AV_SAMPLE_FMT_NONE, AV_OPT_SEARCH_CHILDREN)) <
-        0)
+    if ((ret = av_opt_set_int_list(filt_asink,
+                                   "sample_fmts",
+                                   sample_fmts,
+                                   AV_SAMPLE_FMT_NONE,
+                                   AV_OPT_SEARCH_CHILDREN))
+        < 0)
         goto end;
-    if ((ret = av_opt_set_int(filt_asink, "all_channel_counts", 1,
-                              AV_OPT_SEARCH_CHILDREN)) < 0)
+    if ((ret = av_opt_set_int(filt_asink, "all_channel_counts", 1, AV_OPT_SEARCH_CHILDREN)) < 0)
         goto end;
 
-    if (force_output_format)
-    {
+    if (force_output_format) {
         sample_rates[0] = is->audio_filter_src.freq;
         // channel_layouts[0] = is->audio_filter_src.channel_layout;
         // channels[0] = is->audio_filter_src.channels;
-        if ((ret = av_opt_set_int(filt_asink, "all_channel_counts", 0,
-                                  AV_OPT_SEARCH_CHILDREN)) < 0)
+        if ((ret = av_opt_set_int(filt_asink, "all_channel_counts", 0, AV_OPT_SEARCH_CHILDREN)) < 0)
             goto end;
 
-        if ((ret = av_opt_set(filt_asink, "ch_layouts", bp.str,
-                              AV_OPT_SEARCH_CHILDREN)) < 0)
+        if ((ret = av_opt_set(filt_asink, "ch_layouts", bp.str, AV_OPT_SEARCH_CHILDREN)) < 0)
             goto end;
         /*if ((ret = av_opt_set_int_list(filt_asink, "channel_layouts",
        channel_layouts, -1, AV_OPT_SEARCH_CHILDREN)) < 0) goto end;*/
         /*if ((ret = av_opt_set_int_list(filt_asink, "channel_counts", channels, -1,
        AV_OPT_SEARCH_CHILDREN)) < 0) goto end;*/
-        if ((ret = av_opt_set_int_list(filt_asink, "sample_rates", sample_rates, -1,
-                                       AV_OPT_SEARCH_CHILDREN)) < 0)
+        if ((ret = av_opt_set_int_list(filt_asink,
+                                       "sample_rates",
+                                       sample_rates,
+                                       -1,
+                                       AV_OPT_SEARCH_CHILDREN))
+            < 0)
             goto end;
     }
 
-    if ((ret = configure_filtergraph(is->agraph, afilters, filt_asrc,
-                                     filt_asink)) < 0)
+    if ((ret = configure_filtergraph(is->agraph, afilters, filt_asrc, filt_asink)) < 0)
         goto end;
 
     is->in_audio_filter = filt_asrc;
@@ -1104,14 +1061,16 @@ end:
     return ret;
 }
 
-int configure_video_filters(AVFilterGraph* graph, VideoState* is, const char* vfilters, AVFrame* frame)
+int configure_video_filters(AVFilterGraph* graph,
+                            VideoState* is,
+                            const char* vfilters,
+                            AVFrame* frame)
 {
     enum AVPixelFormat pix_fmts[1]; // FF_ARRAY_ELEMS(sdl_texture_format_map)
     // char sws_flags_str[512] = "";
     char buffersrc_args[256];
     int ret;
-    AVFilterContext *filt_src = nullptr, *filt_out = nullptr,
-                    *last_filter = nullptr;
+    AVFilterContext *filt_src = nullptr, *filt_out = nullptr, *last_filter = nullptr;
     AVCodecParameters* codecpar = is->video_st->codecpar;
     AVRational fr = av_guess_frame_rate(is->ic, is->video_st, nullptr);
     // const AVDictionaryEntry* e = nullptr;
@@ -1143,29 +1102,43 @@ int configure_video_filters(AVFilterGraph* graph, VideoState* is, const char* vf
 
   graph->scale_sws_opts = av_strdup(sws_flags_str);*/
 
-    snprintf(buffersrc_args, sizeof(buffersrc_args),
+    snprintf(buffersrc_args,
+             sizeof(buffersrc_args),
              "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
-             frame->width, frame->height, frame->format,
-             is->video_st->time_base.num, is->video_st->time_base.den,
+             frame->width,
+             frame->height,
+             frame->format,
+             is->video_st->time_base.num,
+             is->video_st->time_base.den,
              codecpar->sample_aspect_ratio.num,
              FFMAX(codecpar->sample_aspect_ratio.den, 1));
     if (fr.num && fr.den)
-        av_strlcatf(buffersrc_args, sizeof(buffersrc_args), ":frame_rate=%d/%d",
-                    fr.num, fr.den);
-
-    if ((ret = avfilter_graph_create_filter(
-             &filt_src, avfilter_get_by_name("buffer"), "ffplay_buffer",
-             buffersrc_args, nullptr, graph)) < 0)
+        av_strlcatf(buffersrc_args, sizeof(buffersrc_args), ":frame_rate=%d/%d", fr.num, fr.den);
+
+    if ((ret = avfilter_graph_create_filter(&filt_src,
+                                            avfilter_get_by_name("buffer"),
+                                            "ffplay_buffer",
+                                            buffersrc_args,
+                                            nullptr,
+                                            graph))
+        < 0)
         goto fail;
 
-    ret = avfilter_graph_create_filter(
-        &filt_out, avfilter_get_by_name("buffersink"), "ffplay_buffersink",
-        nullptr, nullptr, graph);
+    ret = avfilter_graph_create_filter(&filt_out,
+                                       avfilter_get_by_name("buffersink"),
+                                       "ffplay_buffersink",
+                                       nullptr,
+                                       nullptr,
+                                       graph);
     if (ret < 0)
         goto fail;
 
-    if ((ret = av_opt_set_int_list(filt_out, "pix_fmts", pix_fmts,
-                                   AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN)) < 0)
+    if ((ret = av_opt_set_int_list(filt_out,
+                                   "pix_fmts",
+                                   pix_fmts,
+                                   AV_PIX_FMT_NONE,
+                                   AV_OPT_SEARCH_CHILDREN))
+        < 0)
         goto fail;
 
     last_filter = filt_out;
@@ -1173,21 +1146,24 @@ int configure_video_filters(AVFilterGraph* graph, VideoState* is, const char* vf
 #if 0
 	/* Note: this macro adds a filter before the lastly added filter, so the
 	 * processing order of the filters is in reverse */
-#define INSERT_FILT(name, arg)                                                    \
-    do                                                                            \
-    {                                                                             \
-        AVFilterContext* filt_ctx;                                                \
-                                                                                  \
-        ret = avfilter_graph_create_filter(&filt_ctx, avfilter_get_by_name(name), \
-                                           "ffplay_" name, arg, nullptr, graph);  \
-        if (ret < 0)                                                              \
-            goto fail;                                                            \
-                                                                                  \
-        ret = avfilter_link(filt_ctx, 0, last_filter, 0);                         \
-        if (ret < 0)                                                              \
-            goto fail;                                                            \
-                                                                                  \
-        last_filter = filt_ctx;                                                   \
+#define INSERT_FILT(name, arg) \
+    do { \
+        AVFilterContext* filt_ctx; \
+\
+        ret = avfilter_graph_create_filter(&filt_ctx, \
+                                           avfilter_get_by_name(name), \
+                                           "ffplay_" name, \
+                                           arg, \
+                                           nullptr, \
+                                           graph); \
+        if (ret < 0) \
+            goto fail; \
+\
+        ret = avfilter_link(filt_ctx, 0, last_filter, 0); \
+        if (ret < 0) \
+            goto fail; \
+\
+        last_filter = filt_ctx; \
     } while (0)
 
 	if (autorotate) {

+ 16 - 6
AvPlayer2/packets_sync.h

@@ -1,8 +1,11 @@
+#ifndef AVPLAYER2_PACKETS_SYNC_H
+#define AVPLAYER2_PACKETS_SYNC_H
 #pragma once
 
 #include <QMutex>
 #include <QThread>
 #include <QWaitCondition>
+#include "AVPlayer2/ThreadBase.h"
 
 // only need to open audio filter, video will be synced
 #define USE_AVFILTER_AUDIO 1
@@ -188,12 +191,16 @@ typedef struct Decoder
 
 typedef struct Threads
 {
-    QThread* read_tid{nullptr};
-    QThread* video_decode_tid{nullptr};
-    QThread* audio_decode_tid{nullptr};
-    QThread* video_play_tid{nullptr};
-    QThread* audio_play_tid{nullptr};
-    QThread* subtitle_decode_tid{nullptr};
+    ThreadBase* read_tid{nullptr};
+    ThreadBase* video_decode_tid{nullptr};
+    ThreadBase* audio_decode_tid{nullptr};
+    ThreadBase* video_play_tid{nullptr};
+    ThreadBase* audio_play_tid{nullptr};
+    ThreadBase* subtitle_decode_tid{nullptr};
+
+    Threads() = default;
+    Threads(const Threads&) = delete;
+    Threads& operator=(const Threads&) = delete;
 } Threads;
 
 typedef struct VideoState
@@ -326,6 +333,7 @@ typedef struct VideoState
     // void* read_tid; //read thread pointer
 
     Threads threads; // all thread would access VideoState
+
 } VideoState;
 
 #if !NDEBUG
@@ -435,3 +443,5 @@ int configure_video_filters(AVFilterGraph* graph,
                             const char* vfilters,
                             AVFrame* frame);
 #endif
+
+#endif // AVPLAYER2_PACKETS_SYNC_H

+ 3 - 0
AvPlayer2/play_control_window.h

@@ -1,3 +1,5 @@
+#ifndef AVPLAYER2_PLAY_CONTROL_WINDOW_H
+#define AVPLAYER2_PLAY_CONTROL_WINDOW_H
 #pragma once
 
 #include <QSlider>
@@ -87,3 +89,4 @@ private:
     int64_t m_mins{0};
     int64_t m_secs{0};
 };
+#endif // AVPLAYER2_PLAY_CONTROL_WINDOW_H

+ 135 - 150
AvPlayer2/playercontroller.cpp

@@ -24,6 +24,8 @@
 #include "video_play_thread.h"
 #include "video_state.h"
 
+Q_LOGGING_CATEGORY(playerControllerLog, "player.controller")
+
 PlayerController::PlayerController(QWidget* parent)
     : QObject(parent)
 {
@@ -48,30 +50,32 @@ void PlayerController::startToPlay(const QString& file)
     std::lock_guard<std::mutex> lock(m_stopMutex);
     // 自愈:如果状态为Playing但所有线程都已退出,强制Idle
     if (m_state == PlayerState::Playing) {
-        if (!m_packetReadThread && !m_decodeVideoThread && !m_decodeAudioThread &&
-            !m_audioPlayThread && !m_videoPlayThread && !m_decodeSubtitleThread) {
+        if (!m_packetReadThread && !m_decodeVideoThread && !m_decodeAudioThread
+            && !m_audioPlayThread && !m_videoPlayThread && !m_decodeSubtitleThread) {
             m_videoState.reset();
             m_currentFile.clear();
             m_state = PlayerState::Idle;
-            qDebug() << "[PlayerController] All threads stopped, force reset to Idle.";
+            qCDebug(playerControllerLog)
+                << "[PlayerController] All threads stopped, force reset to Idle.";
         }
     }
     if (m_state == PlayerState::Initializing) {
-        qDebug() << "Player is initializing. Ignoring request.";
+        qCDebug(playerControllerLog) << "Player is initializing. Ignoring request.";
         return;
     }
     if (m_state == PlayerState::Playing) {
         if (m_currentFile == file) {
-            qDebug() << "Already playing the same file. Ignoring request.";
+            qCDebug(playerControllerLog) << "Already playing the same file. Ignoring request.";
             return;
         } else {
-            qDebug() << "Player is busy with another file, stopping and switching to:" << file;
+            qCDebug(playerControllerLog)
+                << "Player is busy with another file, stopping and switching to:" << file;
             stopPlay();
             // 这里直接 fallthrough 到 Idle 状态
         }
     }
     if (m_state == PlayerState::Idle) {
-        qDebug() << "Player is idle. Starting playback for:" << file;
+        qCDebug(playerControllerLog) << "Player is idle. Starting playback for:" << file;
         m_state = PlayerState::Initializing;
         m_currentFile = file;
         if (m_initThread.joinable()) {
@@ -86,17 +90,17 @@ void PlayerController::asyncInit(const QString& file)
     bool success = false;
     QElapsedTimer timer;
     timer.start();
-    qDebug("[Init] asyncInit started");
+    qCDebug(playerControllerLog) << "[Init] asyncInit started";
     if (file.isEmpty()) {
-        qWarning("Filename is invalid. Please select a valid media file.");
+        qCWarning(playerControllerLog) << "Filename is invalid. Please select a valid media file.";
         success = false;
     } else {
-        qInfo("Check file: %s", qUtf8Printable(toNativePath(file)));
+        qCInfo(playerControllerLog) << "Check file: " << toNativePath(file);
         success = true;
     }
     m_initSuccess = success;
     emit asyncInitFinished(file, success);
-    qDebug("[Init] asyncInit finished in %lld ms", timer.elapsed());
+    qCDebug(playerControllerLog) << "[Init] asyncInit finished in " << timer.elapsed() << " ms";
 }
 
 void PlayerController::onAsyncInitFinished(const QString& file, bool success)
@@ -107,16 +111,16 @@ void PlayerController::onAsyncInitFinished(const QString& file, bool success)
         m_state = PlayerState::Idle;
         return;
     }
-    qDebug("[Init] createReadThread...");
+    qCDebug(playerControllerLog) << "[Init] createReadThread...";
     if (!createReadThread()) {
-        qWarning("Packet read thread creation failed");
+        qCWarning(playerControllerLog) << "Packet read thread creation failed";
         playFailed(m_currentFile);
         m_state = PlayerState::Idle;
         return;
     }
-    qDebug("[Init] createVideoState...");
+    qCDebug(playerControllerLog) << "[Init] createVideoState...";
     if (!createVideoState(m_currentFile)) {
-        qWarning("Video state creation failed");
+        qCWarning(playerControllerLog) << "Video state creation failed";
         readPacketStopped();
         playFailed(m_currentFile);
         m_state = PlayerState::Idle;
@@ -124,7 +128,7 @@ void PlayerController::onAsyncInitFinished(const QString& file, bool success)
     }
     assert(m_videoState);
     if (!m_videoState) {
-        qWarning("Video state initialization error");
+        qCWarning(playerControllerLog) << "Video state initialization error";
         playFailed(m_currentFile);
         m_state = PlayerState::Idle;
         return;
@@ -135,7 +139,7 @@ void PlayerController::onAsyncInitFinished(const QString& file, bool success)
     const bool hasSubtitle = playingHasSubtitle();
     if (hasVideo) {
         if (!createDecodeVideoThread() || !createVideoPlayThread()) {
-            qWarning("Video processing setup failed");
+            qCWarning(playerControllerLog) << "Video processing setup failed";
             playFailed(m_currentFile);
             stopPlay();
             m_state = PlayerState::Idle;
@@ -144,7 +148,7 @@ void PlayerController::onAsyncInitFinished(const QString& file, bool success)
     }
     if (hasAudio) {
         if (!createDecodeAudioThread() || !createAudioPlayThread()) {
-            qWarning("Audio processing setup failed");
+            qCWarning(playerControllerLog) << "Audio processing setup failed";
             playFailed(m_currentFile);
             stopPlay();
             m_state = PlayerState::Idle;
@@ -152,7 +156,7 @@ void PlayerController::onAsyncInitFinished(const QString& file, bool success)
         }
     }
     if (hasSubtitle && !createDecodeSubtitleThread()) {
-        qWarning("Subtitle processing setup failed");
+        qCWarning(playerControllerLog) << "Subtitle processing setup failed";
         playFailed(m_currentFile);
         stopPlay();
         m_state = PlayerState::Idle;
@@ -175,8 +179,10 @@ void PlayerController::stopPlay()
     m_state = PlayerState::Stopping;
     auto stopAndReset = [](auto& threadPtr) {
         if (threadPtr) {
-            threadPtr->stop_thread();
-            threadPtr->wait(3000); // 最多等3秒
+            qCDebug(playerControllerLog) << "[stopAndReset] try stop/join thread, isRunning=" << threadPtr->isRunning();
+            threadPtr->stop();
+            threadPtr->join();
+            qCDebug(playerControllerLog) << "[stopAndReset] thread joined and will reset.";
             threadPtr.reset();
         }
     };
@@ -295,7 +301,7 @@ void PlayerController::setDeviceVolume(float volume)
 void PlayerController::playStarted(bool success)
 {
     if (!success) {
-        qWarning("Audio device initialization failed!");
+        qCWarning(playerControllerLog) << "Audio device initialization failed!";
         return;
     }
 
@@ -311,39 +317,39 @@ void PlayerController::playFailed(const QString& file)
 // 线程 finished 槽函数只做日志和信号
 void PlayerController::readPacketStopped()
 {
-    qDebug("************* Read packets thread stopped signal received.");
+    qCDebug(playerControllerLog) << "************* Read packets thread stopped signal received.";
     m_packetReadThread.reset();
     checkAndResetState();
     emit audioStopped();
 }
 void PlayerController::decodeVideoStopped()
 {
-    qDebug("************* Video decode thread stopped.");
+    qCDebug(playerControllerLog) << "************* Video decode thread stopped.";
     m_decodeVideoThread.reset();
     checkAndResetState();
 }
 void PlayerController::decodeAudioStopped()
 {
-    qDebug("************* Audio decode thread stopped.");
+    qCDebug(playerControllerLog) << "************* Audio decode thread stopped.";
     m_decodeAudioThread.reset();
     checkAndResetState();
 }
 void PlayerController::decodeSubtitleStopped()
 {
-    qDebug("************* Subtitle decode thread stopped.");
+    qCDebug(playerControllerLog) << "************* Subtitle decode thread stopped.";
     m_decodeSubtitleThread.reset();
     checkAndResetState();
 }
 void PlayerController::audioPlayStopped()
 {
-    qDebug("************* Audio play thread stopped.");
+    qCDebug(playerControllerLog) << "************* Audio play thread stopped.";
     emit audioStopped();
     m_audioPlayThread.reset();
     checkAndResetState();
 }
 void PlayerController::videoPlayStopped()
 {
-    qDebug("************* Video play thread stopped.");
+    qCDebug(playerControllerLog) << "************* Video play thread stopped.";
     emit videoStopped();
     m_videoPlayThread.reset();
     checkAndResetState();
@@ -399,21 +405,21 @@ bool PlayerController::startPlay()
     timer.start();
 
     if (m_currentFile.isEmpty()) {
-        qWarning("Filename is invalid. Please select a valid media file.");
+        qCWarning(playerControllerLog) << "Filename is invalid. Please select a valid media file.";
         return false;
     }
 
-    qInfo("Starting playback: %s", qUtf8Printable(toNativePath(m_currentFile)));
+    qCInfo(playerControllerLog) << "Starting playback:" << toNativePath(m_currentFile);
 
     // 创建数据包读取线程
     if (!createReadThread()) {
-        qWarning("Packet read thread creation failed");
+        qCWarning(playerControllerLog) << "Packet read thread creation failed";
         return false;
     }
 
     // 创建视频状态对象
     if (!createVideoState(m_currentFile)) {
-        qWarning("Video state creation failed");
+        qCWarning(playerControllerLog) << "Video state creation failed";
         readPacketStopped();
         return false;
     }
@@ -421,7 +427,7 @@ bool PlayerController::startPlay()
     // 检查状态有效性
     assert(m_videoState);
     if (!m_videoState) {
-        qWarning("Video state initialization error");
+        qCWarning(playerControllerLog) << "Video state initialization error";
         return false;
     }
 
@@ -434,7 +440,7 @@ bool PlayerController::startPlay()
     // 创建视频相关线程
     if (hasVideo) {
         if (!createDecodeVideoThread() || !createVideoPlayThread()) {
-            qWarning("Video processing setup failed");
+            qCWarning(playerControllerLog) << "Video processing setup failed";
             return false;
         }
     }
@@ -442,14 +448,14 @@ bool PlayerController::startPlay()
     // 创建音频相关线程
     if (hasAudio) {
         if (!createDecodeAudioThread() || !createAudioPlayThread()) {
-            qWarning("Audio processing setup failed");
+            qCWarning(playerControllerLog) << "Audio processing setup failed";
             return false;
         }
     }
 
     // 创建字幕线程
     if (hasSubtitle && !createDecodeSubtitleThread()) {
-        qWarning("Subtitle processing setup failed");
+        qCWarning(playerControllerLog) << "Subtitle processing setup failed";
         return false;
     }
 
@@ -460,24 +466,19 @@ bool PlayerController::startPlay()
         playStarted(); // 同步启动(无音频流)
     }
 
-    qDebug("Playback initialized in %lld ms", timer.elapsed());
+    qCDebug(playerControllerLog) << "Playback initialized in " << timer.elapsed() << " ms";
     return true;
 }
 
-void PlayerController::waitStopPlay(const QString& file)
+bool PlayerController::waitStopPlay(const QString& file)
 {
-    m_stopPlayWaitingThread = std::make_unique<StopWaitingThread>(this, file);
-    connect(m_stopPlayWaitingThread.get(),
-            &StopWaitingThread::stopPlay,
-            this,
-            &PlayerController::stopPlay);
-    connect(m_stopPlayWaitingThread.get(),
-            &StopWaitingThread::startPlay,
-            this,
-            &PlayerController::startToPlay);
-
+    m_stopPlayWaitingThread = std::make_unique<StopWaitingThread>(this, file.toStdString());
+    m_stopPlayWaitingThread->setOnFinished([this]() {
+        // 可根据需要添加额外处理
+    });
     m_stopPlayWaitingThread->start();
-    qDebug("++++++++++ StopPlay waiting thread started");
+    qCDebug(playerControllerLog) << "++++++++++ StopPlay waiting thread started";
+    return true;
 }
 
 void PlayerController::allThreadStart()
@@ -485,32 +486,32 @@ void PlayerController::allThreadStart()
     // 启动所有创建的线程
     if (m_packetReadThread) {
         m_packetReadThread->start();
-        qDebug("++++++++++ Read packets thread started");
+        qCDebug(playerControllerLog) << "++++++++++ Read packets thread started";
     }
 
     if (m_decodeVideoThread) {
         m_decodeVideoThread->start();
-        qDebug("++++++++++ Video decode thread started");
+        qCDebug(playerControllerLog) << "++++++++++ Video decode thread started";
     }
 
     if (m_decodeAudioThread) {
-        m_decodeAudioThread->start(QThread::Priority::HighPriority);
-        qDebug("++++++++++ Audio decode thread started");
+        m_decodeAudioThread->start();
+        qCDebug(playerControllerLog) << "++++++++++ Audio decode thread started";
     }
 
     if (m_decodeSubtitleThread) {
         m_decodeSubtitleThread->start();
-        qDebug("++++++++++ Subtitle decode thread started");
+        qCDebug(playerControllerLog) << "++++++++++ Subtitle decode thread started";
     }
 
     if (m_videoPlayThread) {
         m_videoPlayThread->start();
-        qDebug("++++++++++ Video play thread started");
+        qCDebug(playerControllerLog) << "++++++++++ Video play thread started";
     }
 
     if (m_audioPlayThread) {
         m_audioPlayThread->start();
-        qDebug("++++++++++ Audio play thread started");
+        qCDebug(playerControllerLog) << "++++++++++ Audio play thread started";
     }
 
     // 通知UI更新
@@ -542,21 +543,22 @@ void PlayerController::videoSeekInc(double increment)
 void PlayerController::checkAndResetState()
 {
     std::lock_guard<std::mutex> lock(m_stopMutex);
-    if (!m_packetReadThread && !m_decodeVideoThread && !m_decodeAudioThread &&
-        !m_audioPlayThread && !m_videoPlayThread && !m_decodeSubtitleThread) {
+    if (!m_packetReadThread && !m_decodeVideoThread && !m_decodeAudioThread && !m_audioPlayThread
+        && !m_videoPlayThread && !m_decodeSubtitleThread) {
         m_videoState.reset();
         m_currentFile.clear();
         m_state = PlayerState::Idle;
-        qDebug() << "[PlayerController] All threads stopped, state reset to Idle.";
+        qCDebug(playerControllerLog)
+            << "[PlayerController] All threads stopped, state reset to Idle.";
         emit playbackFinished(); // 新增:通知UI
     } else {
-        qDebug() << "[PlayerController] checkAndResetState: "
-                 << "m_packetReadThread:" << (bool)m_packetReadThread
-                 << "m_decodeVideoThread:" << (bool)m_decodeVideoThread
-                 << "m_decodeAudioThread:" << (bool)m_decodeAudioThread
-                 << "m_audioPlayThread:" << (bool)m_audioPlayThread
-                 << "m_videoPlayThread:" << (bool)m_videoPlayThread
-                 << "m_decodeSubtitleThread:" << (bool)m_decodeSubtitleThread;
+        qCDebug(playerControllerLog) << "[PlayerController] checkAndResetState: "
+                                     << "m_packetReadThread:" << (bool) m_packetReadThread
+                                     << "m_decodeVideoThread:" << (bool) m_decodeVideoThread
+                                     << "m_decodeAudioThread:" << (bool) m_decodeAudioThread
+                                     << "m_audioPlayThread:" << (bool) m_audioPlayThread
+                                     << "m_videoPlayThread:" << (bool) m_videoPlayThread
+                                     << "m_decodeSubtitleThread:" << (bool) m_decodeSubtitleThread;
     }
 }
 
@@ -574,7 +576,7 @@ bool PlayerController::createVideoState(const QString& file)
 
     if (ret < 0) {
         m_videoState.reset();
-        qWarning("Video state creation failed (error: %d)", ret);
+        qCWarning(playerControllerLog) << "Video state creation failed (error: " << ret << ")";
         return false;
     }
 
@@ -590,13 +592,10 @@ bool PlayerController::createReadThread()
 {
     if (m_packetReadThread)
         return false;
-
-    m_packetReadThread = std::make_unique<ReadThread>(this);
-    connect(m_packetReadThread.get(),
-            &ReadThread::finished,
-            this,
-            &PlayerController::readPacketStopped);
-
+    m_packetReadThread = std::make_unique<ReadThread>(m_videoState ? m_videoState->get_state()
+                                                                   : nullptr);
+    m_packetReadThread->setOnFinished(
+        [this]() { QMetaObject::invokeMethod(this, "readPacketStopped", Qt::QueuedConnection); });
     return true;
 }
 
@@ -609,11 +608,9 @@ bool PlayerController::createDecodeVideoThread()
     if (!state)
         return false;
 
-    m_decodeVideoThread = std::make_unique<VideoDecodeThread>(this, state);
-    connect(m_decodeVideoThread.get(),
-            &VideoDecodeThread::finished,
-            this,
-            &PlayerController::decodeVideoStopped);
+    m_decodeVideoThread = std::make_unique<VideoDecodeThread>(state);
+    m_decodeVideoThread->setOnFinished(
+        [this]() { QMetaObject::invokeMethod(this, "decodeVideoStopped", Qt::QueuedConnection); });
 
     auto codecContext = m_videoState->get_contex(AVMEDIA_TYPE_VIDEO);
 
@@ -623,13 +620,13 @@ bool PlayerController::createDecodeVideoThread()
                            &state->videoq,
                            state->continue_read_thread);
     if (ret < 0) {
-        qWarning("Video decoder initialization failed (error: %d)", ret);
+        qCWarning(playerControllerLog) << "Video decoder initialization failed (error: " << ret << ")";
         return false;
     }
 
     ret = decoder_start(&state->viddec, m_decodeVideoThread.get(), "video_decoder");
     if (ret < 0) {
-        qWarning("Video decoder start failed (error: %d)", ret);
+        qCWarning(playerControllerLog) << "Video decoder start failed (error: " << ret << ")";
         return false;
     }
 
@@ -646,11 +643,9 @@ bool PlayerController::createDecodeAudioThread()
     if (!state)
         return false;
 
-    m_decodeAudioThread = std::make_unique<AudioDecodeThread>(this, state);
-    connect(m_decodeAudioThread.get(),
-            &AudioDecodeThread::finished,
-            this,
-            &PlayerController::decodeAudioStopped);
+    m_decodeAudioThread = std::make_unique<AudioDecodeThread>(state);
+    m_decodeAudioThread->setOnFinished(
+        [this]() { QMetaObject::invokeMethod(this, "decodeAudioStopped", Qt::QueuedConnection); });
 
     auto codecContext = m_videoState->get_contex(AVMEDIA_TYPE_AUDIO);
 
@@ -660,13 +655,13 @@ bool PlayerController::createDecodeAudioThread()
                            &state->audioq,
                            state->continue_read_thread);
     if (ret < 0) {
-        qWarning("Audio decoder initialization failed (error: %d)", ret);
+        qCWarning(playerControllerLog) << "Audio decoder initialization failed (error: " << ret << ")";
         return false;
     }
 
     ret = decoder_start(&state->auddec, m_decodeAudioThread.get(), "audio_decoder");
     if (ret < 0) {
-        qWarning("Audio decoder start failed (error: %d)", ret);
+        qCWarning(playerControllerLog) << "Audio decoder start failed (error: " << ret << ")";
         return false;
     }
 
@@ -682,11 +677,10 @@ bool PlayerController::createDecodeSubtitleThread()
     if (!state)
         return false;
 
-    m_decodeSubtitleThread = std::make_unique<SubtitleDecodeThread>(this, state);
-    connect(m_decodeSubtitleThread.get(),
-            &SubtitleDecodeThread::finished,
-            this,
-            &PlayerController::decodeSubtitleStopped);
+    m_decodeSubtitleThread = std::make_unique<SubtitleDecodeThread>(state);
+    m_decodeSubtitleThread->setOnFinished([this]() {
+        QMetaObject::invokeMethod(this, "decodeSubtitleStopped", Qt::QueuedConnection);
+    });
 
     auto codecContext = m_videoState->get_contex(AVMEDIA_TYPE_SUBTITLE);
 
@@ -696,13 +690,13 @@ bool PlayerController::createDecodeSubtitleThread()
                            &state->subtitleq,
                            state->continue_read_thread);
     if (ret < 0) {
-        qWarning("Subtitle decoder initialization failed (error: %d)", ret);
+        qCWarning(playerControllerLog) << "Subtitle decoder initialization failed (error: " << ret << ")";
         return false;
     }
 
     ret = decoder_start(&state->subdec, m_decodeSubtitleThread.get(), "subtitle_decoder");
     if (ret < 0) {
-        qWarning("Subtitle decoder start failed (error: %d)", ret);
+        qCWarning(playerControllerLog) << "Subtitle decoder start failed (error: " << ret << ")";
         return false;
     }
 
@@ -718,32 +712,21 @@ bool PlayerController::createVideoPlayThread()
     if (!state)
         return false;
 
-    m_videoPlayThread = std::make_unique<VideoPlayThread>(this, state);
-
-    // 连接信号
-    connect(m_videoPlayThread.get(),
-            &VideoPlayThread::finished,
-            this,
-            &PlayerController::videoPlayStopped);
-    connect(m_videoPlayThread.get(),
-            &VideoPlayThread::frameReady,
-            this,
-            &PlayerController::frameReady);
-    connect(m_videoPlayThread.get(),
-            &VideoPlayThread::subtitle_ready,
-            this,
-            &PlayerController::subtitleReady);
-    connect(this,
-            &PlayerController::stopVideoPlayThread,
-            m_videoPlayThread.get(),
-            &VideoPlayThread::stop_thread);
+    m_videoPlayThread = std::make_unique<VideoPlayThread>(state);
+    m_videoPlayThread->setOnFinished(
+        [this]() { QMetaObject::invokeMethod(this, "videoPlayStopped", Qt::QueuedConnection); });
+    m_videoPlayThread->setOnFrameReady([this](AVFrame* frame) { this->onFrameReady(frame); });
+    m_videoPlayThread->setOnSubtitleReady([this](const QString& text) {
+        // TODO: 实现 PlayerController::onSubtitleReady(const QString&) 处理字幕
+        // onSubtitleReady(text);
+    });
 
     // 初始化参数
     auto videoContext = m_videoState->get_contex(AVMEDIA_TYPE_VIDEO);
     const bool useHardware = m_videoState->is_hardware_decode();
 
     if (!m_videoPlayThread->init_resample_param(videoContext, useHardware)) {
-        qWarning("Video resample parameters initialization failed");
+        qCWarning(playerControllerLog) << "Video resample parameters initialization failed";
         return false;
     }
 
@@ -759,25 +742,27 @@ bool PlayerController::createAudioPlayThread()
     if (!state)
         return false;
 
-    m_audioPlayThread = std::make_unique<AudioPlayThread>(this, state);
+    m_audioPlayThread = std::make_unique<AudioPlayThread>(state);
+    m_audioPlayThread->setOnFinished(
+        [this]() { QMetaObject::invokeMethod(this, "audioPlayStopped", Qt::QueuedConnection); });
+    m_audioPlayThread->setOnUpdatePlayTime([this]() {
+        // TODO: 实现 PlayerController::onUpdatePlayTime() 处理播放时间更新
+        // onUpdatePlayTime();
+    });
+    m_audioPlayThread->setOnDataVisualReady([this](const AudioData& data) {
+        // TODO: 实现 PlayerController::onDataVisualReady(const AudioData&) 处理可视化数据
+        // onDataVisualReady(data);
+    });
 
     // 连接信号
-    connect(m_audioPlayThread.get(),
-            &AudioPlayThread::finished,
-            this,
-            &PlayerController::audioPlayStopped);
-    connect(this,
-            &PlayerController::stopAudioPlayThread,
-            m_audioPlayThread.get(),
-            &AudioPlayThread::stop_thread);
-    connect(m_audioPlayThread.get(),
-            &AudioPlayThread::update_play_time,
-            this,
-            &PlayerController::updatePlayTime);
-    connect(m_audioPlayThread.get(),
-            &AudioPlayThread::data_visual_ready,
-            this,
-            &PlayerController::audioData);
+    // connect(m_audioPlayThread.get(),
+    //         &AudioPlayThread::update_play_time,
+    //         this,
+    //         &PlayerController::updatePlayTime);
+    // connect(m_audioPlayThread.get(),
+    //         &AudioPlayThread::data_visual_ready,
+    //         this,
+    //         &PlayerController::audioData);
 
     // 音频设备初始化在独立线程中完成
     return true;
@@ -788,14 +773,13 @@ bool PlayerController::startPlayThread()
     if (m_beforePlayThread)
         return false;
 
-    m_beforePlayThread = std::make_unique<StartPlayThread>(this, this);
-    connect(m_beforePlayThread.get(),
-            &StartPlayThread::audio_device_init,
-            this,
-            &PlayerController::playStarted);
-
+    m_beforePlayThread = std::make_unique<StartPlayThread>(this);
+    m_beforePlayThread->setOnFinished([this]() {
+        qCDebug(playerControllerLog) << "[StartPlayThread] finished, call playStarted()";
+        playStarted();
+    });
     m_beforePlayThread->start();
-    qDebug("++++++++++ StartPlay thread (audio init) started");
+    qCDebug(playerControllerLog) << "++++++++++ StartPlay thread (audio init) started";
 
     return true;
 }
@@ -806,19 +790,20 @@ void PlayerController::printDecodeContext(const AVCodecContext* codecCtx, bool i
     if (!codecCtx)
         return;
 
-    qInfo("%s codec: %s", isVideo ? "Video" : "Audio", codecCtx->codec->name);
-    qInfo("  Type: %d, ID: %d, Tag: %d",
-          codecCtx->codec_type,
-          codecCtx->codec_id,
-          codecCtx->codec_tag);
+    qCInfo(playerControllerLog) << (isVideo ? "Video" : "Audio") << " codec: " << codecCtx->codec->name;
+    qCInfo(playerControllerLog) << "  Type:" << codecCtx->codec_type << "ID:" << codecCtx->codec_id << "Tag:" << codecCtx->codec_tag;
 
     if (isVideo) {
-        qInfo("  Dimensions: %dx%d", codecCtx->width, codecCtx->height);
+        qCInfo(playerControllerLog) << "  Dimensions: " << codecCtx->width << "x" << codecCtx->height;
     } else {
-        qInfo("  Sample rate: %d Hz, Channels: %d, Format: %d",
-              codecCtx->sample_rate,
-              codecCtx->ch_layout.nb_channels,
-              codecCtx->sample_fmt);
-        qInfo("  Frame size: %d, Block align: %d", codecCtx->frame_size, codecCtx->block_align);
+        qCInfo(playerControllerLog) << "  Sample rate: " << codecCtx->sample_rate << " Hz, Channels: " << codecCtx->ch_layout.nb_channels << ", Format: " << codecCtx->sample_fmt;
+        qCInfo(playerControllerLog) << "  Frame size: " << codecCtx->frame_size << ", Block align: " << codecCtx->block_align;
     }
 }
+
+// 在合适位置实现 onFrameReady
+void PlayerController::onFrameReady(AVFrame* frame)
+{
+    // 这里可以做帧处理、缓存、同步等操作
+    emit frameReady(frame); // 直接转发给 UI 层
+}

+ 11 - 1
AvPlayer2/playercontroller.h

@@ -1,3 +1,6 @@
+#ifndef AVPLAYER2_PLAYERCONTROLLER_H
+#define AVPLAYER2_PLAYERCONTROLLER_H
+
 #pragma once
 
 #include <QElapsedTimer>
@@ -12,6 +15,8 @@
 #include <functional>
 
 #include "AVPlayer2/audio_play_thread.h"
+#include <QLoggingCategory>
+Q_DECLARE_LOGGING_CATEGORY(playerControllerLog)
 
 class ReadThread;
 class VideoDecodeThread;
@@ -117,13 +122,16 @@ signals:
 
     void asyncInitFinished(const QString& file, bool success);
 
+protected slots:
+    void onFrameReady(AVFrame* frame);
+
 private slots:
     void onAsyncInitFinished(const QString& file, bool success);
 
 private:
     // 核心播放逻辑
     bool startPlay();
-    void waitStopPlay(const QString& file);
+    bool waitStopPlay(const QString& file);
     void allThreadStart();
 
     // 线程创建方法
@@ -174,3 +182,5 @@ private:
     QString m_currentFile; // 更清晰的命名
     void checkAndResetState();
 };
+
+#endif // AVPLAYER2_PLAYERCONTROLLER_H

+ 74 - 81
AvPlayer2/read_thread.cpp

@@ -7,6 +7,7 @@
 // ***********************************************************/
 
 #include "read_thread.h"
+#include "AVPlayer2/playercontroller.h"
 
 extern int infinite_buffer;
 extern int64_t start_time;
@@ -15,10 +16,12 @@ static int64_t duration = AV_NOPTS_VALUE;
 ReadThread::ReadThread(VideoState* pState)
     : m_pPlayData(pState)
 {
+    qCDebug(playerControllerLog) << "[ReadThread] constructed, pState:" << (void*)pState;
 }
 
 ReadThread::~ReadThread()
 {
+    qCDebug(playerControllerLog) << "[ReadThread] destructed.";
     stop();
     join();
 }
@@ -31,7 +34,7 @@ void ReadThread::set_video_state(VideoState* pState)
 
 void ReadThread::stop()
 {
-    m_exit = true;
+    *m_exit = true;
     m_cv.notify_all();
 }
 
@@ -47,25 +50,28 @@ int ReadThread::loop_read()
         return ret;
 
     pkt = av_packet_alloc();
-    if (!pkt)
-    {
+    if (!pkt) {
         av_log(nullptr, AV_LOG_FATAL, "Could not allocate packet.\n");
         ret = AVERROR(ENOMEM);
+        qCWarning(playerControllerLog) << "[ReadThread] av_packet_alloc failed!";
         return ret;
     }
+    qCDebug(playerControllerLog) << "[ReadThread] loop_read start, file:" << (is && is->ic ? is->ic->url : "null");
 
     is->read_thread_exit = 0;
 
-    for (;;)
-    {
-        if (m_exit)
+    for (;;) {
+        if (m_exit) {
+            qCDebug(playerControllerLog) << "[ReadThread] m_exit set, break.";
             break;
+        }
 
-        if (is->abort_request)
+        if (is->abort_request) {
+            qCDebug(playerControllerLog) << "[ReadThread] abort_request set, break.";
             break;
+        }
 
-        if (is->paused != is->last_paused)
-        {
+        if (is->paused != is->last_paused) {
             is->last_paused = is->paused;
             if (is->paused)
                 is->read_pause_return = av_read_pause(is->ic);
@@ -73,35 +79,28 @@ int ReadThread::loop_read()
                 av_read_play(is->ic);
         }
 
-        if (is->seek_req)
-        {
+        if (is->seek_req) {
+            qCDebug(playerControllerLog) << "[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;
-
-            ret = avformat_seek_file(is->ic, -1, seek_min, seek_target, seek_max,
-                                     is->seek_flags);
-            if (ret < 0)
-            {
+            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;
+
+            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);
-            }
-            else
-            {
+                qCWarning(playerControllerLog) << "[ReadThread] avformat_seek_file failed, ret:" << ret;
+            } else {
+                qCDebug(playerControllerLog) << "[ReadThread] avformat_seek_file success, flush queues.";
                 if (is->audio_stream >= 0)
                     packet_queue_flush(&is->audioq);
                 if (is->subtitle_stream >= 0)
                     packet_queue_flush(&is->subtitleq);
                 if (is->video_stream >= 0)
                     packet_queue_flush(&is->videoq);
-                if (is->seek_flags & AVSEEK_FLAG_BYTE)
-                {
+                if (is->seek_flags & AVSEEK_FLAG_BYTE) {
                     set_clock(&is->extclk, NAN, 0);
-                }
-                else
-                {
-                    set_clock(&is->extclk, seek_target / (double)AV_TIME_BASE, 0);
+                } else {
+                    set_clock(&is->extclk, seek_target / (double) AV_TIME_BASE, 0);
                 }
             }
             is->seek_req = 0;
@@ -111,11 +110,9 @@ int ReadThread::loop_read()
                 step_to_next_frame(is);
         }
 
-        if (is->queue_attachments_req)
-        {
-            if (is->video_st &&
-                is->video_st->disposition & AV_DISPOSITION_ATTACHED_PIC)
-            {
+        if (is->queue_attachments_req) {
+            qCDebug(playerControllerLog) << "[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)
                     break;
@@ -126,26 +123,26 @@ int ReadThread::loop_read()
         }
 
         /* if the queue are full, no need to read more */
-        if (infinite_buffer < 1 &&
-            (is->audioq.size + is->videoq.size + is->subtitleq.size >
-                 MAX_QUEUE_SIZE ||
-             (stream_has_enough_packets(is->audio_st, is->audio_stream,
-                                        &is->audioq) &&
-              stream_has_enough_packets(is->video_st, is->video_stream,
-                                        &is->videoq) &&
-              stream_has_enough_packets(is->subtitle_st, is->subtitle_stream,
-                                        &is->subtitleq))))
-        {
+        if (infinite_buffer < 1
+            && (is->audioq.size + is->videoq.size + is->subtitleq.size > MAX_QUEUE_SIZE
+                || (stream_has_enough_packets(is->audio_st, is->audio_stream, &is->audioq)
+                    && stream_has_enough_packets(is->video_st, is->video_stream, &is->videoq)
+                    && stream_has_enough_packets(is->subtitle_st,
+                                                 is->subtitle_stream,
+                                                 &is->subtitleq)))) {
+            qCDebug(playerControllerLog)
+                << "[ReadThread] queues full, waiting... audioq:" << is->audioq.size
+                << ", videoq:" << is->videoq.size << ", subtitleq:" << is->subtitleq.size;
             std::unique_lock<std::mutex> lock(m_mutex);
-            m_cv.wait_for(lock, std::chrono::milliseconds(10), [this]{ return m_exit; });
+            m_cv.wait_for(lock, std::chrono::milliseconds(10), [this] { return m_exit && *m_exit; });
             continue;
         }
 
         ret = av_read_frame(is->ic, pkt);
-        if (ret < 0)
-        {
-            if ((ret == AVERROR_EOF || avio_feof(is->ic->pb)) && !is->eof)
-            {
+        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);
+            if ((ret == AVERROR_EOF || avio_feof(is->ic->pb)) && !is->eof) {
+                qCDebug(playerControllerLog) << "[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)
@@ -153,61 +150,55 @@ int ReadThread::loop_read()
                 if (is->subtitle_stream >= 0)
                     packet_queue_put_nullpacket(&is->subtitleq, pkt, is->subtitle_stream);
 
-                if (is->loop)
-                {
+                if (is->loop) {
                     stream_seek(is, 0, 0, 0);
-                }
-                else
-                {
+                } else {
                     is->eof = 1;
                     break; // added for auto exit read thread
                 }
             }
-            if (is->ic->pb && is->ic->pb->error)
-            {
+            if (is->ic->pb && is->ic->pb->error) {
+                qCWarning(playerControllerLog) << "[ReadThread] IO error detected.";
                 break;
             }
 
             std::unique_lock<std::mutex> lock(m_mutex);
-            m_cv.wait_for(lock, std::chrono::milliseconds(10), [this]{ return m_exit; });
+            m_cv.wait_for(lock, std::chrono::milliseconds(10), [this] { return m_exit && *m_exit; });
             continue;
-        }
-        else
-        {
+        } else {
             is->eof = 0;
+            qCDebug(playerControllerLog) << "[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
      * discard */
         stream_start_time = is->ic->streams[pkt->stream_index]->start_time;
         pkt_ts = pkt->pts == AV_NOPTS_VALUE ? pkt->dts : pkt->pts;
-        pkt_in_play_range =
-            duration == AV_NOPTS_VALUE ||
-            (pkt_ts -
-             (stream_start_time != AV_NOPTS_VALUE ? stream_start_time : 0)) *
-                        av_q2d(is->ic->streams[pkt->stream_index]->time_base) -
-                    (double)(start_time != AV_NOPTS_VALUE ? start_time : 0) /
-                        1000000 <=
-                ((double)duration / 1000000);
-        if (pkt->stream_index == is->audio_stream && pkt_in_play_range)
-        {
+        pkt_in_play_range = duration == AV_NOPTS_VALUE
+                            || (pkt_ts
+                                - (stream_start_time != AV_NOPTS_VALUE ? stream_start_time : 0))
+                                           * av_q2d(is->ic->streams[pkt->stream_index]->time_base)
+                                       - (double) (start_time != AV_NOPTS_VALUE ? start_time : 0)
+                                             / 1000000
+                                   <= ((double) duration / 1000000);
+        if (pkt->stream_index == is->audio_stream && pkt_in_play_range) {
+            qCDebug(playerControllerLog) << "[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))
-        {
+        } 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;
             packet_queue_put(&is->videoq, pkt);
-        }
-        else if (pkt->stream_index == is->subtitle_stream && pkt_in_play_range)
-        {
+        } else if (pkt->stream_index == is->subtitle_stream && pkt_in_play_range) {
+            qCDebug(playerControllerLog) << "[ReadThread] put subtitle packet, pts:" << pkt->pts;
             packet_queue_put(&is->subtitleq, pkt);
-        }
-        else
-        {
+        } else {
+            qCDebug(playerControllerLog)
+                << "[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";
     is->read_thread_exit = -1;
     av_packet_free(&pkt);
     return 0;
@@ -215,6 +206,8 @@ int ReadThread::loop_read()
 
 void ReadThread::run()
 {
+    qCDebug(playerControllerLog) << "[ReadThread] run start";
     int ret = loop_read();
+    qCDebug(playerControllerLog) << "[ReadThread] run end, loop_read ret:" << ret;
     // 可加日志输出
 }

+ 9 - 1
AvPlayer2/read_thread.h

@@ -1,14 +1,20 @@
+#ifndef AVPLAYER2_READ_THREAD_H
+#define AVPLAYER2_READ_THREAD_H
+
 #pragma once
 
 #include "ThreadBase.h"
 #include "packets_sync.h"
-#include <atomic>
 
 class ReadThread : public ThreadBase
 {
 public:
     explicit ReadThread(VideoState* pState = nullptr);
     ~ReadThread();
+    ReadThread(const ReadThread&) = delete;
+    ReadThread& operator=(const ReadThread&) = delete;
+    ReadThread(ReadThread&&) = delete;
+    ReadThread& operator=(ReadThread&&) = delete;
 
     void set_video_state(VideoState* pState = nullptr); // call before start
     void stop() override;
@@ -22,3 +28,5 @@ protected:
 private:
     VideoState* m_pPlayData;
 };
+
+#endif // AVPLAYER2_READ_THREAD_H

+ 2 - 1
AvPlayer2/start_play_thread.cpp

@@ -19,7 +19,7 @@ StartPlayThread::~StartPlayThread() {}
 
 void StartPlayThread::stop()
 {
-    m_exit = true;
+    *m_exit = true;
     m_cv.notify_all();
 }
 
@@ -50,4 +50,5 @@ void StartPlayThread::run()
         }
     }
     // 可加回调或日志
+    qCDebug(playerControllerLog) << "[StartPlayThread] run finished, ret=" << ret;
 }

+ 8 - 0
AvPlayer2/start_play_thread.h

@@ -1,3 +1,5 @@
+#ifndef AVPLAYER2_START_PLAY_THREAD_H
+#define AVPLAYER2_START_PLAY_THREAD_H
 #pragma once
 
 #include "ThreadBase.h"
@@ -8,6 +10,10 @@ class PlayerController;
 class StartPlayThread : public ThreadBase
 {
 public:
+    StartPlayThread(const StartPlayThread&) = delete;
+    StartPlayThread& operator=(const StartPlayThread&) = delete;
+    StartPlayThread(StartPlayThread&&) = delete;
+    StartPlayThread& operator=(StartPlayThread&&) = delete;
     explicit StartPlayThread(PlayerController *playerController);
     ~StartPlayThread();
 
@@ -17,3 +23,5 @@ protected:
     void run() override;
     PlayerController *m_playerController;
 };
+
+#endif // AVPLAYER2_START_PLAY_THREAD_H

+ 1 - 1
AvPlayer2/stopplay_waiting_thread.cpp

@@ -16,7 +16,7 @@ StopWaitingThread::~StopWaitingThread() {}
 
 void StopWaitingThread::stop()
 {
-    m_exit = true;
+    *m_exit = true;
     m_cv.notify_all();
 }
 

+ 9 - 0
AvPlayer2/stopplay_waiting_thread.h

@@ -1,3 +1,6 @@
+#ifndef AVPLAYER2_STOPPLAY_WAITING_THREAD_H
+#define AVPLAYER2_STOPPLAY_WAITING_THREAD_H
+
 #pragma once
 
 #include "ThreadBase.h"
@@ -9,6 +12,10 @@ class PlayerController;
 class StopWaitingThread : public ThreadBase
 {
 public:
+    StopWaitingThread(const StopWaitingThread&) = delete;
+    StopWaitingThread& operator=(const StopWaitingThread&) = delete;
+    StopWaitingThread(StopWaitingThread&&) = delete;
+    StopWaitingThread& operator=(StopWaitingThread&&) = delete;
     explicit StopWaitingThread(PlayerController* parent, const std::string& file = "");
     ~StopWaitingThread();
 
@@ -21,3 +28,5 @@ private:
     std::string m_file;
     PlayerController* m_parent;
 };
+
+#endif // AVPLAYER2_STOPPLAY_WAITING_THREAD_H

+ 1 - 1
AvPlayer2/subtitle_decode_thread.cpp

@@ -19,7 +19,7 @@ SubtitleDecodeThread::~SubtitleDecodeThread()
 
 void SubtitleDecodeThread::stop()
 {
-    m_exit = true;
+    *m_exit = true;
     m_cv.notify_all();
 }
 

+ 10 - 0
AvPlayer2/subtitle_decode_thread.h

@@ -1,3 +1,6 @@
+#ifndef AVPLAYER2_SUBTITLE_DECODE_THREAD_H
+#define AVPLAYER2_SUBTITLE_DECODE_THREAD_H
+
 #pragma once
 
 #include "ThreadBase.h"
@@ -10,6 +13,11 @@ public:
     explicit SubtitleDecodeThread(VideoState* pState = nullptr);
     ~SubtitleDecodeThread();
 
+    SubtitleDecodeThread(const SubtitleDecodeThread&) = delete;
+    SubtitleDecodeThread& operator=(const SubtitleDecodeThread&) = delete;
+    SubtitleDecodeThread(SubtitleDecodeThread&&) = delete;
+    SubtitleDecodeThread& operator=(SubtitleDecodeThread&&) = delete;
+
     void stop() override;
 
 protected:
@@ -18,3 +26,5 @@ protected:
 private:
     VideoState* m_pState;
 };
+
+#endif // AVPLAYER2_SUBTITLE_DECODE_THREAD_H

+ 25 - 17
AvPlayer2/video_decode_thread.cpp

@@ -8,6 +8,7 @@
 // ***********************************************************/
 
 #include "video_decode_thread.h"
+#include "AVPlayer2/playercontroller.h"
 
 VideoDecodeThread::VideoDecodeThread(VideoState* pState)
     : m_pState(pState)
@@ -17,14 +18,16 @@ VideoDecodeThread::~VideoDecodeThread() {}
 
 void VideoDecodeThread::stop()
 {
-    m_exit = true;
+    *m_exit = true;
     m_cv.notify_all();
 }
 
 void VideoDecodeThread::run()
 {
+    qCDebug(playerControllerLog) << "[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;
     AVFrame* frame = av_frame_alloc();
     AVFrame* sw_frame = av_frame_alloc();
     AVFrame* tmp_frame = nullptr;
@@ -33,28 +36,32 @@ void VideoDecodeThread::run()
     int ret;
     AVRational tb = is->video_st->time_base;
     AVRational frame_rate = av_guess_frame_rate(is->ic, is->video_st, nullptr);
-
-#if USE_AVFILTER_VIDEO
-    AVFilterContext *filt_out = nullptr, *filt_in = nullptr;
-    int last_w = 0;
-    int last_h = 0;
-    enum AVPixelFormat last_format = AV_PIX_FMT_NONE;
-    int last_serial = -1;
-    int last_vfilter_idx = 0;
-#endif
-
-    if (!frame)
+    if (!frame) {
+        qCWarning(playerControllerLog) << "[VideoDecodeThread] av_frame_alloc failed!";
         return;
-
+    }
+    int loop_count = 0;
     for (;;) {
-        if (m_exit)
+        if (m_exit) {
+            qCDebug(playerControllerLog) << "[VideoDecodeThread] m_exit set, exit.";
             break;
-
+        }
+        if (is->abort_request) {
+            qCDebug(playerControllerLog) << "[VideoDecodeThread] abort_request set, exit.";
+            break;
+        }
+        qCDebug(playerControllerLog) << "[VideoDecodeThread] call get_video_frame, loop:" << loop_count;
         ret = get_video_frame(is, frame);
-        if (ret < 0)
+        qCDebug(playerControllerLog) << "[VideoDecodeThread] get_video_frame ret:" << ret << ", loop:" << loop_count++;
+        if (ret < 0) {
+            qCWarning(playerControllerLog) << "[VideoDecodeThread] get_video_frame failed, exit.";
             goto the_end;
-        if (!ret)
+        }
+        if (!ret) {
+            qCDebug(playerControllerLog) << "[VideoDecodeThread] no frame, continue.";
             continue;
+        }
+        qCDebug(playerControllerLog) << "[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
@@ -168,5 +175,6 @@ 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;
     return;
 }

+ 10 - 0
AvPlayer2/video_decode_thread.h

@@ -1,3 +1,6 @@
+#ifndef AVPLAYER2_VIDEO_DECODE_THREAD_H
+#define AVPLAYER2_VIDEO_DECODE_THREAD_H
+
 #pragma once
 
 #include "ThreadBase.h"
@@ -12,9 +15,16 @@ public:
 
     void stop() override;
 
+    VideoDecodeThread(const VideoDecodeThread&) = delete;
+    VideoDecodeThread& operator=(const VideoDecodeThread&) = delete;
+    VideoDecodeThread(VideoDecodeThread&&) = delete;
+    VideoDecodeThread& operator=(VideoDecodeThread&&) = delete;
+
 protected:
     void run() override;
 
 private:
     VideoState* m_pState;
 };
+
+#endif // AVPLAYER2_VIDEO_DECODE_THREAD_H

+ 21 - 15
AvPlayer2/video_play_thread.cpp

@@ -9,6 +9,7 @@
 // ***********************************************************/
 
 #include "video_play_thread.h"
+#include "AVPlayer2/playercontroller.h"
 
 extern int framedrop;
 
@@ -30,38 +31,43 @@ VideoPlayThread::~VideoPlayThread()
 
 void VideoPlayThread::stop()
 {
-    m_exit = true;
+    *m_exit = true;
     m_cv.notify_all();
 }
 
 void VideoPlayThread::run()
 {
+    qCDebug(playerControllerLog) << "[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;
     double remaining_time = 0.0;
-
+    int loop_count = 0;
     for (;;) {
-        if (m_exit)
+        if (m_exit) {
+            qCDebug(playerControllerLog) << "[VideoPlayThread] m_exit set, exit.";
             break;
-
-        if (is->abort_request)
+        }
+        if (is->abort_request) {
+            qCDebug(playerControllerLog) << "[VideoPlayThread] abort_request set, exit.";
             break;
-
+        }
         if (is->paused) {
+            qCDebug(playerControllerLog) << "[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_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;
         if (remaining_time > 0.0)
             av_usleep((int64_t) (remaining_time * 1000000.0));
-
         remaining_time = REFRESH_RATE;
-        if ((!is->paused || is->force_refresh))
+        if ((!is->paused || is->force_refresh)) {
+            qCDebug(playerControllerLog) << "[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;
 }
 
 void VideoPlayThread::video_refresh(VideoState* is, double* remaining_time)
@@ -473,8 +479,7 @@ void VideoPlayThread::video_image_display(VideoState* is)
     // }
 
     // emit frame_ready(img);
-
-    emit frameReady(pFrameRGB);
+    if (m_onFrameReady) m_onFrameReady(pFrameRGB);
 }
 
 bool VideoPlayThread::init_resample_param(AVCodecContext* pVideo, bool bHardware)
@@ -550,5 +555,6 @@ void VideoPlayThread::parse_subtitle_ass(const QString& text)
     str.replace(m_assNewLineReplacer, "\n");
     str = str.trimmed();
 
-    emit subtitle_ready(str);
+    // emit subtitle_ready(str);
+    if (m_onSubtitleReady) m_onSubtitleReady(str);
 }

+ 15 - 2
AvPlayer2/video_play_thread.h

@@ -1,4 +1,6 @@
-#pragma once
+#ifndef AVPLAYER2_VIDEO_PLAY_THREAD_H
+#define AVPLAYER2_VIDEO_PLAY_THREAD_H
+#pragma once
 
 #include "ThreadBase.h"
 #include <QDebug>
@@ -21,9 +23,18 @@ public:
     explicit VideoPlayThread(VideoState* pState = nullptr);
     ~VideoPlayThread();
 
+    // 禁止拷贝
+    VideoPlayThread(const VideoPlayThread&) = delete;
+    VideoPlayThread& operator=(const VideoPlayThread&) = delete;
+    VideoPlayThread(VideoPlayThread&&) = delete;
+    VideoPlayThread& operator=(VideoPlayThread&&) = delete;
+
     bool init_resample_param(AVCodecContext* pVideo, bool bHardware = false);
     void stop() override;
 
+    void setOnFrameReady(std::function<void(AVFrame*)> cb) { m_onFrameReady = std::move(cb); }
+    void setOnSubtitleReady(std::function<void(const QString&)> cb) { m_onSubtitleReady = std::move(cb); }
+
 protected:
     void run() override;
 
@@ -38,8 +49,10 @@ private:
 private:
     VideoState* m_pState{nullptr};
     Video_Resample m_Resample;
-    std::atomic<bool> m_bExitThread{false};
 
     const static QRegularExpression m_assFilter;
     const static QRegularExpression m_assNewLineReplacer;
+    std::function<void(AVFrame*)> m_onFrameReady;
+    std::function<void(const QString&)> m_onSubtitleReady;
 };
+#endif // AVPLAYER2_VIDEO_PLAY_THREAD_H

+ 20 - 8
AvPlayer2/video_state.cpp

@@ -271,7 +271,13 @@ VideoState* VideoStateData::stream_open(const char* filename, const AVInputForma
     is->read_thread_exit = -1;
     is->loop = int(m_bLoopPlay);
 
-    is->threads = {nullptr};
+    // is->threads = {nullptr};
+    is->threads.read_tid = nullptr;
+    is->threads.video_decode_tid = nullptr;
+    is->threads.audio_decode_tid = nullptr;
+    is->threads.video_play_tid = nullptr;
+    is->threads.audio_play_tid = nullptr;
+    is->threads.subtitle_decode_tid = nullptr;
 
 #if USE_AVFILTER_AUDIO
     is->audio_speed = 1.0;
@@ -294,7 +300,13 @@ void VideoStateData::threads_setting(VideoState* is, const Threads& threads)
     assert(!is->threads.audio_play_tid);
     assert(!is->threads.subtitle_decode_tid);
 
-    is->threads = threads;
+    // is->threads = threads;
+    is->threads.read_tid = threads.read_tid;
+    is->threads.video_decode_tid = threads.video_decode_tid;
+    is->threads.audio_decode_tid = threads.audio_decode_tid;
+    is->threads.video_play_tid = threads.video_play_tid;
+    is->threads.audio_play_tid = threads.audio_play_tid;
+    is->threads.subtitle_decode_tid = threads.subtitle_decode_tid;
 }
 
 void VideoStateData::read_thread_exit_wait(VideoState* is)
@@ -307,7 +319,7 @@ void VideoStateData::read_thread_exit_wait(VideoState* is)
 
     if (is->threads.read_tid) {
         av_log(nullptr, AV_LOG_INFO, "read thread wait before!\n");
-        is->threads.read_tid->wait();
+        is->threads.read_tid->join();
         av_log(nullptr, AV_LOG_INFO, "read thread wait after!\n");
         is->threads.read_tid = nullptr;
     }
@@ -319,27 +331,27 @@ void VideoStateData::threads_exit_wait(VideoState* is)
         return;
 
     if (is->threads.video_play_tid) {
-        is->threads.video_play_tid->wait();
+        is->threads.video_play_tid->join();
         is->threads.video_play_tid = nullptr;
     }
 
     if (is->threads.audio_play_tid) {
-        is->threads.audio_play_tid->wait();
+        is->threads.audio_play_tid->join();
         is->threads.audio_play_tid = nullptr;
     }
 
     if (is->threads.video_decode_tid) {
-        is->threads.video_decode_tid->wait();
+        is->threads.video_decode_tid->join();
         is->threads.video_decode_tid = nullptr;
     }
 
     if (is->threads.audio_decode_tid) {
-        is->threads.audio_decode_tid->wait();
+        is->threads.audio_decode_tid->join();
         is->threads.audio_decode_tid = nullptr;
     }
 
     if (is->threads.subtitle_decode_tid) {
-        is->threads.subtitle_decode_tid->wait();
+        is->threads.subtitle_decode_tid->join();
         is->threads.subtitle_decode_tid = nullptr;
     }
 }

+ 5 - 0
AvPlayer2/video_state.h

@@ -3,6 +3,9 @@
  * @author Steven Huang
  */
 
+#ifndef AVPLAYER2_VIDEO_STATE_H
+#define AVPLAYER2_VIDEO_STATE_H
+
 #pragma once
 
 #include "packets_sync.h"
@@ -57,3 +60,5 @@ private:
     //enum AVPixelFormat m_hw_pix_fmt;
     bool m_bLoopPlay{false};
 };
+
+#endif // AVPLAYER2_VIDEO_STATE_H

+ 7 - 4
main.cpp

@@ -1,3 +1,4 @@
+#include "AVPlayer2/mainwindowa.h"
 #include "AvPlayer/playerdemowindow.h"
 #include "mainwindow.h"
 #include "thememanager.h"
@@ -14,6 +15,7 @@
 #include <QTextStream>
 #include <QDateTime>
 #include <QMutex>
+#include <QLoggingCategory>
 
 QFile g_logFile;
 QTextStream* g_logStream = nullptr;
@@ -50,6 +52,7 @@ 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"));
     // 打开日志文件(覆盖模式)
     g_logFile.setFileName("log.txt");
     g_logFile.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate);
@@ -94,8 +97,8 @@ docker run -itd  --name zlmediakit --restart=always
 -v /data/zlmediakit/media/conf:/opt/media/conf
 zlmediakit/zlmediakit:master
 */
-    MainWindow w;
-    w.show();
+    // MainWindow w;
+    // w.show();
 
     // ThemeSettingsWidget ThemeSettingsWidget;
     // ThemeSettingsWidget.show();
@@ -104,8 +107,8 @@ zlmediakit/zlmediakit:master
     // w.resize(960, 540);
     // w.show();
 
-    // MainWindowA aa;
-    // aa.show();
+    MainWindowA aa;
+    aa.show();
 
     // // 这里填你的流地址
     // // w.startPlay("http://vd3.bdstatic.com/mda-jennyc5ci1ugrxzi/mda-jennyc5ci1ugrxzi.mp4");