void av_register_all(void) { static int initialized; if (initialized) return; // 如果没有初始化过就直接返回 initialized = 1; avcodec_register_all(); // 注册复用和解复用器,这里其他格式注册的过程是一样的,省略 REGISTER_MUXDEMUX(MP3, mp3); // 注册协议,这里其他协议注册的过程是一样的,省略 REGISTER_PROTOCOL(RTP, rtp); }
原理:在ffmepg中主要通过链表来保存注册的所有的复用和解复用器,使用全局静态变量来保存这些链表的头指针,所以通过向链表中插入指定的节点来完成注册。
av_register_all()函数就是用这种方式完成了endoder和decoder,parser,muxer和demuxer以及protocol的注册。
void avcodec_register_all(void) { static int initialized; if (initialized) return; // 如果已经注册过了,直接返回 initialized = 1; /* hardware accelerators */ REGISTER_HWACCEL(H263_VAAPI, h263_vaapi); /*注册编解码器*/ REGISTER_DECODER(H264, h264); REGISTER_DECODER(LIBSTAGEFRIGHT_H264, libstagefright_h264); /*注册解析器*/ REGISTER_PARSER(H264, h264); }
#define REGISTER_DECODER(X, x) \ { \ extern AVCodec ff_##x##_decoder; \ if (CONFIG_##X##_DECODER) \ avcodec_register(&ff_##x##_decoder); \ } 相当于就是: extern AVCodec ff_h264_decoder; if(CONFIG_H264_DECODER) avcodec_register(&ff_h264_decoder);
刚开始分析不要陷入代码细节中,无法自拔!一句话,把当前的AVCodec加到链表的尾部。
void avcodec_register(AVCodec *codec) { AVCodec **p; avcodec_init(); p = last_avcodec; codec->next = NULL; while(*p || avpriv_atomic_ptr_cas((void * volatile *)p, NULL, codec)) p = &(*p)->next; last_avcodec = &codec->next; if (codec->init_static_data) codec->init_static_data(codec); }
#define REGISTER_PARSER(X, x) \ { \ extern AVCodecParser ff_##x##_parser; \ if (CONFIG_##X##_PARSER) \ av_register_codec_parser(&ff_##x##_parser); \ } extern AVCodecParser ff_h264_parser; if(CONFIG_H264_PARSER) av_register_codec_parser(&ff_h264_parser);
#define REGISTER_MUXDEMUX(X, x) REGISTER_MUXER(X, x); REGISTER_DEMUXER(X, x)
这个宏定义显然是用了两个宏定义。
#define REGISTER_MUXER(X, x) \ { \ extern AVOutputFormat ff_##x##_muxer; \ if (CONFIG_##X##_MUXER) \ av_register_output_format(&ff_##x##_muxer); \ }
#define REGISTER_DEMUXER(X, x) \ { \ extern AVInputFormat ff_##x##_demuxer; \ if (CONFIG_##X##_DEMUXER) \ av_register_input_format(&ff_##x##_demuxer); \ }
这段代码宏定义展开之后是: extern AVOutputFormat ff_mp3_muxer; if(CONFIG_MP3_MUXER) av_register_output_format(&ff_mp3_muxer); extern AVInputFormat ff_mp3_demuxer; if (CONFIG_MP3_DEMUXER) av_register_input_format(&ff_mp3_demuxer);
输入格式和输出格式都是用的链表来管理的,而这两个链表的头尾指针则用静态全局变量(文件内)来保存,如下:
/** head of registered input format linked list */ static AVInputFormat *first_iformat = NULL; /** head of registered output format linked list */ static AVOutputFormat *first_oformat = NULL; static AVInputFormat **last_iformat = &first_iformat; static AVOutputFormat **last_oformat = &first_oformat;
遍历链表把当前的AVInputFormat和AVOutputFormat加到链表的尾部。
void av_register_input_format(AVInputFormat *format) { AVInputFormat **p = last_iformat; format->next = NULL; while(*p || avpriv_atomic_ptr_cas((void * volatile *)p, NULL, format)) p = &(*p)->next; last_iformat = &format->next; } void av_register_output_format(AVOutputFormat *format) { AVOutputFormat **p = last_oformat; format->next = NULL; while(*p || avpriv_atomic_ptr_cas((void * volatile *)p, NULL, format)) p = &(*p)->next; last_oformat = &format->next; }
#define REGISTER_PROTOCOL(X, x) \ { \ extern URLProtocol ff_##x##_protocol; \ if (CONFIG_##X##_PROTOCOL) \ ffurl_register_protocol(&ff_##x##_protocol); \ }
这段代码就相当于: extern URLProtocol ff_rtp_protocol; \ if (CONFIG_RTP_PROTOCOL) \ ffurl_register_protocol(&ff_rtp_protocol);
同样的协议也是用的链表来保存的,由全局静态变量first_protocol指针。
static URLProtocol *first_protocol = NULL;
这样ffurl_register_protocol()函数就是把参数中的这个指针给插入到链表中去(完成注册)。
int ffurl_register_protocol(URLProtocol *protocol) { URLProtocol **p; p = &first_protocol; while (*p) p = &(*p)->next; *p = protocol; protocol->next = NULL; return 0; }
参考资料:
1 http://blog.csdn.net/leixiaohua1020/article/details/12677129
2 http://blog.csdn.net/leixiaohua1020/article/details/12677265