typedef struct URLProtocol { |
每个文件类似都有自己的一个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; |
int av_open_input_file(AVFormatContext **ic_ptr, const char *filename, AVInputFormat *fmt, int buf_size, AVFormatParameters *ap) { int url_fopen(ByteIOContext **s, const char *filename, int flags) { url_open(URLContext **puc, const char *filename, int flags) { 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对像 } } url_fdopen(ByteIOContext **s, URLContext *h) { //初始化ByteIOContext 对像 } } } |
libavformat/file.c文件的file协议:
static int file_open(URLContext *h, const char *filename, int flags) |
#define REGISTER_PROTOCOL(X,x) { \ |
void av_register_all(void) |
URLProtocol *first_protocol = NULL;
int av_register_protocol(URLProtocol *protocol)
{
URLProtocol **p;
p = &first_protocol;
while (*p != NULL) p = &(*p)->next;
*p = protocol;
protocol->next = NULL;
return 0;
}