【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

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

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

相关文章

Windows编程之多线程事件对象(Event Object)用法详解

目录 一、前言 二、基础用法 三、API详解 1.创建事件对象 2控制事件状态 3.等待事件对象&#xff1a; 四、实战案例 1.案例描述 2.代码设计 3.总设计代码 4.运行结果 一、前言 事件对象&#xff08;Event Object&#xff09;是我们在大型项目中&#xff0c;进行多线…

竞赛选题 医学大数据分析 - 心血管疾病分析

文章目录 1 前言1 课题背景2 数据处理3 数据可视化4 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于大数据的心血管疾病分析 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f9…

AI绘画Stable Diffusion 解锁精美壁纸创作:利用SD与LLM定制你的专属壁纸,AI副业变现指南!

大家好&#xff0c;我是画画的小强 今天给大家分享一下用AI绘画Stable Diffusion 制作精美手机壁纸&#xff0c;这也可能是当前最快AIGC变现的一种途径。虽然本文的主题为手机壁纸&#xff0c;当调整不同的比例的分辨率宽高比例&#xff0c;就可以直接复用到手机、电脑和平板、…

机器学习原理之 -- 支持向量机分类:由来及原理详解

支持向量机&#xff08;Support Vector Machine, SVM&#xff09;是统计学习理论的一个重要成果&#xff0c;广泛应用于分类和回归问题。SVM以其高效的分类性能和良好的泛化能力在机器学习领域中占据重要地位。本文将详细介绍支持向量机的由来、基本原理、构建过程及其优缺点。…

LVS负载均衡群集部署之——DR模式的介绍及搭建步骤

一、LVS-DR集群介绍1.1 LVS-DR 工作原理1.2 数据包流向分析1.3 LVS-DR 模式的特点1.4 LVS-DR中的ARP问题1.4.1 问题一1.4.2 问题二二、构建LVS-DR集群2.1 构建LVS-DR集群的步骤&#xff08;理论&#xff09;1.配置负载调度器&#xff08;192.168.80.30&#xff09;&#xff08;…

5分钟教你用AI把老照片动起来,别再去花49块9的冤枉钱了

文章目录 需要的工具 最近&#xff0c;AI视频在各大平台上&#xff0c;又火了。 只是火的形式&#xff0c;变成了将老照片动起来&#xff0c;打情感牌&#xff0c;或者做很多经典电视剧的再整活。 直接把可灵的生成时间&#xff0c;从以前的4分钟&#xff0c;生生的干成了20分钟…

鸿蒙应用笔记

安装就跳过了&#xff0c;一直点点就可以了 配置跳过&#xff0c;就自动下了点东西。 鸿蒙那个下载要12g个内存&#xff0c;大的有点吓人。 里面跟idea没区别 模拟器或者真机运行 真机要鸿蒙4.0&#xff0c;就可以实机调试 直接在手机里面跑&#xff0c;这个牛逼&#xf…

国标GB/T 28181详解:国标GBT28181-2022 SIP服务器发起广播的命令流程

目录 一、定义 二、作用 1、实现信息的集中管理和分发 &#xff08;1&#xff09;信息集中 &#xff08;2&#xff09;信息分发 2、提高信息传输的可靠性和效率 &#xff08;1&#xff09;可靠性 &#xff08;2&#xff09;提高效率 3、支持多种设备和系统的互通 &am…

mongdb学习与使用

1. 基础概念 MongoDB简介&#xff1a; MongoDB是一个基于文档的NoSQL数据库&#xff0c;具有高性能、高可用性和易扩展性。数据存储在类似JSON的BSON格式中。 基本术语&#xff1a; Database&#xff08;数据库&#xff09;&#xff1a; 集合的容器。Collection&#xff08;集合…

国产强大免费WAF, 社区版雷池动态防护介绍

雷池WAF&#xff0c;基于智能语义分析的下一代 Web 应用防火墙 使用情况 我司于2023年4月23日对雷池进行测试&#xff0c;测试一个月后&#xff0c;于2023年5月24日对雷池进行正式切换&#xff0c;此时版本为1.5.1。 里程碑纪念 后续一直跟随雷池进行版本升级&#xff0c;当前…

QT_GUI

