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.pswp.cn/news/445968.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/445968.shtml
英文地址,請注明出處:http://en.pswp.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…