FFmpeg源代碼簡單分析:avio_open2()
來源:程序員人生 發(fā)布時間:2015-03-13 07:59:22 閱讀次數(shù):11194次
本文簡單分析FFmpeg中1個經(jīng)常使用的函數(shù)avio_open2()。該函數(shù)用于打開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()函數(shù)參數(shù)的含義以下:
s:函數(shù)調(diào)用成功以后創(chuàng)建的AVIOContext結(jié)構(gòu)體。
url:輸入輸出協(xié)議的地址(文件也是1種“廣義”的協(xié)議,對文件來講就是文件的路徑)。
flags:打開地址的方式。可以選擇只讀,只寫,或讀寫。取值以下。
AVIO_FLAG_READ:只讀。
AVIO_FLAG_WRITE:只寫。
AVIO_FLAG_READ_WRITE:讀寫。
int_cb:目前還沒有用過。
options:目前還沒有用過。
該函數(shù)最典型的例子可以參考:最簡單的基于FFMPEG的視頻編碼器(YUV編碼為H.264)
函數(shù)調(diào)用結(jié)構(gòu)圖
首先貼出來終究分析得出的函數(shù)調(diào)用結(jié)構(gòu)圖,以下所示。

單擊查看更清晰的圖片
avio_open()
有1個和avio_open2()“長得很像”的函數(shù)avio_open(),應(yīng)當(dāng)是avio_open2()的初期版本。avio_open()比avio_open2()少了最后2個參數(shù)。而它前面幾個參數(shù)的含義和avio_open2()是1樣的。從源代碼中可以看出,avio_open()內(nèi)部調(diào)用了avio_open2(),并且把avio_open2()的后2個參數(shù)設(shè)置成了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()的源代碼可以看出,它主要調(diào)用了2個函數(shù):ffurl_open()和ffio_fdopen()。其中ffurl_open()用于初始化URLContext,ffio_fdopen()用于根據(jù)URLContext初始化AVIOContext。URLContext中包括的URLProtocol完成了具體的協(xié)議讀寫等工作。AVIOContext則是在URLContext的讀寫函數(shù)外面加上了1層“包裝”(通過retry_transfer_wrapper()函數(shù))。
URLProtocol和URLContext
在查看ffurl_open()和ffio_fdopen()函數(shù)之前,首先查看1下URLContext和URLProtocol的定義。這兩個結(jié)構(gòu)體在FFmpeg的初期版本的SDK中是定義在頭文件中可以直接使用的。但是近期的FFmpeg的SDK中已找不到這兩個結(jié)構(gòu)體的定義了。FFmpeg把這兩個結(jié)構(gòu)體移動到了源代碼的內(nèi)部,變成了內(nèi)部結(jié)構(gòu)體。
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的定義可以看出,其中包括了用于協(xié)議讀寫的函數(shù)指針。例如:
url_open():打開協(xié)議。
url_read():讀數(shù)據(jù)。
url_write():寫數(shù)據(jù)。
url_close():關(guān)閉協(xié)議。
每種具體的協(xié)議都包括了1個URLProtocol結(jié)構(gòu)體,例如:
FILE協(xié)議(“文件”在FFmpeg中也被當(dāng)作1種協(xié)議)的結(jié)構(gòu)體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協(xié)議進行讀寫的時候,調(diào)用url_open()實際上就是調(diào)用了file_open()函數(shù),這里限于篇幅不再對file_open()的源代碼進行分析。file_open()函數(shù)實際上調(diào)用了系統(tǒng)的打開文件函數(shù)open()。同理,調(diào)用url_read()實際上就是調(diào)用了file_read()函數(shù);file_read()函數(shù)實際上調(diào)用了系統(tǒng)的讀取文件函數(shù)read()。url_write(),url_seek()等函數(shù)的道理都是1樣的。
LibRTMP協(xié)議的結(jié)構(gòu)體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協(xié)議的結(jié)構(gòu)體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結(jié)構(gòu)體。下面看1下URLContext結(jié)構(gòu)體。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結(jié)構(gòu)體是URLContext結(jié)構(gòu)體的1個成員。由于還沒有對URLContext結(jié)構(gòu)體進行詳細(xì)研究,有關(guān)該結(jié)構(gòu)體的代碼不再做過量分析。
ffurl_open()
前文提到AVIOContext中主要調(diào)用了2個函數(shù):ffurl_open()和ffio_fdopen()。其中ffurl_open()用于初始化URLContext,ffio_fdopen()用于根據(jù)URLContext初始化AVIOContext。下面首先看1下初始化URLContext的函數(shù)ffurl_open()。
ffurl_open()的函數(shù)定義位于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()主要調(diào)用了2個函數(shù):ffurl_alloc()和ffurl_connect()。ffurl_alloc()用于查找適合的URLProtocol,并創(chuàng)建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()主要調(diào)用了2個函數(shù):url_find_protocol()根據(jù)文件路徑查找適合的URLProtocol,url_alloc_for_protocol()為查找到的URLProtocol創(chuàng)建URLContext。
url_find_protocol()
先來看1下url_find_protocol()函數(shù),定義以下所示。
#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 = '
主站蜘蛛池模板:
亚洲爱爱图片
|
www.欧美com|
精品福利一区二区三区
|
free性欧美hd另类精品
|
国产亚洲精品一区二区
|
国产欧美亚洲专区第一页
|
欧美精品一区午夜小说
|
欧美一卡二卡3卡4卡无卡免费
|
精品国产看高清国产毛片
|
亚洲欧美成人永久第一网站
|
欧美国产成人一区二区三区
|
最近中文字幕大全高清视频
|
久久国产精品网
|
日韩福利网站
|
69av视频
|
精品久久久一二三区
|
亚洲资源最新版在线观看
|
天堂mv亚洲mv在线播放9蜜
|
国产免费久久精品99久久
|
波多野结衣在线一区二区
|
免费观看欧美一级牲片一
|
h视频免费高清在线观看
|
国产精品v欧美精品v日韩
|
日本一二线不卡在线观看
|
最近中文字幕高清字幕在线视频
|
亚洲免费视频观看
|
国产亚洲精品线观看77
|
色淫影院|
久久一区二区三区四区
|
一级在线观看视频
|
亚洲精品久久久久久下一站
|
午夜影院网站
|
在线观看视频免费播放
|
久久在线免费观看视频
|
欧美日韩性生活视频
|
久久久久久久久久久观看
|
91久久综合九色综合欧美98
|
poronovideos德国极品
|
国产成人久久精品推最新
|
秋霞日韩理论高清在线观看
|
高清欧美不卡一区二区三区
|