10 - FFmpeg - 重采样 - SoftwareResampleExample

一. 音频帧概率详解:
1. 概念
1)采样率(Sample Rate):每秒从连续信号中提取并组成离散信号的采样个数,它用赫兹(Hz)来表示。
    一般音乐CD的采样率是 44100Hz,所以视频编码中的音频采样率保持在这个级别就完全足够了,通常视频转换器也将这个采样率作为默认设置。
2)帧率(Frame rate):是用于测量显示帧数的量度。所谓的测量单位为每秒显示帧数(Frames per Second,简称:FPS)或“赫兹”(Hz)。
3)码率(Bit Rate):指视频或音频文件在单位时间内使用的数据流量,该参数的单位通常是Kbps,也就是千比特每秒。
    通常2000kbps~3000kbps就已经足以将画质效果表现到极致了。码率参数与视频文件最终体积大小有直接性的关系
4)正常人听觉的频率范围大约在20Hz~20kHz之间,根据奈奎斯特采样理论,为了保证声音不失真,采样频率应该在40kHz左右。
    常用的音频采样频率有8kHz、11.025kHz、22.05kHz、16kHz、37.8kHz、44.1kHz、48kHz等,如果采用更高的采样频率,还可以达到DVD的音质
对采样率为44.1kHz的AAC音频进行解码时,一帧的解码时间须控制在23.22毫秒内。
(一个AAC原始帧包含一段时间内1024个采样及相关数据)
2. 分析:
1) AAC
音频帧的播放时间=一个AAC帧对应的采样样本的个数/采样频率(单位为s)
一帧 1024个 sample。采样率 Samplerate 44.1KHz,每秒44100个sample, 所以根据公式     音频帧的播放时间=一个AAC帧对应的采样样本的个数/采样频率
当前AAC一帧的播放时间是= 1024*1000/44100= 22.32ms (单位为ms)

------------------------------------------------------------------------------------------------------------------------------

1、就是改变音频的采样率、sample format、 声道数等参数,使之按照我们期望的参数输出。

2、当然是原有的音频参数不满足我们的需求,比如在FFmpeg解码音频的时候,
不同的音源有不同的格式,采样率等,在解码后的数据中的这些参数也会不一致
(最新FFmpeg 解码音频后,音频格式为AV SAMPLE FMT FLTP,这个参数应该是一致的),
如果我们接下来需要使用解码后的音频教据做其他操作,而这些参数的不一致导致会有很多额外工作,
此时直接对其进行重采样,获取我们制定的音频参数,这样就会方便很多。
再比如在将音频进行 SDL 播放时候,因为当前的 SDL2.0 不支持planar格式,也不支持浮点型的,
而最新的FFMPEG 16年会将音频解码为AV_SAMPLE_FMT_FLTP格式,因此此时就需要我们对其重采样,使之可以在SDL2 上进行播

1.3 可调节的参数
通过重采样,我们可以对:
 · sample rate (采样率)
 · sample format (采样格式)
 · channel layout(通道布局,可以通过此参数获取声道数)

2 对应参数解析
 分片(plane)和打包(packed)
    以双声道为例,带P(plane)的数据格式在存储时,其左声道和右声道的数据是分开存储的,
    左声道的数据存储在data[0],右声道的数据存储在data[1],每个声道的所占用的字节数为linesize[0]和linesize[1];
    不带P(packed)的音频数据在存储时,是按照LRLRL...的格式交替存储在data[0]中,linesize[0]表示总的数据量。


2.4 声道分布(channel layout)
    声道分布在FFmpeg\libavuti\channel_layout.h 中有定义,一般来说用的比较多的是
    AV_CH_LAYOUT_STEREO(双声道)和AV_CH_LAYOUT SURROUND(三声道),这两者的定义如下:
    #define AV_CH_LAYOUT_STEREO  (AV_CH_FRONT_LEFTI AV_CH_FRONT_RIGHT)
    #define AV_CH_LAYOUT_SURROUND  (AV_CH_LAYOUT_STEREO | AV_CH_FRONT_CENTER)

2.5 音频帧的数据量计算
    一帧音频的数据量(字节) = channel 数 * nb_samples 样本数 * 每个样本占用的字节数
    如果该音频帧是FLTP格式的PCM数据,包含1024个样本,双声道,那么该音频帧包含的音频数据量是2*1024*4=8192字节

