ffmpegvideopuller.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. #include "ffmpegvideopuller.h"
  2. #include <QDebug>
  3. #include <chrono>
  4. #include <thread>
  5. FFmpegVideoPuller::FFmpegVideoPuller(QObject* parent)
  6. : QObject(parent)
  7. {
  8. // av_register_all();
  9. avformat_network_init();
  10. }
  11. FFmpegVideoPuller::~FFmpegVideoPuller()
  12. {
  13. stop();
  14. }
  15. bool FFmpegVideoPuller::open(const QString& url, int videoBufferSec, int audioBufferSec)
  16. {
  17. m_url = url;
  18. // 打开流
  19. if (avformat_open_input(&m_fmtCtx, url.toStdString().c_str(), nullptr, nullptr) < 0)
  20. return false;
  21. if (avformat_find_stream_info(m_fmtCtx, nullptr) < 0)
  22. return false;
  23. // 查找视频流
  24. for (unsigned i = 0; i < m_fmtCtx->nb_streams; ++i) {
  25. if (m_fmtCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO
  26. && m_videoStreamIdx == -1) {
  27. m_videoStreamIdx = i;
  28. }
  29. if (m_fmtCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO
  30. && m_audioStreamIdx == -1) {
  31. m_audioStreamIdx = i;
  32. }
  33. }
  34. if (m_videoStreamIdx == -1)
  35. return false;
  36. // 打开视频解码器
  37. const AVCodec* vcodec = avcodec_find_decoder(
  38. m_fmtCtx->streams[m_videoStreamIdx]->codecpar->codec_id);
  39. m_videoCodecCtx = avcodec_alloc_context3(vcodec);
  40. avcodec_parameters_to_context(m_videoCodecCtx, m_fmtCtx->streams[m_videoStreamIdx]->codecpar);
  41. avcodec_open2(m_videoCodecCtx, vcodec, nullptr);
  42. // 打开音频解码器
  43. if (m_audioStreamIdx != -1) {
  44. const AVCodec* acodec = avcodec_find_decoder(
  45. m_fmtCtx->streams[m_audioStreamIdx]->codecpar->codec_id);
  46. m_audioCodecCtx = avcodec_alloc_context3(acodec);
  47. avcodec_parameters_to_context(m_audioCodecCtx,
  48. m_fmtCtx->streams[m_audioStreamIdx]->codecpar);
  49. avcodec_open2(m_audioCodecCtx, acodec, nullptr);
  50. }
  51. // 计算缓冲区大小
  52. int videoFps = 25;
  53. AVRational fr = m_fmtCtx->streams[m_videoStreamIdx]->avg_frame_rate;
  54. if (fr.num && fr.den)
  55. videoFps = int(av_q2d(fr));
  56. int videoBufferSize = videoBufferSec * videoFps;
  57. int audioBufferSize = audioBufferSec * 50; // 假设每秒50帧
  58. // 创建缓冲区
  59. m_videoBuffer = new RingBuffer<AVFrame*>(videoBufferSize);
  60. m_audioBuffer = new RingBuffer<AVFrame*>(audioBufferSize);
  61. m_videoBuffer->setDeleter([](AVFrame*& f) { av_frame_free(&f); });
  62. m_audioBuffer->setDeleter([](AVFrame*& f) { av_frame_free(&f); });
  63. m_videoPlayIndex = 0;
  64. m_audioPlayIndex = 0;
  65. m_currentPts = 0.0;
  66. // 获取总时长
  67. if (m_fmtCtx->duration > 0) {
  68. m_totalDuration = m_fmtCtx->duration / (double)AV_TIME_BASE;
  69. } else {
  70. m_totalDuration = -1.0;
  71. }
  72. return true;
  73. }
  74. void FFmpegVideoPuller::setSpeed(float speed)
  75. {
  76. std::lock_guard<std::mutex> lock(m_speedMutex);
  77. m_speed = speed;
  78. }
  79. float FFmpegVideoPuller::getSpeed() const
  80. {
  81. std::lock_guard<std::mutex> lock(m_speedMutex);
  82. return m_speed;
  83. }
  84. void FFmpegVideoPuller::start()
  85. {
  86. if (m_running)
  87. return;
  88. m_running = true;
  89. // 初始化PTS
  90. m_videoPts = 0.0;
  91. m_audioPts = 0.0;
  92. // 解码线程
  93. m_decodeThread = QThread::create([this]() { this->decodeLoop(); });
  94. m_decodeThread->start();
  95. // 视频播放线程
  96. m_videoPlayThread = QThread::create([this]() { this->videoPlayLoop(); });
  97. m_videoPlayThread->start();
  98. // 音频播放线程
  99. m_audioPlayThread = QThread::create([this]() { this->audioPlayLoop(); });
  100. m_audioPlayThread->start();
  101. }
  102. void FFmpegVideoPuller::stop()
  103. {
  104. m_running = false;
  105. if (m_decodeThread) {
  106. m_decodeThread->quit();
  107. m_decodeThread->wait();
  108. delete m_decodeThread;
  109. m_decodeThread = nullptr;
  110. }
  111. if (m_videoPlayThread) {
  112. m_videoPlayThread->quit();
  113. m_videoPlayThread->wait();
  114. delete m_videoPlayThread;
  115. m_videoPlayThread = nullptr;
  116. }
  117. if (m_audioPlayThread) {
  118. m_audioPlayThread->quit();
  119. m_audioPlayThread->wait();
  120. delete m_audioPlayThread;
  121. m_audioPlayThread = nullptr;
  122. }
  123. // 释放缓冲区
  124. if (m_videoBuffer) {
  125. m_videoBuffer->clear();
  126. delete m_videoBuffer;
  127. m_videoBuffer = nullptr;
  128. }
  129. if (m_audioBuffer) {
  130. m_audioBuffer->clear();
  131. delete m_audioBuffer;
  132. m_audioBuffer = nullptr;
  133. }
  134. // 释放FFmpeg资源
  135. if (m_videoCodecCtx)
  136. avcodec_free_context(&m_videoCodecCtx);
  137. if (m_audioCodecCtx)
  138. avcodec_free_context(&m_audioCodecCtx);
  139. if (m_fmtCtx)
  140. avformat_close_input(&m_fmtCtx);
  141. }
  142. void FFmpegVideoPuller::decodeLoop()
  143. {
  144. AVPacket* pkt = av_packet_alloc();
  145. AVFrame* frame = av_frame_alloc();
  146. while (m_running) {
  147. if (av_read_frame(m_fmtCtx, pkt) < 0) {
  148. std::this_thread::sleep_for(std::chrono::milliseconds(10));
  149. continue;
  150. }
  151. if (pkt->stream_index == m_videoStreamIdx) {
  152. avcodec_send_packet(m_videoCodecCtx, pkt);
  153. while (avcodec_receive_frame(m_videoCodecCtx, frame) == 0) {
  154. double pts = frame->best_effort_timestamp
  155. * av_q2d(m_fmtCtx->streams[m_videoStreamIdx]->time_base);
  156. m_videoBuffer->push(av_frame_clone(frame), pts);
  157. }
  158. } else if (pkt->stream_index == m_audioStreamIdx) {
  159. avcodec_send_packet(m_audioCodecCtx, pkt);
  160. while (avcodec_receive_frame(m_audioCodecCtx, frame) == 0) {
  161. double pts = frame->best_effort_timestamp
  162. * av_q2d(m_fmtCtx->streams[m_audioStreamIdx]->time_base);
  163. //qDebug() << "解码到音频帧, pts=" << pts << " nb_samples=" << frame->nb_samples;
  164. m_audioBuffer->push(av_frame_clone(frame), pts);
  165. }
  166. }
  167. av_packet_unref(pkt);
  168. }
  169. av_frame_free(&frame);
  170. av_packet_free(&pkt);
  171. }
  172. void FFmpegVideoPuller::videoPlayLoop()
  173. {
  174. // 如果没有视频流,直接返回
  175. if (m_videoStreamIdx == -1) {
  176. return;
  177. }
  178. while (m_running) {
  179. AVFrame* vFrame = getCurrentVideoFrame();
  180. if (!vFrame) {
  181. std::this_thread::sleep_for(std::chrono::milliseconds(5));
  182. continue;
  183. }
  184. double vPts = vFrame->best_effort_timestamp
  185. * av_q2d(m_fmtCtx->streams[m_videoStreamIdx]->time_base);
  186. // 更新视频PTS
  187. m_videoPts = vPts;
  188. // 渲染视频帧
  189. if (m_videoRenderCallback) {
  190. m_videoRenderCallback(vFrame);
  191. }
  192. // 控制倍速
  193. AVRational fr = m_fmtCtx->streams[m_videoStreamIdx]->avg_frame_rate;
  194. double frame_delay = 1.0 / (fr.num ? av_q2d(fr) : 25.0);
  195. float speed = getSpeed();
  196. int delay = int(frame_delay * 1000 / speed);
  197. // 如果只有视频没有音频,直接按照视频帧率播放
  198. if (m_audioStreamIdx == -1) {
  199. if (delay > 0) {
  200. std::this_thread::sleep_for(std::chrono::milliseconds(delay));
  201. }
  202. } else {
  203. // 有音频时,需要考虑音视频同步
  204. double aPts = m_audioPts.load();
  205. // 如果视频比音频快太多,等待音频追上
  206. if (vPts > aPts + 0.1) {
  207. std::this_thread::sleep_for(std::chrono::milliseconds(10));
  208. continue; // 不前进到下一帧,等待音频追上
  209. }
  210. // 正常播放速度控制
  211. if (delay > 0) {
  212. std::this_thread::sleep_for(std::chrono::milliseconds(delay));
  213. }
  214. }
  215. // 前进到下一帧
  216. nextVideoFrame();
  217. // 更新当前pts(用于进度显示)
  218. {
  219. std::lock_guard<std::mutex> lock(m_ptsMutex);
  220. m_currentPts = vPts;
  221. }
  222. }
  223. }
  224. void FFmpegVideoPuller::audioPlayLoop()
  225. {
  226. // 如果没有音频流,直接返回
  227. if (m_audioStreamIdx == -1) {
  228. return;
  229. }
  230. while (m_running) {
  231. // 获取当前音频帧
  232. AVFrame* aFrame = getCurrentAudioFrame();
  233. if (!aFrame) {
  234. std::this_thread::sleep_for(std::chrono::milliseconds(5));
  235. continue;
  236. }
  237. // 计算音频PTS
  238. double aPts = aFrame->best_effort_timestamp
  239. * av_q2d(m_fmtCtx->streams[m_audioStreamIdx]->time_base);
  240. // 更新音频PTS
  241. m_audioPts = aPts;
  242. // 如果只有音频没有视频,直接播放音频
  243. if (m_videoStreamIdx == -1) {
  244. // 播放音频帧
  245. if (m_audioPlayCallback) {
  246. m_audioPlayCallback(aFrame);
  247. }
  248. // 更新当前pts(用于进度显示)
  249. {
  250. std::lock_guard<std::mutex> lock(m_ptsMutex);
  251. m_currentPts = aPts;
  252. }
  253. // 前进到下一帧
  254. nextAudioFrame();
  255. // 控制音频播放速度
  256. float speed = getSpeed();
  257. int samples = aFrame->nb_samples;
  258. int sample_rate = aFrame->sample_rate;
  259. double frame_duration = samples / (double)sample_rate;
  260. int delay = int(frame_duration * 1000 / speed);
  261. if (delay > 0) {
  262. std::this_thread::sleep_for(std::chrono::milliseconds(delay));
  263. }
  264. continue; // 继续下一帧处理
  265. }
  266. // 有视频时,需要考虑音视频同步
  267. double vPts = m_videoPts.load();
  268. // 如果音频PTS超前于视频PTS太多,等待视频追上
  269. if (aPts > vPts + 0.1) {
  270. std::this_thread::sleep_for(std::chrono::milliseconds(5));
  271. continue; // 不前进到下一帧,等待视频追上
  272. }
  273. // 如果音频比视频慢太多,可能需要跳过一些音频帧来追赶视频
  274. if (aPts < vPts - 0.2) {
  275. // 跳过当前音频帧,直接前进
  276. nextAudioFrame();
  277. continue;
  278. }
  279. // 播放音频帧
  280. if (m_audioPlayCallback) {
  281. m_audioPlayCallback(aFrame);
  282. }
  283. // 前进到下一帧
  284. nextAudioFrame();
  285. // 控制音频播放速度,与视频保持一致
  286. float speed = getSpeed();
  287. if (speed != 1.0f) {
  288. // 根据倍速调整音频播放间隔
  289. int samples = aFrame->nb_samples;
  290. int sample_rate = aFrame->sample_rate;
  291. double frame_duration = samples / (double)sample_rate;
  292. int delay = int(frame_duration * 1000 / speed);
  293. if (delay > 0) {
  294. std::this_thread::sleep_for(std::chrono::milliseconds(delay));
  295. }
  296. }
  297. }
  298. }
  299. // 进度相关
  300. double FFmpegVideoPuller::getFirstPts() const
  301. {
  302. return m_videoBuffer ? m_videoBuffer->firstPts() : 0.0;
  303. }
  304. double FFmpegVideoPuller::getLastPts() const
  305. {
  306. return m_videoBuffer ? m_videoBuffer->lastPts() : 0.0;
  307. }
  308. double FFmpegVideoPuller::getCurrentPts() const
  309. {
  310. std::lock_guard<std::mutex> lock(m_ptsMutex);
  311. return m_currentPts;
  312. }
  313. void FFmpegVideoPuller::seekToPts(double pts)
  314. {
  315. // 停止线程
  316. m_running = false;
  317. if (m_decodeThread) { m_decodeThread->quit(); m_decodeThread->wait(); delete m_decodeThread; m_decodeThread = nullptr; }
  318. if (m_videoPlayThread) { m_videoPlayThread->quit(); m_videoPlayThread->wait(); delete m_videoPlayThread; m_videoPlayThread = nullptr; }
  319. if (m_audioPlayThread) { m_audioPlayThread->quit(); m_audioPlayThread->wait(); delete m_audioPlayThread; m_audioPlayThread = nullptr; }
  320. // 清空缓冲区
  321. if (m_videoBuffer) m_videoBuffer->clear();
  322. if (m_audioBuffer) m_audioBuffer->clear();
  323. // FFmpeg seek
  324. int64_t seek_target = pts / av_q2d(m_fmtCtx->streams[m_videoStreamIdx]->time_base);
  325. av_seek_frame(m_fmtCtx, m_videoStreamIdx, seek_target, AVSEEK_FLAG_BACKWARD);
  326. avcodec_flush_buffers(m_videoCodecCtx);
  327. if (m_audioCodecCtx) avcodec_flush_buffers(m_audioCodecCtx);
  328. // 重置索引
  329. m_videoPlayIndex = 0;
  330. m_audioPlayIndex = 0;
  331. // 重置PTS
  332. m_videoPts = pts;
  333. m_audioPts = pts;
  334. m_currentPts = pts;
  335. // 重新启动线程
  336. m_running = true;
  337. m_decodeThread = QThread::create([this]() { this->decodeLoop(); });
  338. m_decodeThread->start();
  339. m_videoPlayThread = QThread::create([this]() { this->videoPlayLoop(); });
  340. m_videoPlayThread->start();
  341. m_audioPlayThread = QThread::create([this]() { this->audioPlayLoop(); });
  342. m_audioPlayThread->start();
  343. }
  344. // 取帧接口
  345. AVFrame* FFmpegVideoPuller::getCurrentVideoFrame()
  346. {
  347. if (!m_videoBuffer)
  348. return nullptr;
  349. return m_videoBuffer->get(m_videoPlayIndex);
  350. }
  351. AVFrame* FFmpegVideoPuller::getCurrentAudioFrame()
  352. {
  353. if (!m_audioBuffer)
  354. return nullptr;
  355. return m_audioBuffer->get(m_audioPlayIndex);
  356. }
  357. void FFmpegVideoPuller::nextVideoFrame()
  358. {
  359. ++m_videoPlayIndex;
  360. if (m_videoBuffer && m_videoPlayIndex >= m_videoBuffer->size())
  361. m_videoPlayIndex = m_videoBuffer->size() - 1;
  362. }
  363. void FFmpegVideoPuller::nextAudioFrame()
  364. {
  365. ++m_audioPlayIndex;
  366. if (m_audioBuffer && m_audioPlayIndex >= m_audioBuffer->size())
  367. m_audioPlayIndex = m_audioBuffer->size() - 1;
  368. }
  369. size_t FFmpegVideoPuller::videoBufferSize() const
  370. {
  371. return m_videoBuffer ? m_videoBuffer->size() : 0;
  372. }
  373. size_t FFmpegVideoPuller::audioBufferSize() const
  374. {
  375. return m_audioBuffer ? m_audioBuffer->size() : 0;
  376. }