ffmpeg源码简析(四)avcodec_find_encoder(),avcodec_open2(),avcodec_close()
来源:互联网 发布:linux路由器搭建局域网 编辑:程序博客网 时间:2024/05/17 12:46
avcodec_find_encoder()和avcodec_find_decoder()
avcodec_find_encoder()用于查找FFmpeg的编码器,avcodec_find_decoder()用于查找FFmpeg的解码器。
avcodec_find_encoder()的声明位于libavcodec\avcodec.h
avcodec_find_encoder()的源代码位于libavcodec\utils.c
AVCodec *avcodec_find_encoder(enum AVCodecID id) { return find_encdec(id, 1); }
find_encdec()
find_encdec()的源代码位于libavcodec\utils.c,如下所示。
static AVCodec *first_avcodec; static AVCodec *find_encdec(enum AVCodecID id, int encoder) { AVCodec *p, *experimental = NULL; p = first_avcodec; id= remap_deprecated_codec_id(id); while (p) { if ((encoder ? av_codec_is_encoder(p) : av_codec_is_decoder(p)) && p->id == id) { if (p->capabilities & CODEC_CAP_EXPERIMENTAL && !experimental) { experimental = p; } else return p; } p = p->next; } return experimental; }
find_encdec()中有一个循环,该循环会遍历AVCodec结构的链表,逐一比较输入的ID和每一个编码器的ID,直到找到ID取值相等的编码器。
在这里有几点需要注意:
(1)first_avcodec是一个全局变量,存储AVCodec链表的第一个元素。
(2)remap_deprecated_codec_id()用于将一些过时的编码器ID映射到新的编码器ID。
(3)函数的第二个参数encoder用于确定查找编码器还是解码器。当该值为1的时候,用于查找编码器,此时会调用av_codec_is_encoder()判断AVCodec是否为编码器;当该值为0的时候,用于查找解码器,此时会调用av_codec_is_decoder()判断AVCodec是否为解码器。
av_codec_is_encoder()
av_codec_is_encoder()是一个判断AVCodec是否为编码器的函数。如果是编码器,返回非0值,否则返回0。
int av_codec_is_encoder(const AVCodec *codec) { return codec && (codec->encode_sub || codec->encode2); }
从源代码可以看出,av_codec_is_encoder()判断了一下AVCodec是否包含了encode2()或者encode_sub()接口函数。
avcodec_open2()
该函数用于初始化一个视音频编解码器的AVCodecContext。avcodec_open2()的声明位于libavcodec\avcodec.h
int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options);
avctx:需要初始化的AVCodecContext。
codec:输入的AVCodec
options:一些选项。例如使用libx264编码的时候,“preset”,“tune”等都可以通过该参数设置。
avcodec_open2()
avcodec_open2()的定义位于libavcodec\utils.c
avcodec_open2()的源代码量是非常长的,但是它的调用关系非常简单——它只调用了一个关键的函数,即AVCodec的init(),后文将会对这个函数进行分析。
我们可以简单梳理一下avcodec_open2()所做的工作,如下所列:
(1)为各种结构体分配内存(通过各种av_malloc()实现)。(2)将输入的AVDictionary形式的选项设置到AVCodecContext。(3)其他一些零零碎碎的检查,比如说检查编解码器是否处于“实验”阶段。(4)如果是编码器,检查输入参数是否符合编码器的要求(5)调用AVCodec的init()初始化具体的解码器。
AVCodec->init()
avcodec_open2()中最关键的一步就是调用AVCodec的init()方法初始化具体的编码器。AVCodec的init()是一个函数指针,指向具体编解码器中的初始化函数。
avcodec_close()
该函数用于关闭编码器。avcodec_close()函数的声明位于libavcodec\avcodec.h
int avcodec_close(AVCodecContext *avctx);
avcodec_close()的定义位于libavcodec\utils.c,如下所示。
av_cold int avcodec_close(AVCodecContext *avctx) { if (!avctx) return 0; if (avcodec_is_open(avctx)) { FramePool *pool = avctx->internal->pool; int i; if (CONFIG_FRAME_THREAD_ENCODER && avctx->internal->frame_thread_encoder && avctx->thread_count > 1) { ff_frame_thread_encoder_free(avctx); } if (HAVE_THREADS && avctx->internal->thread_ctx) ff_thread_free(avctx); //关闭编解码器 if (avctx->codec && avctx->codec->close) avctx->codec->close(avctx); avctx->coded_frame = NULL; avctx->internal->byte_buffer_size = 0; av_freep(&avctx->internal->byte_buffer); av_frame_free(&avctx->internal->to_free); for (i = 0; i < FF_ARRAY_ELEMS(pool->pools); i++) av_buffer_pool_uninit(&pool->pools[i]); av_freep(&avctx->internal->pool); if (avctx->hwaccel && avctx->hwaccel->uninit) avctx->hwaccel->uninit(avctx); av_freep(&avctx->internal->hwaccel_priv_data); av_freep(&avctx->internal); } if (avctx->priv_data && avctx->codec && avctx->codec->priv_class) av_opt_free(avctx->priv_data); av_opt_free(avctx); av_freep(&avctx->priv_data); if (av_codec_is_encoder(avctx->codec)) av_freep(&avctx->extradata); avctx->codec = NULL; avctx->active_thread_type = 0; return 0; }
从avcodec_close()的定义可以看出,该函数释放AVCodecContext中有关的变量,并且调用了AVCodec的close()关闭了解码器。
AVCodec->close()
AVCodec的close()是一个函数指针,指向了特定编码器的关闭函数。在这里我们以libx264为例,看一下它对应的AVCodec的结构体的定义,如下所示。
AVCodec ff_libx264_encoder = { .name = "libx264", .long_name = NULL_IF_CONFIG_SMALL("libx264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10"), .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_H264, .priv_data_size = sizeof(X264Context), .init = X264_init, .encode2 = X264_frame, .close = X264_close, .capabilities = CODEC_CAP_DELAY | CODEC_CAP_AUTO_THREADS, .priv_class = &x264_class, .defaults = x264_defaults, .init_static_data = X264_init_static, };
从ff_libx264_encoder的定义可以看出:close()函数对应的是X264_close()函数。继续看一下X264_close()函数的定义,如下所示。
static av_cold int X264_close(AVCodecContext *avctx) { X264Context *x4 = avctx->priv_data; av_freep(&avctx->extradata); av_freep(&x4->sei); //关闭编码器 if (x4->enc) x264_encoder_close(x4->enc); av_frame_free(&avctx->coded_frame); return 0; }
从X264_close()的定义可以看出,该函数调用了libx264的x264_encoder_close()关闭了libx264编码器。
- ffmpeg源码简析(四)avcodec_find_encoder(),avcodec_open2(),avcodec_close()
- ffmpeg源码跟踪笔记之avcodec_open2
- ffmpeg学习六:avcodec_open2函数源码分析
- FFmpeg源代码简单分析:avcodec_close()
- FFmpeg源代码简单分析:avcodec_open2()
- FFmpeg源代码简单分析:avcodec_open2()
- ffmpeg avcodec_open2 内存泄漏问题
- ffmpeg的avcodec_open或avcodec_open2()的线程安全问题
- ffmpeg源码分析四:transcode_step函数 (转4)
- android 移植 ffmpeg (三) 测试用例(解决avcodec_find_encoder(AV_CODEC_ID_H264)返回为NULL的问题)
- ffmpeg源码简析(十二)FFMPEG中的主要结构体总结
- ffmpeg源码简析(一)结构总览
- ffmpeg源码简析(二)av_register_all(),avcodec_register_all()
- ffmpeg源码简析(六)编码-av_write_frame(),av_write_trailer()
- ffmpeg源码简析(七)解码-avformat_open_input,avformat_find_stream_info()
- ffmpeg源码简析(八)解码 av_read_frame(),avcodec_decode_video2(),avformat_close_input()
- ffmpeg源码简析(九)av_log(),AVClass,AVOption
- ffmpeg源码简析(十)libswscale中的SwsContext,sws_scale()
- Android ListView 简单使用
- Tersorflow深度学习入门—— CIFAR-10 训练示例报错及解决方案
- 利用 Create React Native App 快速创建 React Native 应用
- 《JQuery基础教程》第二章摘记
- centos系统安装openstack—dashboard安装和展示
- ffmpeg源码简析(四)avcodec_find_encoder(),avcodec_open2(),avcodec_close()
- 集合框架-键盘录入多个数据,以0结束,并在控制台输出最大值
- MyBatis学习 之 四、MyBatis配置文件
- springMVC 在controller中将参数封装成对象--日期格式处理问题
- java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setTe
- iOS中 性能优化之浅谈load与initialize 韩俊强的博客
- NSAssert(断言)
- ecplise当中配置maven
- [JZOJ5085]游戏/[JZOJ3996]下棋