音视频开发—FFmpeg 音频重采样详解
音频重采样(audio resampling)是指改变音频信号的采样率的过程。采样率(sample rate)是指每秒钟采集的音频样本数,通常以赫兹(Hz)或每秒样本数(samples per second)表示。例如,CD音频的标准采样率是44.1kHz,表示每秒钟采集44,100个样本。
文章目录
- 什么时候会用到重采样
- 重采样的技术
- 使用FFmpeg命令行对MP3文件进行重采样
- 参数说明
- 更详细的命令
- FFmpeg 对MP3文件重采样代码实现
- 流程图
- 关键步骤:
- 对MP3文件进行解码
- 初始化重采样参数
- 初始化编码器
- 音频帧转换
- 完整代码
- 效果展示
什么时候会用到重采样
-
设备兼容性:
不同的音频设备可能支持不同的采样率。例如,某些音频接口或播放设备可能只支持特定的采样率。在这种情况下,需要将音频文件重采样到兼容的采样率。 -
节省存储空间:
高采样率的音频文件占用更多的存储空间。如果需要节省存储空间或带宽,可以将音频文件重采样到较低的采样率。 -
音频质量调整:
有时候需要在高质量和低质量之间进行平衡。例如,音频工程师可能会将录音采样率设置得很高,以捕捉更多的细节,但在混音或发行时,可能会选择稍低的采样率以便于处理和分发。 -
多媒体项目:
在多媒体项目中,不同来源的音频文件可能具有不同的采样率。为了保持项目的一致性,通常需要对音频文件进行重采样,使它们具有相同的采样率。 -
音频处理和分析:
某些音频处理和分析工具对输入的采样率有特定的要求。在使用这些工具之前,可能需要对音频进行重采样。
重采样的技术
重采样涉及插值算法,例如:
-
线性插值:
是最简单的一种插值方法,但可能会引入较多的失真。 -
多项式插值(如三次样条插值):
能提供更高的精度,但计算复杂度较高。 -
窗函数插值(如Lanczos窗):
常用于高质量音频重采样,能够有效减少伪影和失真。
通过这些算法,重采样过程可以在不同的采样率之间平滑过渡,尽量保持原音频信号的质量。
使用FFmpeg命令行对MP3文件进行重采样
一个名为input.mp3的MP3文件,并且你想将其采样率更改为48kHz(48000Hz),可以使用以下命令:
ffmpeg -i input.mp3 -ar 48000 output.mp3
参数说明
-i input.mp3:指定输入文件。-ar 48000:指定新的采样率,这里是48000Hz。output.mp3:指定输出文件名。
更详细的命令
如果你还想保留原始的比特率(bitrate)和声道数(channels),可以使用更多参数:
ffmpeg -i input.mp3 -ar 48000 -ab 192k -ac 2 output.mp3
-ab 192k:指定音频比特率为192kbps。-ac 2:指定音频通道数为2(立体声)。
FFmpeg 对MP3文件重采样代码实现
流程图

关键步骤:
对MP3文件进行解码
具体流程如下:

