【FFmpeg实战】音频重采样

news2024/11/26 10:26:52

转载自原文地址: https://www.cnblogs.com/zjacky/p/16529648.html

重采样:

将音频进行SDL播放的时候,因为当前的SDL2.0不支持plannar格式,也不支持浮点型的,而最新的FFpemg会将音频解码为AV_SAMPLE_FMT_FLTP,这个时候进行对它重采样的话,就可以在SDL2.0上进行播放这个音频了。

重采样参数

1、sample rate(采样率):采样设备每秒抽取样本的次数

2、sample format(采样格式)和量化精度:每种⾳频格式有不同的量化精度(位宽),位数越多,表示值就越精确,声⾳表现⾃然就越精准。

3、channel layout(通道布局,也就是声道数):这个就是采样的声道数

在FFmpeg里面主要有两种采样格式:floating-point formats 和 planar sample formats;具体采样参数如下(在(libavutil/samplefmt.h头文件里面):

enum AVSampleFormat {
    AV_SAMPLE_FMT_NONE = -1,
    AV_SAMPLE_FMT_U8,          ///< unsigned 8 bits
    AV_SAMPLE_FMT_S16,         ///< signed 16 bits
    AV_SAMPLE_FMT_S32,         ///< signed 32 bits
    AV_SAMPLE_FMT_FLT,         ///< float
    AV_SAMPLE_FMT_DBL,         ///< double

    AV_SAMPLE_FMT_U8P,         ///< unsigned 8 bits, planar
    AV_SAMPLE_FMT_S16P,        ///< signed 16 bits, planar
    AV_SAMPLE_FMT_S32P,        ///< signed 32 bits, planar
    AV_SAMPLE_FMT_FLTP,        ///< float, planar
    AV_SAMPLE_FMT_DBLP,        ///< double, planar
    AV_SAMPLE_FMT_S64,         ///< signed 64 bits
    AV_SAMPLE_FMT_S64P,        ///< signed 64 bits, planar

    AV_SAMPLE_FMT_NB           ///< Number of sample formats. DO NOT USE if linking dynamically
};

说明:

1.U8(无符号整型8bit)、S16(整型16bit)、S32(整型32bit)、FLT(单精度浮点类型)、DBL(双精度浮点类型)、S64(整型64bit),不以P为结尾的都是interleaved(packed)结构,以P为结尾的是planar结构。

2.Planar模式是FFmpeg内部存储模式,我们实际使用的音频文件都是Packed模式的。

3.FFmpeg解码不同格式的音频输出的音频采样格式不是一样。测试发现,其中AAC解码输出的数据为浮点型的 AV_SAMPLE_FMT_FLTP 格式,MP3解码输出的数据为 AV_SAMPLE_FMT_S16P 格式(使用的mp3文件为16位深)。具体采样格式可以查看解码后的AVFrame中的 format 成员或解码器的AVCodecContext中的 sample_fmt 成员。

还有就是声道分布参数,这个在FFmpeg也有说明(声道分布在FFmpeg\libavutil\channel_layout.h中有定义,⼀般来说⽤的⽐较多的是 AV_CH_LAYOUT_STEREO(双声道)和AV_CH_LAYOUT_SURROUND(三声道),这两者的定义如下):

#define AV_CH_LAYOUT_STEREO (AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT) 

#define AV_CH_LAYOUT_SURROUND (AV_CH_LAYOUT_STEREO|AV_CH_FRONT_CENTER)

FFmpeg重采样流程

重采样的处理流程: 1、创建上下文环境:重采样过程上下文环境为SwrContext数据结构。 2、参数设置:转换的参数设置到SwrContext中。SwrContext初始化:swr_init()。 3、分配样本数据内存空间:使用av_samples_alloc_array_and_samples、av_samples_alloc等工具函数。 4、开启重采样转换:通过重复地调用swr_convert来完成。 5、重采样转换完成, 释放相关资源:通过swr_free()释放SwrContext。

流程图如下:

img

编辑

添加图片注释,不超过 140 字(可选)

FFmpeg重采样流程(方法二)(采用swr_convert_frame()进行重采样)

重采样的处理流程: 1、创建上下文环境:重采样过程上下文环境为SwrContext数据结构。(和上面一样) 2、参数设置:转换的参数设置到SwrContext中。SwrContext初始化:swr_init()。 3、直接采用swr_convert_frame()对输入帧和输出帧进行重采样。(不需要提前申请空间,详细看函数介绍) 4、重采样转换完成, 释放相关资源:通过swr_free()释放SwrContext。

FFmpeg采样流程相关api介绍

【第一】音频重采样上下文——结构体SwrContext

【结构声明】

struct SwrContext {
    const AVClass *av_class;                        ///< AVClass used for AVOption and av_log()
    int log_level_offset;                           ///< logging level offset
    void *log_ctx;                                  ///< parent logging context
    enum AVSampleFormat  in_sample_fmt;             ///< input sample format
    enum AVSampleFormat int_sample_fmt;             ///< internal sample format (AV_SAMPLE_FMT_FLTP or AV_SAMPLE_FMT_S16P)
    enum AVSampleFormat out_sample_fmt;             ///< output sample format
    int64_t  in_ch_layout;                          ///< input channel layout
    int64_t out_ch_layout;                          ///< output channel layout
    int      in_sample_rate;                        ///< input sample rate
    int     out_sample_rate;                        ///< output sample rate
    int flags;                                      ///< miscellaneous flags such as SWR_FLAG_RESAMPLE
    float slev;                                     ///< surround mixing level
    float clev;                                     ///< center mixing level
    float lfe_mix_level;                            ///< LFE mixing level
    float rematrix_volume;                          ///< rematrixing volume coefficient
    float rematrix_maxval;                          ///< maximum value for rematrixing output
    int matrix_encoding;                            /**< matrixed stereo encoding */
    const int *channel_map;                         ///< channel index (or -1 if muted channel) map
    int used_ch_count;                              ///< number of used input channels (mapped channel count if channel_map, otherwise in.ch_count)
    int engine;

    int user_in_ch_count;                           ///< User set input channel count
    int user_out_ch_count;                          ///< User set output channel count
    int user_used_ch_count;                         ///< User set used channel count
    int64_t user_in_ch_layout;                      ///< User set input channel layout
    int64_t user_out_ch_layout;                     ///< User set output channel layout
    enum AVSampleFormat user_int_sample_fmt;        ///< User set internal sample format
    int user_dither_method;                         ///< User set dither method

    struct DitherContext dither;

    int filter_size;                                /**< length of each FIR filter in the resampling filterbank relative to the cutoff frequency */
    int phase_shift;                                /**< log2 of the number of entries in the resampling polyphase filterbank */
    int linear_interp;                              /**< if 1 then the resampling FIR filter will be linearly interpolated */
    int exact_rational;                             /**< if 1 then enable non power of 2 phase_count */
    double cutoff;                                  /**< resampling cutoff frequency (swr: 6dB point; soxr: 0dB point). 1.0 corresponds to half the output sample rate */
    int filter_type;                                /**< swr resampling filter type */
    double kaiser_beta;                                /**< swr beta value for Kaiser window (only applicable if filter_type == AV_FILTER_TYPE_KAISER) */
    double precision;                               /**< soxr resampling precision (in bits) */
    int cheby;                                      /**< soxr: if 1 then passband rolloff will be none (Chebyshev) & irrational ratio approximation precision will be higher */

    float min_compensation;                         ///< swr minimum below which no compensation will happen
    float min_hard_compensation;                    ///< swr minimum below which no silence inject / sample drop will happen
    float soft_compensation_duration;               ///< swr duration over which soft compensation is applied
    float max_soft_compensation;                    ///< swr maximum soft compensation in seconds over soft_compensation_duration
    float async;                                    ///< swr simple 1 parameter async, similar to ffmpegs -async
    int64_t firstpts_in_samples;                    ///< swr first pts in samples

    int resample_first;                             ///< 1 if resampling must come first, 0 if rematrixing
    int rematrix;                                   ///< flag to indicate if rematrixing is needed (basically if input and output layouts mismatch)
    int rematrix_custom;                            ///< flag to indicate that a custom matrix has been defined

    AudioData in;                                   ///< input audio data
    AudioData postin;                               ///< post-input audio data: used for rematrix/resample
    AudioData midbuf;                               ///< intermediate audio data (postin/preout)
    AudioData preout;                               ///< pre-output audio data: used for rematrix/resample
    AudioData out;                                  ///< converted output audio data
    AudioData in_buffer;                            ///< cached audio data (convert and resample purpose)
    AudioData silence;                              ///< temporary with silence
    AudioData drop_temp;                            ///< temporary used to discard output
    int in_buffer_index;                            ///< cached buffer position
    int in_buffer_count;                            ///< cached buffer length
    int resample_in_constraint;                     ///< 1 if the input end was reach before the output end, 0 otherwise
    int flushed;                                    ///< 1 if data is to be flushed and no further input is expected
    int64_t outpts;                                 ///< output PTS
    int64_t firstpts;                               ///< first PTS
    int drop_output;                                ///< number of output samples to drop
    double delayed_samples_fixup;                   ///< soxr 0.1.1: needed to fixup delayed_samples after flush has been called.

    struct AudioConvert *in_convert;                ///< input conversion context
    struct AudioConvert *out_convert;               ///< output conversion context
    struct AudioConvert *full_convert;              ///< full conversion context (single conversion for input and output)
    struct ResampleContext *resample;               ///< resampling context
    struct Resampler const *resampler;              ///< resampler virtual function table

    double matrix[SWR_CH_MAX][SWR_CH_MAX];          ///< floating point rematrixing coefficients
    float matrix_flt[SWR_CH_MAX][SWR_CH_MAX];       ///< single precision floating point rematrixing coefficients
    uint8_t *native_matrix;
    uint8_t *native_one;
    uint8_t *native_simd_one;
    uint8_t *native_simd_matrix;
    int32_t matrix32[SWR_CH_MAX][SWR_CH_MAX];       ///< 17.15 fixed point rematrixing coefficients
    uint8_t matrix_ch[SWR_CH_MAX][SWR_CH_MAX+1];    ///< Lists of input channels per output channel that have non zero rematrixing coefficients
    mix_1_1_func_type *mix_1_1_f;
    mix_1_1_func_type *mix_1_1_simd;

    mix_2_1_func_type *mix_2_1_f;
    mix_2_1_func_type *mix_2_1_simd;

    mix_any_func_type *mix_any_f;

    /* TODO: callbacks for ASM optimizations */
};

比较重要的参数: + 采样格式 + 声道类型

【结构体定义和申请空间】

SwrContext* audio_convert_ctx = NULL;
audio_convert_ctx = swr_alloc();

【第二】上下文结构体参数设置

参数设置有两种方式: 【方法一】:采用AVOptions的api,举例如下

av_opt_set_channel_layout(audio_convert_ctx, "in_channel_layout", AV_CH_LAYOUT_5POINT1, 0);
av_opt_set_channel_layou(audio_convert_ctx, "out_channel_layout", AV_CH_LAYOUT_STEREO, 0);
av_opt_set_int(audio_convert_ctx, "in_sample_rate", 44100, 0);
av_opt_set_int(audio_convert_ctx, "out_sample_rate", 16000, 0);
av_opt_set_sample_fmt(audio_convert_ctx, "in_sample_fmt", AV_SAMPLE_FMT_FLPT, 0);
av_opt_set_sample_fmt(audio_convert_ctx, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);

【方法二】:采用swr_alloc_set_opts():如果第一个参数为NULL则创建一个新的SwrContext,否则对已有的SwrContext进行参数设置。

struct SwrContext *swr_alloc_set_opts(struct SwrContext *s, // ⾳频重采样上下⽂ 
int64_t out_ch_layout, // 输出的layout, 如:5.1声道 
enum AVSampleFormat out_sample_fmt, // 输出的采样格式。
Float, S16,⼀般 选⽤是s16 绝⼤部分声卡⽀持 
int out_sample_rate, //输出采样率 
int64_t in_ch_layout, // 输⼊的layout 
enum AVSampleFormat in_sample_fmt, // 输⼊的采样格式 
int in_sample_rate, // 输⼊的采样率 
int log_offset, // ⽇志相关,不⽤管先,直接为0 void *log_ctx // ⽇志相关,不⽤管先,直接为NULL 
);

【第三】初始化SwrContext结构体

参数设置好之后必须调用swr_init()对SwrContext进行初始化。

int swr_init(struct SwrContext *s);

如果需要修改转换的参数:

  • 1、重新进行参数设置。
  • 2、再次调用swr_init()。

【第四】分配采样内存空间

转换之前需要分配内存空间用于保存重采样的输出数据,内存空间的大小跟通道个数、样本格式需要、容纳的样本个数都有关系。主要有两种方式: 【方式一】:输出目标是Frame->data 采用av_frame_get_buffer()函数,举例如下:

AVFrame* pFrame_new;
			pFrame_new = av_frame_alloc();
			pFrame_new->channel_layout = audio_decodec_ctx->channel_layout;
			pFrame_new->channels = av_get_channel_layout_nb_channels(audio_decodec_ctx->channel_layout);
			pFrame_new->format = t->inner_sample_format;
			pFrame_new->sample_rate = t->inner_sample_rate;
			int64_t nb_samples = av_rescale_rnd(pFrame->nb_samples, pFrame_new->sample_rate, pFrame->sample_rate, AV_ROUND_UP);
			pFrame_new->nb_samples = nb_samples; //该帧采样点数
			av_frame_get_buffer(pFrame_new, 0);
			pFrame_new->pts = av_rescale_rnd(pFrame->pts, pFrame_new->sample_rate, pFrame->sample_rate, AV_ROUND_UP);

【方式二】:输出目标直接是内存空间

libavutil中的samples处理API提供了一些函数方便管理样本数据,例如av_samples_alloc()函数用于分配存储sample的buffer。

/**
 * @param[out] audio_data  输出数组,每个元素是指向一个通道的数据的指针。
 * @param[out] linesize    aligned size for audio buffer(s), may be NULL
 * @param nb_channels      通道的个数。
 * @param nb_samples       每个通道的样本个数。
 * @param align            buffer size alignment (0 = default, 1 = no alignment)
 * @return                 成功返回大于0的数,错误返回负数。
 */
int av_samples_alloc(uint8_t **audio_data, int *linesize, int nb_channels,
                     int nb_samples, enum AVSampleFormat sample_fmt, int align);

也有计算所需内存空间的函数av_samples_get_buffer_size()

/*
 *获取给定音频参数所需的缓冲区大小。
 * @param [out] linesize计算的lineize,可能为NULL
 * @param nb_channels频道数
 * @param nb_samples单个通道中的样本数
 * @param sample_fmt样本格式
 * @param对齐缓冲区大小对齐(0 =默认,1 =无对齐)
 * @return需要缓冲区大小,或失败时出现负错误代码
*/
int av_samples_get_buffer_size(int *linesize, int nb_channels, int nb_samples,
                               enum AVSampleFormat sample_fmt, int align);

【第五-1】将输⼊的⾳频按照定义的参数进⾏转换并输出 Swr_convert()

【函数定义】

int swr_convert(struct SwrContext *s, // ⾳频重采样的上下⽂ 
uint8_t **out, // 输出的指针。传递的输出的数组(frame的数据指针)
int out_count, //输出缓冲区每通道样本数据数量(对于音频,每个通道数据长度都相同),注意这里不是以字节为单位
const uint8_t **in , //输⼊的数组,AVFrame解码出来的DATA
int in_count // 输⼊的单通道的样本数量。这里填入frame->nb_samples即可
);

【函数说明】

0、返回值:转换成功后每个通道的输出样本数,出错则为负值

1、如果没有提供足够的空间用于保存输出数据,采样数据会缓存在swr中。可以通过 swr_get_out_samples()来获取下一次调用swr_convert在给定输入样本数量下输出样本数量的上限,来提供足够的空间。

2、如果是采样频率转换,转换完成后采样数据可能会缓存在swr中,它期待你提供更多的输入数据。

3、如果实际上并不需要更多输入数据,通过调用swr_convert(),其中参数in_count设置为0来获取缓存在swr中的数据。

4、转换结束之后需要冲刷swr_context的缓冲区,通过调用swr_convert(),其中参数in设置为NULL,参数in_count设置为0。 注释里面有一句: in and in_count can be set to 0 to flush the last few samples out at the end.

【举例】

ret = swr_convert(audio_convert_ctx, 
				&outBuff, nb_samples,
				(const uint8_t**)audio_frame->data, audio_frame->nb_samples);
			while (ret > 0) {	// 把最后几个样本冲洗出来
				ret = swr_convert(audio_convert_ctx, &outBuff, nb_samples,
					NULL, 0);
			}

【第五-2】采用swr_convert_frame() 输入输出帧的转换

【函数定义】

int swr_convert_frame(SwrContext *swr,
                      AVFrame *output, const AVFrame *input);

【参数说明】 输入:

  • swr:重采样上下文结构体
  • output:输出帧
  • input:输入帧 输出:
  • 0 成功,AVERROR 失败或不匹配的配置。

【函数说明】

  • 转换输入 AVFrame 中的样本,并将其写入输出 AVFrame。
  • 输入和输出 AVFrames 必须设置 channel_layout、sample_rate 和 format。
  • 如果输出 AVFrame 没有分配数据指针,则将自动调用 av_frame_get_buffer() 来设置 nb_samples 字段以分配帧。
  • 输出的 AVFrame 可以为 NULL 或分配的样本少于所需的样本。在这种情况下,任何未写入输出的剩余样本将被添加到内部 FIFO 缓冲区,以在下次调用此函数或 swr_convert() 时返回。
  • 如果转换采样率,内部重采样延迟缓冲区中可能有剩余数据。 swr_get_delay() 告诉剩余样本的数量。要将此数据作为输出,请使用 NULL 输入调用此函数或 swr_convert()。
  • 如果 SwrContext 配置与输出和输入 AVFrame 设置不匹配,则不会进行转换,取决于哪个 AVFrame 不匹配 AVERROR_OUTPUT_CHANGED、AVERROR_INPUT_CHANGED 或它们的按位或结果。

【第六】释放资源

首先释放内存(frame->data可以通过av_frame_free()时释放):

av_freep(outBuffer);

在所有转换完成之后,释放上下文:

void swr_free(struct SwrContext **s)

音频重采样,采样格式转换和混合库

//
// 音频帧格式转换
//
int32_t AudioConvert(
  const AVFrame* pInFrame,      // 输入音频帧
  AVSampleFormat eOutSmplFmt,   // 输出音频格式
  int32_t        nOutChannels,  // 输出音频通道数 
  int32_t        nOutSmplRate,  // 输出音频采样率
  AVFrame**      ppOutFrame)    // 输出视频帧
{
  struct SwrContext* pSwrCtx   = nullptr;
  AVFrame*           pOutFrame = nullptr;


  // 创建格式转换器,
  int64_t nInChnlLayout  = av_get_default_channel_layout(pInFrame->channels);
  int64_t nOutChnlLayout = (nOutChannels == 1) ? AV_CH_LAYOUT_MONO : AV_CH_LAYOUT_STEREO;

  pSwrCtx = swr_alloc();
  if (pSwrCtx == nullptr)
  {
    LOGE("<AudioConvert> [ERROR] fail to swr_alloc()\n");
    return -1;
  }
  swr_alloc_set_opts(pSwrCtx, 
                      nOutChnlLayout, eOutSmplFmt, nOutSmplRate, nInChnlLayout, 
                      (enum AVSampleFormat)(pInFrame->format), pInFrame->sample_rate, 
                      0, nullptr  );


  // 计算重采样转换后的样本数量,从而分配缓冲区大小
  int64_t nCvtBufSamples    = av_rescale_rnd(pInFrame->nb_samples, nOutSmplRate, pInFrame->sample_rate, AV_ROUND_UP);

  // 创建输出音频帧
  pOutFrame                 = av_frame_alloc();
  pOutFrame->format         = eOutSmplFmt;
  pOutFrame->nb_samples     = (int)nCvtBufSamples;
  pOutFrame->channel_layout = (uint64_t)nOutChnlLayout;
  int res                   = av_frame_get_buffer(pOutFrame, 0); // 分配缓冲区
  if (res < 0)
  {
    LOGE("<AudioConvert> [ERROR] fail to av_frame_get_buffer(), res=%d\n", res);
    swr_free(&pSwrCtx);
    av_frame_free(&pOutFrame);
    return -2;
  }


  // 进行重采样转换处理,返回转换后的样本数量
  int nCvtedSamples = swr_convert(pSwrCtx,
                                  const_cast<uint8_t**>(pOutFrame->data),
                                  (int)nCvtBufSamples,
                                  const_cast<const uint8_t**>(pInFrame->data),
                                  pInFrame->nb_samples);
  if (nCvtedSamples <= 0)
  {
    LOGE("<AudioConvert> [ERROR] no data for swr_convert()\n");
    swr_free(&pSwrCtx);
    av_frame_free(&pOutFrame);
    return -3;
  }
  pOutFrame->nb_samples = nCvtedSamples;
  pOutFrame->pts        = pInFrame->pts;      // pts等时间戳沿用
  pOutFrame->pkt_pts    = pInFrame->pkt_pts;

  (*ppOutFrame) = pOutFrame;
  swr_free(&pSwrCtx); // 释放转换器
  return 0;
}

delay

@ see swr_delay() @ see swr_convert() @ see swr_get_delay()

补充

channels 和 channel_layout 是啥

channels  为 音频的 通道数 1 2 3 4 5.....
channel_layout  为音频 通道格式类型 如 单通道 双通道 .....

相互之间获取

av_get_channel_layout_nb_channels()
av_get_default_channel_layout()

对应关系

channel_layout_map[]
	{ "mono",        1,  AV_CH_LAYOUT_MONO },
    { "stereo",      2,  AV_CH_LAYOUT_STEREO },
    { "2.1",         3,  AV_CH_LAYOUT_2POINT1 },
    { "3.0",         3,  AV_CH_LAYOUT_SURROUND },
    { "3.0(back)",   3,  AV_CH_LAYOUT_2_1 },
    { "4.0",         4,  AV_CH_LAYOUT_4POINT0 },
    { "quad",        4,  AV_CH_LAYOUT_QUAD },
    { "quad(side)",  4,  AV_CH_LAYOUT_2_2 },
    { "3.1",         4,  AV_CH_LAYOUT_3POINT1 },
    { "5.0",         5,  AV_CH_LAYOUT_5POINT0_BACK },
    { "5.0(side)",   5,  AV_CH_LAYOUT_5POINT0 },
    { "4.1",         5,  AV_CH_LAYOUT_4POINT1 },
    { "5.1",         6,  AV_CH_LAYOUT_5POINT1_BACK },
    { "5.1(side)",   6,  AV_CH_LAYOUT_5POINT1 },
    { "6.0",         6,  AV_CH_LAYOUT_6POINT0 },
    { "6.0(front)",  6,  AV_CH_LAYOUT_6POINT0_FRONT },
    { "hexagonal",   6,  AV_CH_LAYOUT_HEXAGONAL },
    { "6.1",         7,  AV_CH_LAYOUT_6POINT1 },
    { "6.1",         7,  AV_CH_LAYOUT_6POINT1_BACK },
    { "6.1(front)",  7,  AV_CH_LAYOUT_6POINT1_FRONT },
    { "7.0",         7,  AV_CH_LAYOUT_7POINT0 },
    { "7.0(front)",  7,  AV_CH_LAYOUT_7POINT0_FRONT },
    { "7.1",         8,  AV_CH_LAYOUT_7POINT1 },
    { "7.1(wide)",   8,  AV_CH_LAYOUT_7POINT1_WIDE },
    { "octagonal",   8,  AV_CH_LAYOUT_OCTAGONAL },
    { "downmix",     2,  AV_CH_LAYOUT_STEREO_DOWNMIX, },
>>> 音视频开发 视频教程: https://ke.qq.com/course/3202131?flowToken=1031864 
>>> 音视频开发学习资料、教学视频,免费分享有需要的可以自行添加学习交流群: 739729163  领取

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

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

相关文章

LORA模型原理详解+分层控制使用

一、前言 LoRA模型全称是&#xff1a;Low-Rank Adaptation of Large Language Models&#xff0c;可以理解为Stable-Diffusion中的一个插件&#xff0c;仅需要少量的数据就可以进行训练的一种模型。在生成图片时&#xff0c;LoRA模型会与大模型结合使用&#xff0c;从而实现对…

一张SSL证书支持绑定多个域名吗?

一张SSL证书可支持绑定多个不同类型的域名&#xff0c;选择多域名SSL证书&#xff08;SAN SSL&#xff09;或通配符SSL证书&#xff08;Wildcard SSL&#xff09;类型&#xff0c;就可以实现一张SSL证书绑定多个域名&#xff0c;但绑定的域名类型有些不同。 1、多域名SSL证书&a…

Golang语言介绍、环境搭建以及编译工具( CDN 加速代理)

Go 语言是非常有潜力的语言&#xff0c;是因为它的应用场景是目前互联网非常热门的几个领域&#xff0c;比如 WEB 开发、区块链开发、大型游戏服务端开发、分布式/云计算开发。国内比较知名的B 站就是用 Go 语言开发的&#xff0c;像 Goggle、阿里、京东、百度、腾讯、小米、36…

人工智能开发人员工作流程、看法、工具统计数据

人工智能开发人员工作流程、看法、工具统计数据 本文目录&#xff1a; 一、人工智能开发所需要的技能和知识 二、开发人工智能需要以下工具 2.1、开发过程中的人工智能工具调查 2.2、AI 工具情绪调查 2.3、AI 工具的优势调查 2.4、人工智能工具的准确性调查 2.5、开发工…

rails console (SQL)查找语句

find可以查找一个 where可以查找多个

Flink DataStream之从集合/文件读数据

从集合中读数据方式一 package test01;import org.apache.flink.api.common.eventtime.WatermarkStrategy; import org.apache.flink.connector.file.src.FileSource; import org.apache.flink.connector.file.src.reader.TextLineInputFormat; import org.apache.flink.core.…

牛客·轻拍牛头

b[i]:输入 a[i]:计数 c[i]:答案void solve() {cin>>n;for(int i0;i<n;i){cin>>b[i];a[b[i]];}for(int i1;i<NN;i){if(a[i]){for(int ji;j<NN;ji)c[j]a[i];}}for(int i0;i<n;i){cout<<c[b[i]]-1<<\n;} }

【深度学习】contrastive loss与triplet loss

自己总结一下&#xff0c; 三元组如果正负样本足够开&#xff0c;距离足够远&#xff0c;loss为0&#xff0c;因为模型已经学的不错了&#xff0c;不需要继续学习。 最好的负样本是&#xff0c;model预测负样本的把握不太大的。 如果负样本是很难分的&#xff0c;例如d(a,p)>…

数据结构:Mysql索引原理(通俗易懂)

目录 前言正文索引结构-数组无序数组有序数组 索引数据结构-HashHash冲突-链式寻址法Hash冲突-再哈希法Hash冲突-开放地址法 索引数据结构-树二叉树平衡二叉树红黑树红黑树的特性红黑树如何减少旋转 B树B树 Mysql的索引一级索引二级索引 总结 前言 在工作中如果经常写业务代码…

信号链噪声分析4

目录 概要 整体架构流程 技术名词解释 技术细节 5.计算信号链的噪声 噪声谱密度 重点注意事项 有源滤波器配置 小结 概要 提示&#xff1a;这里可以添加技术概要 本文介绍对高速宽带宽信号链进行噪声性能理论分析的各个步骤。尽管选择了一个特 定信号链&#xff0c;…

传统商超巨头折戟即时零售

今年的618&#xff0c;包含沃尔玛、永辉、大润发、华润、物美、麦德龙、盒马、联华、家家悦、中百、华联在内10大商超巨头都集体“失声”了。 值得注意的是&#xff0c;今年618不仅各大商超没有公布相关数据&#xff0c;且在所有即时零售平台中&#xff0c;仅有商超到家的合作…

怎么用postman进行自动化接口测试,终于学到了

​ 目录 背景描述 创建一个GET请求 在pre-request scripts构建签名 脚本写在环境变量中 postman console的用法 Collection Runner 自动化API测试 创建接口的测试用例 选择并运行自动化接口测试 测试结果 总结&#xff1a; 背景描述 有一个项目要使用postman进行接…

元宇宙虚拟人物3d建模贯穿产业链数字化转型全链条

随着5G、AI、VR/AR、区块链、云计算、脑机等技术的发展&#xff0c;给构建这个虚拟的宇宙提供了技术支撑。今年以来&#xff0c;因为疫情等原因&#xff0c;大众在虚拟空间停留的时间变得更长&#xff0c;元宇宙概念重新火热。 元宇宙虚拟人的基本特征包括&#xff1a; 沉浸式体…

Android hook、检测及对抗相关

frida——hook 内存访问断点 环境&#xff1a;app&#xff1a;arm64 python 3.10 frida 15.2.2 简单的内存访问断点代码&#xff0c;可能还有些bug&#xff0c;根据apk需要自己改&#xff0c;下文为在apk中指定的地址调用函数时内存断点才被激活&#xff0c;以下需要…

【GESP】2023年03月图形化二级 -- 快乐时光

文章目录 快乐时光1. 准备工作2. 功能实现3. 设计思路与实现&#xff08;1&#xff09;角色、舞台背景设置a. 角色设置b. 舞台背景设置 &#xff08;2&#xff09;脚本编写a. 角色&#xff1a;小猫b. 角色&#xff1a;小猴 4. 评分标准 快乐时光 1. 准备工作 &#xff08;1&am…

CSS知识点汇总(十)--移动端适配

文章目录 怎么做移动端的样式适配&#xff1f;1、方案选择2. iPhoneX 适配方案 怎么做移动端的样式适配&#xff1f; 在移动端虽然整体来说大部分浏览器内核都是 webkit&#xff0c;而且大部分都支持 css3 的所有语法。但手机屏幕尺寸不一样&#xff0c;分辨率不一样&#xff0…

jenkins共享库配置及设计

jenkins共享库做模块封装时遇到的问题总结&#xff1a; 背景描述:使用jenkins共享库对SCM subversion操作进行封装时&#xff0c;使用了Checkout插件&#xff0c;生成的检出脚本代码为 checkout([$class: SubversionSCM, additionalCredentials: [], excludedCommitMessages: …

【Dashy安装使用】本地Linux 部署 Dashy 并远程访问

文章目录 简介1. 安装Dashy2. 安装cpolar3.配置公网访问地址4. 固定域名访问 转载自cpolar极点云文章&#xff1a;本地Linux 部署 Dashy 并远程访问 简介 Dashy 是一个开源的自托管的导航页配置服务&#xff0c;具有易于使用的可视化编辑器、状态检查、小工具和主题等功能。你…

spring源码编译笔记

下载源码 地址https://github.com/spring-projects/spring-framework/tree/v5.2.9.RELEASE 查看gradle对应版本 spring-framework-5.2.9.RELEASE/gradle/wrapper/gradle-wrapper.properties # 其他配置暂未了解具体用处&#xff0c;一切默认值 distributionBaseGRADLE_USE…

vue3案例

代码 <template><div class"app-page"><divv-for"title in data.titleArr":key"title.id"class"title-box"click"onClick(title)"><span>{{ title.name }}</span><img v-if"title…