内容简介:其中最主要是调用了 AVCodec 的 init() 初始化,其他还做的有:当满足了
avcodec_open2()
主要作用是初始化一个视音频编解码器的 AVCodecContext
avcodec_open2
int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options) { int ret = 0; AVDictionary *tmp = NULL; const AVPixFmtDescriptor *pixdesc; 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; if (avctx->extradata_size < 0 || avctx->extradata_size >= FF_MAX_EXTRADATA_SIZE) return AVERROR(EINVAL); if (options) av_dict_copy(&tmp, *options, 0); ret = ff_lock_avcodec(avctx, codec); if (ret < 0) return ret; avctx->internal = av_mallocz(sizeof(AVCodecInternal)); if (!avctx->internal) { ret = AVERROR(ENOMEM); goto end; } avctx->internal->pool = av_mallocz(sizeof(*avctx->internal->pool)); if (!avctx->internal->pool) { ret = AVERROR(ENOMEM); goto free_and_end; } avctx->internal->to_free = av_frame_alloc(); if (!avctx->internal->to_free) { ret = AVERROR(ENOMEM); goto free_and_end; } avctx->internal->compat_decode_frame = av_frame_alloc(); if (!avctx->internal->compat_decode_frame) { ret = AVERROR(ENOMEM); goto free_and_end; } avctx->internal->buffer_frame = av_frame_alloc(); if (!avctx->internal->buffer_frame) { ret = AVERROR(ENOMEM); goto free_and_end; } avctx->internal->buffer_pkt = av_packet_alloc(); if (!avctx->internal->buffer_pkt) { ret = AVERROR(ENOMEM); goto free_and_end; } avctx->internal->ds.in_pkt = av_packet_alloc(); if (!avctx->internal->ds.in_pkt) { ret = AVERROR(ENOMEM); goto free_and_end; } avctx->internal->last_pkt_props = av_packet_alloc(); if (!avctx->internal->last_pkt_props) { ret = AVERROR(ENOMEM); goto free_and_end; } avctx->internal->skip_samples_multiplier = 1; if (codec->priv_data_size > 0) { if (!avctx->priv_data) { avctx->priv_data = av_mallocz(codec->priv_data_size); if (!avctx->priv_data) { ret = AVERROR(ENOMEM); goto 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, &tmp)) < 0) goto free_and_end; } else { avctx->priv_data = NULL; } // 将输入的 AVDictionary 形式的选项设置到 AVCodecContext if ((ret = av_opt_set_dict(avctx, &tmp)) < 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 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 the decoder init function was already called previously, * free the already allocated subtitle_header before overwriting it */ if (av_codec_is_decoder(codec)) av_freep(&avctx->subtitle_header); if (avctx->channels > FF_SANE_NB_CHANNELS) { ret = AVERROR(EINVAL); goto free_and_end; } avctx->codec = codec; if ((avctx->codec_type == AVMEDIA_TYPE_UNKNOWN || avctx->codec_type == codec->type) && avctx->codec_id == AV_CODEC_ID_NONE) { avctx->codec_type = codec->type; avctx->codec_id = codec->id; } if (avctx->codec_id != codec->id || (avctx->codec_type != codec->type && avctx->codec_type != AVMEDIA_TYPE_ATTACHMENT)) { av_log(avctx, AV_LOG_ERROR, "Codec type or id mismatches\n"); 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"; 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 (!HAVE_THREADS) av_log(avctx, AV_LOG_WARNING, "Warning: not compiled with thread support, using thread emulation\n"); if (CONFIG_FRAME_THREAD_ENCODER && av_codec_is_encoder(avctx->codec)) { ff_unlock_avcodec(codec); //we will instantiate a few encoders thus kick the counter to prevent false detection of a problem ret = ff_frame_thread_encoder_init(avctx, options ? *options : NULL); ff_lock_avcodec(avctx, codec); if (ret < 0) goto free_and_end; } if (HAVE_THREADS && !(avctx->internal->frame_thread_encoder && (avctx->active_thread_type&FF_THREAD_FRAME))) { ret = ff_thread_init(avctx); if (ret < 0) { goto free_and_end; } } if (!HAVE_THREADS && !(codec->capabilities & AV_CODEC_CAP_AUTO_THREADS)) avctx->thread_count = 1; 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; } #if FF_API_VISMV if (avctx->debug_mv) av_log(avctx, AV_LOG_WARNING, "The 'vismv' option is deprecated, " "see the codecview filter instead.\n"); #endif // 检查输入参数是否符合【编码器】要求 if (av_codec_is_encoder(avctx->codec)) { int i; #if FF_API_CODED_FRAME FF_DISABLE_DEPRECATION_WARNINGS avctx->coded_frame = av_frame_alloc(); if (!avctx->coded_frame) { ret = AVERROR(ENOMEM); goto free_and_end; } FF_ENABLE_DEPRECATION_WARNINGS #endif if (avctx->time_base.num <= 0 || avctx->time_base.den <= 0) { av_log(avctx, AV_LOG_ERROR, "The encoder timebase is not set.\n"); ret = AVERROR(EINVAL); goto free_and_end; } // 如果包含采样率参数(表明是音频),检查采样率是否符合要求 if (avctx->codec->sample_fmts) { // 遍历编码器支持的所有采样率 for (i = 0; avctx->codec->sample_fmts[i] != AV_SAMPLE_FMT_NONE; i++) { // 如果设置的采样率 == 编码器支持的采样率,跳出循环 if (avctx->sample_fmt == avctx->codec->sample_fmts[i]) break; if (avctx->channels == 1 && av_get_planar_sample_fmt(avctx->sample_fmt) == av_get_planar_sample_fmt(avctx->codec->sample_fmts[i])) { avctx->sample_fmt = avctx->codec->sample_fmts[i]; break; } } // 采样率取值是否正确 if (avctx->codec->sample_fmts[i] == AV_SAMPLE_FMT_NONE) { char buf[128]; snprintf(buf, sizeof(buf), "%d", avctx->sample_fmt); av_log(avctx, AV_LOG_ERROR, "Specified sample format %s is invalid or not supported\n", (char *)av_x_if_null(av_get_sample_fmt_name(avctx->sample_fmt), buf)); ret = AVERROR(EINVAL); goto free_and_end; } } // 像素格式 if (avctx->codec->pix_fmts) { for (i = 0; avctx->codec->pix_fmts[i] != AV_PIX_FMT_NONE; i++) if (avctx->pix_fmt == avctx->codec->pix_fmts[i]) break; if (avctx->codec->pix_fmts[i] == AV_PIX_FMT_NONE && !((avctx->codec_id == AV_CODEC_ID_MJPEG || avctx->codec_id == AV_CODEC_ID_LJPEG) && avctx->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL)) { char buf[128]; snprintf(buf, sizeof(buf), "%d", avctx->pix_fmt); av_log(avctx, AV_LOG_ERROR, "Specified pixel format %s is invalid or not supported\n", (char *)av_x_if_null(av_get_pix_fmt_name(avctx->pix_fmt), buf)); ret = AVERROR(EINVAL); goto free_and_end; } if (avctx->codec->pix_fmts[i] == AV_PIX_FMT_YUVJ420P || avctx->codec->pix_fmts[i] == AV_PIX_FMT_YUVJ411P || avctx->codec->pix_fmts[i] == AV_PIX_FMT_YUVJ422P || avctx->codec->pix_fmts[i] == AV_PIX_FMT_YUVJ440P || avctx->codec->pix_fmts[i] == AV_PIX_FMT_YUVJ444P) avctx->color_range = AVCOL_RANGE_JPEG; } // 采样率 if (avctx->codec->supported_samplerates) { for (i = 0; avctx->codec->supported_samplerates[i] != 0; i++) if (avctx->sample_rate == avctx->codec->supported_samplerates[i]) break; if (avctx->codec->supported_samplerates[i] == 0) { av_log(avctx, AV_LOG_ERROR, "Specified sample rate %d is not supported\n", avctx->sample_rate); ret = AVERROR(EINVAL); goto free_and_end; } } if (avctx->sample_rate < 0) { av_log(avctx, AV_LOG_ERROR, "Specified sample rate %d is not supported\n", avctx->sample_rate); ret = AVERROR(EINVAL); goto free_and_end; } // 声道布局 if (avctx->codec->channel_layouts) { if (!avctx->channel_layout) { av_log(avctx, AV_LOG_WARNING, "Channel layout not specified\n"); } else { for (i = 0; avctx->codec->channel_layouts[i] != 0; i++) if (avctx->channel_layout == avctx->codec->channel_layouts[i]) break; if (avctx->codec->channel_layouts[i] == 0) { char buf[512]; av_get_channel_layout_string(buf, sizeof(buf), -1, avctx->channel_layout); av_log(avctx, AV_LOG_ERROR, "Specified channel layout '%s' is not supported\n", buf); ret = AVERROR(EINVAL); goto free_and_end; } } } // 声道 if (avctx->channel_layout && avctx->channels) { int channels = av_get_channel_layout_nb_channels(avctx->channel_layout); if (channels != avctx->channels) { char buf[512]; av_get_channel_layout_string(buf, sizeof(buf), -1, avctx->channel_layout); av_log(avctx, AV_LOG_ERROR, "Channel layout '%s' with %d channels does not match number of specified channels %d\n", buf, channels, avctx->channels); ret = AVERROR(EINVAL); goto free_and_end; } } else if (avctx->channel_layout) { avctx->channels = av_get_channel_layout_nb_channels(avctx->channel_layout); } if (avctx->channels < 0) { av_log(avctx, AV_LOG_ERROR, "Specified number of channels %d is not supported\n", avctx->channels); ret = AVERROR(EINVAL); goto free_and_end; } if(avctx->codec_type == AVMEDIA_TYPE_VIDEO) { pixdesc = av_pix_fmt_desc_get(avctx->pix_fmt); 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"); ret = AVERROR(EINVAL); goto free_and_end; } } // 码率 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; 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); goto free_and_end; } 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"); ret = AVERROR(EINVAL); goto free_and_end; } 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)); ret = AVERROR(EINVAL); goto free_and_end; } avctx->sw_pix_fmt = frames_ctx->sw_format; } } avctx->pts_correction_num_faulty_pts = avctx->pts_correction_num_faulty_dts = 0; avctx->pts_correction_last_pts = avctx->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->codec->init && (!(avctx->active_thread_type&FF_THREAD_FRAME) || avctx->internal->frame_thread_encoder)) { ret = avctx->codec->init(avctx); if (ret < 0) { goto free_and_end; } } ret=0; #if FF_API_AUDIOENC_DELAY if (av_codec_is_encoder(avctx->codec)) avctx->delay = avctx->initial_padding; #endif // 解码器的参数大部分都是由系统自动设定而不是由用户设定,因而不怎么需要检查 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->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->sub_charenc) { if (avctx->codec_type != AVMEDIA_TYPE_SUBTITLE) { av_log(avctx, AV_LOG_ERROR, "Character encoding is only " "supported with subtitles codecs\n"); ret = AVERROR(EINVAL); goto free_and_end; } 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); goto free_and_end; } 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"); ret = AVERROR(ENOSYS); goto free_and_end; #endif } } } #if FF_API_AVCTX_TIMEBASE if (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_data_size > 0 && avctx->priv_data && codec->priv_class) { av_assert0(*(const AVClass **)avctx->priv_data == codec->priv_class); } end: ff_unlock_avcodec(codec); if (options) { av_dict_free(options); *options = tmp; } return ret; free_and_end: if (avctx->codec && (avctx->codec->caps_internal & FF_CODEC_CAP_INIT_CLEANUP)) avctx->codec->close(avctx); if (codec->priv_class && codec->priv_data_size) av_opt_free(avctx->priv_data); av_opt_free(avctx); #if FF_API_CODED_FRAME FF_DISABLE_DEPRECATION_WARNINGS av_frame_free(&avctx->coded_frame); FF_ENABLE_DEPRECATION_WARNINGS #endif av_dict_free(&tmp); av_freep(&avctx->priv_data); if (avctx->internal) { av_frame_free(&avctx->internal->to_free); av_frame_free(&avctx->internal->compat_decode_frame); av_frame_free(&avctx->internal->buffer_frame); av_packet_free(&avctx->internal->buffer_pkt); av_packet_free(&avctx->internal->last_pkt_props); av_packet_free(&avctx->internal->ds.in_pkt); av_freep(&avctx->internal->pool); } av_freep(&avctx->internal); avctx->codec = NULL; goto end; }
其中最主要是调用了 AVCodec 的 init() 初始化,其他还做的有:
av_malloc()
av_codec_is_encoder
当满足了 av_codec_is_encoder()
满足的情况下,进行了参数是否满足编码器规范要求的检查,如:
if (avctx->codec->pix_fmts) { for (i = 0; avctx->codec->pix_fmts[i] != AV_PIX_FMT_NONE; i++) if (avctx->pix_fmt == avctx->codec->pix_fmts[i]) break; if (avctx->codec->pix_fmts[i] == AV_PIX_FMT_NONE && !((avctx->codec_id == AV_CODEC_ID_MJPEG || avctx->codec_id == AV_CODEC_ID_LJPEG) && avctx->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL)) { char buf[128]; snprintf(buf, sizeof(buf), "%d", avctx->pix_fmt); av_log(avctx, AV_LOG_ERROR, "Specified pixel format %s is invalid or not supported\n", (char *)av_x_if_null(av_get_pix_fmt_name(avctx->pix_fmt), buf)); ret = AVERROR(EINVAL); goto free_and_end; } if (avctx->codec->pix_fmts[i] == AV_PIX_FMT_YUVJ420P || avctx->codec->pix_fmts[i] == AV_PIX_FMT_YUVJ411P || avctx->codec->pix_fmts[i] == AV_PIX_FMT_YUVJ422P || avctx->codec->pix_fmts[i] == AV_PIX_FMT_YUVJ440P || avctx->codec->pix_fmts[i] == AV_PIX_FMT_YUVJ444P) avctx->color_range = AVCOL_RANGE_JPEG; }
将 AVCodecContext 中的 pix_fmt 与编码器 AVCodec 中的 pix_fmts 数组中的元素进行对比,其中 AVCodec 中的 pix_fmts 数组存储了该种编码器支持的像素格式,并且规定以 AV_PIX_FMT_NONE(AV_PIX_FMT_NONE 取值为 - 1)为结尾
static const enum AVPixelFormat pix_fmts_8bit[] = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_NV12, AV_PIX_FMT_NV16, AV_PIX_FMT_NONE };
以 libx264 的 pix_fmts 数组为例,从 pix_fmts_8bit 的定义可以看出 libx264 主要支持的是以 YUV 为主的像素格式
avctx->codec->init
AVCodec ff_libx264_encoder = { .name = "libx264", .long_name = NULL_IF_CONFIG_SMALL("libx264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10"), .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_H264, .priv_data_size = sizeof(X264Context), .init = X264_init, .encode2 = X264_frame, .close = X264_close, .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AUTO_THREADS, .priv_class = &x264_class, .defaults = x264_defaults, .init_static_data = X264_init_static, .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, };
以 libx264 为例, init
方法对应的是 X264_init
static av_cold int X264_init(AVCodecContext *avctx) { X264Context *x4 = avctx->priv_data; AVCPBProperties *cpb_props; int sw,sh; 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 x264_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); PARSE_X264_OPT("weightp", wpredp); if (avctx->bit_rate) { 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 FF_API_PRIVATE_OPT FF_DISABLE_DEPRECATION_WARNINGS if (avctx->chromaoffset >= 0) x4->chroma_offset = avctx->chromaoffset; FF_ENABLE_DEPRECATION_WARNINGS #endif if (x4->chroma_offset >= 0) 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 FF_API_PRIVATE_OPT FF_DISABLE_DEPRECATION_WARNINGS if (avctx->scenechange_threshold >= 0) x4->scenechange_threshold = avctx->scenechange_threshold; FF_ENABLE_DEPRECATION_WARNINGS #endif 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->level) { int i; int mbn = AV_CEIL_RSHIFT(avctx->width, 4) * AV_CEIL_RSHIFT(avctx->height, 4); int level_id = -1; char *tail; int scale = X264_BUILD < 129 ? 384 : 1; if (!strcmp(x4->level, "1b")) { level_id = 9; } else if (strlen(x4->level) <= 3){ level_id = av_strtod(x4->level, &tail) * 10 + 0.5; if (*tail) level_id = -1; } if (level_id <= 0) av_log(avctx, AV_LOG_WARNING, "Failed to parse level\n"); for (i = 0; i<x264_levels[i].level_idc; i++) if (x264_levels[i].level_idc == level_id) 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 FF_API_PRIVATE_OPT FF_DISABLE_DEPRECATION_WARNINGS if (avctx->noise_reduction >= 0) x4->noise_reduction = avctx->noise_reduction; FF_ENABLE_DEPRECATION_WARNINGS #endif 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 FF_API_PRIVATE_OPT FF_DISABLE_DEPRECATION_WARNINGS if (avctx->b_frame_strategy >= 0) x4->b_frame_strategy = avctx->b_frame_strategy; FF_ENABLE_DEPRECATION_WARNINGS #endif if (avctx->keyint_min >= 0) x4->params.i_keyint_min = avctx->keyint_min; #if FF_API_CODER_TYPE FF_DISABLE_DEPRECATION_WARNINGS if (avctx->coder_type >= 0) x4->coder = avctx->coder_type == FF_CODER_TYPE_AC; FF_ENABLE_DEPRECATION_WARNINGS #endif 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->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 FF_API_MOTION_EST FF_DISABLE_DEPRECATION_WARNINGS } else { if (avctx->me_method == ME_EPZS) x4->params.analyse.i_me_method = X264_ME_DIA; else if (avctx->me_method == ME_HEX) x4->params.analyse.i_me_method = X264_ME_HEX; else if (avctx->me_method == ME_UMH) x4->params.analyse.i_me_method = X264_ME_UMH; else if (avctx->me_method == ME_FULL) x4->params.analyse.i_me_method = X264_ME_ESA; else if (avctx->me_method == ME_TESA) x4->params.analyse.i_me_method = X264_ME_TESA; FF_ENABLE_DEPRECATION_WARNINGS #endif } 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; 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; x4->params.vui.b_fullrange = avctx->pix_fmt == AV_PIX_FMT_YUVJ420P || avctx->pix_fmt == AV_PIX_FMT_YUVJ422P || avctx->pix_fmt == AV_PIX_FMT_YUVJ444P || avctx->color_range == AVCOL_RANGE_JPEG; 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->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){ OPT_STR(param, "1"); }else OPT_STR(param, val); p= strchr(p, ':'); p+=!!p; } } if (x4->x264_params) { AVDictionary *dict = NULL; AVDictionaryEntry *en = NULL; if (!av_dict_parse_string(&dict, x4->x264_params, "=", ":", 0)) { while ((en = av_dict_get(dict, "", en, AV_DICT_IGNORE_SUFFIX))) { if (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); } av_dict_free(&dict); } } // 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*1000; 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 * 1000; cpb_props->avg_bitrate = x4->params.rc.i_bitrate * 1000; return 0; }
大概的工作
- 设置 X264Context 的参数。X264Context 主要完成了 libx264 和 FFmpeg 对接的功能。可以看出代码主要在设置一个 params 结构体变量,该变量的类型即是 x264 中存储参数的结构体 x264_param_t。
- 调用 libx264 的 API 进行编码器的初始化工作。例如调用 x264_param_default() 设置默认参数,调用 x264_param_apply_profile() 设置 profile,调用 x264_encoder_open() 打开编码器等等。
以上所述就是小编给大家介绍的《ijkplayer框架简析 -- avcodec_open2》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- ijkplayer框架简析 — FFmpeg中重要结构体
- iOS Appium 自动化测试框架原理简析
- ijkplayer框架简析 -- av_register_all
- ijkplayer框架简析 -- avcodec_decode_video2
- Tomcat启动流程简析
- Flux模式简析
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。