1、QT安装 一个跨平台的应用程序和用户界面框架&#xff0c;用于开发图形用户界面&#xff08;GUI&#xff09;应用程序以及命令行工具。QT有商业版额免费开源版&#xff0c;一般使用免费开源版即可&#xff0c;下面安装的是QT5&#xff0c;因为出来较早&#xff0c;使用较多&…

Python特征工程 — 1.4 特征归一化方法详解

目录 1 Min-Max归一化 方法1&#xff1a;自定义的Min-Max归一化封装函数 方法2&#xff1a; scikit-learn库中的MinMaxScaler 2 Z-score归一化 方法1&#xff1a;自定义的Z-score归一化封装函数 方法2&#xff1a; scikit-learn库中的StandardScaler 3 最大值归一化 4 L…

考研生活day1--王道课后习题2.2.1、2.2.2、2.2.3

2.2.1 题目描述&#xff1a; 解题思路&#xff1a; 这是最基础的操作&#xff0c;思路大家应该都有&#xff0c;缺少的应该是如何下笔&#xff0c;很多同学都是有思路但是不知道如何下笔&#xff0c;这时候看思路的意义不大&#xff0c;可以直接看答案怎么写&#xff0c;最好…

Java项目:基于SSM框架实现的游戏攻略网站系统分前后台【ssm+B/S架构+源码+数据库+毕业论文+任务书】

一、项目简介 本项目是一套基于SSM框架实现的游戏攻略网站系统 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;eclipse或者idea 确保可以运行&#xff01; 该系统功能完善、界面美观、操作简单、功能…

redhat7.x 升级openssh至openssh-9.8p1

1.环境准备&#xff1a; OS系统&#xff1a;redhat 7.4 2.备份配置文件&#xff1a; cp -rf /etc/ssh /etc/ssh.bak cp -rf /usr/bin/openssl /usr/bin/openssl.bak cp -rf /etc/pam.d /etc/pam.d.bak cp -rf /usr/lib/systemd/system /usr/lib/systemd/system.bak 3.安装…

UB9A0全系统全频高精度板卡性能指标

UB9A0 板卡是基于和芯星通自主研发的新一代射频基带及高精度算法一体化 GNSS SoC 芯片—Nebulas Ⅳ开发的全系统全频点高精 OEM 板卡 &#xff0c;支持 BDS&#xff0c;GPS&#xff0c; GLONASS&#xff0c;Galileo&#xff0c;QZSS&#xff0c;NavIC&#xff0c;SBAS&#xff…

MySQL环境搭配

下载版本37滴 下载第二个 之后进行安装 进入安装界面 next 选择默认的 进行下一步 安装成功后&#xff0c;进行一系列配置&#xff0c;成功界面如下&#xff1a; 配置 MySQL8.0 环境变量 如果不配置 MySQL 环境变量&#xff0c;就不能在命令行直接输入 MySQL 登录命令。 步…

强烈推荐!12 组超惊艳的 Midjourney 风格提示词!

前言 Midjourney 的 --sref random 随机风格功能推出之后&#xff0c;出现了很多对不同代码生成效果的探索。今天就为大家推荐 12 组我觉得非常惊艳的风格代码&#xff0c;将它们添加在提示词中&#xff0c;不需要写复杂的关键词就能得到高质量的指定风格&#xff0c;并且效果…

CUDA编译配置中来自 CUDA 12.1.targets 的MSB3721错误和核函数调用语法错误‘<’解决及可用的代码示例框架

今天开始整cuda编程处理图像&#xff0c;好久没玩cuda&#xff0c;又从小白开始。情况不妙&#xff0c;第一个工程坑不少&#xff0c;记录一下如下2个重要的错误&#xff1a; &#xff08;1&#xff09;来自 CUDA 12.1.targets 的MSB3721错误 错误 命令““C:\Program Files\N…

Scrapy框架的基本使用教程

1、创建scrapy项目 首先在自己的跟目录文件下执行命令&#xff1a; PS D:\BCprogram\python_pro\bigdata> scrapy startproject theridion_grallatorscrapy startproject 项目名 具体执行操作如下&#xff1a;1、创建项目目录&#xff1a;Scrapy会在当前工作目录下创建一…