FFmpeg源代碼簡單分析:avio_open2()
來源:程序員人生 發布時間:2015-03-13 07:59:22 閱讀次數:11199次
本文簡單分析FFmpeg中1個經常使用的函數avio_open2()。該函數用于打開FFmpeg的輸入輸出文件。avio_open2()的聲明位于libavformatavio.h文件中,以下所示。
/**
* Create and initialize a AVIOContext for
accessing the
* resource indicated by url.
* @note When the resource indicated by url has been opened in
* read+write mode, the AVIOContext can be used only for writing.
*
* @param s Used to return the pointer to the created AVIOContext.
* In case of failure the pointed to value is set to NULL.
* @param url resource to
access
* @param flags flags which control how the resource indicated by url
* is to be opened
* @param int_cb an interrupt callback to be used at the protocols level
* @param options A dictionary filled with protocol-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 in case of success, a negative value corresponding to an
* AVERROR code in case of failure
*/
int avio_open2(AVIOContext **s, const char *url, int flags,
const AVIOInterruptCB *int_cb, AVDictionary **options);
avio_open2()函數參數的含義以下:
s:函數調用成功以后創建的AVIOContext結構體。
url:輸入輸出協議的地址(文件也是1種“廣義”的協議,對文件來講就是文件的路徑)。
flags:打開地址的方式。可以選擇只讀,只寫,或讀寫。取值以下。
AVIO_FLAG_READ:只讀。
AVIO_FLAG_WRITE:只寫。
AVIO_FLAG_READ_WRITE:讀寫。
int_cb:目前還沒有用過。
options:目前還沒有用過。
該函數最典型的例子可以參考:最簡單的基于FFMPEG的視頻編碼器(YUV編碼為H.264)
函數調用結構圖
首先貼出來終究分析得出的函數調用結構圖,以下所示。

