Răsfoiți Sursa

优化 播放到异步

zhuizhu 8 luni în urmă
părinte
comite
e25359aa00
3 a modificat fișierele cu 109 adăugiri și 3 ștergeri
  1. 86 3
      AvPlayer2/playercontroller.cpp
  2. 13 0
      AvPlayer2/playercontroller.h
  3. 10 0
      MainPanel.cpp

+ 86 - 3
AvPlayer2/playercontroller.cpp

@@ -32,6 +32,15 @@ PlayerController::PlayerController(QWidget* parent)
 
 PlayerController::~PlayerController()
 {
+    // 等待初始化线程安全退出
+    if (m_initThread.joinable()) {
+        {
+            std::lock_guard<std::mutex> lock(m_initMutex);
+            m_initInProgress = false;
+        }
+        m_initCv.notify_all();
+        m_initThread.join();
+    }
     stopPlay();
 }
 
@@ -41,14 +50,82 @@ void PlayerController::startToPlay(const QString& file)
     if (isPlaying()) {
         if (m_currentFile == file)
             return;
-
         waitStopPlay(file);
         return;
     }
-
     m_currentFile = file;
+    if (m_initInProgress) return; // 正在初始化,直接返回
+    m_initInProgress = true;
+    if (m_initThread.joinable()) m_initThread.join();
+    m_initThread = std::thread(&PlayerController::asyncInit, this, file);
+}
 
-    if (!startPlay()) {
+void PlayerController::asyncInit(const QString& file)
+{
+    bool success = false;
+    // startPlay 的主体迁移到这里
+    QElapsedTimer timer;
+    timer.start();
+    if (file.isEmpty()) {
+        qWarning("Filename is invalid. Please select a valid media file.");
+        success = false;
+    } else {
+        qInfo("Starting playback: %s", qUtf8Printable(toNativePath(file)));
+        if (!createReadThread()) {
+            qWarning("Packet read thread creation failed");
+            success = false;
+        } else if (!createVideoState(file)) {
+            qWarning("Video state creation failed");
+            readPacketStopped();
+            success = false;
+        } else if (!m_videoState) {
+            qWarning("Video state initialization error");
+            success = false;
+        } else {
+            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()) {
+                    qWarning("Video processing setup failed");
+                    success = false;
+                }
+            }
+            if (hasAudio) {
+                if (!createDecodeAudioThread() || !createAudioPlayThread()) {
+                    qWarning("Audio processing setup failed");
+                    success = false;
+                }
+            }
+            if (hasSubtitle && !createDecodeSubtitleThread()) {
+                qWarning("Subtitle processing setup failed");
+                success = false;
+            }
+            // 开始播放
+            if (hasAudio) {
+                // 音频设备初始化在独立线程中完成
+                startPlayThread();
+            } else {
+                playStarted();
+            }
+            success = true;
+        }
+    }
+    {
+        std::lock_guard<std::mutex> lock(m_initMutex);
+        m_initSuccess = success;
+        m_initInProgress = false;
+    }
+    m_initCv.notify_all();
+    onInitFinished(success);
+    qDebug("Playback initialized in %lld ms", timer.elapsed());
+}
+
+void PlayerController::onInitFinished(bool success)
+{
+    // 这里可以发 Qt 信号或回调
+    if (!success) {
         playFailed(m_currentFile);
         return;
     }
@@ -58,6 +135,12 @@ void PlayerController::startToPlay(const QString& file)
 void PlayerController::stopPlay()
 {
     deleteVideoState();
+    m_packetReadThread.reset();
+    m_decodeVideoThread.reset();
+    m_decodeAudioThread.reset();
+    m_decodeSubtitleThread.reset();
+    m_videoPlayThread.reset();
+    m_audioPlayThread.reset();
 }
 
 void PlayerController::pausePlay()

+ 13 - 0
AvPlayer2/playercontroller.h

@@ -12,6 +12,10 @@
 #include <QTimer>
 #include <QWidget>
 #include <memory>
+#include <thread>
+#include <atomic>
+#include <condition_variable>
+#include <functional>
 
 #include "AVPlayer2/audio_play_thread.h"
 
@@ -136,6 +140,15 @@ private:
     void hideCursor(bool hide = true);
     bool cursorInWindow(QWidget* widget);
 
+    // 异步初始化相关
+    void asyncInit(const QString& file);
+    void onInitFinished(bool success);
+    std::thread m_initThread;
+    std::atomic<bool> m_initInProgress{false};
+    std::mutex m_initMutex;
+    std::condition_variable m_initCv;
+    bool m_initSuccess{false};
+
 private:
     // 多媒体线程
     std::unique_ptr<ReadThread> m_packetReadThread;

+ 10 - 0
MainPanel.cpp

@@ -11,6 +11,8 @@
 #include <qtpromise/qpromisefuture.h>
 #include <qtpromise/qpromisehelpers.h>
 
+#include <QtConcurrent>
+
 #include "widgets/bubbletip.h"
 #include "widgets/chatView/chatwindow.h"
 #include "widgets/maskoverlay.h"
@@ -75,9 +77,17 @@ MainPanel::MainPanel(QWidget *parent)
             qDebug() << "[MainPanel] liveStatus: 直播中";
             if (chatView) {
                 const QString id = webSocketClient->roomId();
+
                 if (PlayWidget *playWidget = qobject_cast<PlayWidget *>(playerWidget)) {
                     if (!playWidget->isPlaying()) {
                         playWidget->startToPlay("rtmp://106.55.186.74:1935/stream/V1/" + id);
+                        // QFuture<void> playFuture = QtConcurrent::run([playWidget, id] {
+                        //     playWidget->startToPlay("rtmp://106.55.186.74:1935/stream/V1/" + id);
+                        // });
+                        // QtPromise::QPromise<void> playPromise = QtPromise::resolve(playFuture);
+                        // playPromise.then([] {
+                        //     // 可选:播放成功后UI反馈
+                        // });
                     }
                 }
             }