打开输入文件: 调用 avformat_open_input 函数打开输入文件,并获得格式上下文 fmt_ctx。
读取流信息: 调用 avformat_find_stream_info 函数读取文件的流信息,以便后续处理。
查找最佳音频流: 调用 av_find_best_stream 函数查找输入文件中的最佳音频流,并返回其索引 audio_stream_index 和对应的解码器 codec。
分配解码器上下文: 调用 avcodec_alloc_context3 函数为找到的解码器分配解码器上下文 codec_ctx。
将流的参数复制到解码器上下文: 调用 avcodec_parameters_to_context 函数将输入文件中音频流的参数复制到解码器上下文中。
打开解码器: 调用 avcodec_open2 函数打开解码器,准备解码音频数据。
代码实现:
int initialize_decoder(const char *input_filename, AVFormatContext **fmt_ctx, AVCodecContext **codec_ctx, int *audio_stream_index)
{AVCodec *codec = NULL;if (avformat_open_input(fmt_ctx, input_filename, NULL, NULL) < 0){fprintf(stderr, "Could not open input file\n");return -1;}if (avformat_find_stream_info(*fmt_ctx, NULL) < 0){fprintf(stderr, "Could not find stream information\n");return -1;}*audio_stream_index = av_find_best_stream(*fmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, &codec, 0);if (*audio_stream_index < 0){fprintf(stderr, "Could not find audio stream in input file\n");return -1;}*codec_ctx = avcodec_alloc_context3(codec);if (!(*codec_ctx)){fprintf(stderr, "Could not allocate audio codec context\n");return -1;}if (avcodec_parameters_to_context(*codec_ctx, (*fmt_ctx)->streams[*audio_stream_index]->codecpar) < 0){fprintf(stderr, "Could not copy codec parameters to codec context\n");return -1;}if (avcodec_open2(*codec_ctx, codec, NULL) < 0){fprintf(stderr, "Could not open codec\n");return -1;}return 0; // 成功
}
初始化重采样参数
具体流程如下

