#ifndef AV_PLAYER_H #define AV_PLAYER_H #include #include #include #include #include "av_clock.h" #include "av_decoder.h" #include "sonic.h" extern "C" { #include } #include "ffmpeg_compat.h" using AVTool::Decoder; class VideoFrame; typedef Decoder::MyFrame MyFrame; class AVPlayer : public QObject { Q_OBJECT friend void fillAStreamCallback(void* userdata, uint8_t* stream, int len); public: enum PlayState { AV_STOPPED, AV_PLAYING, AV_PAUSED }; // 新增:同步主时钟类型 enum SyncType { SYNC_AUDIO, SYNC_VIDEO, SYNC_EXTERNAL }; AVPlayer(); ~AVPlayer(); int play(const QString& url); void pause(bool isPause); void clearPlayer(); AVTool::MediaInfo* detectMediaInfo(const QString& url); AVPlayer::PlayState playState(); void setVFrameSize(const QSize& size) { m_imageWidth = size.width(); m_imageHeight = size.height(); } inline void setVolume(int volumePer) { m_volume = (volumePer * SDL_MIX_MAXVOLUME / 100) % (SDL_MIX_MAXVOLUME + 1); } // 新增:设置同步主时钟类型(默认外部时钟,适合直播/RTSP) inline void setSyncType(SyncType type) { m_syncType = type; } // 修改:根据选定主时钟进行seek,使用微秒时间戳 inline void seekBy(int32_t time_s) { int64_t baseUs = masterClockUs(); int32_t baseSeconds = static_cast(baseUs / 1000000); seekTo(baseSeconds + time_s); } inline void seekTo(int32_t time_s) { if (playState() == AV_STOPPED) return; if (time_s < 0) time_s = 0; int64_t baseUs = masterClockUs(); int32_t baseSeconds = static_cast(baseUs / 1000000); m_decoder->seekTo(time_s, time_s - baseSeconds); } inline uint32_t avDuration() { return m_duration; } inline void setSpeed(float speed) { m_playSpeed = speed; } signals: void frameChanged(QSharedPointer frame); void AVTerminate(); void AVPtsChanged(unsigned int pts); void AVDurationChanged(unsigned int duration); private: int initSDL(); int initVideo(); void videoCallback(std::shared_ptr par); double computeTargetDelay(double delay); double vpDuration(MyFrame* lastFrame, MyFrame* curFrame); void displayImage(AVFrame* frame); void initAVClock(); // 新增:获取当前主时钟(微秒) inline int64_t masterClockUs() { switch (m_syncType) { case SYNC_AUDIO: return m_audioClock.getClock(); case SYNC_VIDEO: return m_videoClock.getClock(); case SYNC_EXTERNAL: default: return m_extClock.getClock(); } } private: //解码器实例 Decoder* m_decoder; AVFormatContext* m_fmtCtx; AVCodecParameters* m_audioCodecPar; SwrContext* m_swrCtx; uint8_t* m_audioBuf; sonicStream m_sonicStream; uint32_t m_audioBufSize; uint32_t m_audioBufIndex; uint32_t m_duration; uint32_t m_lastAudPts; enum AVSampleFormat m_targetSampleFmt; //记录音视频帧最新播放帧的时间戳,用于同步 // double m_audioPts; // double m_videoPts; std::atomic m_playSpeed; //延时时间 double m_delay; //音频播放时钟 AVClock m_audioClock; //视频播放时钟 AVClock m_videoClock; // 新增:外部时钟(以系统时钟为基准) AVClock m_extClock; // 新增:PTS基线(微秒),用于将首帧归零,避免绝对PTS导致的巨幅偏差 int64_t m_audioStartPtsUs = -1; int64_t m_videoStartPtsUs = -1; int m_targetChannels; int m_targetFreq; int m_targetChannelLayout; int m_targetNbSamples; int m_volume; //同步时钟初始化标志,音视频异步线程 //谁先读到初始标志位就由谁初始化时钟 int m_clockInitFlag; int m_audioIndex; int m_videoIndex; int m_imageWidth; int m_imageHeight; //终止标志 std::atomic m_exit; //记录暂停前的时间(微秒) int64_t m_pauseTimeUs; //暂停时钟快照(微秒) int64_t m_pauseAudClockUs = 0; int64_t m_pauseVidClockUs = 0; int64_t m_pauseExtClockUs = 0; //暂停标志 std::atomic m_pause; AVFrame* m_audioFrame; AVCodecParameters* m_videoCodecPar; enum AVPixelFormat m_dstPixFmt; int m_swsFlags; SwsContext* m_swsCtx; uint8_t* m_buffer; uint8_t* m_pixels[4]; int m_pitch[4]; // 新增:是否存在音频/视频流 bool m_hasAudio = false; bool m_hasVideo = false; // 性能优化:添加高精度时间基准(微秒) int64_t m_baseTimeUs = 0; // 高精度时间基准(微秒) int64_t m_frameTimerUs = 0; // 高精度帧定时器(微秒) int m_performanceFrameCount = 0; // 性能监控帧计数 double m_lastDelayValue = 0.0; // 上次延迟值,用于延迟累积检测 // 新增:同步主时钟类型(默认外部时钟,同步策略更接近ffplay -sync ext) SyncType m_syncType = SYNC_EXTERNAL; }; #endif