ffmpegvideopuller.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. #include "ffmpegvideopuller.h"
  2. #include "AvPlayer/AudioPlayer.h"
  3. #include "AvPlayer/VideoPlayer.h"
  4. #include "qdatetime.h"
  5. #include <QDebug>
  6. #include <chrono>
  7. #include <thread>
  8. FFmpegVideoPuller::FFmpegVideoPuller(QObject* parent)
  9. : QObject(parent)
  10. {
  11. // av_register_all();
  12. avformat_network_init();
  13. }
  14. FFmpegVideoPuller::~FFmpegVideoPuller()
  15. {
  16. stop();
  17. }
  18. bool FFmpegVideoPuller::open(const QString& url, int videoBufferSec, int audioBufferSec)
  19. {
  20. m_url = url;
  21. // 打开流
  22. if (avformat_open_input(&m_fmtCtx, url.toStdString().c_str(), nullptr, nullptr) < 0)
  23. return false;
  24. if (avformat_find_stream_info(m_fmtCtx, nullptr) < 0)
  25. return false;
  26. // 查找视频流
  27. for (unsigned i = 0; i < m_fmtCtx->nb_streams; ++i) {
  28. if (m_fmtCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO
  29. && m_videoStreamIdx == -1) {
  30. m_videoStreamIdx = i;
  31. }
  32. if (m_fmtCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO
  33. && m_audioStreamIdx == -1) {
  34. m_audioStreamIdx = i;
  35. }
  36. }
  37. if (m_videoStreamIdx == -1)
  38. return false;
  39. // 打开视频解码器
  40. const AVCodec* vcodec = avcodec_find_decoder(
  41. m_fmtCtx->streams[m_videoStreamIdx]->codecpar->codec_id);
  42. m_videoCodecCtx = avcodec_alloc_context3(vcodec);
  43. avcodec_parameters_to_context(m_videoCodecCtx, m_fmtCtx->streams[m_videoStreamIdx]->codecpar);
  44. avcodec_open2(m_videoCodecCtx, vcodec, nullptr);
  45. // 打开音频解码器
  46. if (m_audioStreamIdx != -1) {
  47. const AVCodec* acodec = avcodec_find_decoder(
  48. m_fmtCtx->streams[m_audioStreamIdx]->codecpar->codec_id);
  49. m_audioCodecCtx = avcodec_alloc_context3(acodec);
  50. avcodec_parameters_to_context(m_audioCodecCtx,
  51. m_fmtCtx->streams[m_audioStreamIdx]->codecpar);
  52. avcodec_open2(m_audioCodecCtx, acodec, nullptr);
  53. }
  54. // 计算缓冲区大小
  55. int videoFps = 25;
  56. AVRational fr = m_fmtCtx->streams[m_videoStreamIdx]->avg_frame_rate;
  57. if (fr.num && fr.den)
  58. videoFps = int(av_q2d(fr));
  59. int videoBufferSize = videoBufferSec * videoFps;
  60. int audioBufferSize = audioBufferSec * 50; // 假设每秒50帧
  61. // 创建缓冲区
  62. m_videoBuffer = new RingBuffer<AVFrame*>(videoBufferSize);
  63. m_audioBuffer = new RingBuffer<AVFrame*>(audioBufferSize);
  64. m_videoBuffer->setDeleter([](AVFrame*& f) { av_frame_free(&f); });
  65. m_audioBuffer->setDeleter([](AVFrame*& f) { av_frame_free(&f); });
  66. // 新增:创建SPSC无锁包队列
  67. if (m_videoPacketQueue) { m_videoPacketQueue->clear(); delete m_videoPacketQueue; }
  68. if (m_audioPacketQueue) { m_audioPacketQueue->clear(); delete m_audioPacketQueue; }
  69. m_videoPacketQueue = new SpscRingBuffer(2000);
  70. m_audioPacketQueue = new SpscRingBuffer(2000);
  71. m_videoPlayIndex = 0;
  72. m_audioPlayIndex = 0;
  73. m_currentPts = 0.0;
  74. // 获取总时长
  75. if (m_fmtCtx->duration > 0) {
  76. m_totalDuration = m_fmtCtx->duration / (double)AV_TIME_BASE;
  77. } else {
  78. m_totalDuration = -1.0;
  79. }
  80. return true;
  81. }
  82. void FFmpegVideoPuller::setSpeed(float speed)
  83. {
  84. std::lock_guard<std::mutex> lock(m_speedMutex);
  85. m_speed = speed;
  86. }
  87. float FFmpegVideoPuller::getSpeed() const
  88. {
  89. std::lock_guard<std::mutex> lock(m_speedMutex);
  90. return m_speed;
  91. }
  92. void FFmpegVideoPuller::start()
  93. {
  94. if (m_running)
  95. return;
  96. m_running = true;
  97. // 初始化PTS
  98. m_videoPts = 0.0;
  99. m_audioPts = 0.0;
  100. // 启动包读取线程
  101. m_packetReadThread = QThread::create([this]() { this->packetReadLoop(); });
  102. m_packetReadThread->start();
  103. // 启动视频解码线程
  104. m_videoDecodeThread = QThread::create([this]() { this->videoDecodeLoop(); });
  105. m_videoDecodeThread->start();
  106. // 启动音频解码线程
  107. m_audioDecodeThread = QThread::create([this]() { this->audioDecodeLoop(); });
  108. m_audioDecodeThread->start();
  109. }
  110. void FFmpegVideoPuller::stop()
  111. {
  112. m_running = false;
  113. if (m_packetReadThread) {
  114. m_packetReadThread->quit();
  115. m_packetReadThread->wait();
  116. delete m_packetReadThread;
  117. m_packetReadThread = nullptr;
  118. }
  119. if (m_videoDecodeThread) {
  120. m_videoDecodeThread->quit();
  121. m_videoDecodeThread->wait();
  122. delete m_videoDecodeThread;
  123. m_videoDecodeThread = nullptr;
  124. }
  125. if (m_audioDecodeThread) {
  126. m_audioDecodeThread->quit();
  127. m_audioDecodeThread->wait();
  128. delete m_audioDecodeThread;
  129. m_audioDecodeThread = nullptr;
  130. }
  131. if (m_videoPlayThread) {
  132. m_videoPlayThread->quit();
  133. m_videoPlayThread->wait();
  134. delete m_videoPlayThread;
  135. m_videoPlayThread = nullptr;
  136. }
  137. if (m_audioPlayThread) {
  138. m_audioPlayThread->quit();
  139. m_audioPlayThread->wait();
  140. delete m_audioPlayThread;
  141. m_audioPlayThread = nullptr;
  142. }
  143. // 清空包队列
  144. if (m_videoPacketQueue) { m_videoPacketQueue->clear(); delete m_videoPacketQueue; m_videoPacketQueue = nullptr; }
  145. if (m_audioPacketQueue) { m_audioPacketQueue->clear(); delete m_audioPacketQueue; m_audioPacketQueue = nullptr; }
  146. // 释放缓冲区
  147. if (m_videoBuffer) {
  148. m_videoBuffer->clear();
  149. delete m_videoBuffer;
  150. m_videoBuffer = nullptr;
  151. }
  152. if (m_audioBuffer) {
  153. m_audioBuffer->clear();
  154. delete m_audioBuffer;
  155. m_audioBuffer = nullptr;
  156. }
  157. // 释放FFmpeg资源
  158. if (m_videoCodecCtx)
  159. avcodec_free_context(&m_videoCodecCtx);
  160. if (m_audioCodecCtx)
  161. avcodec_free_context(&m_audioCodecCtx);
  162. if (m_fmtCtx)
  163. avformat_close_input(&m_fmtCtx);
  164. }
  165. void FFmpegVideoPuller::packetReadLoop()
  166. {
  167. while (m_running) {
  168. AVPacket* pkt = av_packet_alloc();
  169. if (av_read_frame(m_fmtCtx, pkt) < 0) {
  170. av_packet_free(&pkt);
  171. std::this_thread::sleep_for(std::chrono::milliseconds(10));
  172. continue;
  173. }
  174. if (pkt->stream_index == m_videoStreamIdx) {
  175. while (!m_videoPacketQueue->push(pkt)) {
  176. std::this_thread::sleep_for(std::chrono::milliseconds(1));
  177. if (!m_running) { av_packet_free(&pkt); return; }
  178. }
  179. } else if (pkt->stream_index == m_audioStreamIdx) {
  180. while (!m_audioPacketQueue->push(pkt)) {
  181. std::this_thread::sleep_for(std::chrono::milliseconds(1));
  182. if (!m_running) { av_packet_free(&pkt); return; }
  183. }
  184. } else {
  185. av_packet_free(&pkt);
  186. }
  187. }
  188. }
  189. void FFmpegVideoPuller::videoDecodeLoop()
  190. {
  191. AVFrame* frame = av_frame_alloc();
  192. while (m_running) {
  193. AVPacket* pkt = m_videoPacketQueue->pop();
  194. if (!pkt) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); continue; }
  195. avcodec_send_packet(m_videoCodecCtx, pkt);
  196. while (avcodec_receive_frame(m_videoCodecCtx, frame) == 0) {
  197. double pts = frame->best_effort_timestamp
  198. * av_q2d(m_fmtCtx->streams[m_videoStreamIdx]->time_base);
  199. m_videoBuffer->push(av_frame_clone(frame), pts);
  200. }
  201. av_packet_free(&pkt);
  202. }
  203. av_frame_free(&frame);
  204. }
  205. void FFmpegVideoPuller::audioDecodeLoop()
  206. {
  207. if (m_audioStreamIdx == -1) return;
  208. AVFrame* frame = av_frame_alloc();
  209. static qint64 lastDecodeTs = 0;
  210. while (m_running) {
  211. AVPacket* pkt = m_audioPacketQueue->pop();
  212. if (!pkt) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); continue; }
  213. avcodec_send_packet(m_audioCodecCtx, pkt);
  214. while (avcodec_receive_frame(m_audioCodecCtx, frame) == 0) {
  215. double pts = frame->best_effort_timestamp
  216. * av_q2d(m_fmtCtx->streams[m_audioStreamIdx]->time_base);
  217. m_audioBuffer->push(av_frame_clone(frame), pts);
  218. qint64 nowDecode = QDateTime::currentMSecsSinceEpoch();
  219. qDebug() << "[AUDIO-DECODE] 解码间隔(ms):"
  220. << (lastDecodeTs ? nowDecode - lastDecodeTs : 0);
  221. lastDecodeTs = nowDecode;
  222. }
  223. av_packet_free(&pkt);
  224. }
  225. av_frame_free(&frame);
  226. }
  227. // 进度相关
  228. double FFmpegVideoPuller::getFirstPts() const
  229. {
  230. return m_videoBuffer ? m_videoBuffer->firstPts() : 0.0;
  231. }
  232. double FFmpegVideoPuller::getLastPts() const
  233. {
  234. return m_videoBuffer ? m_videoBuffer->lastPts() : 0.0;
  235. }
  236. double FFmpegVideoPuller::getCurrentPts() const
  237. {
  238. std::lock_guard<std::mutex> lock(m_ptsMutex);
  239. return m_currentPts;
  240. }
  241. void FFmpegVideoPuller::seekToPts(double pts)
  242. {
  243. // 停止线程
  244. m_running = false;
  245. if (m_packetReadThread) { m_packetReadThread->quit(); m_packetReadThread->wait(); delete m_packetReadThread; m_packetReadThread = nullptr; }
  246. if (m_videoPlayThread) { m_videoPlayThread->quit(); m_videoPlayThread->wait(); delete m_videoPlayThread; m_videoPlayThread = nullptr; }
  247. if (m_audioPlayThread) { m_audioPlayThread->quit(); m_audioPlayThread->wait(); delete m_audioPlayThread; m_audioPlayThread = nullptr; }
  248. // 清空缓冲区
  249. if (m_videoBuffer) m_videoBuffer->clear();
  250. if (m_audioBuffer) m_audioBuffer->clear();
  251. // FFmpeg seek
  252. int64_t seek_target = pts / av_q2d(m_fmtCtx->streams[m_videoStreamIdx]->time_base);
  253. av_seek_frame(m_fmtCtx, m_videoStreamIdx, seek_target, AVSEEK_FLAG_BACKWARD);
  254. avcodec_flush_buffers(m_videoCodecCtx);
  255. if (m_audioCodecCtx) avcodec_flush_buffers(m_audioCodecCtx);
  256. // 重置索引
  257. m_videoPlayIndex = 0;
  258. m_audioPlayIndex = 0;
  259. // 重置PTS
  260. m_videoPts = pts;
  261. m_audioPts = pts;
  262. m_currentPts = pts;
  263. // 重新启动线程
  264. m_running = true;
  265. m_packetReadThread = QThread::create([this]() { this->packetReadLoop(); });
  266. m_packetReadThread->start();
  267. }
  268. // 取帧接口
  269. AVFrame* FFmpegVideoPuller::getCurrentVideoFrame()
  270. {
  271. if (!m_videoBuffer)
  272. return nullptr;
  273. return m_videoBuffer->get(m_videoPlayIndex);
  274. }
  275. AVFrame* FFmpegVideoPuller::getCurrentAudioFrame()
  276. {
  277. if (!m_audioBuffer)
  278. return nullptr;
  279. return m_audioBuffer->get(m_audioPlayIndex);
  280. }
  281. void FFmpegVideoPuller::nextVideoFrame()
  282. {
  283. ++m_videoPlayIndex;
  284. if (m_videoBuffer && m_videoPlayIndex >= m_videoBuffer->size())
  285. m_videoPlayIndex = m_videoBuffer->size() - 1;
  286. }
  287. void FFmpegVideoPuller::nextAudioFrame()
  288. {
  289. ++m_audioPlayIndex;
  290. if (m_audioBuffer && m_audioPlayIndex >= m_audioBuffer->size())
  291. m_audioPlayIndex = m_audioBuffer->size() - 1;
  292. }
  293. size_t FFmpegVideoPuller::videoBufferSize() const
  294. {
  295. return m_videoBuffer ? m_videoBuffer->size() : 0;
  296. }
  297. size_t FFmpegVideoPuller::audioBufferSize() const
  298. {
  299. return m_audioBuffer ? m_audioBuffer->size() : 0;
  300. }
  301. void FFmpegVideoPuller::startSyncPlay() {
  302. if (m_syncPlayRunning) return;
  303. m_syncPlayRunning = true;
  304. m_syncPlayThread = QThread::create([this]() { this->syncPlayLoop(); });
  305. m_syncPlayThread->start();
  306. }
  307. void FFmpegVideoPuller::stopSyncPlay() {
  308. m_syncPlayRunning = false;
  309. if (m_syncPlayThread) {
  310. m_syncPlayThread->quit();
  311. m_syncPlayThread->wait();
  312. delete m_syncPlayThread;
  313. m_syncPlayThread = nullptr;
  314. }
  315. }
  316. void FFmpegVideoPuller::syncPlayLoop() {
  317. // 以音频为主时钟
  318. using namespace std::chrono;
  319. double basePts = 0.0;
  320. bool baseSet = false;
  321. auto startTime = high_resolution_clock::now();
  322. while (m_syncPlayRunning) {
  323. auto now = high_resolution_clock::now();
  324. double elapsed = duration_cast<milliseconds>(now - startTime).count();
  325. if (!baseSet) {
  326. // 获取首帧音频PTS作为基准
  327. AVFrame* af = m_audioBuffer->get(0);
  328. if (af) {
  329. basePts = af->best_effort_timestamp * av_q2d(m_fmtCtx->streams[m_audioStreamIdx]->time_base);
  330. baseSet = true;
  331. } else {
  332. std::this_thread::sleep_for(milliseconds(1));
  333. continue;
  334. }
  335. }
  336. double curPts = basePts + elapsed / 1000.0 * getSpeed();
  337. // 音频
  338. // AVFrame* audioFrame = m_audioBuffer->popNearest(curPts);
  339. // if (audioFrame && m_audioPlayer) {
  340. // m_audioPlayer->play(audioFrame, getSpeed());
  341. // }
  342. // // 视频
  343. // AVFrame* videoFrame = m_videoBuffer->popNearest(curPts);
  344. // if (videoFrame && m_videoPlayer) {
  345. // m_videoPlayer->render(videoFrame);
  346. // }
  347. // 控制主循环节奏
  348. std::this_thread::sleep_for(milliseconds(1));
  349. }
  350. }
  351. AVFrame* FFmpegVideoPuller::popNearestAudioFrame(double pts) {
  352. if (!m_audioBuffer) return nullptr;
  353. return m_audioBuffer->popNearest(pts);
  354. }
  355. AVFrame* FFmpegVideoPuller::popNearestVideoFrame(double pts) {
  356. if (!m_videoBuffer) return nullptr;
  357. return m_videoBuffer->popNearest(pts);
  358. }