好了,先来看一下这三个struct的定义吧
typedef struct URLProtocol {
const char *name; //Rotocol名称
int (*url_open)(URLContext *h, const char *url, int flags); //open函数指针对象,以下类似
int (*url_read)(URLContext *h, unsigned char *buf, int size);
int (*url_write)(URLContext *h, unsigned char *buf, int size);
int64_t (*url_seek)(URLContext *h, int64_t pos, int whence);
int (*url_close)(URLContext *h);
struct URLProtocol *next; //指向下一个URLProtocol,具体说明见备注1
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);
} URLProtocol;
备注1:FFMpeg所有的Protol类型都用这个变量串成一个链表,表头为avio.c里的URLProtocol *first_protocol = NULL;
每个文件类似都有自己的一个URLProtocol静态对象,如libavformat/file.c里
URLProtocol file_protocol = {
"file",
file_open,
file_read,
file_write,
file_seek,
file_close,
.url_get_file_handle = file_get_handle,
};
再通过av_register_protocol()将他们链接成链表。在FFMpeg中所有的URLProtocol对像值都在编译时确定。
typedef struct URLContext {
#if LIBAVFORMAT_VERSION_MAJOR >= 53
const AVClass *av_class; ///< information for av_log(). Set by url_open().
#endif
struct URLProtocol *prot; //指向具体的I/0类型,在运行时通过文件URL确定,如是file类型时就是file_protocol
int flags;
int is_streamed; /**< true if streamed (no seek possible), default = false */
int max_packet_size; /**< if non zero, the stream is packetized with this max packet size */
void *priv_data; //指向具体的I/O句柄
char *filename; /**< specified URL */
} URLContext;
不同于URLProtocol对象值在编译时确定,URLContext对象值是在运行过程中根据输入的I/O类型动态确定的。这一动一静组合起到了C++的多态继承一样的作用。URLContext像是基类,为大家共同所有,而URLProtocol像是子类部分。
typedef struct {
unsigned char *buffer;
int buffer_size;
unsigned char *buf_ptr, *buf_end;
void *opaque;
int (*read_packet)(void *opaque, uint8_t *buf, int buf_size);
int (*write_packet)(void *opaque, uint8_t *buf, int buf_size);
int64_t (*seek)(void *opaque, int64_t offset, int whence);
int64_t pos; /**< position in the file of the current buffer */
int must_flush; /**< true if the next seek should flush */
int eof_reached; /**< true if eof reached */
int write_flag; /**< true if open for writing */
int is_streamed;
int max_packet_size;
unsigned long checksum;
unsigned char *checksum_ptr;
unsigned long (*update_checksum)(unsigned long checksum, const uint8_t *buf, unsigned int size);
int error; ///< contains the error code or 0 if no error happened
int (*read_pause)(void *opaque, int pause);
int64_t (*read_seek)(void *opaque, int stream_index,
int64_t timestamp, int flags);
} ByteIOContext;
ByteIOContext是URLContext和URLProtocol 一个扩展,也是FFMpeg提供给用户的接口,URLContext和URLProtocol对用户是透明,我们所有的操作是通过ByteIOContext现实。这几个struct的相关的关键函数有:
int av_open_input_file(AVFormatContext **ic_ptr, const char *filename,
AVInputFormat *fmt,
int buf_size,
AVFormatParameters *ap)
{
ByteIOContext pb1, *pb = &pb1;
int url_fopen(ByteIOContext **s, const char *filename, int flags)
{
url_open(URLContext **puc, const char *filename, int flags)//生成URLContext **puc
{
uc = av_malloc(sizeof(URLContext) + strlen(filename));
URLProtocol *up;
//根据filename确定up
url_open_protocol (URLContext **puc, struct URLProtocol *up, const char *filename, int flags)
{
//初始化URLContext对像,并通过 up->url_open()将I/O打开将I/O fd赋值给URLContext的priv_data对像
s = av_malloc(sizeof(UDPContext))//以UDP为例子
h->priv_data = s;
}
*puc = uc;
}
url_fdopen(ByteIOContext **s, URLContext *h)
{
//初始化ByteIOContext 对像
}
}
}
来源:http://blog.youkuaiyun.com/ym012/article/details/6536891
补充:
AVFormatContext、ByteIOContext以及URLContext.此三个结构决定了ffmpeg的构架.首先来看一下AVFormatContext.我就不贴结构的全部了,我们主要关注于这三者直接的联系以及这三者之间不可或缺的帮凶们.
AVFormatContext包含三个重要的结构:AVInputFormat、AVOutputFormat以及 ByteIOContext.前两者顾名思义:输入文件的格式(我们这里就是asf格式)、输出文件格式.那么ByteIOContext就是完成他们两者之间转换的桥梁.也就是说通过调用ByteIOContext结构中的回调函数,完成了我们拿到了数据包(不论是本地的还是流媒体).那么URLContext与ByteIOContext呢?同样,URLContext被包含在了ByteIOContext中,可是我们在ByteIOContext中并未见到对URLContext的包含啊?注意这里对ByteIOContext这个结构的初始化,函数是init_put_byte(),而ByteIOContext结构中的void*opaque指针指向的正是URLContext结构.而URLContext结构中的URLProtocol结构则指明了我们的流媒体采用的是什么样的协议.