目录
- 1. avcodec_open2
- 1.1 编解码器的预初始化(ff_encode_preinit & ff_decode_preinit)
- 1.2 编解码器的初始化(init)
- 1.3 释放编解码器(ff_codec_close)
FFmpeg相关记录:
示例工程:
【FFmpeg】调用ffmpeg库实现264软编
【FFmpeg】调用ffmpeg库实现264软解
【FFmpeg】调用ffmpeg库进行RTMP推流和拉流
【FFmpeg】调用ffmpeg库进行SDL2解码后渲染
流程分析:
【FFmpeg】编码链路上主要函数的简单分析
【FFmpeg】解码链路上主要函数的简单分析
结构体分析:
【FFmpeg】AVCodec结构体
【FFmpeg】AVCodecContext结构体
【FFmpeg】AVStream结构体
【FFmpeg】AVFormatContext结构体
【FFmpeg】AVIOContext结构体
【FFmpeg】AVPacket结构体
函数分析:
【通用】
【FFmpeg】avcodec_find_encoder和avcodec_find_decoder
【FFmpeg】关键结构体的初始化和释放(AVFormatContext、AVIOContext等)
【推流】
【FFmpeg】avformat_open_input函数
【FFmpeg】avformat_find_stream_info函数
【FFmpeg】avformat_alloc_output_context2函数
【FFmpeg】avio_open2函数
【FFmpeg】avformat_write_header函数
【FFmpeg】av_write_frame函数
avcodec_open2的函数调用关系为
1. avcodec_open2
/**
* Initialize the AVCodecContext to use the given AVCodec. Prior to using this
* function the context has to be allocated with avcodec_alloc_context3().
*
* The functions avcodec_find_decoder_by_name(), avcodec_find_encoder_by_name(),
* avcodec_find_decoder() and avcodec_find_encoder() provide an easy way for
* retrieving a codec.
*
* Depending on the codec, you might need to set options in the codec context
* also for decoding (e.g. width, height, or the pixel or audio sample format in
* the case the information is not available in the bitstream, as when decoding
* raw audio or video).
*
* Options in the codec context can be set either by setting them in the options
* AVDictionary, or by setting the values in the context itself, directly or by
* using the av_opt_set() API before calling this function.
*
* Example:
* @code
* av_dict_set(&opts, "b", "2.5M", 0);
* codec = avcodec_find_decoder(AV_CODEC_ID_H264);
* if (!codec)
* exit(1);
*
* context = avcodec_alloc_context3(codec);
*
* if (avcodec_open2(context, codec, opts) < 0)
* exit(1);
* @endcode
*
* In the case AVCodecParameters are available (e.g. when demuxing a stream
* using libavformat, and accessing the AVStream contained in the demuxer), the
* codec parameters can be copied to the codec context using
* avcodec_parameters_to_context(), as in the following example:
*
* @code
* AVStream *stream = ...;
* context = avcodec_alloc_context3(codec);
* if (avcodec_parameters_to_context(context, stream->codecpar) < 0)
* exit(1);
* if (avcodec_open2(context, codec, NULL) < 0)
* exit(1);
* @endcode
*
* @note Always call this function before using decoding routines (such as
* @ref avcodec_receive_frame()).
*
* @param avctx The context to initialize.
* @param codec The codec to open this context for. If a non-NULL codec has been
* previously passed to avcodec_alloc_context3() or
* for this context, then this parameter MUST be either NULL or
* equal to the previously passed codec.
* @param options A dictionary filled with AVCodecContext and codec-private
* options, which are set on top of the options already set in
* avctx, can be NULL. On return this object will be filled with
* options that were not found in the avctx codec context.
*
* @return zero on success, a negative value on error
* @see avcodec_alloc_context3(), avcodec_find_decoder(), avcodec_find_encoder(),
* av_dict_set(), av_opt_set(), av_opt_find(), avcodec_parameters_to_context()
*/
int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options);
函数的定义位于libavcodec\avcodec.c中,从注释上看,主要的功能是使用给定的AVCodec情况下,来初始化AVCodecContext。在使用此函数之前,必须使用avcodec_alloc_context3来分配上下文,可以在外面配置options,作为codec初始化的参数
int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options)
{
int ret = 0;
AVCodecInternal *avci;
const FFCodec *codec2;
// 1.输入检查
// 已经打开,直接返回
if (avcodec_is_open(avctx))
return 0;
// 一些错误信息打印
if (!codec && !avctx->codec) {
av_log(avctx, AV_LOG_ERROR, "No codec provided to avcodec_open2()\n");
return AVERROR(EINVAL);
}
if (codec && avctx->codec && codec != avctx->codec) {
av_log(avctx, AV_LOG_ERROR, "This AVCodecContext was allocated for %s, "
"but %s passed to avcodec_open2()\n", avctx->codec->name, codec->name);
return AVERROR(EINVAL);
}
if (!codec)
codec = avctx->codec;
codec2 = ffcodec(codec);
if ((avctx->codec_type != AVMEDIA_TYPE_UNKNOWN && avctx->codec_type != codec->type) ||
(avctx->codec_id != AV_CODEC_ID_NONE && avctx->codec_id != codec->id)) {
av_log(avctx, AV_LOG_ERROR, "Codec type or id mismatches\n");
return AVERROR(EINVAL);
}
avctx->codec_type = codec->type;
avctx->codec_id = codec->id;
avctx->codec = codec;
if (avctx->extradata_size < 0 || avctx->extradata_size >= FF_MAX_EXTRADATA_SIZE)
return AVERROR(EINVAL);
// 2.部分结构体内存分配
avci = av_codec_is_decoder(codec) ?
ff_decode_internal_alloc() :
ff_encode_internal_alloc();
if (!avci) {
ret = AVERROR(ENOMEM);
goto end;
}
avctx->internal = avci;
avci->buffer_frame = av_frame_alloc();
avci->buffer_pkt = av_packet_alloc();
if (!avci->buffer_frame || !avci->buffer_pkt) {
ret = AVERROR(ENOMEM);
goto free_and_end;
}
if (codec2->priv_data_size > 0) {
if (!avctx->priv_data) {
avctx->priv_data = av_mallocz(codec2->priv_data_size);
if (!avctx->priv_data) {
ret = AVERROR(ENOMEM);
goto free_and_end;
}
if (codec->priv_class) {
*(const AVClass **)avctx->priv_data = codec->priv_class;
av_opt_set_defaults(avctx->priv_data);
}
}
if (codec->priv_class && (ret = av_opt_set_dict(avctx->priv_data, options)) < 0)
goto free_and_end;
} else {
avctx->priv_data = NULL;
}
if ((ret = av_opt_set_dict(avctx, options)) < 0)
goto free_and_end;
// 3.一些琐碎的检查
// 白名单的检查
if (avctx->codec_whitelist && av_match_list(codec->name, avctx->codec_whitelist, ',') <= 0) {
av_log(avctx, AV_LOG_ERROR, "Codec (%s) not on whitelist \'%s\'\n", codec->name, avctx->codec_whitelist);
ret = AVERROR(EINVAL);
goto free_and_end;
}
// only call ff_set_dimensions() for non H.264/VP6F/DXV codecs so as not to overwrite previously setup dimensions
// 对于非H.264/VP6F/DXV编解码器,只调用ff_set_dimensions(),以免覆盖先前设置的尺寸
if (!(avctx->coded_width && avctx->coded_height && avctx->width && avctx->height &&
(avctx->codec_id == AV_CODEC_ID_H264 || avctx->codec_id == AV_CODEC_ID_VP6F || avctx->codec_id == AV_CODEC_ID_DXV))) {
if (avctx->coded_width && avctx->coded_height)
ret = ff_set_dimensions(avctx, avctx->coded_width, avctx->coded_height);
else if (avctx->width && avctx->height)
ret = ff_set_dimensions(avctx, avctx->width, avctx->height);
if (ret < 0)
goto free_and_end;
}
// 检查宽高
if ((avctx->coded_width || avctx->coded_height || avctx->width || avctx->height)
&& ( av_image_check_size2(avctx->coded_width, avctx->coded_height, avctx->max_pixels, AV_PIX_FMT_NONE, 0, avctx) < 0
|| av_image_check_size2(avctx->width, avctx->height, avctx->max_pixels, AV_PIX_FMT_NONE, 0, avctx) < 0)) {
av_log(avctx, AV_LOG_WARNING, "Ignoring invalid width/height values\n");
ff_set_dimensions(avctx, 0, 0);
}
// 检查宽高比
if (avctx->width > 0 && avctx->height > 0) {
if (av_image_check_sar(avctx->width, avctx->height,
avctx->sample_aspect_ratio) < 0) {
av_log(avctx, AV_LOG_WARNING, "ignoring invalid SAR: %u/%u\n",
avctx->sample_aspect_ratio.num,
avctx->sample_aspect_ratio.den);
avctx->sample_aspect_ratio = (AVRational){ 0, 1 };
}
}
// 检查采样率
if (avctx->sample_rate < 0) {
av_log(avctx, AV_LOG_ERROR, "Invalid sample rate: %d\n", avctx->sample_rate);
ret = AVERROR(EINVAL);
goto free_and_end;
}
if (avctx->block_align < 0) {
av_log(avctx, AV_LOG_ERROR, "Invalid block align: %d\n", avctx->block_align);
ret = AVERROR(EINVAL);
goto free_and_end;
}
/* AV_CODEC_CAP_CHANNEL_CONF is a decoder-only flag; so the code below
* in particular checks that nb_channels is set for all audio encoders. */
if (avctx->codec_type == AVMEDIA_TYPE_AUDIO && !avctx->ch_layout.nb_channels
&& !(codec->capabilities & AV_CODEC_CAP_CHANNEL_CONF)) {
av_log(avctx, AV_LOG_ERROR, "%s requires channel layout to be set\n",
av_codec_is_decoder(codec) ? "Decoder" : "Encoder");
ret = AVERROR(EINVAL);
goto free_and_end;
}
// 检查音频的声道数
if (avctx->ch_layout.nb_channels && !av_channel_layout_check(&avctx->ch_layout)) {
av_log(avctx, AV_LOG_ERROR, "Invalid channel layout\n");
ret = AVERROR(EINVAL);
goto free_and_end;
}
if (avctx->ch_layout.nb_channels > FF_SANE_NB_CHANNELS) {
av_log(avctx, AV_LOG_ERROR, "Too many channels: %d\n", avctx->ch_layout.nb_channels);
ret = AVERROR(EINVAL);
goto free_and_end;
}
avctx->frame_num = 0;
avctx->codec_descriptor = avcodec_descriptor_get(avctx->codec_id);
// 如果codec的能力包括了experimental
if ((avctx->codec->capabilities & AV_CODEC_CAP_EXPERIMENTAL) &&
avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) {
const char *codec_string = av_codec_is_encoder(codec) ? "encoder" : "decoder";
const AVCodec *codec2;
av_log(avctx, AV_LOG_ERROR,
"The %s '%s' is experimental but experimental codecs are not enabled, "
"add '-strict %d' if you want to use it.\n",
codec_string, codec->name, FF_COMPLIANCE_EXPERIMENTAL);
codec2 = av_codec_is_encoder(codec) ? avcodec_find_encoder(codec->id) : avcodec_find_decoder(codec->id);
if (!(codec2->capabilities & AV_CODEC_CAP_EXPERIMENTAL))
av_log(avctx, AV_LOG_ERROR, "Alternatively use the non experimental %s '%s'.\n",
codec_string, codec2->name);
ret = AVERROR_EXPERIMENTAL;
goto free_and_end;
}
if (avctx->codec_type == AVMEDIA_TYPE_AUDIO &&
(!avctx->time_base.num || !avctx->time_base.den)) {
avctx->time_base.num = 1;
avctx->time_base.den = avctx->sample_rate;
}
// 4.编解码器的预初始化
if (av_codec_is_encoder(avctx->codec))
ret = ff_encode_preinit(avctx);
else
ret = ff_decode_preinit(avctx);
if (ret < 0)
goto free_and_end;
if (HAVE_THREADS && !avci->frame_thread_encoder) {
/* Frame-threaded decoders call FFCodec.init for their child contexts. */
lock_avcodec(codec2);
ret = ff_thread_init(avctx);
unlock_avcodec(codec2);
if (ret < 0) {
goto free_and_end;
}
}
if (!HAVE_THREADS && !(codec2->caps_internal & FF_CODEC_CAP_AUTO_THREADS))
avctx->thread_count = 1;
if (!(avctx->active_thread_type & FF_THREAD_FRAME) ||
avci->frame_thread_encoder) {
if (codec2->init) {
lock_avcodec(codec2);
// 5.编解码器的初始化
ret = codec2->init(avctx);
unlock_avcodec(codec2);
if (ret < 0) {
avci->needs_close = codec2->caps_internal & FF_CODEC_CAP_INIT_CLEANUP;
goto free_and_end;
}
}
avci->needs_close = 1;
}
ret=0;
// 如果是解码器
if (av_codec_is_decoder(avctx->codec)) {
if (!avctx->bit_rate)
avctx->bit_rate = get_bit_rate(avctx);
/* validate channel layout from the decoder */
// 从解码器验证声道布局
if ((avctx->ch_layout.nb_channels && !av_channel_layout_check(&avctx->ch_layout)) ||
avctx->ch_layout.nb_channels > FF_SANE_NB_CHANNELS) {
ret = AVERROR(EINVAL);
goto free_and_end;
}
if (avctx->bits_per_coded_sample < 0) {
ret = AVERROR(EINVAL);
goto free_and_end;
}
}
if (codec->priv_class)
av_assert0(*(const AVClass **)avctx->priv_data == codec->priv_class);
end:
return ret;
free_and_end:
// 6.创建失败则释放codec
ff_codec_close(avctx);
goto end;
}
从代码中看,函数主要的流程分为几个步骤:
(1)一些检查,例如codec是否给入,检查codec type等等
(2)部分结构体内存的分配
(3)一些琐碎的检查
(4)编解码器的预初始化(ff_encode_preinit和ff_decode_preinit)
(5)编解码器的初始化(codec2->init)
(6)创建失败则释放codec(ff_codec_close)
1.1 编解码器的预初始化(ff_encode_preinit & ff_decode_preinit)
两个预初始化函数都定义在libavcodec\encode.c中
(1)编码器的预初始化(ff_encode_preinit)
/*
* Perform encoder initialization and validation.
* Called when opening the encoder, before the FFCodec.init() call.
*/
// 执行编码器初始化和验证
// 在打开编码器时调用,在FFCodec.init()调用之前
int ff_encode_preinit(AVCodecContext *avctx)
{
AVCodecInternal *avci = avctx->internal;
EncodeContext *ec = encode_ctx(avci);
int ret = 0;
// 检查编码器的时间基
if (avctx->time_base.num <= 0 || avctx->time_base.den <= 0) {
av_log(avctx, AV_LOG_ERROR, "The encoder timebase is not set.\n");
return AVERROR(EINVAL);
}
if (avctx->flags & AV_CODEC_FLAG_COPY_OPAQUE &&
!(avctx->codec->capabilities & AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE)) {
av_log(avctx, AV_LOG_ERROR, "The copy_opaque flag is set, but the "
"encoder does not support it.\n");
return AVERROR(EINVAL);
}
switch (avctx->codec_type) {
case AVMEDIA_TYPE_VIDEO: ret = encode_preinit_video(avctx); break; // 视频预初始化
case AVMEDIA_TYPE_AUDIO: ret = encode_preinit_audio(avctx); break;
}
if (ret < 0)
return ret;
// 检查码率是否太小
if ( (avctx->codec_type == AVMEDIA_TYPE_VIDEO || avctx->codec_type == AVMEDIA_TYPE_AUDIO)
&& avctx->bit_rate>0 && avctx->bit_rate<1000) {
av_log(avctx, AV_LOG_WARNING, "Bitrate %"PRId64" is extremely low, maybe you mean %"PRId64"k\n", avctx->bit_rate, avctx->bit_rate);
}
if (!avctx->rc_initial_buffer_occupancy)
avctx->rc_initial_buffer_occupancy = avctx->rc_buffer_size * 3LL / 4;
// AV_CODEC_PROP_INTRA_ONLY表示只进行帧内压缩,仅用于video和audio
if (avctx->codec_descriptor->props & AV_CODEC_PROP_INTRA_ONLY)
ec->intra_only_flag = AV_PKT_FLAG_KEY;
// FF_CODEC_CB_TYPE_ENCODER表示编解码器是使用encode回调的编码器;仅限音频和视频编解码器
if (ffcodec(avctx->codec)->cb_type == FF_CODEC_CB_TYPE_ENCODE) {
avci->in_frame = av_frame_alloc();
if (!avci->in_frame)
return AVERROR(ENOMEM);
}
// AV_CODEC_FLAG_RECON_FRAME表示请求编码器输出重构的帧
if ((avctx->flags & AV_CODEC_FLAG_RECON_FRAME)) {
if (!(avctx->codec->capabilities & AV_CODEC_CAP_ENCODER_RECON_FRAME)) {
av_log(avctx, AV_LOG_ERROR, "Reconstructed frame output requested "
"from an encoder not supporting it\n");
return AVERROR(ENOSYS);
}
avci->recon_frame = av_frame_alloc();
if (!avci->recon_frame)
return AVERROR(ENOMEM);
}
if (CONFIG_FRAME_THREAD_ENCODER) {
ret = ff_frame_thread_encoder_init(avctx);
if (ret < 0)
return ret;
}
return 0;
}
上面的代码中,主要是进行一些检查和配置,如时间基,码率,编码flag等,还会调用encode_preinit_video进行编码信息的预初始化,如下所示,主要进行了pix fmt的检查和color_range的设置
static int encode_preinit_video(AVCodecContext *avctx)
{
const AVCodec *c = avctx->codec;
const AVPixFmtDescriptor *pixdesc = av_pix_fmt_desc_get(avctx->pix_fmt);
int i;
if (!av_get_pix_fmt_name(avctx->pix_fmt)) {
av_log(avctx, AV_LOG_ERROR, "Invalid video pixel format: %d\n",
avctx->pix_fmt);
return AVERROR(EINVAL);
}
// 检查编码格式
if (c->pix_fmts) {
for (i = 0; c->pix_fmts[i] != AV_PIX_FMT_NONE; i++)
if (avctx->pix_fmt == c->pix_fmts[i])
break;
if (c->pix_fmts[i] == AV_PIX_FMT_NONE) {
// 编码格式为NONE
av_log(avctx, AV_LOG_ERROR,
"Specified pixel format %s is not supported by the %s encoder.\n",
av_get_pix_fmt_name(avctx->pix_fmt), c->name);
// 输出支持的format
av_log(avctx, AV_LOG_ERROR, "Supported pixel formats:\n");
for (int p = 0; c->pix_fmts[p] != AV_PIX_FMT_NONE; p++) {
av_log(avctx, AV_LOG_ERROR, " %s\n",
av_get_pix_fmt_name(c->pix_fmts[p]));
}
return AVERROR(EINVAL);
}
// 设置color_range
if (c->pix_fmts[i] == AV_PIX_FMT_YUVJ420P ||
c->pix_fmts[i] == AV_PIX_FMT_YUVJ411P ||
c->pix_fmts[i] == AV_PIX_FMT_YUVJ422P ||
c->pix_fmts[i] == AV_PIX_FMT_YUVJ440P ||
c->pix_fmts[i] == AV_PIX_FMT_YUVJ444P)
avctx->color_range = AVCOL_RANGE_JPEG;
}
// bit depth的检查
if ( avctx->bits_per_raw_sample < 0
|| (avctx->bits_per_raw_sample > 8 && pixdesc->comp[0].depth <= 8)) {
av_log(avctx, AV_LOG_WARNING, "Specified bit depth %d not possible with the specified pixel formats depth %d\n",
avctx->bits_per_raw_sample, pixdesc->comp[0].depth);
avctx->bits_per_raw_sample = pixdesc->comp[0].depth;
}
if (avctx->width <= 0 || avctx->height <= 0) {
av_log(avctx, AV_LOG_ERROR, "dimensions not set\n");
return AVERROR(EINVAL);
}
#if FF_API_TICKS_PER_FRAME
FF_DISABLE_DEPRECATION_WARNINGS
if (avctx->ticks_per_frame && avctx->time_base.num &&
avctx->ticks_per_frame > INT_MAX / avctx->time_base.num) {
av_log(avctx, AV_LOG_ERROR,
"ticks_per_frame %d too large for the timebase %d/%d.",
avctx->ticks_per_frame,
avctx->time_base.num,
avctx->time_base.den);
return AVERROR(EINVAL);
}
FF_ENABLE_DEPRECATION_WARNINGS
#endif
if (avctx->hw_frames_ctx) {
AVHWFramesContext *frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data;
if (frames_ctx->format != avctx->pix_fmt) {
av_log(avctx, AV_LOG_ERROR,
"Mismatching AVCodecContext.pix_fmt and AVHWFramesContext.format\n");
return AVERROR(EINVAL);
}
// 软编格式的检查
if (avctx->sw_pix_fmt != AV_PIX_FMT_NONE &&
avctx->sw_pix_fmt != frames_ctx->sw_format) {
av_log(avctx, AV_LOG_ERROR,
"Mismatching AVCodecContext.sw_pix_fmt (%s) "
"and AVHWFramesContext.sw_format (%s)\n",
av_get_pix_fmt_name(avctx->sw_pix_fmt),
av_get_pix_fmt_name(frames_ctx->sw_format));
return AVERROR(EINVAL);
}
avctx->sw_pix_fmt = frames_ctx->sw_format;
}
return 0;
}
(2)解码器的预初始化(ff_decode_preinit)
int ff_decode_preinit(AVCodecContext *avctx)
{
AVCodecInternal *avci = avctx->internal;
DecodeContext *dc = decode_ctx(avci);
int ret = 0;
/* if the decoder init function was already called previously,
* free the already allocated subtitle_header before overwriting it */
// 如果先前已经调用了解码器init函数,则在覆盖之前释放已经分配的subtitle_header
av_freep(&avctx->subtitle_header);
// lowres的检查
if (avctx->codec->max_lowres < avctx->lowres || avctx->lowres < 0) {
av_log(avctx, AV_LOG_WARNING, "The maximum value for lowres supported by the decoder is %d\n",
avctx->codec->max_lowres);
avctx->lowres = avctx->codec->max_lowres;
}
// sub_charenc表示输入字幕文件的字符编码
if (avctx->sub_charenc) {
if (avctx->codec_type != AVMEDIA_TYPE_SUBTITLE) {
av_log(avctx, AV_LOG_ERROR, "Character encoding is only "
"supported with subtitles codecs\n");
return AVERROR(EINVAL);
} else if (avctx->codec_descriptor->props & AV_CODEC_PROP_BITMAP_SUB) {
av_log(avctx, AV_LOG_WARNING, "Codec '%s' is bitmap-based, "
"subtitles character encoding will be ignored\n",
avctx->codec_descriptor->name);
avctx->sub_charenc_mode = FF_SUB_CHARENC_MODE_DO_NOTHING;
} else {
/* input character encoding is set for a text based subtitle
* codec at this point */
if (avctx->sub_charenc_mode == FF_SUB_CHARENC_MODE_AUTOMATIC)
avctx->sub_charenc_mode = FF_SUB_CHARENC_MODE_PRE_DECODER;
if (avctx->sub_charenc_mode == FF_SUB_CHARENC_MODE_PRE_DECODER) {
#if CONFIG_ICONV
iconv_t cd = iconv_open("UTF-8", avctx->sub_charenc);
if (cd == (iconv_t)-1) {
ret = AVERROR(errno);
av_log(avctx, AV_LOG_ERROR, "Unable to open iconv context "
"with input character encoding \"%s\"\n", avctx->sub_charenc);
return ret;
}
iconv_close(cd);
#else
av_log(avctx, AV_LOG_ERROR, "Character encoding subtitles "
"conversion needs a libavcodec built with iconv support "
"for this codec\n");
return AVERROR(ENOSYS);
#endif
}
}
}
dc->pts_correction_num_faulty_pts =
dc->pts_correction_num_faulty_dts = 0;
dc->pts_correction_last_pts =
dc->pts_correction_last_dts = INT64_MIN;
if ( !CONFIG_GRAY && avctx->flags & AV_CODEC_FLAG_GRAY
&& avctx->codec_descriptor->type == AVMEDIA_TYPE_VIDEO)
av_log(avctx, AV_LOG_WARNING,
"gray decoding requested but not enabled at configuration time\n");
if (avctx->flags2 & AV_CODEC_FLAG2_EXPORT_MVS) {
avctx->export_side_data |= AV_CODEC_EXPORT_DATA_MVS;
}
if (avctx->nb_side_data_prefer_packet == 1 &&
avctx->side_data_prefer_packet[0] == -1)
dc->side_data_pref_mask = ~0ULL;
else {
// 检查side data
for (unsigned i = 0; i < avctx->nb_side_data_prefer_packet; i++) {
int val = avctx->side_data_prefer_packet[i];
if (val < 0 || val >= AV_PKT_DATA_NB) {
av_log(avctx, AV_LOG_ERROR, "Invalid side data type: %d\n", val);
return AVERROR(EINVAL);
}
for (unsigned j = 0; j < FF_ARRAY_ELEMS(sd_global_map); j++) {
if (sd_global_map[j].packet == val) {
val = sd_global_map[j].frame;
// this code will need to be changed when we have more than
// 64 frame side data types
if (val >= 64) {
av_log(avctx, AV_LOG_ERROR, "Side data type too big\n");
return AVERROR_BUG;
}
dc->side_data_pref_mask |= 1ULL << val;
}
}
}
}
// 分配pkt的内存
avci->in_pkt = av_packet_alloc();
avci->last_pkt_props = av_packet_alloc();
if (!avci->in_pkt || !avci->last_pkt_props)
return AVERROR(ENOMEM);
// 解码的bitstream filter初始化
ret = decode_bsfs_init(avctx);
if (ret < 0)
return ret;
#if FF_API_DROPCHANGED
if (avctx->flags & AV_CODEC_FLAG_DROPCHANGED)
av_log(avctx, AV_LOG_WARNING, "The dropchanged flag is deprecated.\n");
#endif
return 0;
}
1.2 编解码器的初始化(init)
在进行了前面的参数检查和配置之后,需要进行编解码器的初始化,这是依据具体编解码器进行的,参考雷博的文章,记录一下libx264的初始化过程,参考下面的代码,初始化使用的是X264_init()函数
FFCodec ff_libx264_encoder = {
.p.name = "libx264",
CODEC_LONG_NAME("libx264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10"),
.p.type = AVMEDIA_TYPE_VIDEO,
.p.id = AV_CODEC_ID_H264,
.p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY |
AV_CODEC_CAP_OTHER_THREADS |
AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE |
AV_CODEC_CAP_ENCODER_FLUSH |
AV_CODEC_CAP_ENCODER_RECON_FRAME,
.p.priv_class = &x264_class,
.p.wrapper_name = "libx264",
.priv_data_size = sizeof(X264Context),
.init = X264_init,
FF_CODEC_ENCODE_CB(X264_frame),
.flush = X264_flush,
.close = X264_close,
.defaults = x264_defaults,
#if X264_BUILD < 153
.init_static_data = X264_init_static,
#else
.p.pix_fmts = pix_fmts_all,
#endif
.caps_internal = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_AUTO_THREADS
#if X264_BUILD < 158
| FF_CODEC_CAP_NOT_INIT_THREADSAFE
#endif
,
};
X264_init函数的定义位于libavcodec\libx264.c中,进行x264编码器的初始化,下面配置参数都是x264当中一些参数,包括帧间预测、码控、编码profile、编码level等等一些信息的初始化
static av_cold int X264_init(AVCodecContext *avctx)
{
X264Context *x4 = avctx->priv_data;
AVCPBProperties *cpb_props;
int sw,sh;
int ret;
if (avctx->global_quality > 0)
av_log(avctx, AV_LOG_WARNING, "-qscale is ignored, -crf is recommended.\n");
#if CONFIG_LIBX262_ENCODER
if (avctx->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
x4->params.b_mpeg2 = 1;
x264_param_default_mpeg2(&x4->params);
} else
#endif
// 配置默认的参数,x4从actx->priv_data中来
x264_param_default(&x4->params);
// 是否进行环路滤波
x4->params.b_deblocking_filter = avctx->flags & AV_CODEC_FLAG_LOOP_FILTER;
// 检查是否配置了preset档位或者是tune优化
if (x4->preset || x4->tune)
if (x264_param_default_preset(&x4->params, x4->preset, x4->tune) < 0) {
int i;
av_log(avctx, AV_LOG_ERROR, "Error setting preset/tune %s/%s.\n", x4->preset, x4->tune);
av_log(avctx, AV_LOG_INFO, "Possible presets:");
for (i = 0; x264_preset_names[i]; i++)
av_log(avctx, AV_LOG_INFO, " %s", x264_preset_names[i]);
av_log(avctx, AV_LOG_INFO, "\n");
av_log(avctx, AV_LOG_INFO, "Possible tunes:");
for (i = 0; x264_tune_names[i]; i++)
av_log(avctx, AV_LOG_INFO, " %s", x264_tune_names[i]);
av_log(avctx, AV_LOG_INFO, "\n");
return AVERROR(EINVAL);
}
if (avctx->level > 0)
x4->params.i_level_idc = avctx->level;
// log信息配置
x4->params.pf_log = X264_log;
x4->params.p_log_private = avctx;
x4->params.i_log_level = X264_LOG_DEBUG;
x4->params.i_csp = convert_pix_fmt(avctx->pix_fmt);
#if X264_BUILD >= 153
x4->params.i_bitdepth = av_pix_fmt_desc_get(avctx->pix_fmt)->comp[0].depth;
#endif
PARSE_X264_OPT("weightp", wpredp);
// 码控参数配置
if (avctx->bit_rate) {
if (avctx->bit_rate / 1000 > INT_MAX || avctx->rc_max_rate / 1000 > INT_MAX) {
av_log(avctx, AV_LOG_ERROR, "bit_rate and rc_max_rate > %d000 not supported by libx264\n", INT_MAX);
return AVERROR(EINVAL);
}
x4->params.rc.i_bitrate = avctx->bit_rate / 1000;
x4->params.rc.i_rc_method = X264_RC_ABR;
}
x4->params.rc.i_vbv_buffer_size = avctx->rc_buffer_size / 1000;
x4->params.rc.i_vbv_max_bitrate = avctx->rc_max_rate / 1000;
x4->params.rc.b_stat_write = avctx->flags & AV_CODEC_FLAG_PASS1;
if (avctx->flags & AV_CODEC_FLAG_PASS2) {
x4->params.rc.b_stat_read = 1;
} else {
if (x4->crf >= 0) {
x4->params.rc.i_rc_method = X264_RC_CRF;
x4->params.rc.f_rf_constant = x4->crf;
} else if (x4->cqp >= 0) {
x4->params.rc.i_rc_method = X264_RC_CQP;
x4->params.rc.i_qp_constant = x4->cqp;
}
if (x4->crf_max >= 0)
x4->params.rc.f_rf_constant_max = x4->crf_max;
}
if (avctx->rc_buffer_size && avctx->rc_initial_buffer_occupancy > 0 &&
(avctx->rc_initial_buffer_occupancy <= avctx->rc_buffer_size)) {
x4->params.rc.f_vbv_buffer_init =
(float)avctx->rc_initial_buffer_occupancy / avctx->rc_buffer_size;
}
PARSE_X264_OPT("level", level);
if (avctx->i_quant_factor > 0)
x4->params.rc.f_ip_factor = 1 / fabs(avctx->i_quant_factor);
if (avctx->b_quant_factor > 0)
x4->params.rc.f_pb_factor = avctx->b_quant_factor;
if (x4->chroma_offset)
x4->params.analyse.i_chroma_qp_offset = x4->chroma_offset;
if (avctx->gop_size >= 0)
x4->params.i_keyint_max = avctx->gop_size;
if (avctx->max_b_frames >= 0)
x4->params.i_bframe = avctx->max_b_frames;
if (x4->scenechange_threshold >= 0)
x4->params.i_scenecut_threshold = x4->scenechange_threshold;
// 编码质量参数
if (avctx->qmin >= 0)
x4->params.rc.i_qp_min = avctx->qmin;
if (avctx->qmax >= 0)
x4->params.rc.i_qp_max = avctx->qmax;
if (avctx->max_qdiff >= 0)
x4->params.rc.i_qp_step = avctx->max_qdiff;
if (avctx->qblur >= 0)
x4->params.rc.f_qblur = avctx->qblur; /* temporally blur quants */
if (avctx->qcompress >= 0)
x4->params.rc.f_qcompress = avctx->qcompress; /* 0.0 => cbr, 1.0 => constant qp */
if (avctx->refs >= 0)
x4->params.i_frame_reference = avctx->refs;
else if (x4->params.i_level_idc > 0) {
int i;
int mbn = AV_CEIL_RSHIFT(avctx->width, 4) * AV_CEIL_RSHIFT(avctx->height, 4);
int scale = X264_BUILD < 129 ? 384 : 1;
for (i = 0; i<x264_levels[i].level_idc; i++)
if (x264_levels[i].level_idc == x4->params.i_level_idc)
x4->params.i_frame_reference = av_clip(x264_levels[i].dpb / mbn / scale, 1, x4->params.i_frame_reference);
}
// 运动搜索参数配置
if (avctx->trellis >= 0)
x4->params.analyse.i_trellis = avctx->trellis;
if (avctx->me_range >= 0)
x4->params.analyse.i_me_range = avctx->me_range;
if (x4->noise_reduction >= 0)
x4->params.analyse.i_noise_reduction = x4->noise_reduction;
if (avctx->me_subpel_quality >= 0)
x4->params.analyse.i_subpel_refine = avctx->me_subpel_quality;
if (avctx->keyint_min >= 0)
x4->params.i_keyint_min = avctx->keyint_min;
if (avctx->me_cmp >= 0)
x4->params.analyse.b_chroma_me = avctx->me_cmp & FF_CMP_CHROMA;
if (x4->aq_mode >= 0)
x4->params.rc.i_aq_mode = x4->aq_mode;
if (x4->aq_strength >= 0)
x4->params.rc.f_aq_strength = x4->aq_strength;
PARSE_X264_OPT("psy-rd", psy_rd);
PARSE_X264_OPT("deblock", deblock);
PARSE_X264_OPT("partitions", partitions);
PARSE_X264_OPT("stats", stats);
if (x4->psy >= 0)
x4->params.analyse.b_psy = x4->psy;
if (x4->rc_lookahead >= 0)
x4->params.rc.i_lookahead = x4->rc_lookahead;
if (x4->weightp >= 0)
x4->params.analyse.i_weighted_pred = x4->weightp;
if (x4->weightb >= 0)
x4->params.analyse.b_weighted_bipred = x4->weightb;
if (x4->cplxblur >= 0)
x4->params.rc.f_complexity_blur = x4->cplxblur;
if (x4->ssim >= 0)
x4->params.analyse.b_ssim = x4->ssim;
if (x4->intra_refresh >= 0)
x4->params.b_intra_refresh = x4->intra_refresh;
if (x4->bluray_compat >= 0) {
x4->params.b_bluray_compat = x4->bluray_compat;
x4->params.b_vfr_input = 0;
}
if (x4->avcintra_class >= 0)
#if X264_BUILD >= 142
x4->params.i_avcintra_class = x4->avcintra_class;
#else
av_log(avctx, AV_LOG_ERROR,
"x264 too old for AVC Intra, at least version 142 needed\n");
#endif
if (x4->avcintra_class > 200) {
#if X264_BUILD < 164
av_log(avctx, AV_LOG_ERROR,
"x264 too old for AVC Intra 300/480, at least version 164 needed\n");
return AVERROR(EINVAL);
#else
/* AVC-Intra 300/480 only supported by Sony XAVC flavor */
x4->params.i_avcintra_flavor = X264_AVCINTRA_FLAVOR_SONY;
#endif
}
// 帧结构
if (x4->b_bias != INT_MIN)
x4->params.i_bframe_bias = x4->b_bias;
if (x4->b_pyramid >= 0)
x4->params.i_bframe_pyramid = x4->b_pyramid;
if (x4->mixed_refs >= 0)
x4->params.analyse.b_mixed_references = x4->mixed_refs;
// dct变换
if (x4->dct8x8 >= 0)
x4->params.analyse.b_transform_8x8 = x4->dct8x8;
if (x4->fast_pskip >= 0)
x4->params.analyse.b_fast_pskip = x4->fast_pskip;
if (x4->aud >= 0)
x4->params.b_aud = x4->aud;
// 是否启用mbtree
if (x4->mbtree >= 0)
x4->params.rc.b_mb_tree = x4->mbtree;
if (x4->direct_pred >= 0)
x4->params.analyse.i_direct_mv_pred = x4->direct_pred;
if (x4->slice_max_size >= 0)
x4->params.i_slice_max_size = x4->slice_max_size;
if (x4->fastfirstpass)
x264_param_apply_fastfirstpass(&x4->params);
x4->profile = x4->profile_opt;
/* Allow specifying the x264 profile through AVCodecContext. */
// 检查profile
if (!x4->profile)
switch (avctx->profile) {
case AV_PROFILE_H264_BASELINE:
x4->profile = "baseline";
break;
case AV_PROFILE_H264_HIGH:
x4->profile = "high";
break;
case AV_PROFILE_H264_HIGH_10:
x4->profile = "high10";
break;
case AV_PROFILE_H264_HIGH_422:
x4->profile = "high422";
break;
case AV_PROFILE_H264_HIGH_444:
x4->profile = "high444";
break;
case AV_PROFILE_H264_MAIN:
x4->profile = "main";
break;
default:
break;
}
if (x4->nal_hrd >= 0)
x4->params.i_nal_hrd = x4->nal_hrd;
if (x4->motion_est >= 0)
x4->params.analyse.i_me_method = x4->motion_est;
if (x4->coder >= 0)
x4->params.b_cabac = x4->coder;
if (x4->b_frame_strategy >= 0)
x4->params.i_bframe_adaptive = x4->b_frame_strategy;
if (x4->profile)
if (x264_param_apply_profile(&x4->params, x4->profile) < 0) {
int i;
av_log(avctx, AV_LOG_ERROR, "Error setting profile %s.\n", x4->profile);
av_log(avctx, AV_LOG_INFO, "Possible profiles:");
for (i = 0; x264_profile_names[i]; i++)
av_log(avctx, AV_LOG_INFO, " %s", x264_profile_names[i]);
av_log(avctx, AV_LOG_INFO, "\n");
return AVERROR(EINVAL);
}
// 长宽和fps的设置
x4->params.i_width = avctx->width;
x4->params.i_height = avctx->height;
av_reduce(&sw, &sh, avctx->sample_aspect_ratio.num, avctx->sample_aspect_ratio.den, 4096);
x4->params.vui.i_sar_width = sw;
x4->params.vui.i_sar_height = sh;
x4->params.i_timebase_den = avctx->time_base.den;
x4->params.i_timebase_num = avctx->time_base.num;
if (avctx->framerate.num > 0 && avctx->framerate.den > 0) {
x4->params.i_fps_num = avctx->framerate.num;
x4->params.i_fps_den = avctx->framerate.den;
} else {
x4->params.i_fps_num = avctx->time_base.den;
FF_DISABLE_DEPRECATION_WARNINGS
x4->params.i_fps_den = avctx->time_base.num
#if FF_API_TICKS_PER_FRAME
* avctx->ticks_per_frame
#endif
;
FF_ENABLE_DEPRECATION_WARNINGS
}
x4->params.analyse.b_psnr = avctx->flags & AV_CODEC_FLAG_PSNR;
x4->params.i_threads = avctx->thread_count;
if (avctx->thread_type)
x4->params.b_sliced_threads = avctx->thread_type == FF_THREAD_SLICE;
x4->params.b_interlaced = avctx->flags & AV_CODEC_FLAG_INTERLACED_DCT;
x4->params.b_open_gop = !(avctx->flags & AV_CODEC_FLAG_CLOSED_GOP);
x4->params.i_slice_count = avctx->slices;
if (avctx->color_range != AVCOL_RANGE_UNSPECIFIED)
x4->params.vui.b_fullrange = avctx->color_range == AVCOL_RANGE_JPEG;
else if (avctx->pix_fmt == AV_PIX_FMT_YUVJ420P ||
avctx->pix_fmt == AV_PIX_FMT_YUVJ422P ||
avctx->pix_fmt == AV_PIX_FMT_YUVJ444P)
x4->params.vui.b_fullrange = 1;
if (avctx->colorspace != AVCOL_SPC_UNSPECIFIED)
x4->params.vui.i_colmatrix = avctx->colorspace;
if (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED)
x4->params.vui.i_colorprim = avctx->color_primaries;
if (avctx->color_trc != AVCOL_TRC_UNSPECIFIED)
x4->params.vui.i_transfer = avctx->color_trc;
if (avctx->chroma_sample_location != AVCHROMA_LOC_UNSPECIFIED)
x4->params.vui.i_chroma_loc = avctx->chroma_sample_location - 1;
handle_side_data(avctx, &x4->params);
if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER)
x4->params.b_repeat_headers = 0;
if (avctx->flags & AV_CODEC_FLAG_RECON_FRAME)
x4->params.b_full_recon = 1;
if(x4->x264opts){
const char *p= x4->x264opts;
while(p){
char param[4096]={0}, val[4096]={0};
if(sscanf(p, "%4095[^:=]=%4095[^:]", param, val) == 1){
ret = parse_opts(avctx, param, "1");
if (ret < 0)
return ret;
} else {
ret = parse_opts(avctx, param, val);
if (ret < 0)
return ret;
}
p= strchr(p, ':');
if (p) {
++p;
}
}
}
#if X264_BUILD >= 142
/* Separate headers not supported in AVC-Intra mode */
if (x4->avcintra_class >= 0)
x4->params.b_repeat_headers = 1;
#endif
{
AVDictionaryEntry *en = NULL;
while (en = av_dict_get(x4->x264_params, "", en, AV_DICT_IGNORE_SUFFIX)) {
if ((ret = x264_param_parse(&x4->params, en->key, en->value)) < 0) {
av_log(avctx, AV_LOG_WARNING,
"Error parsing option '%s = %s'.\n",
en->key, en->value);
#if X264_BUILD >= 161
if (ret == X264_PARAM_ALLOC_FAILED)
return AVERROR(ENOMEM);
#endif
}
}
}
x4->params.analyse.b_mb_info = x4->mb_info;
// update AVCodecContext with x264 parameters
avctx->has_b_frames = x4->params.i_bframe ?
x4->params.i_bframe_pyramid ? 2 : 1 : 0;
if (avctx->max_b_frames < 0)
avctx->max_b_frames = 0;
avctx->bit_rate = x4->params.rc.i_bitrate*1000LL;
// 打开编码器
x4->enc = x264_encoder_open(&x4->params);
if (!x4->enc)
return AVERROR_EXTERNAL;
if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) {
ret = set_extradata(avctx);
if (ret < 0)
return ret;
}
// cpb信息配置
cpb_props = ff_encode_add_cpb_side_data(avctx);
if (!cpb_props)
return AVERROR(ENOMEM);
cpb_props->buffer_size = x4->params.rc.i_vbv_buffer_size * 1000;
cpb_props->max_bitrate = x4->params.rc.i_vbv_max_bitrate * 1000LL;
cpb_props->avg_bitrate = x4->params.rc.i_bitrate * 1000LL;
// Overestimate the reordered opaque buffer size, in case a runtime
// reconfigure would increase the delay (which it shouldn't).
x4->nb_reordered_opaque = x264_encoder_maximum_delayed_frames(x4->enc) + 17;
x4->reordered_opaque = av_calloc(x4->nb_reordered_opaque,
sizeof(*x4->reordered_opaque));
if (!x4->reordered_opaque) {
x4->nb_reordered_opaque = 0;
return AVERROR(ENOMEM);
}
return 0;
}
1.3 释放编解码器(ff_codec_close)
函数的主要功能是释放编解码器,其核心是调用了close进行编解码器的关闭,对于libx264而言,调用的是X264_close()函数
av_cold void ff_codec_close(AVCodecContext *avctx)
{
int i;
if (!avctx)
return;
if (avcodec_is_open(avctx)) {
AVCodecInternal *avci = avctx->internal;
if (CONFIG_FRAME_THREAD_ENCODER &&
avci->frame_thread_encoder && avctx->thread_count > 1) {
ff_frame_thread_encoder_free(avctx);
}
if (HAVE_THREADS && avci->thread_ctx)
ff_thread_free(avctx);
if (avci->needs_close && ffcodec(avctx->codec)->close)
ffcodec(avctx->codec)->close(avctx); // 关闭编解码器
avci->byte_buffer_size = 0;
av_freep(&avci->byte_buffer);
av_frame_free(&avci->buffer_frame);
av_packet_free(&avci->buffer_pkt);
av_packet_free(&avci->last_pkt_props);
av_packet_free(&avci->in_pkt);
av_frame_free(&avci->in_frame);
av_frame_free(&avci->recon_frame);
ff_refstruct_unref(&avci->pool);
ff_hwaccel_uninit(avctx);
av_bsf_free(&avci->bsf);
#if FF_API_DROPCHANGED
av_channel_layout_uninit(&avci->initial_ch_layout);
#endif
#if CONFIG_LCMS2
ff_icc_context_uninit(&avci->icc);
#endif
av_freep(&avctx->internal);
}
for (i = 0; i < avctx->nb_coded_side_data; i++)
av_freep(&avctx->coded_side_data[i].data);
av_freep(&avctx->coded_side_data);
avctx->nb_coded_side_data = 0;
av_buffer_unref(&avctx->hw_frames_ctx);
av_buffer_unref(&avctx->hw_device_ctx);
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->extradata_size = 0;
} else if (av_codec_is_decoder(avctx->codec))
av_freep(&avctx->subtitle_header);
avctx->codec = NULL;
avctx->active_thread_type = 0;
}
X264_close函数的定义位于libavcodec\libx264.c中,如下所示,先释放了sei信息和opaque信息,随后调用x264_param_cleanup()清理x264相关的参数,最后调用x264_encoder_close来关闭x264的encoder
static av_cold int X264_close(AVCodecContext *avctx)
{
X264Context *x4 = avctx->priv_data;
av_freep(&x4->sei);
for (int i = 0; i < x4->nb_reordered_opaque; i++)
opaque_uninit(&x4->reordered_opaque[i]);
av_freep(&x4->reordered_opaque);
#if X264_BUILD >= 161
// 清理x264相关参数
x264_param_cleanup(&x4->params);
#endif
if (x4->enc) {
// 关闭x264的encoder
x264_encoder_close(x4->enc);
x4->enc = NULL;
}
return 0;
}
CSDN : https://blog.csdn.net/weixin_42877471
Github : https://github.com/DoFulangChen