FFmpeg源代码简单分析-通用-avcodec_open2()

参考链接

  • FFmpeg源代码简单分析:avcodec_open2()_雷霄骅的博客-CSDN博客

avcodec_open2()

  • 该函数用于初始化一个音视频编解码器的AVCodecContext
  • avcodec_open2()的声明位于libavcodec\avcodec.h,如下所示。
/*** Initialize the AVCodecContext to use the given AVCodec. Prior to using this* function the context has to be allocated with avcodec_alloc_context3().* 初始化 AVCodecContext 以使用给定的 AVCodec* 在使用此函数之前,必须使用 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.* 函数 avcodec_find_decoder_by_name()、avcodec_find_encoder_by_name()、avcodec_find_decoder() * avcodec_find_encoder() 为检索编解码器提供了一种简单的方法** @note Always call this function before using decoding routines (such as* @ref avcodec_receive_frame()).** @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** @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.*                On return this object will be filled with options that were not found.** @return zero on success, a negative value on error* @see avcodec_alloc_context3(), avcodec_find_decoder(), avcodec_find_encoder(),*      av_dict_set(), av_opt_find().*/
int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options);
  • 用中文简单转述一下avcodec_open2()各个参数的含义:
  • avctx:需要初始化的AVCodecContext。
  • codec:输入的AVCodec
  • options:一些选项。例如使用libx264编码的时候,“preset”,“tune”等都可以通过该参数设置。

函数调用关系图

int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options)
{int ret = 0;AVCodecInternal *avci;const FFCodec *codec2;//如果已经打开,直接返回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);avci = av_mallocz(sizeof(*avci));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;}avci->skip_samples_multiplier = 1;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;}//将输入的AVDictionary形式的选项设置到AVCodecContextif ((ret = av_opt_set_dict(avctx, options)) < 0)goto free_and_end;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 dimensionsif (!(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;}#if FF_API_OLD_CHANNEL_LAYOUT
FF_DISABLE_DEPRECATION_WARNINGS/* compat wrapper for old-style callers */if (avctx->channel_layout && !avctx->channels)avctx->channels = av_popcount64(avctx->channel_layout);if ((avctx->channels > 0 && avctx->ch_layout.nb_channels != avctx->channels) ||(avctx->channel_layout && (avctx->ch_layout.order != AV_CHANNEL_ORDER_NATIVE ||avctx->ch_layout.u.mask != avctx->channel_layout))) {if (avctx->channel_layout) {av_channel_layout_from_mask(&avctx->ch_layout, avctx->channel_layout);} else {avctx->ch_layout.order       = AV_CHANNEL_ORDER_UNSPEC;avctx->ch_layout.nb_channels = avctx->channels;}}
FF_ENABLE_DEPRECATION_WARNINGS
#endifif (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_number = 0;avctx->codec_descriptor = avcodec_descriptor_get(avctx->codec_id);//检查编码器是否出于“实验”阶段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;}//检查输入参数是否符合【编码器】要求if (av_codec_is_encoder(avctx->codec))ret = ff_encode_preinit(avctx);elseret = ff_decode_preinit(avctx);if (ret < 0)goto free_and_end;if (CONFIG_FRAME_THREAD_ENCODER && av_codec_is_encoder(avctx->codec)) {ret = ff_frame_thread_encoder_init(avctx);if (ret < 0)goto free_and_end;}if (HAVE_THREADS&& !(avci->frame_thread_encoder && (avctx->active_thread_type&FF_THREAD_FRAME))) {/* 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);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);#if FF_API_OLD_CHANNEL_LAYOUT
FF_DISABLE_DEPRECATION_WARNINGS/* update the deprecated fields for old-style callers */avctx->channels = avctx->ch_layout.nb_channels;avctx->channel_layout = avctx->ch_layout.order == AV_CHANNEL_ORDER_NATIVE ?avctx->ch_layout.u.mask : 0;/* validate channel layout from the decoder */if (avctx->channel_layout) {int channels = av_get_channel_layout_nb_channels(avctx->channel_layout);if (!avctx->channels)avctx->channels = channels;else if (channels != avctx->channels) {char buf[512];av_get_channel_layout_string(buf, sizeof(buf), -1, avctx->channel_layout);av_log(avctx, AV_LOG_WARNING,"Channel layout '%s' with %d channels does not match specified number of channels %d: ""ignoring specified channel layout\n",buf, channels, avctx->channels);avctx->channel_layout = 0;}}if (avctx->channels && avctx->channels < 0 ||avctx->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;}
FF_ENABLE_DEPRECATION_WARNINGS
#endif#if FF_API_AVCTX_TIMEBASEif (avctx->framerate.num > 0 && avctx->framerate.den > 0)avctx->time_base = av_inv_q(av_mul_q(avctx->framerate, (AVRational){avctx->ticks_per_frame, 1}));
#endif}if (codec->priv_class)av_assert0(*(const AVClass **)avctx->priv_data == codec->priv_class);end:return ret;
free_and_end:avcodec_close(avctx);goto end;
}
  • 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()是一个函数指针,指向具体编解码器中的初始化函数。
  • 这里我们以libx264为例,看一下它对应的AVCodec的定义。
  • libx264对应的AVCodec的定义位于libavcodec\libx264.c,如下所示。