2.6 音频播放时间计算
    以采样率44100Hz来计算,每秒44100个sample,而正常一帧为1024个 sample,
    可知每帧播放时间/1024 = 1000ms/44100,得到每帧播放时间=1024*1000/44100=23.2ms(更精确的是23.21995464852608)。
    一帧播放时间(毫秒) =  nb_samples  * 1000 / 采样率

 


int GetFormatFromSampleFormat(const char **format, enum AVSampleFormat sampleFormat)
{struct SampleFormatEntry{enum AVSampleFormat SampleFormat;const char *Format_be;const char *Format_le;} SampleFormatEntries[] = {{AV_SAMPLE_FMT_U8, "u8", "u8"},{AV_SAMPLE_FMT_S16, "s16be", "s16le"},{AV_SAMPLE_FMT_S32, "s32be", "s32le"},{AV_SAMPLE_FMT_FLT, "f32be", "f32le"},{AV_SAMPLE_FMT_DBL, "f64be", "f64le"},};*format = NULL;for (int i = 0; i < FF_ARRAY_ELEMS(SampleFormatEntries); i++) // FF_ARRAY_ELEMS 数组元素个数{struct SampleFormatEntry *entry = &SampleFormatEntries[i];if (sampleFormat == entry->SampleFormat){/*** 这段代码定义了一个宏AV_NE(be, le),用来根据系统的字节序编码来选择参数be或le。* 如果系统是大端序(big endian),则AV_NE(be, le)会返回be;* 如果系统是小端序(little endian),则会返回le。* 这个宏可以在跨平台开发中用来处理不同字节序下的数据处理问题。*/*format = AV_NE(entry->Format_be, entry->Format_le); // AV_NE -- 返回适配的大小端return 0;}}// av_get_sample_fmt_name 是一个函数,用于获取音频采样格式的名称。// 该函数接受一个音频采样格式的枚举值作为参数,并返回对应的格式名称作为字符串。// 这样可以方便地将枚举值转换为可读性更好的格式名称,用于输出日志、调试信息或用户界面上显示音频采样格式。av_log(NULL, AV_LOG_ERROR, "音频采样格式: %s 无法作为输出格式输出\n", av_get_sample_fmt_name(sampleFormat));return AVERROR(EINVAL);
}

// 填充指定长度、声道数的正弦波样本数据到目标缓冲区中 --- 交错模式
void FillAudioSampleData(double *destination /*目标缓冲区*/, int samples /*样本数*/, int channels /*声道数*/, int SampleRate /*采样率*/, double *time /*时间变量*/)
{// DeltaTime 每帧之间的时间差double DeltaTime = 1.0 / SampleRate;double *destinationPointer = destination;const double SineWaveCoefficient = 2 * M_PI * 440.0; // 正弦波系数for (int i = 0; i < samples; i++){*destinationPointer = sin(SineWaveCoefficient * (*time));for (int j = 1; j < channels; j++)destinationPointer[j] = destinationPointer[0];destinationPointer += channels;*time += DeltaTime;}
}

