FFmpeg 源码学习(一):avformat_open_input 源码分析
一、源碼方法參數分析
下面是avformat_open_input的方法及參數:
/*** 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)
這里我們提供的是英文的參數注釋,主要是翻譯不好,對此方法的理解也沒有什么幫助。下面針對此方法的這幾個參數進行一下說明:
- AVFormatContext **ps : 參數ps包含一切媒體相關的上下文結構,有它就有了一切,本函數如果打開媒體成功,會返回一個AVFormatContext的實例。此參數可以為avformat_alloc_context創建的,也可以是NULL。
- 參數filename是媒體文件名或URL.??
- 參數fmt是要打開的媒體格式的操作結構,因為是讀,所以是inputFormat.此處可以傳入一個調用者定義的inputFormat,對應命令行中的?-f?xxx段,如果指定了它,在打開文件中就不會探測文件的實際格式了,以它為準了.?
- 參數options是對某種格式的一些操作,是為了在命令行中可以對不同的格式傳入,特殊的操作參數而建的, 可以無視。
二、方法的作用及流程
1. 輸入輸出結構體AVIOContext的初始化;
2.?輸入數據的協議(例如RTMP,或者File)的識別(通過一套評分機制)
-
判斷文件名的后綴
-
讀取文件頭的數據進行比對;
3.?使用獲得最高分的文件協議對應的URLProtocol,通過函數指針的方式,與FFMPEG連接,剩下的就是調用該URLProtocol的函數進行open,read等操作。
?
下圖用來了解一下和avformat_open_input有關系的函數調用流程圖:
?
可見最終都調用了URLProtocol結構體中的函數指針。
下面是URLProtocol結構,可以看出來URLProtocol是一大堆函數指針的集合(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功能就是完成各種輸入協議的讀寫等操作
但輸入協議種類繁多,它是怎樣做到“大一統”的呢?
原來,每個具體的輸入協議都有自己對應的URLProtocol。
比如file協議(FFMPEG把文件也當做一種特殊的協議)(*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協議(此處使用了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, };可見它們把各自的函數指針都賦值給了URLProtocol結構體的函數指針
因此avformat_open_input只需調用url_open,url_read這些函數就可以完成各種具體輸入協議的open,read等操作了
三、方法的使用技巧
合理的使用 avformat_open_input 方法能夠加快視頻的首屏播放。
首先我們知道avformat_open_input這個函數的作用是打開文件的鏈接,如果是網絡連接,還會發起網絡請求,并一直等待網絡數據的返回,然后讀取視頻流的數據。
那如何加快首屏播放呢?
我們可以利用方法中的第三個參數——AVInputFormat。AVInputFormat的結構體比較復雜,主要是封裝媒體數據封裝類型的結構體,比如flv, mpegts, mp4等,在這里可以傳入空(或者0),如果為空(或者0),那么FFmpeg就會自行去檢測獲取。
當然如果我們知道文件的類型,先用av_find_input_format("flv")初始化出對應的結構體,這里我們用的是flv,先初始化好這個結構體,就能夠節約時間加快首屏播放了。
?
總結
以上是生活随笔為你收集整理的FFmpeg 源码学习(一):avformat_open_input 源码分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android 架构 -- Room
- 下一篇: python模块基础之getpass模块