当前位置: 首页 > news >正文

【FFmpeg】avcodec_open2函数

目录

  • 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的能力包括了experimentalif ((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);elseret = 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.创建失败则释放codecff_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和audioif (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) {// 编码格式为NONEav_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);// 输出支持的formatav_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_rangeif (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_WARNINGSif (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
#endifif (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_headerav_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_ICONViconv_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);
#elseav_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 datafor (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 typesif (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_DROPCHANGEDif (avctx->flags & AV_CODEC_FLAG_DROPCHANGED)av_log(avctx, AV_LOG_WARNING, "The dropchanged flag is deprecated.\n");
#endifreturn 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_ENCODERif (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 >= 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;// 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;// 是否启用mbtreeif (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. */// 检查profileif (!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_WARNINGSx4->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 >= 161if (ret == X264_PARAM_ALLOC_FAILED)return AVERROR(ENOMEM);
#endif}}}x4->params.analyse.b_mb_info = x4->mb_info;// 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) {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_DROPCHANGEDav_channel_layout_uninit(&avci->initial_ch_layout);
#endif#if CONFIG_LCMS2ff_icc_context_uninit(&avci->icc);
#endifav_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);
#endifif (x4->enc) {// 关闭x264的encoderx264_encoder_close(x4->enc);x4->enc = NULL;}return 0;
}

CSDN : https://blog.csdn.net/weixin_42877471
Github : https://github.com/DoFulangChen

相关文章:

【FFmpeg】avcodec_open2函数

目录 1. avcodec_open21.1 编解码器的预初始化&#xff08;ff_encode_preinit & ff_decode_preinit&#xff09;1.2 编解码器的初始化&#xff08;init&#xff09;1.3 释放编解码器&#xff08;ff_codec_close&#xff09; FFmpeg相关记录&#xff1a; 示例工程&#xff…...

matlab:对带参数a关于x的方程求解

题目 讲解 简洁对各个式子的内部含义用浅显易懂的话语总结出来了&#xff0c;耐心体会 f(a) (x)exp(x)x^ax^(sqrt(x))-100;%因为下面的fzero的第一个数需要一个fun&#xff0c;所以这里有两个句柄&#xff0c;第一个a是输入的&#xff0c;第二个x是需要被解出的 A0:0.1:2;%创…...

Yolov10训练,转化onnx,推理

yolov10对于大目标的效果好&#xff0c;小目标不好 一、如果你训练过yolov5&#xff0c;yolov8&#xff0c;的话那么你可以直接用之前的环境就行 目录 一、如果你训练过yolov5&#xff0c;yolov8&#xff0c;的话那么你可以直接用之前的环境就行 二、配置好后就可以配置文件…...

GEE代码实例教程详解:洪水灾害监测

简介 在本篇博客中&#xff0c;我们将使用Google Earth Engine (GEE) 进行洪水灾害监测。通过分析Sentinel-1雷达数据&#xff0c;我们可以识别特定时间段内的洪水变化情况。 背景知识 Sentinel-1数据集 Sentinel-1是欧洲空间局提供的雷达卫星数据集&#xff0c;它能够提供…...

运维锅总详解系统设计原则

本文对CAP、BASE、ACID、SOLID 原则、12-Factor 应用方法论等12种系统设计原则进行分析举例&#xff0c;希望对您在进行系统设计、理解系统运行背后遵循的原理有所帮助&#xff01; 一、CAP、BASE、ACID简介 以下是 ACID、CAP 和 BASE 系统设计原则的详细说明及其应用举例&am…...

深度学习笔记: 最详尽解释预测系统的分类指标(精确率、召回率和 F1 值)

欢迎收藏Star我的Machine Learning Blog:https://github.com/purepisces/Wenqing-Machine_Learning_Blog。如果收藏star, 有问题可以随时与我交流, 谢谢大家&#xff01; 预测系统的分类指标(精确率、召回率和 F1 值) 简介 让我们来谈谈预测系统的分类指标以及对精确率、召回…...

GEE代码实例教程详解:MODIS土地覆盖分类与面积计算

简介 在本篇博客中&#xff0c;我们将使用Google Earth Engine (GEE) 对MODIS土地覆盖数据进行分析。通过MODIS/061/MCD12Q1数据集&#xff0c;我们可以识别不同的土地覆盖类型&#xff0c;并计算每种类型的总面积。 背景知识 MODIS MCD12Q1数据集 MODIS/061/MCD12Q1是NASA…...

LT86101UXE 国产原装 HDMI2.0 / DVI中继器方案 分辨率 4Kx2K 用于多显示器 DVI/HDMI电缆扩展模块

1. 描述 Lontium LT86101UXE HDMI2.0 / DVI中继器特性高速中继器符合HDMI2.0/1.4规范,最大6 gbps高速数据率、自适应均衡RX输入和pre-emphasized TX输出支持长电缆应用程序,没有晶体在船上保存BOM成本,内部灵活的PCB TX巷交换路由。 LT86101UXE HDMI2.0/DVI中继器自动检测线缆损…...

FastApi中的常见请求类型

FastApi中的常见请求类型 后端开发语言中&#xff0c;我钟情于node&#xff0c;高效的异步处理真是让我眼前一亮&#xff0c;同时&#xff0c;简单易懂的语法也让我非常倾心 但是但是&#xff0c;因为考虑要写一个深度学习算法的后端接口&#xff0c;所以不得不选用python作为…...

服务器,云、边缘计算概念简单理解

目录 服务器,云、边缘计算概念简单理解 一、服务器 二、云计算 三、边缘计算 服务器和云之间区别 性质 可用性 弹性扩展 管理和维护 成本 应用场景 服务器,云、边缘计算概念简单理解 一、服务器 概念简单理解: 服务器是计算机网络上最重要的设备之一,它在网络…...

【Linux系列2】Cmake安装记录

方法一 1. 查看当前cmake版本 [rootlocalhost ~]# cmake -version cmake version 2.8.12.22. 进行卸载 [rootlocalhost ~]# yum remove -y cmake3. 进行安装包的下载&#xff0c;也可以下载好安装包后传至相应的目录 [rootlocalhost ~]# mkdir /opt/cmake [rootlocalhost ~…...

C++ STL 多线程库用法介绍

目录 一&#xff1a;Atomic&#xff1a; 二&#xff1a;Thread 1. 创建线程 2. 小心移动(std::move)线程 3. 如何创建带参数的线程 4. 线程参数是引用类型时&#xff0c;要小心谨慎。 5. 获取线程ID 6. jthread 7. 如何在线程中使用中断 stop_token 三&#xff1a;如何…...

Jmeter实现接口自动化

自动化测试理论知识 什么是自动化测试&#xff1f; 让程序或工具代替人为执行测试用例什么样的项目适合做自动化&#xff1f; 1、项目周期长 --多长算长&#xff1f;&#xff08;自己公司运营项目&#xff09; 2、需求稳定&#xff08;更多具体功能/模块&#xff09; 3、需要…...

【大模型】多模型在大模型中的调度艺术:解锁效率与协同的新境界

多模型在大模型中的调度艺术&#xff1a;解锁效率与协同的新境界 引言一、多模型与大模型的概念解析二、多模型调度的必要性三、多模型调度的关键技术3.1 负载均衡与动态分配3.2 模型间通信与协作3.3 模型选择与优化 四、多模型运行优化策略4.1 异构计算平台的利用4.2 模型压缩…...

LeetCode 704, 290, 200

目录 704. 二分查找题目链接标签思路代码 290. 单词规律题目链接标签思路代码 200. 岛屿数量题目链接标签思路代码 704. 二分查找 题目链接 704. 二分查找 标签 数组 二分查找 思路 这道题是 二分查找 最经典的一道题&#xff0c;掌握了本题的思想就进入了 二分 思想的大…...

如何利用Java进行大数据处理?

如何利用Java进行大数据处理&#xff1f; 大家好&#xff0c;我是微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 1. 引言 在当今信息爆炸的时代&#xff0c;处理大数据是许多应用程序和系统的核心需求之一。Java作为一种…...

【论文通读】GUICourse: From General Vision Language Model to Versatile GUI Agent

GUICourse: From General Vision Language Model to Versatile GUI Agent 前言AbstractMotivationSolutionGUICourseGUIEnvGUIEnv-globalGUIEnv-local GUIActGUIAct (web-single)GUIAct (web-multi)GUIAct (smartphone) GUIChat ExperimentsMain ResultAblation Study Conclusi…...

王道考研数据机构:中缀表达式转为后缀表达式

实现方法&#xff1a; 初始化一个栈&#xff0c;用于保存暂时还不能确定运算顺序的运算符。从左到右处理各个元素&#xff0c;直到末尾。可能遇到三种情况: 遇到操作数。直接加入后缀表达式遇到界限符。遇到“(”直接入栈;遇到“)”则依次弹出栈内运算符并加入后缀表达式&…...

PL/SQL安装+汉化教程

PL/SQL安装教程 一、安装&#xff1a; 登陆官网&#xff1a;PL/SQL Developer - Allround Automations下载 下载PL/SQL稳定版本12.0.7 根据自己计算机版本安装相适配的版本。我这里安装X64-bit版本 进行安装&#xff1a; 根据情况去更改安装&#xff0c;我这里全部下一步…...

Qt | Qt 线程相关类概述和举例

Qt 是一个广泛用于跨平台应用开发的框架。在 Qt 中,多线程支持是其核心特性之一,它允许开发者在不同平台上创建并发应用。以下是 Qt 中与线程相关的类概述及其使用示例。 Qt 中的线程相关类 QThread QThread 是 Qt 中用于创建和管理线程的基类。通过派生并重写 run() 函数…...

【位运算】消失的两个数字(hard)

消失的两个数字&#xff08;hard&#xff09; 题⽬描述&#xff1a;解法&#xff08;位运算&#xff09;&#xff1a;Java 算法代码&#xff1a;更简便代码 题⽬链接&#xff1a;⾯试题 17.19. 消失的两个数字 题⽬描述&#xff1a; 给定⼀个数组&#xff0c;包含从 1 到 N 所有…...

QT: `long long` 类型转换为 `QString` 2025.6.5

在 Qt 中&#xff0c;将 long long 类型转换为 QString 可以通过以下两种常用方法实现&#xff1a; 方法 1&#xff1a;使用 QString::number() 直接调用 QString 的静态方法 number()&#xff0c;将数值转换为字符串&#xff1a; long long value 1234567890123456789LL; …...

Map相关知识

数据结构 二叉树 二叉树&#xff0c;顾名思义&#xff0c;每个节点最多有两个“叉”&#xff0c;也就是两个子节点&#xff0c;分别是左子 节点和右子节点。不过&#xff0c;二叉树并不要求每个节点都有两个子节点&#xff0c;有的节点只 有左子节点&#xff0c;有的节点只有…...

如何理解 IP 数据报中的 TTL?

目录 前言理解 前言 面试灵魂一问&#xff1a;说说对 IP 数据报中 TTL 的理解&#xff1f;我们都知道&#xff0c;IP 数据报由首部和数据两部分组成&#xff0c;首部又分为两部分&#xff1a;固定部分和可变部分&#xff0c;共占 20 字节&#xff0c;而即将讨论的 TTL 就位于首…...

MySQL 知识小结(一)

一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库&#xff0c;分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷&#xff0c;但是文件存放起来数据比较冗余&#xff0c;用二进制能够更好管理咱们M…...

scikit-learn机器学习

# 同时添加如下代码, 这样每次环境(kernel)启动的时候只要运行下方代码即可: # Also add the following code, # so that every time the environment (kernel) starts, # just run the following code: import sys sys.path.append(/home/aistudio/external-libraries)机…...

人工智能--安全大模型训练计划:基于Fine-tuning + LLM Agent

安全大模型训练计划&#xff1a;基于Fine-tuning LLM Agent 1. 构建高质量安全数据集 目标&#xff1a;为安全大模型创建高质量、去偏、符合伦理的训练数据集&#xff0c;涵盖安全相关任务&#xff08;如有害内容检测、隐私保护、道德推理等&#xff09;。 1.1 数据收集 描…...

Visual Studio Code 扩展

Visual Studio Code 扩展 change-case 大小写转换EmmyLua for VSCode 调试插件Bookmarks 书签 change-case 大小写转换 https://marketplace.visualstudio.com/items?itemNamewmaurer.change-case 选中单词后&#xff0c;命令 changeCase.commands 可预览转换效果 EmmyLua…...

【免费数据】2005-2019年我国272个地级市的旅游竞争力多指标数据(33个指标)

旅游业是一个城市的重要产业构成。旅游竞争力是一个城市竞争力的重要构成部分。一个城市的旅游竞争力反映了其在旅游市场竞争中的比较优势。 今日我们分享的是2005-2019年我国272个地级市的旅游竞争力多指标数据&#xff01;该数据集源自2025年4月发表于《地理学报》的论文成果…...

【PX4飞控】mavros gps相关话题分析,经纬度海拔获取方法,卫星数锁定状态获取方法

使用 ROS1-Noetic 和 mavros v1.20.1&#xff0c; 携带经纬度海拔的话题主要有三个&#xff1a; /mavros/global_position/raw/fix/mavros/gpsstatus/gps1/raw/mavros/global_position/global 查看 mavros 源码&#xff0c;来分析他们的发布过程。发现前两个话题都对应了同一…...