int ResamplePCM(const char *outFileName)
{int ret = -1; // 记录 FFmpeg 调用返回值// 输出文件FILE *outFile = fopen(outFileName, "wb");if (!outFile){av_log(NULL, AV_LOG_ERROR, "[%s] open file: %s error -- line:%d\n", __FUNCTION__, outFileName, __LINE__);goto _end;}size_t DestinationBufSize;// 输入参数int64_t SourceChannelLayout = AV_CH_LAYOUT_STEREO;          // 立体声声道布局的宏int SourceSampleRate = 48000;                               // 采样率enum AVSampleFormat SourceSampleFormat = AV_SAMPLE_FMT_DBL; // 音频样本的数据类型 -- 双精度浮点采样格式int SourceChannels = 0;                                     // 声道数uint8_t **SourceData = NULL;int SourceLinesize;size_t SourceSampleSize = 1024; // 源样本数量 -  一帧包含的采样点数量 - 通常一个AAC帧包含1024个采样点// 输出参数int64_t DestinationChannelLayout = AV_CH_LAYOUT_STEREO;          // 立体声声道布局的宏int DestinationSampleRate = 44100;                               // 采样率enum AVSampleFormat DestinationSampleFormat = AV_SAMPLE_FMT_S16; // 代表有符号16位整数的音频采样格式,通常用于表示音频数据中每个采样点的数据类型。int DestinationChannels = 0;                                     // 声道数uint8_t **DestinationData = NULL;int DestinationLinesize;size_t DestinationSampleSize;    // 目的样本数量size_t MaxDestinationSampleSize; // 目的最大样本数量// 重采样实例struct SwrContext *swrCtx;// 创建重采样器swrCtx = swr_alloc();if (!swrCtx){av_log(NULL, AV_LOG_ERROR, "[%s] swr_alloc error -- line:%d\n", __FUNCTION__, __LINE__);ret = AVERROR(ENOMEM);goto _end;}// 设置采样参数// 设置音频重采样上下文的输入声道布局选项值为 SourceChannelLayout,这里的SourceChannelLayout应该是一个代表声道布局的整数值,这样设置输入声道布局的选项可以告诉音频重采样器如何处理输入数据的声道布局。av_opt_set_int(swrCtx /*要设置选项的对象的指针*/, "in_channel_layout" /*选项名称字符串*/, SourceChannelLayout /*待设置的整数值*/, 0 /*选项搜索标志,通常可以设为0*/);// 这行代码设置音频重采样上下文的输入采样率选项值为 SourceSampleRate, 表示输入数据的采样率。这个选项的设置告诉音频重采样器输入音频数据的采样率是多少。av_opt_set_int(swrCtx, "in_sample_rate", SourceSampleRate, 0);// 设置音频重采样上下文的输入采样格式选项值为 SourceSampleFormat,这里的SourceSampleFormat应该是一个代表采样格式的枚举值,通过设置输入采样格式的选项,可以告诉音频重采样器输入音频数据的采样格式是什么。av_opt_set_sample_fmt(swrCtx, "in_sample_fmt", SourceSampleFormat, 0);// 输出参数av_opt_set_int(swrCtx, "out_channel_layout", DestinationChannelLayout, 0);av_opt_set_int(swrCtx, "out_sample_rate", DestinationSampleRate, 0);av_opt_set_sample_fmt(swrCtx, "out_sample_fmt", DestinationSampleFormat, 0);// 初始化重采样ret = swr_init(swrCtx);if (ret < 0){av_log(NULL, AV_LOG_ERROR, "[%s] Failed to initialize the resampling context -- line:%d\n", __FUNCTION__, __LINE__);goto _end;}// 计算输入源的通道数量SourceChannels = av_get_channel_layout_nb_channels(SourceChannelLayout);av_log(NULL, AV_LOG_INFO, "[%s] SourceChannels:%d -- line:%d\n", __FUNCTION__, SourceChannels, __LINE__);// 给输入源分配内存空间/* int av_samples_alloc_array_and_samples(uint8_t ***audio_data, int *linesize, int nb_channels, int nb_samples, enum AVSampleFormat sample_fmt, int align)* 分配一个数据指针数组,为nb_samples样本分配样本缓冲区,并相应地填充数据指针和linesize。这与av_samples_alloc()相同,但也会分配数据指针数组。*/ret = av_samples_alloc_array_and_samples(&SourceData, &SourceLinesize, SourceChannels, SourceSampleSize, SourceSampleFormat, 0);if (ret < 0){av_log(NULL, AV_LOG_ERROR, "[%s] Allocate memory space for the input source -- line:%d\n", __FUNCTION__, __LINE__);goto _end;}// 计算输出采样数量// int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding rnd)// av_rescale_rnd - 使用指定的舍入值重新缩放64位整数。该操作在数学上等同于a * b / c,但直接写入可能溢出,并且不支持不同的舍入方法。如果结果不可表示,则返回INT64_MIN。// SourceSampleSize * DestinationSampleRate / SourceSampleRateMaxDestinationSampleSize = DestinationSampleSize = av_rescale_rnd(SourceSampleSize, DestinationSampleRate, SourceSampleRate, AV_ROUND_UP);av_log(NULL, AV_LOG_INFO, "[%s] MaxDestinationSampleSize = DestinationSampleSize = %ld -- line:%d\n", __FUNCTION__, MaxDestinationSampleSize, __LINE__);// av_get_channel_layout_nb_channels - 用于获取指定声道布局的声道数量。DestinationChannels = av_get_channel_layout_nb_channels(DestinationChannelLayout);av_log(NULL, AV_LOG_INFO, "[%s] DestinationChannels:%d -- line:%d\n", __FUNCTION__, DestinationChannels, __LINE__);// 分配输出缓存内存ret = av_samples_alloc_array_and_samples(&DestinationData, &DestinationLinesize, DestinationChannels, DestinationSampleSize, DestinationSampleFormat, 0);if (ret < 0){av_log(NULL, AV_LOG_ERROR, "[%s] Allocate output cache memory error! -- line:%d\n", __FUNCTION__, __LINE__);goto _end;}double time = 0;do{// 生成输入源FillAudioSampleData((double *)SourceData[0], SourceSampleSize, SourceChannels, SourceSampleRate, &time);// 计算目标样本数量int64_t delay = swr_get_delay(swrCtx, SourceSampleRate);// 将延迟值和源音频大小转换为目标音频大小DestinationSampleSize = av_rescale_rnd(delay + SourceSampleSize, DestinationSampleRate, SourceSampleRate, AV_ROUND_UP);if (DestinationSampleSize > MaxDestinationSampleSize){av_freep(&DestinationData[0]);// 重新分配// 为nb_samples样本分配一个样本缓冲区,并相应地填充数据指针和linesize。分配的样本缓冲区可以使用av_freep(&audio_data[0])释放,分配的数据将初始化为静音。ret = av_samples_alloc(DestinationData /*数组,以填充每个通道的指针*/,&DestinationLinesize /*音频缓冲区的对齐大小,可以为NULL*/,DestinationChannels /*音频通道数*/,DestinationSampleSize /*每个通道的采样数*/,DestinationSampleFormat /*示例格式*/,1 /*缓冲区大小对齐方式(0 =默认,1 =没有对齐)*/);if (ret < 0){av_log(NULL, AV_LOG_ERROR, "[%s] Reoutput allocated memory error! -- line:%d\n", __FUNCTION__, __LINE__);break;}MaxDestinationSampleSize = DestinationSampleSize;}/** 转换音频。 int swr_convert(struct SwrContext *s, uint8_t **out, int out_count, const uint8_t **in, int in_count)* In和in_count可以设置为0,以在结束时将最后几个样本清除。* 如果提供的输入空间大于输出空间,则输入将被缓冲。* 可以使用swr_get_out_samples()来获取给定输入样本数量所需输出样本数量的上界,从而避免这种缓冲。* 转换将直接运行,而不需要尽可能地复制。**/int SampleSize /*每个通道输出的样本数*/ = swr_convert(swrCtx,                       // 已分配的Swr上下文,并设置了参数DestinationData,              // 输出缓冲,打包音频时只需要设置第一个DestinationSampleSize,        // 每个通道中可供输出样本的空间量(const uint8_t **)SourceData, // 输入缓冲器,在打包音频的情况下,只需要设置第一个SourceSampleSize                // 一个通道中可用的输入样本数);if (SampleSize < 0){av_log(NULL, AV_LOG_ERROR, "[%s] Reoutput allocated memory error! -- line:%d\n", __FUNCTION__, __LINE__);goto _end;}// 获取给定音频参数所需的缓冲区大小。DestinationBufSize = av_samples_get_buffer_size(&DestinationLinesize, DestinationChannels, SampleSize, DestinationSampleFormat, 1);if (DestinationBufSize < 0){av_log(NULL, AV_LOG_ERROR, "[%s] av samples get buffer size error! -- line:%d\n", __FUNCTION__, __LINE__);goto _end;}av_log(NULL, AV_LOG_DEBUG, "[%s] time:%f, in:%ld out:%d -- line:%d\n", __FUNCTION__, time, SourceSampleSize, SampleSize, __LINE__);fwrite(DestinationData[0], 1, DestinationBufSize, outFile);} while (time < 3);int FlushSampleSize = swr_convert(swrCtx, DestinationData, DestinationSampleSize, NULL, 0);if (FlushSampleSize < 0){av_log(NULL, AV_LOG_ERROR, "[%s] allocated memory error! -- line:%d\n", __FUNCTION__, __LINE__);goto _end;}DestinationBufSize = av_samples_get_buffer_size(&DestinationLinesize, DestinationChannels, FlushSampleSize, DestinationSampleFormat, 1);if (DestinationBufSize < 0){av_log(NULL, AV_LOG_ERROR, "[%s] av samples get buffer size error! -- line:%d\n", __FUNCTION__, __LINE__);goto _end;}av_log(NULL, AV_LOG_INFO, "[%s] flush in:%d out:%d -- line:%d\n ", __FUNCTION__, 0, ret, __LINE__);fwrite(DestinationData[0], 1, DestinationBufSize, outFile);const char *FormatString;if ((ret = GetFormatFromSampleFormat(&FormatString, DestinationSampleFormat)) < 0){goto _end;}av_log(NULL, AV_LOG_INFO, "ffplay -f %s -channel_layout %ld -channels %d -ar %d %s\n", FormatString, DestinationChannelLayout, DestinationChannels, DestinationSampleRate, outFileName);_end:if (outFile){fclose(outFile);}if (SourceData){av_freep(&SourceData[0]);}av_freep(&SourceData);if (DestinationData){av_freep(&DestinationData[0]);}av_freep(&DestinationData);swr_free(&swrCtx);return ret;
}

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

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

