zhuizhu 8 luni în urmă
părinte
comite
21f72c75c8
3 a modificat fișierele cu 297 adăugiri și 211 ștergeri
  1. 166 0
      AvPlayer2/ThreadBase.h
  2. 127 209
      AvPlayer2/playercontroller.cpp
  3. 4 2
      AvPlayer2/playercontroller.h

+ 166 - 0
AvPlayer2/ThreadBase.h

@@ -0,0 +1,166 @@
+#ifndef AVPLAYER2_THREADBASE_H
+#define AVPLAYER2_THREADBASE_H
+
+#include <atomic>
+#include <chrono>
+#include <condition_variable>
+#include <functional>
+#include <mutex>
+#include <thread>
+
+class ThreadBase
+{
+public:
+    ThreadBase()
+        : m_exit(std::make_shared<std::atomic<bool>>(false))
+        , m_running(false)
+    {}
+
+    virtual ~ThreadBase()
+    {
+        if (m_running.load()) {
+            // 原子化停止请求
+            requestExit();
+
+            // 安全等待线程结束
+            safeJoin();
+        }
+    }
+
+    // 禁止拷贝
+    ThreadBase(const ThreadBase&) = delete;
+    ThreadBase& operator=(const ThreadBase&) = delete;
+    ThreadBase(ThreadBase&&) = delete;
+    ThreadBase& operator=(ThreadBase&&) = delete;
+
+    // 启动线程
+    void start()
+    {
+        if (m_running)
+            return;
+        *m_exit = false;
+        m_running = true;
+        m_thread = std::thread(&ThreadBase::threadEntry, this);
+    }
+
+    // 请求线程退出
+    virtual void stop()
+    {
+        *m_exit = true;
+        m_cv.notify_all();
+    }
+
+    // 等待线程退出
+    void join()
+    {
+        if (!m_thread.joinable() || m_joined)
+            return;
+
+        if (std::this_thread::get_id() != m_thread.get_id()) {
+            m_thread.join();
+            m_joined = true;
+            m_running = false;
+        }
+    }
+
+    bool isRunning() const { return m_running.load(); }
+    bool isExit() const { return m_exit && m_exit->load(); }
+
+    // 设置线程结束回调
+    void setOnFinished(std::function<void()> cb)
+    {
+        // 使用弱引用避免悬空指针
+        auto weakExit = std::weak_ptr(m_exit);
+        m_onFinished = [weakExit, cb]() {
+            if (auto exitPtr = weakExit.lock()) {
+                // 仅当退出标志设置后执行回调
+                if (*exitPtr) {
+                    cb();
+                }
+            }
+        };
+    }
+
+protected:
+    virtual void run() = 0;
+    std::shared_ptr<std::atomic<bool>> m_exit;
+    std::atomic<bool> m_running;
+    std::thread m_thread;
+    std::condition_variable m_cv;
+    std::mutex m_mutex;
+
+private:
+    // 新增辅助变量用于安全退出检测
+    std::atomic<bool> m_finishFlag{false};
+    std::mutex m_finishMutex;
+    std::condition_variable m_finishCv;
+    bool m_joined = false;
+    std::function<void()> m_onFinished;
+
+    // 安全的退出请求
+    void requestExit() noexcept
+    {
+        if (m_exit) {
+            m_exit->store(true);
+            m_cv.notify_all();
+        }
+    }
+
+    // 使用条件变量实现安全的超时等待
+    void safeJoin() noexcept
+    {
+        if (!m_thread.joinable())
+            return;
+
+        // 检查是否在自身线程中
+        if (std::this_thread::get_id() == m_thread.get_id()) {
+            m_thread.detach();
+            m_joined = true;
+            return;
+        }
+
+        // 超时等待线程结束
+        {
+            std::unique_lock<std::mutex> lock(m_finishMutex);
+            if (m_finishCv.wait_for(lock, std::chrono::milliseconds(500), [this] {
+                    return m_finishFlag.load();
+                })) {
+                // 线程已正常结束
+                join();
+            }
+        }
+
+        // 最终资源释放
+        if (m_thread.joinable()) {
+            try {
+                m_thread.join();
+            } catch (...) {
+                // 忽略所有异常
+            }
+            m_joined = true;
+        }
+    }
+
+    // 线程入口点
+    void threadEntry() noexcept
+    {
+        try {
+            run(); // 用户逻辑
+        } catch (...) {
+            // 异常安全处理
+        }
+        if (m_exit) {
+            *m_exit = true;
+        }
+        // 设置完成标志
+        m_finishFlag = true;
+        m_running = false;
+        m_finishCv.notify_one();
+
+        // 安全执行回调
+        if (m_onFinished) {
+            m_onFinished();
+        }
+    }
+};
+#endif // AVPLAYER2_THREADBASE_H

