FFmpeg源码分析。
来源:互联网 发布:linux安装软件包命令 编辑:程序博客网 时间:2024/06/05 09:23
前言
ffmeg源码讲解的博客很多,可是完全讲解清楚原理的,觉得还不太多,这里就稍微分析一下,无论是编码器,和解码器,都是注册一下,然后在特定的流,对应特定的编解码器。具体我们借助官方的提供的ffpalyer,稍微分析下。
正文
首先是使用,这里超级简单
ffplayer.exe +"文件名"
这是最简单的方法,这里我们目光不是控制,仅仅大概了解ffpeg的流程,这里我们就不详细介绍。
下面我们开始代码阅读
int main(int argc, char **argv){ ......#if CONFIG_AVDEVICE avdevice_register_all();#endif#if CONFIG_AVFILTER avfilter_register_all();#endif av_register_all(); avformat_network_init(); ...... is = stream_open(input_filename, file_iformat); ...... event_loop(is); ......}
这里显示用的SDL,这是一个开源的可以用来渲染支持surface的一个多平台的玩意,代码量比较小,如果有机会可以研究下,不过这里暂时不再纠结这个问题,反正,得到的每一帧数据,都是用SDL来渲染的,知道这些就够了。我们关注我们的重点。
前边几个是条件编译,我做过详细阅读。这些其实不是关键,最核心的几个函数是
av_register_all(); //这是吧所有的编解码结构体给注册完成is = stream_open(input_filename, file_iformat);//开启四个线程,完成视频音频,和读取文件的工作event_loop(is); //更新页面相应键盘。
首先看下注册的函数
void av_register_all(void){ static AVOnce control = AV_ONCE_INIT; ff_thread_once(&control, register_all);}static void register_all(void){ avcodec_register_all(); /* (de)muxers */ REGISTER_MUXER (A64, a64); REGISTER_DEMUXER (AA, aa); REGISTER_DEMUXER (AAC, aac); REGISTER_MUXDEMUX(AC3, ac3); ......}void avcodec_register_all(void){ static AVOnce control = AV_ONCE_INIT; ff_thread_once(&control, register_all);}static void register_all(void){ /* hardware accelerators */ REGISTER_HWACCEL(H263_VAAPI, h263_vaapi); ...... REGISTER_ENCODER(A64MULTI5, a64multi5); REGISTER_DECODER(AASC, aasc); }
看到代码的第一反应,着都是干啥的呢,乌七八糟的,不过耐心看,其实这些整整齐齐的东西,会觉得很可爱。
#define REGISTER_MUXER(X, x) \ { \ extern AVOutputFormat ff_##x##_muxer; \ if (CONFIG_##X##_MUXER) \ av_register_output_format(&ff_##x##_muxer); \ }void av_register_output_format(AVOutputFormat *format){ AVOutputFormat **p = last_oformat; while(p != &format->next && !format->next && avpriv_atomic_ptr_cas((void * volatile *)p, NULL, format)) p = &(*p)->next; if (!format->next) last_oformat = &format->next;}
这些结构非常简单,也就是把extern AVOutputFormat ff_##x##_muxer;
这个变量给注册到一个叫做last_oformat
中。
其他都是同理,这些触发器,这里暂时不说,关键看下我们的编解码器。
#define REGISTER_DECODER(X, x) \ { \ extern AVCodec ff_##x##_decoder; \ if (CONFIG_##X##_DECODER) \ avcodec_register(&ff_##x##_decoder); \ }
其实这里很容易理解,还是注册到一个全局的链表,这里暂时不要纠结到底在哪里,不用纠结,可是这个变量到底是啥呢?我们试着找一找,毕竟假如这个是h264,我应该定义一个exterel的ff_h264_decoder
AVCodec ff_h264_decoder = { .name = "h264", .long_name = NULL_IF_CONFIG_SMALL("H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10"), .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_H264, .priv_data_size = sizeof(H264Context), .init = h264_decode_init, .close = h264_decode_end, .decode = h264_decode_frame, .capabilities = /*AV_CODEC_CAP_DRAW_HORIZ_BAND |*/ AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_FRAME_THREADS, .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_EXPORTS_CROPPING, .flush = flush_dpb, .init_thread_copy = ONLY_IF_THREADS_ENABLED(decode_init_thread_copy), .update_thread_context = ONLY_IF_THREADS_ENABLED(ff_h264_update_thread_context), .profiles = NULL_IF_CONFIG_SMALL(ff_h264_profiles), .priv_class = &h264_class,};
这里解码也是这个东东,总之,就是吧全局的解码器,集中到一个列表中,便于查找。
is = stream_open(input_filename, file_iformat)
这个是控制开启解码库,等等读取文件等操作,限于篇幅,暂时不做详细解析。
static void event_loop(VideoState *cur_stream){ SDL_Event event; double incr, pos, frac; for (;;) { double x; //这里一直刷新,用来更新通过stream_open函数打开的线程更新出来的视频帧。 refresh_loop_wait_event(cur_stream, &event); switch (event.type) { case SDL_KEYDOWN: ......//这里是处理键盘操作的。 } } }
这里代码逻辑比较复杂,就不追踪,有机会好好分析这里。
后记
这里其实没有过多的介绍,不过对于整个代码架构稍微有些了解,下一篇我们研究一些stream_open函数的具体做了啥。
- ffmpeg源码分析
- FFMPEG 源码分析
- FFMPEG 源码分析
- FFMPEG源码分析
- 最新版ffmpeg源码分析
- FFMPEG源码分析
- FFMPEG源码分析
- FFMPEG 源码分析
- FFMPEG 源码分析(-)
- ffmpeg源码分析
- ffmpeg源码分析三
- FFMPEG 源码分析(-)
- FFMPEG 源码分析
- ffmpeg源码分析
- FFMPEG源码分析
- FFMPEG 源码分析
- FFMPEG源码分析
- ffmpeg 源码分析
- 关于解决python文件中文注释报错问题
- js-subString与slice差异
- 信号量详解
- debug到手软的筛法,输出条件很重要。
- JAVA基础(一)------认识JAVA
- FFmpeg源码分析。
- 神奇的计算机画图学
- 关于(void**)&的理解
- Permission denied: user=administrator, access=WRITE, inode="/":root:supergroup:drwxr-xr-x
- populating-next-right-pointers-in-each-node-ii
- VIM基本命令
- 第9届北信校赛
- [生产力工具]Mysql入门
- 计算圆的面积