相关文章

Mac Electron 应用如何进行签名(signature)和公证(notarization)?

最近很多客户反映&#xff0c;从官网下载的Mac Electron应用打不开&#xff0c;直接报病毒&#xff0c;类似于这种&#xff1a; 这是因为在MacOS 10.14.5之后&#xff0c;如果应用没有在苹果官方平台进行公证notarization(我们可以理解为安装包需要审核&#xff0c;来判断是否存…

spring 同类方法调用事务失效解决办法

可以使用AopContext.currentProxy()获取到当前类的代理对象&#xff0c;然后再用代理对象进行调用本类中的方法 如下 f1 和f2 属于同一个类 public voidf1() {((本类名)AopContext.currentProxy()).f2();}Transactionalpublic f2() {} AopContext.currentProxy()方法的使用场景…

Python(字典)

字典根据一个信息查找另外一个信息&#xff0c;也是可变数据类型&#xff0c;底层元素是无序的&#xff0c;第一个添加的元素&#xff0c;地址不一定在第一位&#xff0c;键只能有一个不能重复&#xff0c;但是值可以重复&#xff0c;字典当中的键要求是不可以变的数据类型&…

第6章 单片机的定时器/计数器

6.1 定时/计数器的结构与工作原理 6.2 定时器的控制 6.3 定时/计数器的工作方式 6.4 定时/计数器的编程和应用 6.1 定时/计数器的结构与工作原理 6.1.1 定时/计数器的基本原理 纯软件定时/计数方法&#xff1a; 定时——空循环预定周次&#xff0c;等待预定时间 计数—…

