ffmpeg rtsp转hls_Qt音视频开发24-ffmpeg音视频同步
## 一、前言
用ffmpeg來做音視頻同步,個人認為這個是ffmpeg基礎處理中最難的一個,無數人就卡在這里,怎么也不準,本人也是嘗試過網上各種demo,基本上都是渣渣,要么僅僅支持極其少量的視頻文件比如收到的數據包是一幀視頻一幀音頻的,要么根本沒法同步歪七八糟的,要么進度跳過去直接蹦蹦蹦崩潰的,其實最完美的音視頻同步處理demo就是ffplay,我親測過幾十種各種各樣的音視頻本地文件,數十種視頻流文件,都是非常完美,當然啦這是親生的啦,不完美還玩個屁。
如果僅僅是播放視頻流(不帶音頻流),可能不需要音視頻同步,所以最開始只做rtsp視頻流播放的時候根本沒有考慮同步的問題,因為沒遇到也不需要,等到后期發現各種rtmp、http、m3u8這種視頻流的時候,問題大了去了,他是hls格式的視頻流文件一次性過來的,一個個小視頻文件過來的,如果沒有同步的話,意味著突然之間刷刷刷的圖片過去很多,下一次來的又是刷刷的,這就需要自己計算同步了,上次接收到的數據包放入隊列,到了需要顯示的時候就顯示。
常用的音視頻同步方法:
1. 通過fps來控制,fps表示一秒鐘播放多少幀,比如25幀,可以自行計算一幀解碼用掉的時間,一幀占用(1000/25=40毫秒),通過延時來處理,這其實是最渣渣的辦法。
2. 記住開始解碼的時間startTime,通過av_rescale_q計算pts時間,兩者的差值就是需要延時的時間,調用av_usleep來延時,這種只有部分文件正常,很多時候不正常。
3. 音頻同步到視頻,視頻時鐘作為主時鐘,沒試過,網上很多人說這個辦法不好。
4. 視頻同步到音頻,音頻時鐘作為主時鐘,沒試過,據說大部分人采用的此辦法。
5. 音視頻同步到外部時鐘,外部時鐘作為主時鐘,最終采用的辦法,容易理解互不干擾,各自按照外部時鐘去同步自己。
6. ffplay自身內置了三種同步策略,可以通過參數來控制采用何種策略,默認是視頻同步到音頻。
## 二、功能特點
1. 多線程實時播放視頻流+本地視頻+USB攝像頭等。
2. 支持windows+linux+mac,支持ffmpeg3和ffmpeg4,支持32位和64位。
3. 多線程顯示圖像,不卡主界面。
4. 自動重連網絡攝像頭。
5. 可設置邊框大小即偏移量和邊框顏色。
6. 可設置是否繪制OSD標簽即標簽文本或圖片和標簽位置。
7. 可設置兩種OSD位置和風格。
8. 可設置是否保存到文件以及文件名。
9. 可直接拖曳文件到ffmpegwidget控件播放。
10. 支持h265視頻流+rtmp等常見視頻流。
11. 可暫停播放和繼續播放。
12. 支持存儲單個視頻文件和定時存儲視頻文件。
13. 自定義頂部懸浮條,發送單擊信號通知,可設置是否啟用。
14. 可設置畫面拉伸填充或者等比例填充。
15. 可設置解碼是速度優先、質量優先、均衡處理。
16. 可對視頻進行截圖(原始圖片)和截屏。
17. 錄像文件存儲支持裸流和MP4文件。
18. 音視頻完美同步,采用外部時鐘同步策略。
19. 支持seek定位播放位置。
20. 支持qsv、dxva2、d3d11va等硬解碼。
21. 支持opengl繪制視頻數據,極低CPU占用。
22. 支持安卓和嵌入式linux,交叉編譯即可。
## 三、效果圖
## 四、相關站點
1. 國內站點:[https://gitee.com/feiyangqingyun/QWidgetDemo](https://gitee.com/feiyangqingyun/QWidgetDemo)
2. 國際站點:[https://github.com/feiyangqingyun/QWidgetDemo](https://github.com/feiyangqingyun/QWidgetDemo)
3. 個人主頁:[https://blog.csdn.net/feiyangqingyun](https://blog.csdn.net/feiyangqingyun)
4. 知乎主頁:[https://www.zhihu.com/people/feiyangqingyun/](https://www.zhihu.com/people/feiyangqingyun/)
5. 體驗地址:[https://blog.csdn.net/feiyangqingyun/article/details/97565652](https://blog.csdn.net/feiyangqingyun/article/details/97565652)
## 五、核心代碼
void FFmpegSync::run(){ reset(); while (!stopped) { //暫停狀態或者隊列中沒有幀則不處理 if (!thread->isPause && packets.count() > 0) { mutex.lock(); AVPacket *packet = packets.first(); mutex.unlock(); //h264的裸流文件同步有問題,獲取不到pts和dts,暫時用最蠢的辦法延時解決 if (thread->formatName == "h264") { int sleepTime = (1000 / thread->videoFps) - 5; msleep(sleepTime); } //計算當前幀顯示時間 外部時鐘同步 ptsTime = getPtsTime(thread->formatCtx, packet); if (!this->checkPtsTime()) { msleep(1); continue; } //顯示當前的播放進度 checkShowTime(); //0-表示音頻 1-表示視頻 if (type == 0) { thread->decodeAudio(packet); } else if (type == 1) { thread->decodeVideo(packet); } //釋放資源并移除 thread->free(packet); mutex.lock(); packets.removeFirst(); mutex.unlock(); } msleep(1); } clear(); stopped = false;}bool FFmpegSync::checkPtsTime(){ bool ok = false; if (ptsTime > 0) { if (ptsTime > offsetTime + 100000) { bufferTime = ptsTime - offsetTime + 100000; } int offset = (type == 0 ? 1000 : 5000); offsetTime = av_gettime() - startTime + bufferTime; if ((offsetTime <= ptsTime && ptsTime - offsetTime <= offset) || (offsetTime > ptsTime)) { ok = true; } } else { ok = true; } return ok;}總結
以上是生活随笔為你收集整理的ffmpeg rtsp转hls_Qt音视频开发24-ffmpeg音视频同步的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: php截断上传,截断在文件包含和上传中的
- 下一篇: rfcv函数实现_OpenSSL AES