#if X264_BUILD >= 153
const
#endif
FFCodec ff_libx264_encoder = {.p.name           = "libx264",.p.long_name      = NULL_IF_CONFIG_SMALL("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,.p.priv_class     = &x264_class,.p.wrapper_name   = "libx264",.priv_data_size   = sizeof(X264Context),.init             = X264_init,FF_CODEC_ENCODE_CB(X264_frame),.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_INIT_THREADSAFE
#endif,
};
#endif
  • 可以看出在ff_libx264_encoder中init()指向X264_init()。X264_init()的定义同样位于libavcodec\libx264.c,如下所示。
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_ENCODERif (avctx->codec_id == AV_CODEC_ID_MPEG2VIDEO) {x4->params.b_mpeg2 = 1;x264_param_default_mpeg2(&x4->params);} else
#endifx264_param_default(&x4->params);x4->params.b_deblocking_filter         = avctx->flags & AV_CODEC_FLAG_LOOP_FILTER;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;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 >= 153x4->params.i_bitdepth           = av_pix_fmt_desc_get(avctx->pix_fmt)->comp[0].depth;
#endifPARSE_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 >= 142x4->params.i_avcintra_class = x4->avcintra_class;
#elseav_log(avctx, AV_LOG_ERROR,"x264 too old for AVC Intra, at least version 142 needed\n");
#endifif (x4->avcintra_class > 200) {
#if X264_BUILD < 164av_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;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;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);/* Allow specifying the x264 profile through AVCodecContext. */if (!x4->profile)switch (avctx->profile) {case FF_PROFILE_H264_BASELINE:x4->profile = av_strdup("baseline");break;case FF_PROFILE_H264_HIGH:x4->profile = av_strdup("high");break;case FF_PROFILE_H264_HIGH_10:x4->profile = av_strdup("high10");break;case FF_PROFILE_H264_HIGH_422:x4->profile = av_strdup("high422");break;case FF_PROFILE_H264_HIGH_444:x4->profile = av_strdup("high444");break;case FF_PROFILE_H264_MAIN:x4->profile = av_strdup("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);}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;x4->params.i_fps_den = avctx->time_base.num * avctx->ticks_per_frame;}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;if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER)x4->params.b_repeat_headers = 0;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, ':');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 >= 161if (ret == X264_PARAM_ALLOC_FAILED)return AVERROR(ENOMEM);
#endif}}}// update AVCodecContext with x264 parametersavctx->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) {x264_nal_t *nal;uint8_t *p;int nnal, s, i;s = x264_encoder_headers(x4->enc, &nal, &nnal);avctx->extradata = p = av_mallocz(s + AV_INPUT_BUFFER_PADDING_SIZE);if (!p)return AVERROR(ENOMEM);for (i = 0; i < nnal; i++) {/* Don't put the SEI in extradata. */if (nal[i].i_type == NAL_SEI) {av_log(avctx, AV_LOG_INFO, "%s\n", nal[i].p_payload+25);x4->sei_size = nal[i].i_payload;x4->sei      = av_malloc(x4->sei_size);if (!x4->sei)return AVERROR(ENOMEM);memcpy(x4->sei, nal[i].p_payload, nal[i].i_payload);continue;}memcpy(p, nal[i].p_payload, nal[i].i_payload);p += nal[i].i_payload;}avctx->extradata_size = p - avctx->extradata;}cpb_props = ff_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_malloc_array(x4->nb_reordered_opaque,sizeof(*x4->reordered_opaque));if (!x4->reordered_opaque)return AVERROR(ENOMEM);return 0;
}
  • X264_init()的代码的两项工作:
  • (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,如下所示。

typedef struct X264Context {AVClass        *class;x264_param_t    params;x264_t         *enc;x264_picture_t  pic;uint8_t        *sei;int             sei_size;char *preset;char *tune;char *profile;char *level;int fastfirstpass;char *wpredp;char *x264opts;float crf;float crf_max;int cqp;int aq_mode;float aq_strength;char *psy_rd;int psy;int rc_lookahead;int weightp;int weightb;int ssim;int intra_refresh;int bluray_compat;int b_bias;int b_pyramid;int mixed_refs;int dct8x8;int fast_pskip;int aud;int mbtree;char *deblock;float cplxblur;char *partitions;int direct_pred;int slice_max_size;char *stats;int nal_hrd;int avcintra_class;int motion_est;int forced_idr;int coder;int a53_cc;int b_frame_strategy;int chroma_offset;int scenechange_threshold;int noise_reduction;int udu_sei;AVDictionary *x264_params;int nb_reordered_opaque, next_reordered_opaque;X264Opaque *reordered_opaque;/*** If the encoder does not support ROI then warn the first time we* encounter a frame with ROI side data.*/int roi_warned;
} X264Context;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/445968.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

统计MySQL中某数据库硬盘占用量大小

放码过来 select TABLE_NAME, concat(truncate(data_length/1024/1024,2), MB) as data_size, concat(truncate(index_length/1024/1024,2), MB) as index_size from information_schema.tables where TABLE_SCHEMA your_db_name order by data_length desc;运行结果 参考…

halcon 相似度_Halcon分类函数,shape模型

《zw版Halcon-delphi系列原创教程》 Halcon分类函数013,shape模型为方便阅读&#xff0c;在不影响说明的前提下&#xff0c;笔者对函数进行了简化&#xff1a;:: 用符号“**”&#xff0c;替换&#xff1a;“procedure”:: 用大写字母“X”&#xff0c;替换&#xff1a;“IHUnt…

用Python将文件夹打包成Zip并备份至U盘

需求概要 将maven工程打包并备份至U盘。为了简单起见&#xff0c;只需备份工程中的src文件夹和pom.xml文件即可。 放码过来 import os import zipfile import datetime import shutilnowTimeStr datetime.datetime.now().strftime("%Y%m%d%H%M") newZipFileName …

FFmpeg源代码简单分析-通用-avcodec_close()

参考链接 FFmpeg源代码简单分析&#xff1a;avcodec_close()_雷霄骅的博客-CSDN博客_avcodec_close avcodec_close() 该函数用于关闭编码器avcodec_close()函数的声明位于libavcodec\avcodec.h&#xff0c;如下所示。 ​该函数只有一个参数&#xff0c;就是需要关闭的编码器的…

redis 缓存过期默认时间_redis缓存过期机制

笔者在线上使用redis缓存的时候发现即使某些查询已经设置了无过期时间的缓存,但是查询仍然非常耗时。经过排查,发现缓存确实已经不存在,导致了缓存击穿,查询直接访问了mysql数据库。因为我们用的是公司公共的redis缓存服务器,在和运维人员交流后发现可能是redis的内存淘汰…

FFmpeg源代码简单分析-解码-打开媒体的函数avformat_open_input

参考链接 图解FFMPEG打开媒体的函数avformat_open_input_雷霄骅的博客-CSDN博客_avformat_open_input 使用FFmpeg源代码简单分析&#xff1a;avformat_open_input()_雷霄骅的博客-CSDN博客_avformat_open_input() avformat_open_input FFmpeg打开媒体的的过程开始于avformat_…

redis session java获取attribute_面试题:给我说说你能想到几种分布式session实现?...

作者&#xff1a;yanglbme 来源&#xff1a;https://github.com/doocs/advanced-java/blob/master/docs/distributed-system/distributed-session.md# 面试官心理分析面试官问了你一堆 dubbo 是怎么玩儿的&#xff0c;你会玩儿 dubbo 就可以把单块系统弄成分布式系统&#xff0…

Projection投影

解释一 Projection means choosing which columns (or expressions) the query shall return. Selection means which rows are to be returned. if the query is select a, b, c from foobar where x3;then “a, b, c” is the projection part, “where x3” the selecti…

FFmpeg源代码简单分析-解码-avformat_find_stream_info()

参考链接 FFmpeg源代码简单分析&#xff1a;avformat_find_stream_info()_雷霄骅的博客-CSDN博客_avformat_find_stream_info avformat_find_stream_info() ​该函数可以读取一部分视音频数据并且获得一些相关的信息avformat_find_stream_info()的声明位于libavformat\avform…

Tail Recursion尾递归

什么是尾递归 Tail Recursion /teɪl rɪˈkɜːrʒn/ In traditional recursion, the typical model is that you perform your recursive calls first, and then you take the return value of the recursive call and calculate the result. In this manner, you don’t g…

python递归算法案例教案_python教案

第五单元进阶程序设计(总10课时)第一节选择编程语言(1课时)一、教学目标1、了解程序设计语言和两种翻译方式&#xff1b;2、了解Python背景、功能、安装&#xff0c;熟悉Python编程环境&#xff1b;3、编程初体验。体验一个小程序从建立、输入、调试、运行、保存的全过程。掌握…

FFmpeg源代码简单分析-解码-av_read_frame()

参考链接 ffmpeg 源代码简单分析 &#xff1a; av_read_frame()_雷霄骅的博客-CSDN博客_ffmpeg frame av_read_frame() ffmpeg中的av_read_frame()的作用是读取码流中的音频若干帧或者视频一帧。例如&#xff0c;解码视频的时候&#xff0c;每解码一个视频帧&#xff0c;需要…

数据库 流量切分_私域流量之社群运营技巧,社群运营技巧解析

一、明白社群运营的目的1、社群的目的确立任何一个社群(组织)成立的时分&#xff0c;都是承载着一定的目的的&#xff0c;这个目的就像是北极星一样&#xff0c;指引着我们的方向。确立运营目的的过程&#xff0c;也是在寻觅北极星的过程。社群运营属于触达用户的一种方式&…

用Python在Tomcat成功启动后自动打开浏览器访问Web应用

前提条件 WindowsPython 2.7需设置CATALINA_HOME环境变量 放码过来 # -*- coding: utf-8 -* import os import time import subprocesstomcatStartFilePath C:\\tomcat\\apache-tomcat-7.0.90-windows-x64\\apache-tomcat-7.0.90\\bin\\startup.bat browserPath C:\\Users…

FFmpeg源代码简单分析-解码-avcodec_send_packet 和 avcodec_receive_frame 替代 avcodec_decode_video2

参考链接 ffmpeg 源代码简单分析 &#xff1a; avcodec_decode_video2()_雷霄骅的博客-CSDN博客_avcodec_decode_video2 avcodec_decode_video2 ffmpeg中的avcodec_decode_video2()的作用是解码一帧视频数据。输入一个压缩编码的结构体AVPacket&#xff0c;输出一个解码后的结…

FFmpeg源代码简单分析-解码-avformat_close_input()

参考链接 FFmpeg源代码简单分析&#xff1a;avformat_close_input()_雷霄骅的博客-CSDN博客_avformat_close_input avformat_close_input() 本文简单分析FFmpeg的avformat_close_input()函数。该函数用于关闭一个AVFormatContext&#xff0c;一般情况下是和avformat_open_inp…

android 使用shell模拟触屏_[Android]通过adb shell input上报命令模拟屏幕点击事件【转】...

常用的 input上报命令&#xff1a;input text 1234 实际向界面注入1234文字&#xff0c;有输入框&#xff0c;能明显看到效果input keyevent 4 键盘事件&#xff0c;4 为返回input tap 100 300 单击触屏事件 &#xff0c;模拟点击x100 y 300 位置input swipe 100 300 500 300 …

用Python连接MySQL并进行CRUD

Tag: MySQL, PyMySQL, Python 准备条件 Python 2.7MySQL 5.5安装 PyMySQL pip install PyMySQL 放码过来 创建一数据表 CREATE TABLE users (id int(11) NOT NULL AUTO_INCREMENT,email varchar(255) COLLATE utf8_bin NOT NULL,password varchar(255) COLLATE utf8_bin N…

python网络爬虫的方法有几种_Python网络爬虫过程中5种网页去重方法简要介绍

一般的&#xff0c;我们想抓取一个网站所有的URL&#xff0c;首先通过起始URL&#xff0c;之后通过网络爬虫提取出该网页中所有的URL链接&#xff0c;之后再对提取出来的每个URL进行爬取&#xff0c;提取出各个网页中的新一轮URL&#xff0c;以此类推。整体的感觉就是自上而下进…

FFmpeg源代码简单分析-编码-avformat_alloc_output_context2()

参考链接 FFmpeg源代码简单分析&#xff1a;avformat_alloc_output_context2()_雷霄骅的博客-CSDN博客_avformat_alloc_context avformat_alloc_output_context2() 在基于FFmpeg的视音频编码器程序中&#xff0c;该函数通常是第一个调用的函数&#xff08;除了组件注册函数av…