【Qt】之【Bug】error:C1083 无法打开包括文件

背景 a.cpp引用b.h正常&#xff0c;但是a.h引用b.h就报 “无法打开包括文件”的错误 分析 查看“编译输出”&#xff0c;显示不是a.h引起的错误&#xff0c;而是C插件&#xff0c; 查看后发现&#xff0c;C插件引用了a所在插件pro&#xff0c;但是没有引用a依赖的b所在的插件…

Axure中继器进阶指南:打造专业级交互

中继器进阶篇 前言 经过了基础篇的学习,我们已经掌握了中继器的基本操作,接下来来解锁中继器的进阶操作。 1. 修改删除指定行 首先拖入中继器,加上【修改】 【删除】的按钮,然后给修改按钮添加单击事件选择【更新行】。 这里可以看到我们在中继器内部添加的事件,在编…

IDEA关联数据库

《IDEA破解、配置、使用技巧与实战教程》系列文章目录 第一章 IDEA破解与HelloWorld的实战编写 第二章 IDEA的详细设置 第三章 IDEA的工程与模块管理 第四章 IDEA的常见代码模板的使用 第五章 IDEA中常用的快捷键 第六章 IDEA的断点调试&#xff08;Debug&#xff09; 第七章 …

2024-07-16 Unity插件 Odin Inspector7 —— Number Attributes

文章目录 1 说明2 Number 特性2.1 MaxValue / MinValue2.2 MinMaxSlider2.3 ProgressBar2.4 PropertyRange2.5 Unit2.6 Wrap 1 说明 ​ 本文介绍 Odin Inspector 插件中有关 Number 特性的使用方法。 2 Number 特性 2.1 MaxValue / MinValue 在 Inspector 窗口中对象能够被设…

LLM 构建Data Multi-Agents 赋能数据分析平台的实践之④:数据分析之三(数据展示)

