#ifndef FFMPEGVIDEOPULLER_H #define FFMPEGVIDEOPULLER_H #pragma once extern "C" { #include #include } #include #include #include #include #include #include #include #include #include "RingBuffer.h" // SPSC无锁环形缓冲区 class SpscRingBuffer { public: SpscRingBuffer(size_t size) : size_(size + 1), buffer_(new AVPacket*[size_]), head_(0), tail_(0) {} ~SpscRingBuffer() { delete[] buffer_; } bool push(AVPacket* pkt) { size_t next = (head_ + 1) % size_; if (next == tail_.load(std::memory_order_acquire)) return false; // full buffer_[head_] = pkt; head_.store(next, std::memory_order_release); return true; } AVPacket* pop() { size_t tail = tail_.load(std::memory_order_acquire); if (tail == head_.load(std::memory_order_acquire)) return nullptr; // empty AVPacket* pkt = buffer_[tail]; tail_.store((tail + 1) % size_, std::memory_order_release); return pkt; } bool empty() const { return tail_.load(std::memory_order_acquire) == head_.load(std::memory_order_acquire); } void clear() { while (!empty()) { AVPacket* pkt = pop(); if (pkt) av_packet_free(&pkt); } } private: size_t size_; AVPacket** buffer_; std::atomic head_; std::atomic tail_; }; class FFmpegVideoPuller : public QObject { Q_OBJECT public: explicit FFmpegVideoPuller(QObject* parent = nullptr); ~FFmpegVideoPuller(); bool open(const QString& url, int videoBufferSec = 300, int audioBufferSec = 300); void setSpeed(float speed); // 设置倍速 float getSpeed() const; void start(); void stop(); // 进度相关 double getFirstPts() const; double getLastPts() const; double getCurrentPts() const; void seekToPts(double pts); // 跳转到指定pts // 取帧接口 AVFrame* getCurrentVideoFrame(); AVFrame* getCurrentAudioFrame(); void nextVideoFrame(); void nextAudioFrame(); size_t videoBufferSize() const; size_t audioBufferSize() const; double getTotalDuration() const { return m_totalDuration; } // 主时钟驱动同步播放 void startSyncPlay(); void stopSyncPlay(); AVFrame* popNearestAudioFrame(double pts); AVFrame* popNearestVideoFrame(double pts); private: void packetReadLoop(); void videoDecodeLoop(); void audioDecodeLoop(); QThread* m_packetReadThread = nullptr; QThread* m_videoDecodeThread = nullptr; QThread* m_audioDecodeThread = nullptr; SpscRingBuffer* m_videoPacketQueue = nullptr; SpscRingBuffer* m_audioPacketQueue = nullptr; QThread* m_syncPlayThread = nullptr; void syncPlayLoop(); std::atomic m_syncPlayRunning{false}; // 音视频同步 std::atomic m_audioPts{0.0}; std::atomic m_videoPts{0.0}; std::mutex m_syncMutex; QString m_url; std::atomic m_running{false}; mutable std::mutex m_speedMutex; float m_speed = 1.0f; // FFmpeg相关 AVFormatContext* m_fmtCtx = nullptr; AVCodecContext* m_videoCodecCtx = nullptr; AVCodecContext* m_audioCodecCtx = nullptr; int m_videoStreamIdx = -1; int m_audioStreamIdx = -1; // 缓冲区 RingBuffer* m_videoBuffer = nullptr; RingBuffer* m_audioBuffer = nullptr; // 线程 QThread* m_videoPlayThread = nullptr; QThread* m_audioPlayThread = nullptr; // 播放指针 std::atomic m_videoPlayIndex{0}; std::atomic m_audioPlayIndex{0}; std::atomic m_currentPts{0.0}; mutable std::mutex m_ptsMutex; double m_totalDuration = -1.0; }; #endif // FFMPEGVIDEOPULLER_H