ffmpegvideopuller.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  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. // 解码线程
  90. m_decodeThread = QThread::create([this]() { this->decodeLoop(); });
  91. m_decodeThread->start();
  92. // 播放线程
  93. m_playThread = QThread::create([this]() { this->playLoop(); });
  94. m_playThread->start();
  95. }
  96. void FFmpegVideoPuller::stop()
  97. {
  98. m_running = false;
  99. if (m_decodeThread) {
  100. m_decodeThread->quit();
  101. m_decodeThread->wait();
  102. delete m_decodeThread;
  103. m_decodeThread = nullptr;
  104. }
  105. if (m_playThread) {
  106. m_playThread->quit();
  107. m_playThread->wait();
  108. delete m_playThread;
  109. m_playThread = nullptr;
  110. }
  111. // 释放缓冲区
  112. if (m_videoBuffer) {
  113. m_videoBuffer->clear();
  114. delete m_videoBuffer;
  115. m_videoBuffer = nullptr;
  116. }
  117. if (m_audioBuffer) {
  118. m_audioBuffer->clear();
  119. delete m_audioBuffer;
  120. m_audioBuffer = nullptr;
  121. }
  122. // 释放FFmpeg资源
  123. if (m_videoCodecCtx)
  124. avcodec_free_context(&m_videoCodecCtx);
  125. if (m_audioCodecCtx)
  126. avcodec_free_context(&m_audioCodecCtx);
  127. if (m_fmtCtx)
  128. avformat_close_input(&m_fmtCtx);
  129. }
  130. void FFmpegVideoPuller::decodeLoop()
  131. {
  132. AVPacket* pkt = av_packet_alloc();
  133. AVFrame* frame = av_frame_alloc();
  134. while (m_running) {
  135. if (av_read_frame(m_fmtCtx, pkt) < 0) {
  136. std::this_thread::sleep_for(std::chrono::milliseconds(10));
  137. continue;
  138. }
  139. if (pkt->stream_index == m_videoStreamIdx) {
  140. avcodec_send_packet(m_videoCodecCtx, pkt);
  141. while (avcodec_receive_frame(m_videoCodecCtx, frame) == 0) {
  142. double pts = frame->best_effort_timestamp
  143. * av_q2d(m_fmtCtx->streams[m_videoStreamIdx]->time_base);
  144. m_videoBuffer->push(av_frame_clone(frame), pts);
  145. }
  146. } else if (pkt->stream_index == m_audioStreamIdx) {
  147. avcodec_send_packet(m_audioCodecCtx, pkt);
  148. while (avcodec_receive_frame(m_audioCodecCtx, frame) == 0) {
  149. double pts = frame->best_effort_timestamp
  150. * av_q2d(m_fmtCtx->streams[m_audioStreamIdx]->time_base);
  151. //qDebug() << "解码到音频帧, pts=" << pts << " nb_samples=" << frame->nb_samples;
  152. m_audioBuffer->push(av_frame_clone(frame), pts);
  153. }
  154. }
  155. av_packet_unref(pkt);
  156. }
  157. av_frame_free(&frame);
  158. av_packet_free(&pkt);
  159. }
  160. void FFmpegVideoPuller::playLoop()
  161. {
  162. // while (m_running) {
  163. // AVFrame* vFrame = getCurrentVideoFrame();
  164. // if (!vFrame) {
  165. // std::this_thread::sleep_for(std::chrono::milliseconds(5));
  166. // continue;
  167. // }
  168. // double vPts = vFrame->best_effort_timestamp
  169. // * av_q2d(m_fmtCtx->streams[m_videoStreamIdx]->time_base);
  170. // // 这里你可以直接把vFrame送到OpenGL渲染
  171. // // 例如: renderFrame(vFrame);
  172. // // 控制倍速
  173. // AVRational fr = m_fmtCtx->streams[m_videoStreamIdx]->avg_frame_rate;
  174. // double frame_delay = 1.0 / (fr.num ? av_q2d(fr) : 25.0);
  175. // float speed = getSpeed();
  176. // int delay = int(frame_delay * 1000 / speed);
  177. // qDebug() << "playLoop, m_speed=" << speed << delay;
  178. // if (delay > 0)
  179. // std::this_thread::sleep_for(std::chrono::milliseconds(delay));
  180. // // 前进
  181. // nextVideoFrame();
  182. // // 更新当前pts
  183. // {
  184. // std::lock_guard<std::mutex> lock(m_ptsMutex);
  185. // m_currentPts = vPts;
  186. // }
  187. // }
  188. while (m_running) {
  189. AVFrame* vFrame = getCurrentVideoFrame();
  190. double vPts = vFrame ? (vFrame->best_effort_timestamp
  191. * av_q2d(m_fmtCtx->streams[m_videoStreamIdx]->time_base))
  192. : m_currentPts.load();
  193. if (vFrame && m_videoRenderCallback) {
  194. m_videoRenderCallback(vFrame);
  195. }
  196. // 音频同步:只要音频帧PTS小于等于视频帧PTS,就顺序播放
  197. while (true) {
  198. AVFrame* aFrame = getCurrentAudioFrame();
  199. if (!aFrame)
  200. break;
  201. double aPts = aFrame->best_effort_timestamp
  202. * av_q2d(m_fmtCtx->streams[m_audioStreamIdx]->time_base);
  203. if (aPts <= vPts + 0.02) { // 允许微小误差
  204. if (m_audioPlayCallback)
  205. m_audioPlayCallback(aFrame);
  206. nextAudioFrame();
  207. } else {
  208. break;
  209. }
  210. }
  211. // 控制倍速
  212. AVRational fr = m_fmtCtx->streams[m_videoStreamIdx]->avg_frame_rate;
  213. double frame_delay = 1.0 / (fr.num ? av_q2d(fr) : 25.0);
  214. float speed = getSpeed();
  215. int delay = int(frame_delay * 1000 / speed);
  216. if (delay > 0)
  217. std::this_thread::sleep_for(std::chrono::milliseconds(delay));
  218. // 前进
  219. nextVideoFrame();
  220. // 更新当前pts
  221. {
  222. std::lock_guard<std::mutex> lock(m_ptsMutex);
  223. m_currentPts = vPts;
  224. }
  225. }
  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_decodeThread) { m_decodeThread->quit(); m_decodeThread->wait(); delete m_decodeThread; m_decodeThread = nullptr; }
  246. if (m_playThread) { m_playThread->quit(); m_playThread->wait(); delete m_playThread; m_playThread = nullptr; }
  247. // 清空缓冲区
  248. if (m_videoBuffer) m_videoBuffer->clear();
  249. if (m_audioBuffer) m_audioBuffer->clear();
  250. // FFmpeg seek
  251. int64_t seek_target = pts / av_q2d(m_fmtCtx->streams[m_videoStreamIdx]->time_base);
  252. av_seek_frame(m_fmtCtx, m_videoStreamIdx, seek_target, AVSEEK_FLAG_BACKWARD);
  253. avcodec_flush_buffers(m_videoCodecCtx);
  254. if (m_audioCodecCtx) avcodec_flush_buffers(m_audioCodecCtx);
  255. // 重置索引
  256. m_videoPlayIndex = 0;
  257. m_audioPlayIndex = 0;
  258. // 重新启动线程
  259. m_running = true;
  260. m_decodeThread = QThread::create([this]() { this->decodeLoop(); });
  261. m_decodeThread->start();
  262. m_playThread = QThread::create([this]() { this->playLoop(); });
  263. m_playThread->start();
  264. }
  265. // 取帧接口
  266. AVFrame* FFmpegVideoPuller::getCurrentVideoFrame()
  267. {
  268. if (!m_videoBuffer)
  269. return nullptr;
  270. return m_videoBuffer->get(m_videoPlayIndex);
  271. }
  272. AVFrame* FFmpegVideoPuller::getCurrentAudioFrame()
  273. {
  274. if (!m_audioBuffer)
  275. return nullptr;
  276. return m_audioBuffer->get(m_audioPlayIndex);
  277. }
  278. void FFmpegVideoPuller::nextVideoFrame()
  279. {
  280. ++m_videoPlayIndex;
  281. if (m_videoBuffer && m_videoPlayIndex >= m_videoBuffer->size())
  282. m_videoPlayIndex = m_videoBuffer->size() - 1;
  283. }
  284. void FFmpegVideoPuller::nextAudioFrame()
  285. {
  286. ++m_audioPlayIndex;
  287. if (m_audioBuffer && m_audioPlayIndex >= m_audioBuffer->size())
  288. m_audioPlayIndex = m_audioBuffer->size() - 1;
  289. }
  290. size_t FFmpegVideoPuller::videoBufferSize() const
  291. {
  292. return m_videoBuffer ? m_videoBuffer->size() : 0;
  293. }
  294. size_t FFmpegVideoPuller::audioBufferSize() const
  295. {
  296. return m_audioBuffer ? m_audioBuffer->size() : 0;
  297. }