概述 在先前探讨的文章中&#xff0c;我们构建了一个全面的数据测试体系&#xff0c;该体系遵循“数据获取—数据治理—数据分析”的流程。如何高效地构建数据可视化看板&#xff0c;以直观展现分析结果&#xff0c;正逐渐成为利用新兴技术提升效能的关键领域。伴随业务拓展、数…

java json 实体互转 null现象

结论 相对于json字符串转为实体&#xff0c;再转回为json字符串&#xff0c;更接近高保真的是 “com.google.gson.Gson {}”, new GsonBuilder().create().toJson(bo1)); 和 “com.alibaba.fastjson.JSON {}”, JSON.toJSONString(bo1)); 代码 BusinessInsertBO bo Business…

《驾驭AI浪潮:伦理挑战与应对策略》

AI发展下的伦理挑战&#xff0c;应当如何应对&#xff1f; 人工智能飞速发展的同时&#xff0c;也逐渐暴露出侵犯数据隐私、制造“信息茧房”等种种伦理风险。随着AI技术在社会各个领域的广泛应用&#xff0c;关于AI伦理和隐私保护问题日趋凸显。尽管国外已出台系列法规来规范…

YOLOv7网络结构学习

YOLOV7详细解读&#xff08;一&#xff09;网络架构解读 YOLOV7学习记录之原理代码介绍 【Make YOLO Great Again】YOLOv1-v7全系列大解析&#xff08;Backbone篇&#xff09; yolov7 图解 深入浅出 Yolo 系列之 Yolov7 基础网络结构详解 我觉得Head、Neck和Head的划分不太…

从产品手册用户心理学分析到程序可用性与易用性的重要区别

注&#xff1a;机翻&#xff0c;未校对。 Designing for People Who Have Better Things To Do With Their Lives 为那些生活中有更重要事情要做的人设计 When you design user interfaces, it’s a good idea to keep two principles in mind: 在设计用户界面时&#xff0c;…

FTPS 和 SFTP

FTPS 和 SFTP 都是用于安全文件传输的协议&#xff0c;但它们之间存在一些关键的区别&#xff0c;包括它们如何实现安全性、工作方式以及与 FTP 的关系。下面是关于这两种协议的详细信息&#xff1a; FTPS (FTP over SSL/TLS) FTPS 是 FTP 协议的扩展&#xff0c;它通过在 FT…

三大ip代理服务商PK,IPFoxy黑马逆袭成首选?

最近亚马逊的Prime Day ,小编我呀忙得不可开交。因为小编负责的店铺数量多且需要稳定的长期连接&#xff0c;我用某一海外ip代理竟然不稳定&#xff0c;这还是号称老牌的ip代理服务商&#xff0c;因为它的漏洞&#xff0c;让我加班了好久处理工作上的问题。 吃一堑&#xff0c…

RPA鼠标按键使用技巧

RPA鼠标按键使用技巧 Mouse.MouseAuto.Action命令出错&#xff0c;调用的目标发生了异常&#xff0c;Exception in Mouse.Action元素不可用怎么解决 出现问题 1.想要实现的效果鼠标移动到录屏工具的小球上2.点击开始按钮开始录屏现象&#xff0c;鼠标没有移动痕迹&#xff0c…

【C++】C++ 职工信息管理系统(源码)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

C++系列-Vector模拟实现(补充)

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” 迭代器失效 这篇文章是基于上一篇的Vector的模拟实现的补充知识点&#xff0c;首先我们需要重点关注的便是迭代器失效的问题。 void test_vector3(){std::vector<int> v…

【C++】类与对象的学习(中)

目录 一、默认成员函数&#xff1a; 二、构造函数&#xff1a; 1、定义&#xff1a; 2、理解&#xff1a; 三、析构函数&#xff1a; 1、定义&#xff1a; 2、理解&#xff1a; 四、拷贝构造&#xff1a; 1、定义&#xff1a; 2、理解&#xff1a; 五、运算符的重载&…

抖音视频素材是哪里找的?热门的抖音素材网站分享

抖音视频创作高手们&#xff0c;你们是否在寻找下一个爆款视频的完美素材&#xff1f;今天&#xff0c;我将为你们介绍几个优质的视频素材网站&#xff0c;确保你们能在素材的海洋中轻松找到那最耀眼的“珍珠”&#xff01; 蛙学网 首先&#xff0c;我们要推荐的是蛙学网。这个…