代码实现
int initialize_resampler(SwrContext **swr_ctx, AVCodecContext *codec_ctx, AVFrame **swr_frame)
{*swr_ctx = swr_alloc_set_opts(NULL, // ctxAV_CH_LAYOUT_STEREO, // 输出的channel 的布局AV_SAMPLE_FMT_FLTP, // 输出的采样格式48000, // 输出的采样率codec_ctx->channel_layout, // 输入的channel布局codec_ctx->sample_fmt, // 输入的采样格式codec_ctx->sample_rate, // 输入的采样率0, NULL);if (!(*swr_ctx)){fprintf(stderr, "Could not allocate resampler context\n");return -1;}if (swr_init(*swr_ctx) < 0){fprintf(stderr, "Could not initialize the resampling context\n");swr_free(swr_ctx);return -1;}*swr_frame = av_frame_alloc();if (!(*swr_frame)){fprintf(stderr, "Could not allocate resampled frame\n");swr_free(swr_ctx);return -1;}return 0; // 成功
}
初始化编码器
大体流程如下:
设置输出文件格式和路径: 调用 av_guess_format 函数猜测输出文件的格式,并根据输出文件名设置格式。
分配输出格式的上下文: 调用 avformat_alloc_output_context2 函数为输出文件分配格式上下文。
创建输出流: 调用 avformat_new_stream 函数为输出文件创建一个新的音频流。
查找编码器: 调用 avcodec_find_encoder 函数查找MP3编码器。
创建编码器上下文: 调用 avcodec_alloc_context3 函数为编码器分配上下文。
设置编码器参数: 设置编码器的比特率、采样格式、采样率和声道布局等参数。
打开编码器: 调用 avcodec_open2 函数打开编码器。
给输出流设置编码器参数: 调用 avcodec_parameters_from_context 函数将编码器的参数复制到输出流。
打开输出文件: 如果输出格式不支持直接输出到文件,则调用 avio_open 函数打开输出文件。
写入文件头部: 调用 avformat_write_header 函数写入输出文件的头部信息。
初始化输出数据包: 调用 av_packet_alloc 函数初始化一个数据包,用于存储编码后的音频数据。
代码实现
int initialize_encoder(const char *output_filename, AVFormatContext **out_fmt_ctx, AVCodecContext **enc_ctx, AVStream **out_stream,AVPacket **outpack)
{AVOutputFormat *out_fmt = NULL;AVCodec *encoder = NULL;AVCodecContext *encoder_ctx = NULL;AVStream *stream = NULL;// 设置输出文件的格式与路径out_fmt = av_guess_format(NULL, output_filename, NULL);if (!out_fmt){fprintf(stderr, "could not guess file format\n");return -1;}// 打开输出格式的上下文if (avformat_alloc_output_context2(out_fmt_ctx, out_fmt, NULL, output_filename) < 0){fprintf(stderr, "could not create output context\n");return -1;}// 创建输出流stream = avformat_new_stream(*out_fmt_ctx, NULL);if (!stream){fprintf(stderr, "could not create output stream\n");return -1;}// 查找编码器encoder = avcodec_find_encoder(AV_CODEC_ID_MP3);if (!encoder){fprintf(stderr, "Codec not found\n");return -1;}// 创建编码器上下文encoder_ctx = avcodec_alloc_context3(encoder);if (!encoder_ctx){fprintf(stderr, "Could not allocate audio codec context\n");return -1;}// 设置编码器参数encoder_ctx->bit_rate = 192000; // 比特率为192kbpsencoder_ctx->sample_fmt = AV_SAMPLE_FMT_FLTP; // 采样格式encoder_ctx->sample_rate = 48000; // 采样率encoder_ctx->channel_layout = AV_CH_LAYOUT_STEREO; // 双声道布局encoder_ctx->channels = 2;// 打开编码器if (avcodec_open2(encoder_ctx, encoder, NULL) < 0){fprintf(stderr, "Could not open codec\n");avcodec_free_context(&encoder_ctx);return -1;}// 给输出流设置编码器if (avcodec_parameters_from_context(stream->codecpar, encoder_ctx) < 0){fprintf(stderr, "Failed to copy encoder parameters to output stream\n");avcodec_free_context(&encoder_ctx);return -1;}// 打开输出文件if (!((*out_fmt_ctx)->oformat->flags & AVFMT_NOFILE)){if (avio_open(&(*out_fmt_ctx)->pb, output_filename, AVIO_FLAG_WRITE) < 0){fprintf(stderr, "Could not open output file\n");return -1;}}// 写入文件头部if (avformat_write_header((*out_fmt_ctx), NULL) < 0){fprintf(stderr, "Error occurred when opening output file\n");return -1;}*enc_ctx = encoder_ctx;*out_stream = stream;//初始化输出的数据包*outpack = av_packet_alloc();return 0; // 成功
}
音频帧转换
需要转换的帧要与编码器的参数注意对应,否则编码器无法编码
重点是swr_convert_frame
swr_convert_frame 是 FFmpeg 中用于将一个音频帧从一种格式转换为另一种格式的函数。它使用 SwrContext(重采样上下文)来执行转换,包括采样率、通道布局和采样格式的转换。
函数定义
int swr_convert_frame(SwrContext *swr_ctx, AVFrame *out_frame, const AVFrame *in_frame);
参数说明
swr_ctx:指向SwrContext的指针,包含重采样所需的上下文信息。这个上下文在之前需要通过swr_alloc_set_opts和swr_init等函数进行初始化。out_frame:指向目标AVFrame的指针,存储转换后的音频数据。这个AVFrame需要预先分配并设置好其参数,例如采样率、通道布局和采样格式等。in_frame:指向源AVFrame的指针,包含需要转换的音频数据。
返回值
函数返回一个整数,成功时返回0,失败时返回负数。
使用步骤
- 初始化
SwrContext: 使用swr_alloc_set_opts和swr_init函数初始化重采样上下文,设置输入和输出的采样率、通道布局和采样格式等。 - 分配并设置
AVFrame: 分配并设置输入和输出AVFrame,并确保out_frame的参数与SwrContext的输出参数一致。 - 调用
swr_convert_frame: 调用swr_convert_frame函数进行音频数据的转换。 - 处理转换后的音频数据: 转换完成后,可以使用
out_frame中的数据进行后续处理。
// 确保有足够的缓冲区来容纳转换后的数据swr_frame->channel_layout = AV_CH_LAYOUT_STEREO;swr_frame->format = AV_SAMPLE_FMT_FLTP;swr_frame->sample_rate = 48000;swr_frame->nb_samples = encodec_ctx->frame_size; //与编码器帧大小保持一致// 分配缓冲区if (av_frame_get_buffer(swr_frame, 0) < 0){fprintf(stderr, "Could not allocate output frame samples\n");av_frame_free(&swr_frame);return -1;}// 执行重采样if (swr_convert_frame(swr_ctx, swr_frame, frame) < 0){fprintf(stderr, "Error while converting\n");av_frame_free(&swr_frame);return -1;}// 将重采样后的帧发送给编码器if (avcodec_send_frame(encodec_ctx, swr_frame) == 0){while (avcodec_receive_packet(encodec_ctx, out_packet) == 0){// 正确设置数据包中的流索引out_packet->stream_index = out_stream->index;// 调整时间戳,使其基于输出流的时间基av_packet_rescale_ts(out_packet, encodec_ctx->time_base, out_stream->time_base);// 写入一个编码的数据包到输出文件if (av_interleaved_write_frame(out_fmt_ctx, out_packet) < 0){fprintf(stderr, "Error while writing output packet\n");break;}}}av_frame_unref(swr_frame); // 清理帧数据以便重用
完整代码
extern "C"
{
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavutil/channel_layout.h>
#include <libswresample/swresample.h>
}
#include <string>
#include <iostream>
using namespace std;int initialize_encoder(const char *output_filename, AVFormatContext **out_fmt_ctx, AVCodecContext **enc_ctx, AVStream **out_stream,AVPacket **outpack)
{AVOutputFormat *out_fmt = NULL;AVCodec *encoder = NULL;AVCodecContext *encoder_ctx = NULL;AVStream *stream = NULL;// 设置输出文件的格式与路径out_fmt = av_guess_format(NULL, output_filename, NULL);if (!out_fmt){fprintf(stderr, "could not guess file format\n");return -1;}// 打开输出格式的上下文if (avformat_alloc_output_context2(out_fmt_ctx, out_fmt, NULL, output_filename) < 0){fprintf(stderr, "could not create output context\n");return -1;}// 创建输出流stream = avformat_new_stream(*out_fmt_ctx, NULL);if (!stream){fprintf(stderr, "could not create output stream\n");return -1;}// 查找编码器encoder = avcodec_find_encoder(AV_CODEC_ID_MP3);if (!encoder){fprintf(stderr, "Codec not found\n");return -1;}// 创建编码器上下文encoder_ctx = avcodec_alloc_context3(encoder);if (!encoder_ctx){fprintf(stderr, "Could not allocate audio codec context\n");return -1;}// 设置编码器参数encoder_ctx->bit_rate = 192000; // 比特率为192kbpsencoder_ctx->sample_fmt = AV_SAMPLE_FMT_FLTP; // 采样格式encoder_ctx->sample_rate = 48000; // 采样率encoder_ctx->channel_layout = AV_CH_LAYOUT_STEREO; // 双声道布局encoder_ctx->channels = 2;// 打开编码器if (avcodec_open2(encoder_ctx, encoder, NULL) < 0){fprintf(stderr, "Could not open codec\n");avcodec_free_context(&encoder_ctx);return -1;}// 给输出流设置编码器if (avcodec_parameters_from_context(stream->codecpar, encoder_ctx) < 0){fprintf(stderr, "Failed to copy encoder parameters to output stream\n");avcodec_free_context(&encoder_ctx);return -1;}// 打开输出文件if (!((*out_fmt_ctx)->oformat->flags & AVFMT_NOFILE)){if (avio_open(&(*out_fmt_ctx)->pb, output_filename, AVIO_FLAG_WRITE) < 0){fprintf(stderr, "Could not open output file\n");return -1;}}// 写入文件头部if (avformat_write_header((*out_fmt_ctx), NULL) < 0){fprintf(stderr, "Error occurred when opening output file\n");return -1;}*enc_ctx = encoder_ctx;*out_stream = stream;//初始化输出的数据包*outpack = av_packet_alloc();return 0; // 成功
}int initialize_decoder(const char *input_filename, AVFormatContext **fmt_ctx, AVCodecContext **codec_ctx, int *audio_stream_index)
{AVCodec *codec = NULL;if (avformat_open_input(fmt_ctx, input_filename, NULL, NULL) < 0){fprintf(stderr, "Could not open input file\n");return -1;}if (avformat_find_stream_info(*fmt_ctx, NULL) < 0){fprintf(stderr, "Could not find stream information\n");return -1;}*audio_stream_index = av_find_best_stream(*fmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, &codec, 0);if (*audio_stream_index < 0){fprintf(stderr, "Could not find audio stream in input file\n");return -1;}*codec_ctx = avcodec_alloc_context3(codec);if (!(*codec_ctx)){fprintf(stderr, "Could not allocate audio codec context\n");return -1;}if (avcodec_parameters_to_context(*codec_ctx, (*fmt_ctx)->streams[*audio_stream_index]->codecpar) < 0){fprintf(stderr, "Could not copy codec parameters to codec context\n");return -1;}if (avcodec_open2(*codec_ctx, codec, NULL) < 0){fprintf(stderr, "Could not open codec\n");return -1;}return 0; // 成功
}int initialize_resampler(SwrContext **swr_ctx, AVCodecContext *codec_ctx, AVFrame **swr_frame)
{*swr_ctx = swr_alloc_set_opts(NULL, // ctxAV_CH_LAYOUT_STEREO, // 输出的channel 的布局AV_SAMPLE_FMT_FLTP, // 输出的采样格式48000, // 输出的采样率codec_ctx->channel_layout, // 输入的channel布局codec_ctx->sample_fmt, // 输入的采样格式codec_ctx->sample_rate, // 输入的采样率0, NULL);if (!(*swr_ctx)){fprintf(stderr, "Could not allocate resampler context\n");return -1;}if (swr_init(*swr_ctx) < 0){fprintf(stderr, "Could not initialize the resampling context\n");swr_free(swr_ctx);return -1;}*swr_frame = av_frame_alloc();if (!(*swr_frame)){fprintf(stderr, "Could not allocate resampled frame\n");swr_free(swr_ctx);return -1;}return 0; // 成功
}int main()
{AVFormatContext *fmt_ctx = NULL;AVOutputFormat *out_fmt = NULL; // 输出格式AVFormatContext *out_fmt_ctx = NULL; // 输出格式上下文AVCodecContext *codec_ctx = NULL; // 解码器上下文AVCodec *codec = NULL; // 解码器AVCodec *encodec = NULL; // 编码器AVCodecContext *encodec_ctx = NULL; // 编码器上下文AVPacket *packet;AVFrame *frame;AVStream *out_stream = NULL; // 输出流AVPacket *out_packet;int audio_stream_index;SwrContext *swr_ctx;AVFrame *swr_frame;int ret;ret = initialize_encoder("output.mp3", &out_fmt_ctx, &encodec_ctx, &out_stream,&out_packet);if (ret != 0){fprintf(stderr, "init encode failed\n");return -1;}// 初始化解码器ret = initialize_decoder("test.mp3", &fmt_ctx, &codec_ctx, &audio_stream_index);if (ret != 0){fprintf(stderr, "init decode failed\n");return -1;}packet = av_packet_alloc(); // 初始化数据包frame = av_frame_alloc();// 初始化重采样上下文ret = initialize_resampler(&swr_ctx, codec_ctx, &swr_frame);if (ret != 0){fprintf(stderr, "init resampler failed\n");return -1;}// 解码 ---- 重采样 -----编码while (av_read_frame(fmt_ctx, packet) >= 0){if (packet->stream_index == audio_stream_index){if (avcodec_send_packet(codec_ctx, packet) == 0){while (avcodec_receive_frame(codec_ctx, frame) == 0){// 确保有足够的缓冲区来容纳转换后的数据swr_frame->channel_layout = AV_CH_LAYOUT_STEREO;swr_frame->format = AV_SAMPLE_FMT_FLTP;swr_frame->sample_rate = 48000;swr_frame->nb_samples = encodec_ctx->frame_size; //与编码器帧大小保持一致// 分配缓冲区if (av_frame_get_buffer(swr_frame, 0) < 0){fprintf(stderr, "Could not allocate output frame samples\n");av_frame_free(&swr_frame);return -1;}// 执行重采样if (swr_convert_frame(swr_ctx, swr_frame, frame) < 0){fprintf(stderr, "Error while converting\n");av_frame_free(&swr_frame);return -1;}// 将重采样后的帧发送给编码器if (avcodec_send_frame(encodec_ctx, swr_frame) == 0){while (avcodec_receive_packet(encodec_ctx, out_packet) == 0){// 正确设置数据包中的流索引out_packet->stream_index = out_stream->index;// 调整时间戳,使其基于输出流的时间基av_packet_rescale_ts(out_packet, encodec_ctx->time_base, out_stream->time_base);// 写入一个编码的数据包到输出文件if (av_interleaved_write_frame(out_fmt_ctx, out_packet) < 0){fprintf(stderr, "Error while writing output packet\n");break;}}}av_frame_unref(swr_frame); // 清理帧数据以便重用}}}av_packet_unref(packet);}// 收尾工作// 写入文件尾部信息if (av_write_trailer(out_fmt_ctx) < 0){fprintf(stderr, "Error writing trailer of the output file\n");}// 关闭输出文件和释放输出上下文if (!(out_fmt_ctx->oformat->flags & AVFMT_NOFILE)){avio_closep(&out_fmt_ctx->pb);}avformat_free_context(out_fmt_ctx);// 其他资源清理av_packet_free(&out_packet);av_frame_free(&frame);av_frame_free(&swr_frame);av_packet_free(&packet);avcodec_close(codec_ctx);avcodec_close(encodec_ctx);avformat_close_input(&fmt_ctx);swr_free(&swr_ctx);return 0;
}
效果展示
ffmpeg 可以查看MP3文件的具体参数
命令:ffmpeg -i test.mp3

Stream #0:0:
Stream:表示这是一个流。#0:0:表示这是第一个输入文件中的第一个流(通常第一个流是视频流,第二个流是音频流,依此类推)。
Audio: mp3:
Audio:表示这个流是一个音频流。mp3:表示音频编码格式是 MP3(MPEG Audio Layer III)。
44100 Hz:
- 表示音频采样率为 44.1 kHz(44100 赫兹),即每秒钟采集 44100 次音频样本。
stereo:
- 表示音频是立体声(双声道),即音频信号包含两个独立的声道。
fltp:
- 表示音频采样格式是
float planar(浮点平面格式),即每个音频样本用浮点数表示,并且每个声道的数据存储在单独的平面中。
320 kb/s:
- 表示音频比特率为 320 kbps(千比特每秒),即每秒钟有 320000 比特的数据传输速率。
经过重采样之后,再次查看参数

音频采样率改为了 48 kHz(48000 赫兹),并且正常播放
相关文章:
音视频开发—FFmpeg 音频重采样详解
音频重采样(audio resampling)是指改变音频信号的采样率的过程。采样率(sample rate)是指每秒钟采集的音频样本数,通常以赫兹(Hz)或每秒样本数(samples per second)表示。…...
统计本地端口占用情况
要查看MongoDB是否正在备份,可以通过以下几种方法: 查看MongoDB的进程列表: 使用命令ps -ef | grep mongo,这将列出所有正在运行的MongoDB进程。在输出的列表中,你可以查看是否有与备份相关的进程或任务正在运行。 查…...
【MySQL精通之路】SQL优化(1)-查询优化(9)-外部联接优化
主博客: 【MySQL精通之路】SQL优化(1)-查询优化-CSDN博客 上一篇: 【MySQL精通之路】SQL优化(1)-查询优化(8)-嵌套联接优化-CSDN博客 下一篇: 【MySQL精通之路】SQL优化(1)-查询优化(10)-外部联接简化-CSDN博客 外部联接包括LEFT JOIN和…...
Python应用开发——30天学习Streamlit Python包进行APP的构建(1)
关于 #30天学Streamlit #30天学Streamlit 是一个旨在帮助你学习构建 Streamlit 应用的编程挑战。 你将学会: 如何搭建一个编程环境用于构建 Streamlit 应用构建你的第一个 Streamlit 应用学习所有好玩的、能用在 Streamlit 应用里的输入输出组件🗓️ 天 1 设置本地开发环境…...
轻兔推荐 —— 一个好用的软件服务推荐平台
给大家推荐一个好用的的软件服务推荐平台:轻兔推荐 网站界面简洁大方,没有太多杂七杂八的功能和页面,有明暗主题色可以选择,默认为亮色,可在网站上方手动切换。 每工作日都会推荐一款软件,有时会加更&…...
LeetCode hot100-57-G
17. 电话号码的字母组合 给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。不会,放IDEA里执行了一下大概理解了流程 …...
基于Vue uni-app的自定义列表表格信息展示组件
摘要:随着软件技术的不断发展,前端开发面临着越来越多的挑战。特别是在业务场景复杂多变的情况下,如何提高开发效率和降低维护成本成为了关键。本文旨在探讨组件化开发在前端应用中的重要性,并以Vue uni-app自定义列表表格为例&am…...
计网(部分在session学习章)
TCP/UDP TCP:面向连接,先三次握手建立连接,可靠传输。 UDP:无连接,不可靠,传递的快。 TCP可靠传输 1.分块编号传输; 2.校验和,校验首部和数据的检验和,检测数据在传输中的变化; 3.丢弃重复数据; 4.流量控制,TCP 利⽤滑动窗⼝实现流量控制。TCP的拥塞控制采⽤…...
TypeScript 枚举
什么是 TypeScript 枚举? 简单来说,枚举是一种用于命名一组常量的数据类型。在 TypeScript 中,枚举允许我们定义一个命名的常量集合,并为这些常量分配相关的数值。通过枚举,我们可以为一组相关的值提供一个友好的名字…...
(1) 初识QT5
文章目录 Qt Quickdemo信号的命名方式 qml语言一个很重要的概念 qt 模块 Qt Quick Qt Quick是Qt5中⽤户界⾯技术的涵盖。Qt Quick⾃⾝包含了以下⼏种技术: QML-使⽤于⽤户界⾯的标识语⾔JavaScript-动态脚本语⾔Qt C具有⾼度可移植性的C库. 类似HTML语⾔…...
2024年认证杯二阶段数学建模赛题浅析
一图流 问题模型复杂度数据收集难度数据处理难度实现难度专业知识需求A题中高中中中材料科学、热物理、机械工程B题高高高高生物力学、神经学、医学成像C题高高高高环境科学、气象学、气候工程D题中中高高中高机器学习、数据科学、AI设计 【腾讯文档】2024年认证杯二阶段资料助…...
Redis教程(十八):Redis的Redisson的看门狗机制
传送门:Redis教程汇总篇,让你从入门到精通 Redisson的看门狗机制 Redisson的看门狗机制主要是指客户端在获取到锁之后,通过后台线程或定时任务自动续期的功能,以避免在锁持有期间因为处理时间过长而导致锁自动释放,进而确保操作的安全性与原子性。 这个机制的工作原理是…...
docker-compose 映射端口失败! docker端口映射失败 ,docker映射只能使用老端口,映射无法使用
1. 现象 使用docker-compose 启动项目,发现映射端口出现问题,不能映射端口! 如图: 使用原来端口是可以使用的 2. 问题原因: 使用了docker-mode 为host模式,所以不能换端口,只能写为"8086:…...
AIGC笔记--基于PEFT库使用LoRA
1--相关讲解 LORA: LOW-RANK ADAPTATION OF LARGE LANGUAGE MODELS LoRA 在 Stable Diffusion 中的三种应用:原理讲解与代码示例 PEFT-LoRA 2--基本原理 固定原始层,通过添加和训练两个低秩矩阵,达到微调模型的效果; 3--简单代…...
yolo 算法 易主
标题:YOLOv10: Real-Time End-to-End Object Detection 论文:https://arxiv.org/pdf/2405.14458ethttps%3A//arxiv.org/pdf/2405.14458.zhihu.com/?targethttps%3A//arxiv.org/pdf/2405.14458 源码:https://github.com/THU-MIG/yolov10 分析…...
用这8种方法在海外媒体推广发稿平台上获得突破-华媒舍
在今天的数字时代,海外媒体推广发稿平台已经成为了许多机构和个人宣传和推广的有效途径。如何在这些平台上获得突破并吸引更多的关注是一个关键问题。本文将介绍8种方法,帮助您在海外媒体推广发稿平台上实现突破。 1. 确定目标受众 在开始使用海外媒体推…...
怎么调试前端文件:一步步揭开前端调试的神秘面纱
怎么调试前端文件:一步步揭开前端调试的神秘面纱 在前端开发的世界中,调试是一项至关重要的技能。它能够帮助我们定位并解决代码中的错误,提升应用的性能和用户体验。本文将从四个方面、五个方面、六个方面和七个方面,为你揭示前…...
【深入学习Redis丨第一篇】Redis服务器部署详解
前言 小伙伴们大家好,我是陈橘又青,今天起 《深入学习Redis》 专栏开始更新。本专栏将专为希望深入了解Redis的开发者、系统架构师以及数据库爱好者而写的免费专栏。从Redis的基本概念入手,逐步深入到其内部实现和高级用法。希望能帮助你更好…...
git教程(IDEA + 命令行)
首先假设你已经安装 git 且 已经初始化完成: // 初始化git config --global user.name "你的用户名" git config --global user.email "你的邮箱"在当前文件夹下创建一个仓库,且该文件夹下会有多个项目 首先在当前文件夹下新建git…...
树莓派部署harbor_arm64
文章目录 树莓派4b部署Harbor-arm64版本docker-compose维护命令访问harbor 192.168.1.111认用户名密码admin/Harbor12345 树莓派4b部署Harbor-arm64版本 harbor-arm版本 部署:参考 wget https://github.com/hzliangbin/harbor-arm64/releases/download/v1.9.3/ha…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序
一、开发准备 环境搭建: 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 项目创建: File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...
页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...
WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成
厌倦手动写WordPress文章?AI自动生成,效率提升10倍! 支持多语言、自动配图、定时发布,让内容创作更轻松! AI内容生成 → 不想每天写文章?AI一键生成高质量内容!多语言支持 → 跨境电商必备&am…...
在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案
这个问题我看其他博主也写了,要么要会员、要么写的乱七八糟。这里我整理一下,把问题说清楚并且给出代码,拿去用就行,照着葫芦画瓢。 问题 在继承QWebEngineView后,重写mousePressEvent或event函数无法捕获鼠标按下事…...
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...
使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
给网站添加live2d看板娘
给网站添加live2d看板娘 参考文献: stevenjoezhang/live2d-widget: 把萌萌哒的看板娘抱回家 (ノ≧∇≦)ノ | Live2D widget for web platformEikanya/Live2d-model: Live2d model collectionzenghongtu/live2d-model-assets 前言 网站环境如下,文章也主…...
Linux系统部署KES
1、安装准备 1.版本说明V008R006C009B0014 V008:是version产品的大版本。 R006:是release产品特性版本。 C009:是通用版 B0014:是build开发过程中的构建版本2.硬件要求 #安全版和企业版 内存:1GB 以上 硬盘…...
