|
@@ -19,6 +19,7 @@
|
|
|
#include "AVPlayer2/audio_play_thread.h"
|
|
#include "AVPlayer2/audio_play_thread.h"
|
|
|
Q_DECLARE_LOGGING_CATEGORY(playerControllerLog)
|
|
Q_DECLARE_LOGGING_CATEGORY(playerControllerLog)
|
|
|
|
|
|
|
|
|
|
+// 前置声明
|
|
|
class ReadThread;
|
|
class ReadThread;
|
|
|
class VideoDecodeThread;
|
|
class VideoDecodeThread;
|
|
|
class AudioDecodeThread;
|
|
class AudioDecodeThread;
|
|
@@ -28,44 +29,142 @@ class VideoPlayThread;
|
|
|
class VideoStateData;
|
|
class VideoStateData;
|
|
|
class StartPlayThread;
|
|
class StartPlayThread;
|
|
|
class StopWaitingThread;
|
|
class StopWaitingThread;
|
|
|
-
|
|
|
|
|
struct VideoState;
|
|
struct VideoState;
|
|
|
-
|
|
|
|
|
class OpenGLVideoWidget;
|
|
class OpenGLVideoWidget;
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * @brief 媒体播放控制器
|
|
|
|
|
+ *
|
|
|
|
|
+ * 负责协调音视频解码和播放线程,管理播放状态和用户交互
|
|
|
|
|
+ */
|
|
|
class PlayerController : public QObject
|
|
class PlayerController : public QObject
|
|
|
{
|
|
{
|
|
|
Q_OBJECT
|
|
Q_OBJECT
|
|
|
|
|
|
|
|
public:
|
|
public:
|
|
|
- enum class PlayerState { Idle, Initializing, Playing, Stopping };
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * @brief 播放器状态枚举
|
|
|
|
|
+ */
|
|
|
|
|
+ enum class PlayerState {
|
|
|
|
|
+ Idle, ///< 空闲状态
|
|
|
|
|
+ Initializing, ///< 初始化中
|
|
|
|
|
+ Playing, ///< 播放中
|
|
|
|
|
+ Stopping ///< 停止中
|
|
|
|
|
+ };
|
|
|
|
|
|
|
|
explicit PlayerController(QWidget* parent = nullptr);
|
|
explicit PlayerController(QWidget* parent = nullptr);
|
|
|
~PlayerController();
|
|
~PlayerController();
|
|
|
|
|
|
|
|
- // 播放控制接口
|
|
|
|
|
|
|
+ //--------------------------------------------------------------------------
|
|
|
|
|
+ // 播放控制公共接口
|
|
|
|
|
+ //--------------------------------------------------------------------------
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * @brief 开始播放指定文件
|
|
|
|
|
+ * @param file 媒体文件路径
|
|
|
|
|
+ */
|
|
|
void startToPlay(const QString& file);
|
|
void startToPlay(const QString& file);
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * @brief 停止当前播放
|
|
|
|
|
+ */
|
|
|
void stopPlay();
|
|
void stopPlay();
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * @brief 暂停/继续播放
|
|
|
|
|
+ */
|
|
|
void pausePlay();
|
|
void pausePlay();
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * @brief 静音控制
|
|
|
|
|
+ * @param mute 是否静音
|
|
|
|
|
+ */
|
|
|
void playMute(bool mute);
|
|
void playMute(bool mute);
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * @brief 开始拖动进度条
|
|
|
|
|
+ */
|
|
|
void playStartSeek();
|
|
void playStartSeek();
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * @brief 快退
|
|
|
|
|
+ */
|
|
|
void playSeekPre();
|
|
void playSeekPre();
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * @brief 快进
|
|
|
|
|
+ */
|
|
|
void playSeekNext();
|
|
void playSeekNext();
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * @brief 设置音量
|
|
|
|
|
+ * @param volume 音量值
|
|
|
|
|
+ * @param maxValue 最大音量值
|
|
|
|
|
+ */
|
|
|
void setVolume(int volume, int maxValue = 100);
|
|
void setVolume(int volume, int maxValue = 100);
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * @brief 设置播放速度
|
|
|
|
|
+ * @param speed 播放速度倍率
|
|
|
|
|
+ */
|
|
|
void setPlaySpeed(double speed);
|
|
void setPlaySpeed(double speed);
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * @brief 是否正在播放
|
|
|
|
|
+ * @return 播放状态
|
|
|
|
|
+ */
|
|
|
bool isPlaying() const;
|
|
bool isPlaying() const;
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * @brief 获取当前播放文件路径
|
|
|
|
|
+ * @return 文件路径
|
|
|
|
|
+ */
|
|
|
QString playingFile() const;
|
|
QString playingFile() const;
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * @brief 当前媒体是否包含视频流
|
|
|
|
|
+ * @return 是否有视频
|
|
|
|
|
+ */
|
|
|
bool playingHasVideo();
|
|
bool playingHasVideo();
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * @brief 当前媒体是否包含音频流
|
|
|
|
|
+ * @return 是否有音频
|
|
|
|
|
+ */
|
|
|
bool playingHasAudio();
|
|
bool playingHasAudio();
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * @brief 当前媒体是否包含字幕流
|
|
|
|
|
+ * @return 是否有字幕
|
|
|
|
|
+ */
|
|
|
bool playingHasSubtitle();
|
|
bool playingHasSubtitle();
|
|
|
|
|
|
|
|
|
|
+ //--------------------------------------------------------------------------
|
|
|
// 状态访问接口
|
|
// 状态访问接口
|
|
|
|
|
+ //--------------------------------------------------------------------------
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * @brief 获取视频状态对象
|
|
|
|
|
+ * @return VideoState指针
|
|
|
|
|
+ */
|
|
|
VideoState* state();
|
|
VideoState* state();
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * @brief 获取设备音量
|
|
|
|
|
+ * @return 音量值(0.0-1.0)
|
|
|
|
|
+ */
|
|
|
float deviceVolume() const;
|
|
float deviceVolume() const;
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * @brief 设置设备音量
|
|
|
|
|
+ * @param volume 音量值(0.0-1.0)
|
|
|
|
|
+ */
|
|
|
void setDeviceVolume(float volume);
|
|
void setDeviceVolume(float volume);
|
|
|
|
|
|
|
|
public slots:
|
|
public slots:
|
|
|
- // 线程生命周期管理
|
|
|
|
|
|
|
+ //--------------------------------------------------------------------------
|
|
|
|
|
+ // 线程生命周期管理槽函数
|
|
|
|
|
+ //--------------------------------------------------------------------------
|
|
|
void readPacketStopped();
|
|
void readPacketStopped();
|
|
|
void decodeVideoStopped();
|
|
void decodeVideoStopped();
|
|
|
void decodeAudioStopped();
|
|
void decodeAudioStopped();
|
|
@@ -73,17 +172,23 @@ public slots:
|
|
|
void audioPlayStopped();
|
|
void audioPlayStopped();
|
|
|
void videoPlayStopped();
|
|
void videoPlayStopped();
|
|
|
|
|
|
|
|
- // 播放状态回调
|
|
|
|
|
|
|
+ //--------------------------------------------------------------------------
|
|
|
|
|
+ // 播放状态回调槽函数
|
|
|
|
|
+ //--------------------------------------------------------------------------
|
|
|
void playStarted(bool success = true);
|
|
void playStarted(bool success = true);
|
|
|
void playFailed(const QString& file);
|
|
void playFailed(const QString& file);
|
|
|
|
|
|
|
|
- // 线程管理
|
|
|
|
|
|
|
+ //--------------------------------------------------------------------------
|
|
|
|
|
+ // 线程管理槽函数
|
|
|
|
|
+ //--------------------------------------------------------------------------
|
|
|
void setThreads();
|
|
void setThreads();
|
|
|
void startSendData(bool send = true);
|
|
void startSendData(bool send = true);
|
|
|
void videoSeek(double pos = 0, double incr = 0);
|
|
void videoSeek(double pos = 0, double incr = 0);
|
|
|
|
|
|
|
|
signals:
|
|
signals:
|
|
|
|
|
+ //--------------------------------------------------------------------------
|
|
|
// 线程控制信号
|
|
// 线程控制信号
|
|
|
|
|
+ //--------------------------------------------------------------------------
|
|
|
void startToPlaySignal();
|
|
void startToPlaySignal();
|
|
|
void stopAudioPlayThread();
|
|
void stopAudioPlayThread();
|
|
|
void stopVideoPlayThread();
|
|
void stopVideoPlayThread();
|
|
@@ -92,16 +197,23 @@ signals:
|
|
|
void waitStopAudioPlayThread();
|
|
void waitStopAudioPlayThread();
|
|
|
void waitStopVideoPlayThread();
|
|
void waitStopVideoPlayThread();
|
|
|
|
|
|
|
|
- void audioStopped(); // 音频结束
|
|
|
|
|
- void videoStopped(); // 视频结束
|
|
|
|
|
- void playbackFinished(); // 新增:播放自然结束
|
|
|
|
|
|
|
+ //--------------------------------------------------------------------------
|
|
|
|
|
+ // 播放状态信号
|
|
|
|
|
+ //--------------------------------------------------------------------------
|
|
|
|
|
+ void audioStopped(); ///< 音频结束
|
|
|
|
|
+ void videoStopped(); ///< 视频结束
|
|
|
|
|
+ void playbackFinished(); ///< 播放自然结束
|
|
|
|
|
|
|
|
- // 多媒体数据处理
|
|
|
|
|
|
|
+ //--------------------------------------------------------------------------
|
|
|
|
|
+ // 多媒体数据处理信号
|
|
|
|
|
+ //--------------------------------------------------------------------------
|
|
|
void frameReady(AVFrame*);
|
|
void frameReady(AVFrame*);
|
|
|
void audioData(const AudioData& data);
|
|
void audioData(const AudioData& data);
|
|
|
void subtitleReady(const QString& text);
|
|
void subtitleReady(const QString& text);
|
|
|
|
|
|
|
|
|
|
+ //--------------------------------------------------------------------------
|
|
|
// UI更新信号
|
|
// UI更新信号
|
|
|
|
|
+ //--------------------------------------------------------------------------
|
|
|
void setPlayControlWnd(bool set);
|
|
void setPlayControlWnd(bool set);
|
|
|
void updatePlayControlVolume();
|
|
void updatePlayControlVolume();
|
|
|
void updatePlayControlStatus();
|
|
void updatePlayControlStatus();
|
|
@@ -111,6 +223,9 @@ signals:
|
|
|
void requestFullscreen(bool fullscreen);
|
|
void requestFullscreen(bool fullscreen);
|
|
|
void requestHideStatusBar(bool hide);
|
|
void requestHideStatusBar(bool hide);
|
|
|
|
|
|
|
|
|
|
+ //--------------------------------------------------------------------------
|
|
|
|
|
+ // 异步初始化信号
|
|
|
|
|
+ //--------------------------------------------------------------------------
|
|
|
void asyncInitFinished(const QString& file, bool success);
|
|
void asyncInitFinished(const QString& file, bool success);
|
|
|
|
|
|
|
|
protected slots:
|
|
protected slots:
|
|
@@ -120,6 +235,9 @@ private slots:
|
|
|
void onAsyncInitFinished(const QString& file, bool success);
|
|
void onAsyncInitFinished(const QString& file, bool success);
|
|
|
|
|
|
|
|
private:
|
|
private:
|
|
|
|
|
+ //--------------------------------------------------------------------------
|
|
|
|
|
+ // 线程类型枚举
|
|
|
|
|
+ //--------------------------------------------------------------------------
|
|
|
enum class ThreadType {
|
|
enum class ThreadType {
|
|
|
Video,
|
|
Video,
|
|
|
Audio,
|
|
Audio,
|
|
@@ -132,12 +250,17 @@ private:
|
|
|
};
|
|
};
|
|
|
std::unordered_map<ThreadType, std::mutex> m_threadMutexes;
|
|
std::unordered_map<ThreadType, std::mutex> m_threadMutexes;
|
|
|
|
|
|
|
|
|
|
+ //--------------------------------------------------------------------------
|
|
|
// 核心播放逻辑
|
|
// 核心播放逻辑
|
|
|
|
|
+ //--------------------------------------------------------------------------
|
|
|
bool startPlay();
|
|
bool startPlay();
|
|
|
bool waitStopPlay(const QString& file);
|
|
bool waitStopPlay(const QString& file);
|
|
|
void allThreadStart();
|
|
void allThreadStart();
|
|
|
|
|
+ void checkAndResetState();
|
|
|
|
|
|
|
|
|
|
+ //--------------------------------------------------------------------------
|
|
|
// 线程创建方法
|
|
// 线程创建方法
|
|
|
|
|
+ //--------------------------------------------------------------------------
|
|
|
bool createVideoState(const QString& file);
|
|
bool createVideoState(const QString& file);
|
|
|
void deleteVideoState();
|
|
void deleteVideoState();
|
|
|
bool createReadThread();
|
|
bool createReadThread();
|
|
@@ -148,7 +271,9 @@ private:
|
|
|
bool createAudioPlayThread();
|
|
bool createAudioPlayThread();
|
|
|
bool startPlayThread(); // 避免UI冻结的线程
|
|
bool startPlayThread(); // 避免UI冻结的线程
|
|
|
|
|
|
|
|
|
|
+ //--------------------------------------------------------------------------
|
|
|
// 播放辅助方法
|
|
// 播放辅助方法
|
|
|
|
|
+ //--------------------------------------------------------------------------
|
|
|
void videoSeekInc(double incr);
|
|
void videoSeekInc(double incr);
|
|
|
void printDecodeContext(const AVCodecContext* videoCtx, bool isVideo = true) const;
|
|
void printDecodeContext(const AVCodecContext* videoCtx, bool isVideo = true) const;
|
|
|
void displayStatusMessage(const QString& message);
|
|
void displayStatusMessage(const QString& message);
|
|
@@ -158,34 +283,38 @@ private:
|
|
|
void hideCursor(bool hide = true);
|
|
void hideCursor(bool hide = true);
|
|
|
bool cursorInWindow(QWidget* widget);
|
|
bool cursorInWindow(QWidget* widget);
|
|
|
|
|
|
|
|
|
|
+ //--------------------------------------------------------------------------
|
|
|
// 异步初始化相关
|
|
// 异步初始化相关
|
|
|
|
|
+ //--------------------------------------------------------------------------
|
|
|
void asyncInit(const QString& file);
|
|
void asyncInit(const QString& file);
|
|
|
std::thread m_initThread;
|
|
std::thread m_initThread;
|
|
|
std::atomic<bool> m_initInProgress{false};
|
|
std::atomic<bool> m_initInProgress{false};
|
|
|
std::atomic<bool> m_initSuccess{false};
|
|
std::atomic<bool> m_initSuccess{false};
|
|
|
std::mutex m_stopMutex;
|
|
std::mutex m_stopMutex;
|
|
|
|
|
|
|
|
|
|
+ //--------------------------------------------------------------------------
|
|
|
// 状态机
|
|
// 状态机
|
|
|
|
|
+ //--------------------------------------------------------------------------
|
|
|
std::atomic<PlayerState> m_state{PlayerState::Idle};
|
|
std::atomic<PlayerState> m_state{PlayerState::Idle};
|
|
|
|
|
|
|
|
-private:
|
|
|
|
|
|
|
+ //--------------------------------------------------------------------------
|
|
|
// 多媒体线程
|
|
// 多媒体线程
|
|
|
- std::unique_ptr<ReadThread> m_packetReadThread;
|
|
|
|
|
- std::unique_ptr<VideoDecodeThread> m_decodeVideoThread;
|
|
|
|
|
- std::unique_ptr<AudioDecodeThread> m_decodeAudioThread;
|
|
|
|
|
- std::unique_ptr<SubtitleDecodeThread> m_decodeSubtitleThread;
|
|
|
|
|
- std::unique_ptr<AudioPlayThread> m_audioPlayThread;
|
|
|
|
|
- std::unique_ptr<VideoPlayThread> m_videoPlayThread;
|
|
|
|
|
-
|
|
|
|
|
|
|
+ //--------------------------------------------------------------------------
|
|
|
|
|
+ std::unique_ptr<ReadThread> m_packetReadThread; ///< 数据包读取线程
|
|
|
|
|
+ std::unique_ptr<VideoDecodeThread> m_decodeVideoThread; ///< 视频解码线程
|
|
|
|
|
+ std::unique_ptr<AudioDecodeThread> m_decodeAudioThread; ///< 音频解码线程
|
|
|
|
|
+ std::unique_ptr<SubtitleDecodeThread> m_decodeSubtitleThread; ///< 字幕解码线程
|
|
|
|
|
+ std::unique_ptr<AudioPlayThread> m_audioPlayThread; ///< 音频播放线程
|
|
|
|
|
+ std::unique_ptr<VideoPlayThread> m_videoPlayThread; ///< 视频播放线程
|
|
|
|
|
+
|
|
|
|
|
+ //--------------------------------------------------------------------------
|
|
|
// 状态管理
|
|
// 状态管理
|
|
|
- std::unique_ptr<VideoStateData> m_videoState;
|
|
|
|
|
- std::unique_ptr<StartPlayThread> m_beforePlayThread;
|
|
|
|
|
- std::unique_ptr<StopWaitingThread> m_stopPlayWaitingThread;
|
|
|
|
|
-
|
|
|
|
|
- std::thread m_eventThread;
|
|
|
|
|
-
|
|
|
|
|
- QString m_currentFile; // 更清晰的命名
|
|
|
|
|
- void checkAndResetState();
|
|
|
|
|
|
|
+ //--------------------------------------------------------------------------
|
|
|
|
|
+ std::unique_ptr<VideoStateData> m_videoState; ///< 视频状态数据
|
|
|
|
|
+ std::unique_ptr<StartPlayThread> m_beforePlayThread; ///< 播放前准备线程
|
|
|
|
|
+ std::unique_ptr<StopWaitingThread> m_stopPlayWaitingThread; ///< 停止等待线程
|
|
|
|
|
+ std::thread m_eventThread; ///< 事件处理线程
|
|
|
|
|
+ QString m_currentFile; ///< 当前播放文件路径
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
#endif // AVPLAYER2_PLAYERCONTROLLER_H
|
|
#endif // AVPLAYER2_PLAYERCONTROLLER_H
|