+ 127 - 209
AvPlayer2/playercontroller.cpp

@@ -46,65 +46,24 @@ void PlayerController::startToPlay(const QString& file)
 {
     std::lock_guard<std::mutex> lock(m_stopMutex);
     qCDebug(playerControllerLog) << "[PlayerController] m_state" << (int) m_state.load();
-    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 << Qt::endl
-             << "m_packetReadThread:"
-             << (m_packetReadThread ? m_packetReadThread->isRunning() : false)
-             << "m_decodeVideoThread:"
-             << (m_decodeVideoThread ? m_decodeVideoThread->isRunning() : false)
-             << "m_decodeAudioThread:"
-             << (m_decodeAudioThread ? m_decodeAudioThread->isRunning() : false)
-             << "m_audioPlayThread:" << (m_audioPlayThread ? m_audioPlayThread->isRunning() : false)
-             << "m_videoPlayThread:" << (m_videoPlayThread ? m_videoPlayThread->isRunning() : false)
-             << "m_decodeSubtitleThread:"
-             << (m_decodeSubtitleThread ? m_decodeSubtitleThread->isRunning() : false);
+
     // 自愈:如果状态为Playing但所有线程都已退出,强制Idle
-    if (m_state == PlayerState::Playing) {
-        // 检查线程指针是否存在并且是否正在运行
-        bool allThreadsStopped = 
-            (!m_packetReadThread || !m_packetReadThread->isRunning()) &&
-            (!m_decodeVideoThread || !m_decodeVideoThread->isRunning()) &&
-            (!m_decodeAudioThread || !m_decodeAudioThread->isRunning()) &&
-            (!m_audioPlayThread || !m_audioPlayThread->isRunning()) &&
-            (!m_videoPlayThread || !m_videoPlayThread->isRunning()) &&
-            (!m_decodeSubtitleThread || !m_decodeSubtitleThread->isRunning());
-            
-        if (allThreadsStopped) {
-            auto stopAndReset = [](auto& threadPtr) {
-                if (threadPtr) {
-                    qCDebug(playerControllerLog)
-                        << "[stopAndReset] try stop/join thread, isRunning="
-                        << threadPtr->isRunning();
-                    threadPtr->stop();
-                    threadPtr->join();
-                    qCDebug(playerControllerLog) << "[stopAndReset] thread joined and will reset.";
-                    threadPtr.reset();
-                }
-            };
-            stopAndReset(m_stopPlayWaitingThread);
-            stopAndReset(m_beforePlayThread);
-            stopAndReset(m_packetReadThread);
-            stopAndReset(m_decodeVideoThread);
-            stopAndReset(m_decodeAudioThread);
-            stopAndReset(m_decodeSubtitleThread);
-            stopAndReset(m_videoPlayThread);
-            stopAndReset(m_audioPlayThread);
-
-            m_currentFile.clear();
-            m_state = PlayerState::Idle;
-            qCDebug(playerControllerLog)
-                << "[PlayerController] All threads stopped, force reset to Idle.";
-        }
+    if (m_state == PlayerState::Playing && areAllThreadsStopped()) {
+        stopAndResetThreads();
+        m_videoState.reset();
+        m_currentFile.clear();
+        m_state = PlayerState::Idle;
+        qCDebug(playerControllerLog)
+            << "[PlayerController] All threads stopped, force reset to Idle.";
     }
+
+    // 初始化中,忽略新请求
     if (m_state == PlayerState::Initializing) {
         qCDebug(playerControllerLog) << "Player is initializing. Ignoring request.";
         return;
     }
+
+    // 正在播放中,检查是否需要切换文件
     if (m_state == PlayerState::Playing) {
         if (m_currentFile == file) {
             qCDebug(playerControllerLog) << "Already playing the same file. Ignoring request.";
@@ -116,46 +75,24 @@ void PlayerController::startToPlay(const QString& file)
             // 这里直接 fallthrough 到 Idle 状态
         }
     }
+
+    // 空闲状态,开始新播放
     if (m_state == PlayerState::Idle) {
-        bool allThreadsStopped = (!m_packetReadThread || !m_packetReadThread->isRunning())
-                                 && (!m_decodeVideoThread || !m_decodeVideoThread->isRunning())
-                                 && (!m_decodeAudioThread || !m_decodeAudioThread->isRunning())
-                                 && (!m_audioPlayThread || !m_audioPlayThread->isRunning())
-                                 && (!m_videoPlayThread || !m_videoPlayThread->isRunning())
-                                 && (!m_decodeSubtitleThread
-                                     || !m_decodeSubtitleThread->isRunning());
-
-        if (allThreadsStopped) {
-            auto stopAndReset = [](auto& threadPtr) {
-                if (threadPtr) {
-                    qCDebug(playerControllerLog)
-                        << "[stopAndReset] try stop/join thread, isRunning="
-                        << threadPtr->isRunning();
-                    threadPtr->stop();
-                    threadPtr->join();
-                    qCDebug(playerControllerLog) << "[stopAndReset] thread joined and will reset.";
-                    threadPtr.reset();
-                }
-            };
-            m_videoState.reset();
-            stopAndReset(m_stopPlayWaitingThread);
-            stopAndReset(m_beforePlayThread);
-            stopAndReset(m_packetReadThread);
-            stopAndReset(m_decodeVideoThread);
-            stopAndReset(m_decodeAudioThread);
-            stopAndReset(m_decodeSubtitleThread);
-            stopAndReset(m_videoPlayThread);
-            stopAndReset(m_audioPlayThread);
-
-            m_currentFile.clear();
-            m_state = PlayerState::Idle;
-            qCDebug(playerControllerLog)
-                << "[PlayerController] All threads stopped, force reset to Idle.";
+        // 确保所有线程已停止
+        if (!areAllThreadsStopped()) {
+            qCDebug(playerControllerLog) << "Some threads still running, stopping them first";
+            stopAndResetThreads();
         }
 
+        // 重置状态
+        m_videoState.reset();
+        m_currentFile.clear();
+
         qCDebug(playerControllerLog) << "Player is idle. Starting playback for:" << file;
         m_state = PlayerState::Initializing;
         m_currentFile = file;
+
+        // 启动异步初始化线程
         if (m_initThread.joinable()) {
             m_initThread.join();
         }
@@ -169,13 +106,24 @@ void PlayerController::asyncInit(const QString& file)
     QElapsedTimer timer;
     timer.start();
     qCDebug(playerControllerLog) << "[Init] asyncInit started";
+
+    // 检查文件有效性
     if (file.isEmpty()) {
         qCWarning(playerControllerLog) << "Filename is invalid. Please select a valid media file.";
         success = false;
     } else {
-        qCInfo(playerControllerLog) << "Check file: " << toNativePath(file);
-        success = true;
+        // 检查文件是否存在和可访问
+        QFileInfo fileInfo(file);
+        if (!fileInfo.exists() || !fileInfo.isReadable()) {
+            qCWarning(playerControllerLog)
+                << "File does not exist or is not readable:" << toNativePath(file);
+            success = false;
+        } else {
+            qCInfo(playerControllerLog) << "File check passed:" << toNativePath(file);
+            success = true;
+        }
     }
+
     m_initSuccess = success;
     onAsyncInitFinished(file, success);
     qCDebug(playerControllerLog) << "[Init] asyncInit finished in " << timer.elapsed() << " ms";
@@ -184,11 +132,17 @@ void PlayerController::asyncInit(const QString& file)
 void PlayerController::onAsyncInitFinished(const QString& file, bool success)
 {
     std::lock_guard<std::mutex> lock(m_stopMutex);
+    QElapsedTimer timer;
+    timer.start();
+
+    // 初始化失败处理
     if (!success) {
         playFailed(m_currentFile);
         m_state = PlayerState::Idle;
         return;
     }
+
+    // 创建视频状态对象
     qCDebug(playerControllerLog) << "[Init] createVideoState...";
     if (!createVideoState(m_currentFile)) {
         qCWarning(playerControllerLog) << "Video state creation failed";
@@ -197,24 +151,34 @@ void PlayerController::onAsyncInitFinished(const QString& file, bool success)
         m_state = PlayerState::Idle;
         return;
     }
+
+    // 检查状态有效性
     assert(m_videoState);
-    qCDebug(playerControllerLog) << "[Init] createReadThread...";
-    if (!createReadThread()) {
-        qCWarning(playerControllerLog) << "Packet read thread creation failed";
+    if (!m_videoState) {
+        qCWarning(playerControllerLog) << "Video state initialization error";
         playFailed(m_currentFile);
         m_state = PlayerState::Idle;
         return;
     }
-    if (!m_videoState) {
-        qCWarning(playerControllerLog) << "Video state initialization error";
+
+    // 创建数据包读取线程
+    qCDebug(playerControllerLog) << "[Init] createReadThread...";
+    if (!createReadThread()) {
+        qCWarning(playerControllerLog) << "Packet read thread creation failed";
         playFailed(m_currentFile);
         m_state = PlayerState::Idle;
         return;
     }
+
+    // 设置视频状态
     m_packetReadThread->set_video_state(m_videoState->get_state());
+
+    // 检查媒体流类型
     const bool hasVideo = playingHasVideo();
     const bool hasAudio = playingHasAudio();
     const bool hasSubtitle = playingHasSubtitle();
+
+    // 创建视频相关线程
     if (hasVideo) {
         if (!createDecodeVideoThread() || !createVideoPlayThread()) {
             qCWarning(playerControllerLog) << "Video processing setup failed";
@@ -224,6 +188,8 @@ void PlayerController::onAsyncInitFinished(const QString& file, bool success)
             return;
         }
     }
+
+    // 创建音频相关线程
     if (hasAudio) {
         if (!createDecodeAudioThread() || !createAudioPlayThread()) {
             qCWarning(playerControllerLog) << "Audio processing setup failed";
@@ -233,6 +199,8 @@ void PlayerController::onAsyncInitFinished(const QString& file, bool success)
             return;
         }
     }
+
+    // 创建字幕线程
     if (hasSubtitle && !createDecodeSubtitleThread()) {
         qCWarning(playerControllerLog) << "Subtitle processing setup failed";
         playFailed(m_currentFile);
@@ -240,13 +208,18 @@ void PlayerController::onAsyncInitFinished(const QString& file, bool success)
         m_state = PlayerState::Idle;
         return;
     }
+
+    // 开始播放
     if (hasAudio) {
-        startPlayThread();
+        startPlayThread(); // 异步启动(处理音频设备初始化)
     } else {
-        playStarted();
+        playStarted(); // 同步启动(无音频流)
     }
+
     emit startToPlaySignal();
     m_state = PlayerState::Playing;
+
+    qCDebug(playerControllerLog) << "Playback initialized in " << timer.elapsed() << " ms";
 }
 
 void PlayerController::stopPlay()
@@ -254,11 +227,19 @@ void PlayerController::stopPlay()
     std::lock_guard<std::mutex> lock(m_stopMutex);
     if (m_state == PlayerState::Idle)
         return;
+
+    qCDebug(playerControllerLog) << "Stopping playback...";
     m_state = PlayerState::Stopping;
 
+    // 停止并重置所有线程
+    stopAndResetThreads();
+
+    // 清理视频状态和文件信息
     m_videoState.reset();
     m_currentFile.clear();
     m_state = PlayerState::Idle;
+
+    qCDebug(playerControllerLog) << "Playback stopped.";
 }
 
 void PlayerController::pausePlay()
@@ -381,7 +362,6 @@ void PlayerController::readPacketStopped()
 {
     qCDebug(playerControllerLog) << "************* Read packets thread stopped signal received.";
     //m_packetReadThread.reset();
-    checkAndResetState();
 
     // stopPlay();
     if (m_videoState) {
@@ -393,34 +373,24 @@ void PlayerController::readPacketStopped()
 void PlayerController::decodeVideoStopped()
 {
     qCDebug(playerControllerLog) << "************* Video decode thread stopped.";
-    //m_decodeVideoThread.reset();
-    checkAndResetState();
 }
 void PlayerController::decodeAudioStopped()
 {
     qCDebug(playerControllerLog) << "************* Audio decode thread stopped.";
-    //m_decodeAudioThread.reset();
-    checkAndResetState();
 }
 void PlayerController::decodeSubtitleStopped()
 {
     qCDebug(playerControllerLog) << "************* Subtitle decode thread stopped.";
-    //m_decodeSubtitleThread.reset();
-    checkAndResetState();
 }
 void PlayerController::audioPlayStopped()
 {
     qCDebug(playerControllerLog) << "************* Audio play thread stopped.";
     emit audioStopped();
-    //m_audioPlayThread.reset();
-    checkAndResetState();
 }
 void PlayerController::videoPlayStopped()
 {
     qCDebug(playerControllerLog) << "************* Video play thread stopped.";
     emit videoStopped();
-    // m_videoPlayThread.reset();
-    checkAndResetState();
 }
 
 // 线程管理槽函数
@@ -466,76 +436,40 @@ void PlayerController::videoSeek(double position, double increment)
                 0);
 }
 
-// 核心私有实现
-bool PlayerController::startPlay()
+// 线程管理辅助方法
+void PlayerController::stopAndResetThreads()
 {
-    QElapsedTimer timer;
-    timer.start();
-
-    if (m_currentFile.isEmpty()) {
-        qCWarning(playerControllerLog) << "Filename is invalid. Please select a valid media file.";
-        return false;
-    }
-
-    qCInfo(playerControllerLog) << "Starting playback:" << toNativePath(m_currentFile);
-
-    // 创建数据包读取线程
-    if (!createReadThread()) {
-        qCWarning(playerControllerLog) << "Packet read thread creation failed";
-        return false;
-    }
-
-    // 创建视频状态对象
-    if (!createVideoState(m_currentFile)) {
-        qCWarning(playerControllerLog) << "Video state creation failed";
-        readPacketStopped();
-        return false;
-    }
-
-    // 检查状态有效性
-    assert(m_videoState);
-    if (!m_videoState) {
-        qCWarning(playerControllerLog) << "Video state initialization error";
-        return false;
-    }
-
-    m_packetReadThread->set_video_state(m_videoState->get_state());
-
-    const bool hasVideo = playingHasVideo();
-    const bool hasAudio = playingHasAudio();
-    const bool hasSubtitle = playingHasSubtitle();
-
-    // 创建视频相关线程
-    if (hasVideo) {
-        if (!createDecodeVideoThread() || !createVideoPlayThread()) {
-            qCWarning(playerControllerLog) << "Video processing setup failed";
-            return false;
-        }
-    }
-
-    // 创建音频相关线程
-    if (hasAudio) {
-        if (!createDecodeAudioThread() || !createAudioPlayThread()) {
-            qCWarning(playerControllerLog) << "Audio processing setup failed";
-            return false;
+    auto stopAndReset = [](auto& threadPtr) {
+        if (threadPtr) {
+            qCDebug(playerControllerLog)
+                << "[stopAndReset] try stop/join thread, isRunning=" << threadPtr->isRunning();
+            threadPtr->stop();
+            threadPtr->join();
+            qCDebug(playerControllerLog) << "[stopAndReset] thread joined and will reset.";
+            threadPtr.reset();
         }
-    }
-
-    // 创建字幕线程
-    if (hasSubtitle && !createDecodeSubtitleThread()) {
-        qCWarning(playerControllerLog) << "Subtitle processing setup failed";
-        return false;
-    }
+    };
 
-    // 开始播放
-    if (hasAudio) {
-        startPlayThread(); // 异步启动(处理音频设备初始化)
-    } else {
-        playStarted(); // 同步启动(无音频流)
-    }
+    // 按依赖顺序停止线程
+    stopAndReset(m_stopPlayWaitingThread);
+    stopAndReset(m_beforePlayThread);
+    stopAndReset(m_packetReadThread);
+    stopAndReset(m_decodeVideoThread);
+    stopAndReset(m_decodeAudioThread);
+    stopAndReset(m_decodeSubtitleThread);
+    stopAndReset(m_videoPlayThread);
+    stopAndReset(m_audioPlayThread);
+}
 
-    qCDebug(playerControllerLog) << "Playback initialized in " << timer.elapsed() << " ms";
-    return true;
+bool PlayerController::areAllThreadsStopped() const
+{
+    // 检查所有线程是否已停止
+    return (!m_packetReadThread || !m_packetReadThread->isRunning())
+           && (!m_decodeVideoThread || !m_decodeVideoThread->isRunning())
+           && (!m_decodeAudioThread || !m_decodeAudioThread->isRunning())
+           && (!m_audioPlayThread || !m_audioPlayThread->isRunning())
+           && (!m_videoPlayThread || !m_videoPlayThread->isRunning())
+           && (!m_decodeSubtitleThread || !m_decodeSubtitleThread->isRunning());
 }
 
 bool PlayerController::waitStopPlay(const QString& file)
@@ -613,29 +547,6 @@ void PlayerController::videoSeekInc(double increment)
     videoSeek(position, 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) {
-    //     m_videoState.reset();
-    //     m_currentFile.clear();
-    //     m_state = PlayerState::Idle;
-    //     qCDebug(playerControllerLog)
-    //         << "[PlayerController] All threads stopped, state reset to Idle.";
-    //     emit playbackFinished(); // 新增:通知UI
-    // } else {
-    //     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;
-    // }
-}
-
 // 线程创建方法
 bool PlayerController::createVideoState(const QString& file)
 {
@@ -668,10 +579,7 @@ bool PlayerController::createReadThread()
         return false;
     m_packetReadThread = std::make_unique<ReadThread>(m_videoState ? m_videoState->get_state()
                                                                    : nullptr);
-    m_packetReadThread->setOnFinished([this]() {
-
-        readPacketStopped();
-    });
+    m_packetReadThread->setOnFinished([this]() { readPacketStopped(); });
     return true;
 }
 
@@ -695,7 +603,8 @@ bool PlayerController::createDecodeVideoThread()
                            &state->videoq,
                            state->continue_read_thread);
     if (ret < 0) {
-        qCWarning(playerControllerLog) << "Video decoder initialization failed (error: " << ret << ")";
+        qCWarning(playerControllerLog)
+            << "Video decoder initialization failed (error: " << ret << ")";
         return false;
     }
 
@@ -729,7 +638,8 @@ bool PlayerController::createDecodeAudioThread()
                            &state->audioq,
                            state->continue_read_thread);
     if (ret < 0) {
-        qCWarning(playerControllerLog) << "Audio decoder initialization failed (error: " << ret << ")";
+        qCWarning(playerControllerLog)
+            << "Audio decoder initialization failed (error: " << ret << ")";
         return false;
     }
 
@@ -762,7 +672,8 @@ bool PlayerController::createDecodeSubtitleThread()
                            &state->subtitleq,
                            state->continue_read_thread);
     if (ret < 0) {
-        qCWarning(playerControllerLog) << "Subtitle decoder initialization failed (error: " << ret << ")";
+        qCWarning(playerControllerLog)
+            << "Subtitle decoder initialization failed (error: " << ret << ")";
         return false;
     }
 
@@ -833,7 +744,8 @@ bool PlayerController::startPlayThread()
     if (m_beforePlayThread)
         return false;
 
-    m_beforePlayThread = std::make_unique<StartPlayThread>(m_audioPlayThread.get(), m_videoState.get());
+    m_beforePlayThread = std::make_unique<StartPlayThread>(m_audioPlayThread.get(),
+                                                           m_videoState.get());
 
     m_beforePlayThread->setOnFinished([this]() {
         qCDebug(playerControllerLog) << "[StartPlayThread] finished, call playStarted()";
@@ -851,14 +763,20 @@ void PlayerController::printDecodeContext(const AVCodecContext* codecCtx, bool i
     if (!codecCtx)
         return;
 
-    qCInfo(playerControllerLog) << (isVideo ? "Video" : "Audio") << " codec: " << codecCtx->codec->name;
-    qCInfo(playerControllerLog) << "  Type:" << codecCtx->codec_type << "ID:" << codecCtx->codec_id << "Tag:" << 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) {
-        qCInfo(playerControllerLog) << "  Dimensions: " << codecCtx->width << "x" << codecCtx->height;
+        qCInfo(playerControllerLog)
+            << "  Dimensions: " << codecCtx->width << "x" << codecCtx->height;
     } else {
-        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;
+        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;
     }
 }
 

+ 4 - 2
AvPlayer2/playercontroller.h

@@ -253,10 +253,12 @@ private:
     //--------------------------------------------------------------------------
     // 核心播放逻辑
     //--------------------------------------------------------------------------
-    bool startPlay();
     bool waitStopPlay(const QString& file);
     void allThreadStart();
-    void checkAndResetState();
+
+    // 线程管理辅助方法
+    void stopAndResetThreads();
+    bool areAllThreadsStopped() const;
 
     //--------------------------------------------------------------------------
     // 线程创建方法