FFmpeg 源码学习(一):avformat_open_input 源码分析
一、源碼方法參數(shù)分析
下面是avformat_open_input的方法及參數(shù):
/*** Open an input stream and read the header. The codecs are not opened.
* The stream must be closed with avformat_close_input().
*
* @param ps Pointer to user-supplied AVFormatContext (allocated by avformat_alloc_context).
* May be a pointer to NULL, in which case an AVFormatContext is allocated by this
* function and written into ps.
* Note that a user-supplied AVFormatContext will be freed on failure.
* @param url URL of the stream to open.
* @param fmt If non-NULL, this parameter forces a specific input format.
* Otherwise the format is autodetected.
* @param options A dictionary filled with AVFormatContext and demuxer-private options.
* On return this parameter will be destroyed and replaced with a dict containing
* options that were not found. May be NULL.
*
* @return 0 on success, a negative AVERROR on failure.
*
* @note If you want to use custom IO, preallocate the format context and set its pb field.
*/ int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputFormat *fmt, AVDictionary **options)
這里我們提供的是英文的參數(shù)注釋,主要是翻譯不好,對此方法的理解也沒有什么幫助。下面針對此方法的這幾個參數(shù)進行一下說明:
- AVFormatContext **ps : 參數(shù)ps包含一切媒體相關(guān)的上下文結(jié)構(gòu),有它就有了一切,本函數(shù)如果打開媒體成功,會返回一個AVFormatContext的實例。此參數(shù)可以為avformat_alloc_context創(chuàng)建的,也可以是NULL。
- 參數(shù)filename是媒體文件名或URL.??
- 參數(shù)fmt是要打開的媒體格式的操作結(jié)構(gòu),因為是讀,所以是inputFormat.此處可以傳入一個調(diào)用者定義的inputFormat,對應(yīng)命令行中的?-f?xxx段,如果指定了它,在打開文件中就不會探測文件的實際格式了,以它為準了.?
- 參數(shù)options是對某種格式的一些操作,是為了在命令行中可以對不同的格式傳入,特殊的操作參數(shù)而建的, 可以無視。
二、方法的作用及流程
1. 輸入輸出結(jié)構(gòu)體AVIOContext的初始化;
2.?輸入數(shù)據(jù)的協(xié)議(例如RTMP,或者File)的識別(通過一套評分機制)
-
判斷文件名的后綴
-
讀取文件頭的數(shù)據(jù)進行比對;
3.?使用獲得最高分的文件協(xié)議對應(yīng)的URLProtocol,通過函數(shù)指針的方式,與FFMPEG連接,剩下的就是調(diào)用該URLProtocol的函數(shù)進行open,read等操作。
?
下圖用來了解一下和avformat_open_input有關(guān)系的函數(shù)調(diào)用流程圖:
?
可見最終都調(diào)用了URLProtocol結(jié)構(gòu)體中的函數(shù)指針。
下面是URLProtocol結(jié)構(gòu),可以看出來URLProtocol是一大堆函數(shù)指針的集合(avio.h文件)
typedef struct URLProtocol {const char *name;int (*url_open)(URLContext *h, const char *url, int flags);int (*url_read)(URLContext *h, unsigned char *buf, int size);int (*url_write)(URLContext *h, const unsigned char *buf, int size);int64_t (*url_seek)(URLContext *h, int64_t pos, int whence);int (*url_close)(URLContext *h);struct URLProtocol *next;int (*url_read_pause)(URLContext *h, int pause);int64_t (*url_read_seek)(URLContext *h, int stream_index,int64_t timestamp, int flags);int (*url_get_file_handle)(URLContext *h);int priv_data_size;const AVClass *priv_data_class;int flags;int (*url_check)(URLContext *h, int mask); } URLProtocol;URLProtocol功能就是完成各種輸入?yún)f(xié)議的讀寫等操作
但輸入?yún)f(xié)議種類繁多,它是怎樣做到“大一統(tǒng)”的呢?
原來,每個具體的輸入?yún)f(xié)議都有自己對應(yīng)的URLProtocol。
比如file協(xié)議(FFMPEG把文件也當(dāng)做一種特殊的協(xié)議)(*file.c文件)
URLProtocol ff_pipe_protocol = {.name = "pipe",.url_open = pipe_open,.url_read = file_read,.url_write = file_write,.url_get_file_handle = file_get_handle,.url_check = file_check, };或者rtmp協(xié)議(此處使用了librtmp)(librtmp.c文件)
URLProtocol ff_rtmp_protocol = {.name = "rtmp",.url_open = rtmp_open,.url_read = rtmp_read,.url_write = rtmp_write,.url_close = rtmp_close,.url_read_pause = rtmp_read_pause,.url_read_seek = rtmp_read_seek,.url_get_file_handle = rtmp_get_file_handle,.priv_data_size = sizeof(RTMP),.flags = URL_PROTOCOL_FLAG_NETWORK, };可見它們把各自的函數(shù)指針都賦值給了URLProtocol結(jié)構(gòu)體的函數(shù)指針
因此avformat_open_input只需調(diào)用url_open,url_read這些函數(shù)就可以完成各種具體輸入?yún)f(xié)議的open,read等操作了
三、方法的使用技巧
合理的使用 avformat_open_input 方法能夠加快視頻的首屏播放。
首先我們知道avformat_open_input這個函數(shù)的作用是打開文件的鏈接,如果是網(wǎng)絡(luò)連接,還會發(fā)起網(wǎng)絡(luò)請求,并一直等待網(wǎng)絡(luò)數(shù)據(jù)的返回,然后讀取視頻流的數(shù)據(jù)。
那如何加快首屏播放呢?
我們可以利用方法中的第三個參數(shù)——AVInputFormat。AVInputFormat的結(jié)構(gòu)體比較復(fù)雜,主要是封裝媒體數(shù)據(jù)封裝類型的結(jié)構(gòu)體,比如flv, mpegts, mp4等,在這里可以傳入空(或者0),如果為空(或者0),那么FFmpeg就會自行去檢測獲取。
當(dāng)然如果我們知道文件的類型,先用av_find_input_format("flv")初始化出對應(yīng)的結(jié)構(gòu)體,這里我們用的是flv,先初始化好這個結(jié)構(gòu)體,就能夠節(jié)約時間加快首屏播放了。
?
總結(jié)
以上是生活随笔為你收集整理的FFmpeg 源码学习(一):avformat_open_input 源码分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android 架构 -- Room
- 下一篇: python模块基础之getpass模块