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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

avformat_seek_file使用

發布時間:2023/12/20 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 avformat_seek_file使用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

? ? 最近一個播放器項目基于ijkplayer做二次開發,是http-mp4點播,需要做精準seek,用到了avformat_seek_file接口,這里簡要介紹下ffmpeg下的這個接口使用、注意事項,以及http-mp4網絡流精準seek的方案。

接口介紹

? ? int avformat_seek_file(AVFormatContext *s,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?int stream_index,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?int64_t min_ts,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?int64_t ts,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?int64_t max_ts,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?int flags);

解釋:

1)AVFormatContext *s,AVFormatContext實例。

2)int stream_index,流索引,但是只有在 flags 包含 AVSEEK_FLAG_FRAME 的時候才是 設置某個流的讀取位置。其他情況都只是把這個流的 time_base (時間基)作為參考。

3)int64_t min_ts,跳轉到的最小的時間,或時間單位,或字節單位,或幀數序號(第幾幀)。

4)int64_t ts,目標seek位置,單位同上,通常填INT64_MIN即可。

5)int64_t max_ts,跳轉到的最大的時間,單位同上,通常填 INT64_MAX 即可。

6)int flags,seek方式,如下:

? ? ? AVSEEK_FLAG_BYTE,按字節大小進行seek。
? ? ? AVSEEK_FLAG_FRAME,按幀數大小進行seek。
? ? ? AVSEEK_FLAG_ANY,會seek到非IDR,解碼會出現馬賽克、花屏現象。
? ? ? AVSEEK_FLAG_BACKWARD,往 ts 后面找最近的IDR。

本地mp4文件

? ? ? 經測試,avformat_seek_file接口,可通過將flag設置為AVSEEK_FLAG_BACKWARD,可seek到離ts最近的IDR幀(方向是ts的后面),參考示例:

? ? ? avformat_seek_file(s, -1, INT64_MIN, target_ts, INT64_MAX, AVSEEK_FLAG_BACKWARD)

? ? ? 本地mp4文件,如果要做精準seek,則按如上方案實施即可,可找到target_ts后面最近的IDR幀,然后逐幀解碼后,當視頻的pts == target_ts,或者誤差在指定范圍內認為是精準seek即可。

http-mp4

? ? ? 然而,網絡流http-mp4卻不能通過avformat_seek_file接口來找到離target_ts后面最近的IDR幀,可通過服務器來實現,讓服務器返回最近的IDR幀。

? ? ? 此處,介紹一個本人自己經實踐可行的方案

// 此處指http-mp4流 static bool is_http_stream(const char* filename) {assert(filename);char* pos = strstr(filename, "http://");if (pos != NULL) {return true;}pos = strstr(filename, "https://");return pos != NULL; }

? ? ? 而后,在ijkplayer的ff_ffplay.c文件read_thread方法的seek_req判斷里,增加如下代碼:

if (is->seek_req) {int64_t seek_target = is->seek_pos;if (is_http_stream(is->filename)) {int gop_size = is->viddec.avctx->gop_size;if (gop_size > 0) {int64_t backward = gop_size * 1000 * 1000;if (seek_target > backward) {seek_target -= backward;}}}int64_t seek_min = is->seek_rel > 0 ? seek_target - is->seek_rel + 2: INT64_MIN;int64_t seek_max = is->seek_rel < 0 ? seek_target - is->seek_rel - 2: INT64_MAX; // FIXME the +-2 is due to rounding being not done in the correct direction in generation // of the seek_pos/seek_rel variablesffp_toggle_buffering(ffp, 1);ffp_notify_msg3(ffp, FFP_MSG_BUFFERING_UPDATE, 0, 0);ret = avformat_seek_file(is->ic, -1, seek_min, seek_target, seek_max, is->seek_flags);

? ? ? 關鍵的代碼段邏輯:

1)即首先判斷是否是http-mp4網絡流(本地文件不走此邏輯)

2)通過VideoState結構體的Decoder類型字段viddec,找到AVCodecContext類型變量avctx

3)再通過avctx拿到本片源的gop_size

4)再將seek_target -= gop_size * 1000 * 1000,再按seek_target此值往回找IDR,可實現http-mp4的精準定位。

if (is_http_stream(is->filename)) {int gop_size = is->viddec.avctx->gop_size;if (gop_size > 0) {int64_t backward = gop_size * 1000 * 1000;if (seek_target > backward) {seek_target -= backward;}}}

注意:

1.如果gop較小,比如1s一個關鍵幀,則精準定位按ijkplayer的代碼基本就能滿足需求;

2.但本項目中,遇到了10s甚至更長的gop大小,這對精準seek提出了更高的要求,增加了精準seek的難度?,avformat_seek_file接口無法seek到最近的IDR幀,如果您也是遇到gop較大情形,而又沒有后端服務支持,可參考本精準seek方案。

總結

以上是生活随笔為你收集整理的avformat_seek_file使用的全部內容,希望文章能夠幫你解決所遇到的問題。

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