ffmpegvideopuller.h 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. #ifndef FFMPEGVIDEOPULLER_H
  2. #define FFMPEGVIDEOPULLER_H
  3. #pragma once
  4. extern "C" {
  5. #include <libavcodec/avcodec.h>
  6. #include <libavformat/avformat.h>
  7. }
  8. #include <QObject>
  9. #include <QString>
  10. #include <QThread>
  11. #include <atomic>
  12. #include <functional>
  13. #include <queue>
  14. #include <mutex>
  15. #include <condition_variable>
  16. #include "RingBuffer.h"
  17. // SPSC无锁环形缓冲区
  18. class SpscRingBuffer {
  19. public:
  20. SpscRingBuffer(size_t size) : size_(size + 1), buffer_(new AVPacket*[size_]), head_(0), tail_(0) {}
  21. ~SpscRingBuffer() { delete[] buffer_; }
  22. bool push(AVPacket* pkt) {
  23. size_t next = (head_ + 1) % size_;
  24. if (next == tail_.load(std::memory_order_acquire)) return false; // full
  25. buffer_[head_] = pkt;
  26. head_.store(next, std::memory_order_release);
  27. return true;
  28. }
  29. AVPacket* pop() {
  30. size_t tail = tail_.load(std::memory_order_acquire);
  31. if (tail == head_.load(std::memory_order_acquire)) return nullptr; // empty
  32. AVPacket* pkt = buffer_[tail];
  33. tail_.store((tail + 1) % size_, std::memory_order_release);
  34. return pkt;
  35. }
  36. bool empty() const { return tail_.load(std::memory_order_acquire) == head_.load(std::memory_order_acquire); }
  37. void clear() {
  38. while (!empty()) {
  39. AVPacket* pkt = pop();
  40. if (pkt) av_packet_free(&pkt);
  41. }
  42. }
  43. private:
  44. size_t size_;
  45. AVPacket** buffer_;
  46. std::atomic<size_t> head_;
  47. std::atomic<size_t> tail_;
  48. };
  49. class FFmpegVideoPuller : public QObject
  50. {
  51. Q_OBJECT
  52. public:
  53. explicit FFmpegVideoPuller(QObject* parent = nullptr);
  54. ~FFmpegVideoPuller();
  55. bool open(const QString& url,
  56. int videoBufferSec = 300,
  57. int audioBufferSec = 300);
  58. void setSpeed(float speed); // 设置倍速
  59. float getSpeed() const;
  60. void start();
  61. void stop();
  62. // 进度相关
  63. double getFirstPts() const;
  64. double getLastPts() const;
  65. double getCurrentPts() const;
  66. void seekToPts(double pts); // 跳转到指定pts
  67. // 取帧接口
  68. AVFrame* getCurrentVideoFrame();
  69. AVFrame* getCurrentAudioFrame();
  70. void nextVideoFrame();
  71. void nextAudioFrame();
  72. size_t videoBufferSize() const;
  73. size_t audioBufferSize() const;
  74. double getTotalDuration() const { return m_totalDuration; }
  75. // 主时钟驱动同步播放
  76. void startSyncPlay();
  77. void stopSyncPlay();
  78. AVFrame* popNearestAudioFrame(double pts);
  79. AVFrame* popNearestVideoFrame(double pts);
  80. private:
  81. void packetReadLoop();
  82. void videoDecodeLoop();
  83. void audioDecodeLoop();
  84. QThread* m_packetReadThread = nullptr;
  85. QThread* m_videoDecodeThread = nullptr;
  86. QThread* m_audioDecodeThread = nullptr;
  87. SpscRingBuffer* m_videoPacketQueue = nullptr;
  88. SpscRingBuffer* m_audioPacketQueue = nullptr;
  89. QThread* m_syncPlayThread = nullptr;
  90. void syncPlayLoop();
  91. std::atomic<bool> m_syncPlayRunning{false};
  92. // 音视频同步
  93. std::atomic<double> m_audioPts{0.0};
  94. std::atomic<double> m_videoPts{0.0};
  95. std::mutex m_syncMutex;
  96. QString m_url;
  97. std::atomic<bool> m_running{false};
  98. mutable std::mutex m_speedMutex;
  99. float m_speed = 1.0f;
  100. // FFmpeg相关
  101. AVFormatContext* m_fmtCtx = nullptr;
  102. AVCodecContext* m_videoCodecCtx = nullptr;
  103. AVCodecContext* m_audioCodecCtx = nullptr;
  104. int m_videoStreamIdx = -1;
  105. int m_audioStreamIdx = -1;
  106. // 缓冲区
  107. RingBuffer<AVFrame*>* m_videoBuffer = nullptr;
  108. RingBuffer<AVFrame*>* m_audioBuffer = nullptr;
  109. // 线程
  110. QThread* m_videoPlayThread = nullptr;
  111. QThread* m_audioPlayThread = nullptr;
  112. // 播放指针
  113. std::atomic<size_t> m_videoPlayIndex{0};
  114. std::atomic<size_t> m_audioPlayIndex{0};
  115. std::atomic<double> m_currentPts{0.0};
  116. mutable std::mutex m_ptsMutex;
  117. double m_totalDuration = -1.0;
  118. };
  119. #endif // FFMPEGVIDEOPULLER_H