日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Seek 策略以及在有 B 帧情况下的处理

發(fā)布時間:2023/12/20 编程问答 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Seek 策略以及在有 B 帧情况下的处理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在知識星球分享的文章,順便也在公眾號發(fā)表一下,不足之處,歡迎指正。

一個關于音視頻領域專業(yè)問答的小圈子!!

最近在做 Seek 相關功能時遇到的問題排查,順便也學到了一些新的東西,和大家分享下。

在視頻播放時執(zhí)行 Seek 到任意點的操作,一般都是 Seek 到任意點往前最近的 I 幀,然后再逐幀解碼到指定時間點。

這里可以優(yōu)化,假設當前時間和指定時間在一個 GOP 內,就可以不用 seek ,直接順序向下解碼就好。

而正是這個優(yōu)化出現了一點問題,現象如下:

已經判斷播放點 A 和 Seek 點 B 不在一個 GOP 內,然后執(zhí)行 av_seek_frame 方法還是把時間點 A 所在 GOP 全部解碼了,導致播放上出現了卡頓。

這里就很奇怪了,明明判斷不在一個 GOP ,那 Seek 時就應該從時間點 B 所在 GOP 的 I 幀開始解碼, 但執(zhí)行時還是解碼了上一個 GOP 的內容。

到底是判斷是否同一個 GOP 的函數出問題了還是 Seek 方法有問題呢?

帶著疑問開始深入源碼探索。

FFmpeg 沒有直接提供判斷兩幀是否同一個 GOP 的方法,所以通過 av_index_search_timestamp 方法得到傳入時間點最近的 I 幀的 index 索引,如果兩個時間點的索引相同則表示為同一個 GOP 內,因為最近的 I 幀相同。

然而 av_index_search_timestamp 方法是通過 AVIndexEntry 中的 timestamp 來判斷的,它是一個 DTS 值,通過二分查找得到最近的索引。

在沒有 B 幀的情況下,I 幀的 PTS 等于 DTS ,所以判斷不會出問題。然而正是有了 B 幀,如果 I 幀的 PTS 和 DTS 不相等的話,那么上面的判斷相當于是拿一個 PTS 值和 I 幀的 DTS 比較是否同一個 GOP 了。

如果將錯就錯,判斷 GOP 時得到結論是非同一個 GOP ,那么 Seek 也應該是非同一個 GOP ,但現實恰恰相反,Seek 當做了同一個 GOP ,這里面肯定有計算出問題了,繼續(xù)深入源碼。

通過在 mov.c 源碼中看到了如下的操作:

static?int?mov_seek_stream(AVFormatContext?*s,?AVStream?*st,?int64_t?timestamp,?int?flags) {MOVStreamContext?*sc?=?st->priv_data;FFStream?*const?sti?=?ffstream(st);int?sample,?time_sample,?ret;unsigned?int?i;//?Here?we?consider?timestamp?to?be?PTS,?hence?try?to?offset?it?so?that?we//?can?search?over?the?DTS?timeline.timestamp?-=?(sc->min_corrected_pts?+?sc->dts_shift);ret?=?mov_seek_fragment(s,?st,?timestamp);if?(ret?<?0)return?ret;sample?=?av_index_search_timestamp(st,?timestamp,?flags);av_log(s,?AV_LOG_TRACE,?"stream?%d,?timestamp?%"PRId64",?sample?%d\n",?st->index,?timestamp,?sample);//?省略部分代碼

注意到如下一行代碼:

timestamp?-=?(sc->min_corrected_pts?+?sc->dts_shift);

也就是說我們傳入的時間都會被減上一個值,然后再執(zhí)行 av_index_search_timestamp 方法,而這個值導致判斷 GOP 和 Seek 之間的關鍵幀索引出問題了。

正如代碼中的注釋所示,假設傳入的時間是 PTS 值,然后給它減去偏移以得到 DTS 值,因為 av_index_search_timestamp 方法就通過 DTS 進行比較的嘛。

出現問題的原因就是 seek 的時間點正好在 I 幀的 PTS 和 DTS 范圍之間了,執(zhí)行 seek 時減去偏差值就小于 DTS 了,所以變成了同一個 GOP 。

現在要解決問題就是如何得到 sc->min_corrected_pts + sc->dts_shif 之和,然后判斷 GOP 時減去它以修正得到 DTS 值。

還好通過遍歷源碼發(fā)現它的值是不會運行時改變的,一旦決定了就定下來了。另外我們可以用第一個 I 幀的 DTS 值作為偏移值。

auto?indexEntry?=?avStream->index_entries;auto?nbIndexEntry?=?avStream->nb_index_entries;for?(int?i?=?0;?i?<?nbIndexEntry;?++i)?{if?(indexEntry[i].flags?==?AVINDEX_KEYFRAME)?{DTSOffset?=?indexEntry[i].timestamp;return;}}

如果沒有 B 幀,DTS 值為 0 ,有 B 幀,那么首幀的 DTS 值就可以用來做偏差值進行計算了。

一個音視頻領域專業(yè)問答的小圈子!

推薦閱讀:

音視頻開發(fā)工作經驗分享 || 視頻版

OpenGL ES 學習資源分享

開通專輯 | 細數那些年寫過的技術文章專輯

Android NDK 免費視頻在線學習!!!

你想要的音視頻開發(fā)資料庫來了

推薦幾個堪稱教科書級別的 Android 音視頻入門項目

覺得不錯,點個在看唄~

總結

以上是生活随笔為你收集整理的Seek 策略以及在有 B 帧情况下的处理的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。