單擊查看更清晰的圖片
avio_open()
有1個和avio_open2()“長得很像”的函數avio_open(),應當是avio_open2()的初期版本。avio_open()比avio_open2()少了最后2個參數。而它前面幾個參數的含義和avio_open2()是1樣的。從源代碼中可以看出,avio_open()內部調用了avio_open2(),并且把avio_open2()的后2個參數設置成了NULL,因此它的功能實際上和avio_open2()是1樣的。avio_open()源代碼以下所示。
int avio_open(AVIOContext **s, const char *filename, int flags)
{
return avio_open2(s, filename, flags, NULL, NULL);
}
avio_open2()
下面看1下avio_open2()的源代碼,位于libavformataviobuf.c文件中。
int avio_open2(AVIOContext **s, const char *filename, int flags,
const AVIOInterruptCB *int_cb, AVDictionary **options)
{
URLContext *h;
int err;
err = ffurl_open(&h, filename, flags, int_cb, options);
if (err < 0)
return err;
err = ffio_fdopen(s, h);
if (err < 0) {
ffurl_close(h);
return err;
}
return 0;
}
從avio_open2()的源代碼可以看出,它主要調用了2個函數:ffurl_open()和ffio_fdopen()。其中ffurl_open()用于初始化URLContext,ffio_fdopen()用于根據URLContext初始化AVIOContext。URLContext中包括的URLProtocol完成了具體的協議讀寫等工作。AVIOContext則是在URLContext的讀寫函數外面加上了1層“包裝”(通過retry_transfer_wrapper()函數)。
URLProtocol和URLContext
在查看ffurl_open()和ffio_fdopen()函數之前,首先查看1下URLContext和URLProtocol的定義。這兩個結構體在FFmpeg的初期版本的SDK中是定義在頭文件中可以直接使用的。但是近期的FFmpeg的SDK中已找不到這兩個結構體的定義了。FFmpeg把這兩個結構體移動到了源代碼的內部,變成了內部結構體。
URLProtocol的定義位于libavformaturl.h,以下所示。
typedef struct URLProtocol {
const char *name;
int (*url_open)( URLContext *h, const char *url, int flags);
/**
* This callback is to be used by protocols which open further nested
* protocols. options are then to be passed to ffurl_open()/ffurl_connect()
* for those nested protocols.
*/
int (*url_open2)(URLContext *h, const char *url, int flags, AVDictionary **options);
/**
* Read data from the protocol.
* If data is immediately available (even less than size), EOF is
* reached or an error occurs (including EINTR), return immediately.
* Otherwise:
* In non-blocking mode, return AVERROR(EAGAIN) immediately.
* In blocking mode, wait for data/EOF/error with a short timeout (0.1s),
* and return AVERROR(EAGAIN) on timeout.
* Checking interrupt_callback, looping on EINTR and EAGAIN and until
* enough data has been read is left to the calling function; see
* retry_transfer_wrapper in avio.c.
*/
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 (*url_get_multi_file_handle)(URLContext *h, int **handles,
int *numhandles);
int (*url_shutdown)(URLContext *h, int flags);
int priv_data_size;
const AVClass *priv_data_class;
int flags;
int (*url_check)(URLContext *h, int mask);
} URLProtocol;
從URLProtocol的定義可以看出,其中包括了用于協議讀寫的函數指針。例如:
url_open():打開協議。
url_read():讀數據。
url_write():寫數據。
url_close():關閉協議。
每種具體的協議都包括了1個URLProtocol結構體,例如:
FILE協議(“文件”在FFmpeg中也被當作1種協議)的結構體ff_file_protocol的定義以下所示(位于libavformatfile.c)。
URLProtocol ff_file_protocol = {
.name = "file",
.url_open = file_open,
.url_read = file_read,
.url_write = file_write,
.url_seek = file_seek,
.url_close = file_close,
.url_get_file_handle = file_get_handle,
.url_check = file_check,
.priv_data_size = sizeof(FileContext),
.priv_data_class = &file_class,
};
在使用FILE協議進行讀寫的時候,調用url_open()實際上就是調用了file_open()函數,這里限于篇幅不再對file_open()的源代碼進行分析。file_open()函數實際上調用了系統的打開文件函數open()。同理,調用url_read()實際上就是調用了file_read()函數;file_read()函數實際上調用了系統的讀取文件函數read()。url_write(),url_seek()等函數的道理都是1樣的。
LibRTMP協議的結構體ff_librtmp_protocol的定義以下所示(位于libavformatlibrtmp.c)。
URLProtocol ff_librtmp_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(LibRTMPContext),
.priv_data_class = &librtmp_class,
.flags = URL_PROTOCOL_FLAG_NETWORK,
};
UDP協議的結構體ff_udp_protocol的定義以下所示(位于libavformatudp.c)。
URLProtocol ff_udp_protocol = {
.name = "udp",
.url_open = udp_open,
.url_read = udp_read,
.url_write = udp_write,
.url_close = udp_close,
.url_get_file_handle = udp_get_file_handle,
.priv_data_size = sizeof(UDPContext),
.priv_data_class = &udp_context_class,
.flags = URL_PROTOCOL_FLAG_NETWORK,
};
上文中簡單介紹了URLProtocol結構體。下面看1下URLContext結構體。URLContext的定義也位于libavformaturl.h,以下所示。
typedef struct URLContext {
const AVClass *av_class; /**< information for av_log(). Set by url_open(). */
struct URLProtocol *prot;
void *priv_data;
char *filename; /**< specified URL */
int flags;
int max_packet_size; /**< if non zero, the stream is packetized with this max packet size */
int is_streamed; /**< true if streamed (no seek possible), default = false */
int is_connected;
AVIOInterruptCB interrupt_callback;
int64_t rw_timeout; /**< maximum time to wait for (network) read/write operation completion, in mcs */
} URLContext;
從代碼中可以看出,URLProtocol結構體是URLContext結構體的1個成員。由于還沒有對URLContext結構體進行詳細研究,有關該結構體的代碼不再做過量分析。
ffurl_open()
前文提到AVIOContext中主要調用了2個函數:ffurl_open()和ffio_fdopen()。其中ffurl_open()用于初始化URLContext,ffio_fdopen()用于根據URLContext初始化AVIOContext。下面首先看1下初始化URLContext的函數ffurl_open()。
ffurl_open()的函數定義位于libavformatavio.c中,以下所示。
int ffurl_open(URLContext **puc, const char *filename, int flags,
const AVIOInterruptCB *int_cb, AVDictionary **options)
{
int ret = ffurl_alloc(puc, filename, flags, int_cb);
if (ret < 0)
return ret;
if (options && (*puc)->prot->priv_data_class &&
(ret = av_opt_set_dict((*puc)->priv_data, options)) < 0)
goto fail;
if ((ret = av_opt_set_dict(*puc, options)) < 0)
goto fail;
ret = ffurl_connect(*puc, options);
if (!ret)
return 0;
fail:
ffurl_close(*puc);
*puc = NULL;
return ret;
}
從代碼中可以看出,ffurl_open()主要調用了2個函數:ffurl_alloc()和ffurl_connect()。ffurl_alloc()用于查找適合的URLProtocol,并創建1個URLContext;ffurl_connect()用于打開取得的URLProtocol。
ffurl_alloc()
ffurl_alloc()的定義位于libavformatavio.c中,以下所示。
int ffurl_alloc(URLContext **puc, const char *filename, int flags,
const AVIOInterruptCB *int_cb)
{
URLProtocol *p = NULL;
if (!first_protocol) {
av_log(NULL, AV_LOG_WARNING, "No URL Protocols are registered. "
"Missing call to av_register_all()?
");
}
p = url_find_protocol(filename);
if (p)
return url_alloc_for_protocol(puc, p, filename, flags, int_cb);
*puc = NULL;
if (av_strstart(filename, "https:", NULL))
av_log(NULL, AV_LOG_WARNING, "https protocol not found, recompile with openssl or gnutls enabled.
");
return AVERROR_PROTOCOL_NOT_FOUND;
}
從代碼中可以看出,ffurl_alloc()主要調用了2個函數:url_find_protocol()根據文件路徑查找適合的URLProtocol,url_alloc_for_protocol()為查找到的URLProtocol創建URLContext。
url_find_protocol()
先來看1下url_find_protocol()函數,定義以下所示。
#define URL_SCHEME_CHARS
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789+-."
static struct URLProtocol *url_find_protocol(const char *filename)
{
URLProtocol *up = NULL;
char proto_str[128], proto_nested[128], *ptr;
size_t proto_len = strspn(filename, URL_SCHEME_CHARS);
if (filename[proto_len] != ':' &&
(filename[proto_len] != ',' || !strchr(filename + proto_len + 1, ':')) ||
is_dos_path(filename))
strcpy(proto_str, "file");
else
av_strlcpy(proto_str, filename,
FFMIN(proto_len + 1, sizeof(proto_str)));
if ((ptr = strchr(proto_str, ',')))
*ptr = '
主站蜘蛛池模板:
超黄网站
|
美女一级黄色毛片
|
久久噜
|
成人一区二区三区四区
|
麻豆视频在线免费观看
|
国产不卡视频一区二区三区
|
日韩中文字幕视频
|
日韩一区二区三区四区五区
|
久久国产精品免费一区二区三区
|
免费a v在线
|
欧美精品导航
|
久久精品一
|
久久com
|
亚洲一区视频
|
国产高清第一页
|
欧美二三四区
|
中文字幕国产一区
|
97午夜
|
久久婷婷国产麻豆91天堂徐州
|
国产伦精品一区二区三区视频黑人
|
亚洲午夜久久久久久久久久久
|
国产99区
|
天堂电影在线观看
|
夜夜久久久
|
www久|
五月婷婷网
|
在线视频一区二区三区
|
欧美成人精品一区二区
|
久久久国产精品一区二区三区
|
最近最新2019免费中文视频
|
久久精品播放
|
国产三级欧美三级日产三级99
|
国产专区一区
|
日韩欧美中文字幕在线观看
|
九九视频在线
|
久久精品一区
|
av看片|
国产精品国产a级
|
黄色网页在线看
|
免费a级毛片视频
|
国偷自产视频一区二区久
|