您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關Qt如何實現ffmpeg音視頻同步,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
用ffmpeg來做音視頻同步,個人認為這個是ffmpeg基礎處理中最難的一個,無數人就卡在這里,怎么也不準,本人也是嘗試過網上各種demo,基本上都是渣渣,要么僅僅支持極其少量的視頻文件比如收到的數據包是一幀視頻一幀音頻的,要么根本沒法同步歪七八糟的,要么進度跳過去直接蹦蹦蹦崩潰的,其實最完美的音視頻同步處理demo就是ffplay,我親測過幾十種各種各樣的音視頻本地文件,數十種視頻流文件,都是非常完美,當然啦這是親生的啦,不完美還玩個屁。
如果僅僅是播放視頻流(不帶音頻流),可能不需要音視頻同步,所以最開始只做rtsp視頻流播放的時候根本沒有考慮同步的問題,因為沒遇到也不需要,等到后期發現各種rtmp、http、m3u8這種視頻流的時候,問題大了去了,他是hls格式的視頻流文件一次性過來的,一個個小視頻文件過來的,如果沒有同步的話,意味著突然之間刷刷刷的圖片過去很多,下一次來的又是刷刷的,這就需要自己計算同步了,上次接收到的數據包放入隊列,到了需要顯示的時候就顯示。
常用的音視頻同步方法:
通過fps來控制,fps表示一秒鐘播放多少幀,比如25幀,可以自行計算一幀解碼用掉的時間,一幀占用(1000/25=40毫秒),通過延時來處理,這其實是最渣渣的辦法。
記住開始解碼的時間startTime,通過av_rescale_q計算pts時間,兩者的差值就是需要延時的時間,調用av_usleep來延時,這種只有部分文件正常,很多時候不正常。
音頻同步到視頻,視頻時鐘作為主時鐘,沒試過,網上很多人說這個辦法不好。
視頻同步到音頻,音頻時鐘作為主時鐘,沒試過,據說大部分人采用的此辦法。
音視頻同步到外部時鐘,外部時鐘作為主時鐘,最終采用的辦法,容易理解互不干擾,各自按照外部時鐘去同步自己。
ffplay自身內置了三種同步策略,可以通過參數來控制采用何種策略,默認是視頻同步到音頻。
多線程實時播放視頻流+本地視頻+USB攝像頭等。
支持windows+linux+mac,支持ffmpeg3和ffmpeg4,支持32位和64位。
多線程顯示圖像,不卡主界面。
自動重連網絡攝像頭。
可設置邊框大小即偏移量和邊框顏色。
可設置是否繪制OSD標簽即標簽文本或圖片和標簽位置。
可設置兩種OSD位置和風格。
可設置是否保存到文件以及文件名。
可直接拖曳文件到ffmpegwidget控件播放。
支持h365視頻流+rtmp等常見視頻流。
可暫停播放和繼續播放。
支持存儲單個視頻文件和定時存儲視頻文件。
自定義頂部懸浮條,發送單擊信號通知,可設置是否啟用。
可設置畫面拉伸填充或者等比例填充。
可設置解碼是速度優先、質量優先、均衡處理。
可對視頻進行截圖(原始圖片)和截屏。
錄像文件存儲支持裸流和MP4文件。
音視頻完美同步,采用外部時鐘同步策略。
支持seek定位播放位置。
支持qsv、dxva2、d3d11va等硬解碼。
支持opengl繪制視頻數據,極低CPU占用。
支持安卓和嵌入式linux,交叉編譯即可。
void FFmpegSync::run() { reset(); while (!stopped) { //暫停狀態或者隊列中沒有幀則不處理 if (!thread->isPause && packets.count() > 0) { mutex.lock(); AVPacket *packet = packets.first(); mutex.unlock(); //h364的裸流文件同步有問題,獲取不到pts和dts,暫時用最蠢的辦法延時解決 if (thread->formatName == "h364") { 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; }
關于“Qt如何實現ffmpeg音視頻同步”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。