相关文章推荐
该函数用于 初始化 一个视音频编解码器的AVCodecContext。
int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options);
各个参数的含义:
avctx:需要初始化的AVCodecContext。
codec:输入的AVCodec
options:一些选项。例如使用libx264编码的时候,“preset”,“tune”等都可以通过该参数设置。
函数调用关系图
avcodec_open2()
avcodec_open2()的源代码量是非常长的,但是它的调用关系非常简单—— 它只调用了一个关键的函数,即AVCodec的init(), 后文将会对这个函数进行分析。
我们可以简单梳理一下avcodec_open2()所做的工作,如下所列:
(1)为各种结构体分配内存(通过各种av_malloc()实现)。
(2)将输入的AVDictionary形式的选项设置到AVCodecContext。
(3)其他一些零零碎碎的检查,比如说检查编解码器是否处于“实验”阶段。
(4)如果是编码器,检查输入参数是否符合编码器的要求
(5)调用AVCodec的init() 初始化具体的解码器。
我们分析一下第4步和第5步。
检查输入参数是否符合编码器要求
在这里简单分析一下第4步,即“检查输入参数是否符合编码器的要求”。这一步中检查了很多的参数,在这里我们随便选一个参数pix_fmts(像素格式)看一下,如下所示。
  1. //检查像素格式
  2. if (avctx->codec->pix_fmts) {
  3. for (i = 0 ; avctx->codec->pix_fmts[i] != AV_PIX_FMT_NONE; i++)
  4. if (avctx->pix_fmt == avctx->codec->pix_fmts[i])
  5. break ;
  6. if (avctx->codec->pix_fmts[i] == AV_PIX_FMT_NONE
  7. && !((avctx->codec_id == AV_CODEC_ID_MJPEG || avctx->codec_id == AV_CODEC_ID_LJPEG)
  8. && avctx->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL)) {
  9. char buf[ 128 ];
  10. snprintf (buf, sizeof (buf), "%d" , avctx->pix_fmt);
  11. av_log(avctx, AV_LOG_ERROR, "Specified pixel format %s is invalid or not supported\n" ,
  12. ( char *)av_x_if_null(av_get_pix_fmt_name(avctx->pix_fmt), buf));
  13. ret = AVERROR(EINVAL);
  14. goto free_and_end;
  15. }
  16. if (avctx->codec->pix_fmts[i] == AV_PIX_FMT_YUVJ420P ||
  17. avctx->codec->pix_fmts[i] == AV_PIX_FMT_YUVJ411P ||
  18. avctx->codec->pix_fmts[i] == AV_PIX_FMT_YUVJ422P ||
  19. avctx->codec->pix_fmts[i] == AV_PIX_FMT_YUVJ440P ||
  20. avctx->codec->pix_fmts[i] == AV_PIX_FMT_YUVJ444P)
  21. avctx->color_range = AVCOL_RANGE_JPEG;
  22. }
可以看出,该代码首先进入了一个for()循环,将AVCodecContext中设定的pix_fmt与编码器AVCodec中的pix_fmts数组中的元素逐一比较。
先简单介绍一下AVCodec中的pix_fmts数组。AVCodec中的pix_fmts数组存储了该种编码器支持的像素格式,并且规定以AV_PIX_FMT_NONE(AV_PIX_FMT_NONE取值为-1)为结尾。例如,libx264的pix_fmts数组的定义位于libavcodec\libx264.c,如下所示。
  1. staticconstenum AVPixelFormat pix_fmts_8bit[] = {
  2. AV_PIX_FMT_YUV420P,
  3. AV_PIX_FMT_YUVJ420P,
  4. AV_PIX_FMT_YUV422P,
  5. AV_PIX_FMT_YUVJ422P,
  6. AV_PIX_FMT_YUV444P,
  7. AV_PIX_FMT_YUVJ444P,
  8. AV_PIX_FMT_NV12,
  9. AV_PIX_FMT_NV16,
  10. AV_PIX_FMT_NONE
  11. };
从pix_fmts_8bit的定义可以看出libx264主要支持的是以YUV为主的像素格式。
现在回到“检查输入pix_fmt是否符合编码器的要求”的那段代码。如果for()循环从AVCodec->pix_fmts数组中找到了符合AVCodecContext->pix_fmt的像素格式,或者完成了AVCodec->pix_fmts数组的遍历,都会跳出循环。如果发现AVCodec->pix_fmts数组中索引为i的元素是AV_PIX_FMT_NONE(即最后一个元素,取值为-1)的时候,就认为没有找到合适的像素格式,并且最终提示错误信息。
AVCodec->init()
avcodec_open2()中 最关键的一步 就是调用AVCodec的init()方法初始化具体的编码器。AVCodec的init()是一个 函数指针 ,指向具体编解码器中的初始化函数。这里我们以libx264为例,看一下它对应的AVCodec的定义。libx264对应的AVCodec的定义位于libavcodec\libx264.c,如下所示。
  1. AVCodec ff_libx264_encoder = {
  2. .name = "libx264" ,
  3. .long_name = NULL_IF_CONFIG_SMALL( "libx264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10" ),
  4. .type = AVMEDIA_TYPE_VIDEO,
  5. .id = AV_CODEC_ID_H264,
  6. .priv_data_size = sizeof (X264Context),
  7. .init = X264_init ,
  8. .encode2 = X264_frame,
  9. .close = X264_close,
  10. .capabilities = CODEC_CAP_DELAY | CODEC_CAP_AUTO_THREADS,
  11. .priv_class = &x264_class,
  12. .defaults = x264_defaults,
  13. .init_static_data = X264_init_static,
  14. };
可以看出在ff_libx264_encoder中init()指向X264_init()。X264_init()的定义同样位于libavcodec\libx264.c,
X264_init()的代码以后研究X264的时候再进行细节的分析,在这里简单记录一下它做的两项工作:
(1)设置X264Context的参数。X264Context主要完成了libx264和FFmpeg对接的功能。可以看出代码主要在设置一个params结构体变量,该变量的类型即是x264中存储参数的结构体x264_param_t。
(2)调用libx264的API进行编码器的初始化工作。例如调用x264_param_default()设置默认参数,调用x264_param_apply_profile()设置profile,调用x264_encoder_open()打开编码器等等。
X264Context的定义,位于libavcodec\libx264.c,
时间宝贵,只能复制+粘贴,若图片无法显示或排版混乱,请访问https://elesos.github.io查找原文
 
推荐文章