11 - FFmpeg - 编码 AAC

Planar 模式是 ffmpeg内部存储模式,我们实际使用的音频文件都是Packed模式的。
FFmpeq解码不同格式的音频输出的音频采样格式不是一样。
其中AAC解码输出的数据为浮点型的 AV_SAMPLE_FMT_FLTP 格式,MP3 解码输出的数据为 AV_SAMPLE_FMT_S16P 格式(使用的mp3文件为16位深)。
具体采样格式可以査看解码后的 AVframe 中的 format 成员或解码器的AVCodecContext中的sample_fmt成员。
Planar或者Packed模式直接影响到保存文件时写文件的操作,操作数据的时候一定要先检测音频采样格式。

方法1

int encodeAudioInterface(AVCodecContext *encoderCtx, AVFrame *frame, AVPacket *packet, FILE *dest_fp)
{int ret = avcodec_send_frame(encoderCtx, frame);if (ret < 0){av_log(NULL, AV_LOG_ERROR, "send frame to encoder failed:%s\n", av_err2str(ret));ret = -1;}while (ret >= 0){ret = avcodec_receive_packet(encoderCtx, packet);if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF){av_log(NULL, AV_LOG_WARNING, "[encodeAudioInterface] -- AVERROR(EAGAIN) || AVERROR_EOF \n");return 0;}else if (ret < 0){av_log(NULL, AV_LOG_ERROR, "encode frame failed:%s\n", av_err2str(ret));return -1;}fwrite(packet->data, 1, packet->size, dest_fp);av_packet_unref(packet);}return 0;
}
int encodeAudio(const char *inFileName, const char *outFileName)
{int ret = 0;/*****************************************************************************/FILE *src_fp = fopen(inFileName, "rb");if (src_fp == NULL){av_log(NULL, AV_LOG_ERROR, "open infile:%s failed!\n", inFileName);ret = -1;goto end;}FILE *dest_fp = fopen(outFileName, "wb+");if (dest_fp == NULL){av_log(NULL, AV_LOG_ERROR, "open outfile:%s failed!\n", outFileName);ret = -1;goto end;}/*****************************************************************************/AVFrame *frame = av_frame_alloc();frame->sample_rate = 48 * 1000; // 采样率 - 48Kframe->channels = 2;frame->channel_layout = AV_CH_LAYOUT_STEREO;frame->format = AV_SAMPLE_FMT_S16;frame->nb_samples = 1024;// libfdk_aacav_frame_get_buffer(frame, 0);AVCodec *encoder = avcodec_find_encoder_by_name("libfdk_aac");if (encoder == NULL){av_log(NULL, AV_LOG_ERROR, "find encoder failed!\n");ret = -1;goto end;}AVCodecContext *encoderCtx = avcodec_alloc_context3(encoder);if (encoderCtx == NULL){av_log(NULL, AV_LOG_ERROR, "alloc encoder context failed!\n");ret = -1;goto end;}encoderCtx->sample_fmt = frame->format;encoderCtx->sample_rate = frame->sample_rate;encoderCtx->channels = frame->channels;encoderCtx->channel_layout = frame->channel_layout;ret = avcodec_open2(encoderCtx, encoder, NULL);if (ret < 0){av_log(NULL, AV_LOG_ERROR, "open encoder failed:%s\n", av_err2str(ret));goto end;}AVPacket packet;av_init_packet(&packet);while (1){// packet L R L R// 2 * 2 * 1024 = 4096int readSize = fread(frame->data[0], 1, frame->linesize[0], src_fp);if (readSize == 0){av_log(NULL, AV_LOG_INFO, "finish read infile!\n");break;}encodeAudioInterface(encoderCtx, frame, &packet, dest_fp);}encodeAudioInterface(encoderCtx, NULL, &packet, dest_fp);end:if (frame){av_frame_free(&frame);}if (encoderCtx){avcodec_free_context(&encoderCtx);return ret;}if (src_fp){fclose(src_fp);}if (dest_fp){fclose(dest_fp);}
}

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

方法 2

int CheckSampleRate(const AVCodec *encoder, const int SampleRate)
{// encoder->supported_samplerates 支持的音频采样数组,如果未知则为NULL,数组以0结尾const int *SupportSampleRate = encoder->supported_samplerates;while (*SupportSampleRate != 0){av_log(NULL, AV_LOG_DEBUG, "[%s] encoder->name: %s, support %d hz -- line:%d\n", __FUNCTION__, encoder->name, *SupportSampleRate, __LINE__); // 受 frame->format等参数影响if (*SupportSampleRate == SampleRate){av_log(NULL, AV_LOG_INFO, "[%s] This sampling rate is supported by the encoder %d hz -- line:%d\n", __FUNCTION__, *SupportSampleRate, __LINE__); // 受 frame->format等参数影响return 1;}SupportSampleRate++;}return 0;
}
int CheckChannelLayout(const AVCodec *encoder, const uint64_t ChannelLayout)
{// 支持通道布局的数组,如果未知则为NULL。数组以0结尾const uint64_t *SupportsChannelLayout = encoder->channel_layouts;if (!SupportsChannelLayout){ // 不是每个AVCodec都给出支持的channel_layoutav_log(NULL, AV_LOG_WARNING, "[%s] the encoder %s no set channel_layouts -- line:%d\n", __FUNCTION__, encoder->name, __LINE__);return 1;}while (*SupportsChannelLayout != 0){av_log(NULL, AV_LOG_DEBUG, "[%s] encoder->name: %s, support channel_layout %ld -- line:%d\n", __FUNCTION__, encoder->name, *SupportsChannelLayout, __LINE__); // 受 frame->format等参数影响if (*SupportsChannelLayout == ChannelLayout){av_log(NULL, AV_LOG_INFO, "[%s] This channel layout is supported by the encoder %d -- line:%d\n", __FUNCTION__, *SupportsChannelLayout, __LINE__); // 受 frame->format等参数影响return 1;}*SupportsChannelLayout++;}return 0;
}
int CheckSampleFmt(const AVCodec *codecCtx, enum AVSampleFormat SampleFmt)
{ // 数组支持的样例格式,如果未知则为NULL,数组以-1结尾const enum AVSampleFormat *SampleFmts = codecCtx->sample_fmts;while (*SampleFmts != AV_SAMPLE_FMT_NONE) // 通过 AV_SAMPLE_FMT_NONE 作为结束{if (*SampleFmts == SampleFmt){return 1;}*SampleFmts++;}return 0;
}
void GetAdtsHeader(AVCodecContext *codecCtx, uint8_t *adtsHeader, int aacLength)
{uint8_t freqIdx = 0; // 0: 96000HZ 3:48000Hz 4:44100Hzswitch (codecCtx->sample_rate){case 96000:freqIdx = 0;break;case 88200:freqIdx = 1;break;case 64000:freqIdx = 2;break;case 48000:freqIdx = 3;break;case 44100:freqIdx = 4;break;case 32000:freqIdx = 5;break;case 24000:freqIdx = 6;break;case 22050:freqIdx = 7;break;case 16000:freqIdx = 8;break;case 12000:freqIdx = 9;break;case 11025:freqIdx = 10;break;case 8000:freqIdx = 11;break;case 7350:freqIdx = 12;break;default:freqIdx = 4;break;}uint8_t chanCfg = codecCtx->channels;uint32_t frameLength = aacLength + 7;adtsHeader[0] = 0xff;adtsHeader[1] = 0xF1;adtsHeader[2] = ((codecCtx->profile) << 6) + (freqIdx << 2) + (chanCfg >> 2);adtsHeader[3] = (((chanCfg & 3) << 6) + (frameLength >> 11));adtsHeader[4] = ((frameLength & 0x7FF) >> 3);adtsHeader[5] = (((frameLength & 7) << 5) + 0x1F);adtsHeader[6] = 0xFC;
}
int decodeAudioInterface(AVCodecContext *codecCtx, AVFrame *frame, AVPacket *pkt, FILE *output)
{int ret = avcodec_send_frame(codecCtx, frame);if (ret < 0){av_log(NULL, AV_LOG_ERROR, "[%s] sending the frame to the encoder error! -- line:%d\n", __FUNCTION__, __LINE__);return -1;}// 编码和解码都是一样的,都是send 1次,然后 receive 多次,直到AVERROR(EAGAIN)或者AVERROR_EOFwhile (ret >= 0){ret = avcodec_receive_packet(codecCtx, pkt);if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF){return 0;}else if (ret < 0){av_log(NULL, AV_LOG_ERROR, "[%s] encoding audio frameerror! -- line:%d\n", __FUNCTION__, __LINE__);return -1;}uint8_t aacHeader[7];GetAdtsHeader(codecCtx, aacHeader, pkt->size);size_t len = fwrite(aacHeader, 1, 7, output);if (len != 7){av_log(NULL, AV_LOG_ERROR, "[%s] fwrite aac_header failed! -- line:%d\n", __FUNCTION__, __LINE__);return -1;}len = fwrite(pkt->data, 1, pkt->size, output);if (len != pkt->size){av_log(NULL, AV_LOG_ERROR, "[%s] fwrite aac data failed! -- line:%d\n", __FUNCTION__, __LINE__);return -1;}}return -1;
}
void f32leConvert2fltp(float *f32le, float *fltp, int nb_samples)
{float *fltp_l = fltp;              // 左通道float *fltp_r = fltp + nb_samples; // 右声道for (int i = 0; i < nb_samples; i++){fltp_l[i] = f32le[i * 2];     // 1 0 - 2 3fltp_r[i] = f32le[i * 2 + 1]; // 可以尝试注释左声道或者右声道听听声音}
}
int decodeAudio(const char *pcmFileName, const char *aacFileName, const char *encoderName)
{FILE *pcmfile = fopen(pcmFileName, "rb");FILE *aacfile = fopen(aacFileName, "wb");if (pcmfile == NULL || aacfile == NULL){av_log(NULL, AV_LOG_ERROR, "[%s] open %s or %s file failed -- line:%d \n", __FUNCTION__, aacFileName, pcmFileName, __LINE__);goto _end;}const AVCodec *encoder = NULL;if (encoderName != NULL && (strcmp(encoderName, "libfdk_aac") == 0 || strcmp(encoderName, "aac") == 0)) // encoderName 如果制定了编码器{encoder = avcodec_find_encoder_by_name(encoderName); // 设置为指定编码器av_log(NULL, AV_LOG_INFO, "[%s] force codec name: %s -- line:%d\n", __FUNCTION__, encoderName, __LINE__);}else{encoder = avcodec_find_encoder(AV_CODEC_ID_AAC);av_log(NULL, AV_LOG_INFO, "[%s] default codec name: %s -- line:%d\n", __FUNCTION__, "aac", __LINE__);}if (encoder == NULL){av_log(NULL, AV_LOG_ERROR, "[%s] Codec found error! -- line:%d\n", __FUNCTION__, __LINE__);goto _end;}// 创建编码器上下文AVCodecContext *codecCtx = avcodec_alloc_context3(encoder);if (codecCtx == NULL){av_log(NULL, AV_LOG_ERROR, "[%s] Conld not allocate audio codec context -- line:%d\n", __FUNCTION__, __LINE__);goto _end;}codecCtx->codec_id = AV_CODEC_ID_AAC;codecCtx->codec_type = AVMEDIA_TYPE_AUDIO;codecCtx->bit_rate = 128 * 1024;codecCtx->channel_layout = AV_CH_LAYOUT_STEREO;codecCtx->sample_rate = 48000;codecCtx->channels = av_get_channel_layout_nb_channels(codecCtx->channel_layout);codecCtx->profile = FF_PROFILE_AAC_LOW;if (strcmp(encoder->name, "libfdk_aac") == 0){codecCtx->sample_fmt = AV_SAMPLE_FMT_S16;}else{codecCtx->sample_fmt = AV_SAMPLE_FMT_FLTP;}// 检测采样格式的支持情况if (!CheckSampleFmt(encoder, codecCtx->sample_fmt)){av_log(NULL, AV_LOG_ERROR, "[%s] Encoder does not support sample format %s -- line:%d\n", __FUNCTION__, av_get_sample_fmt_name(codecCtx->sample_fmt), __LINE__);goto _end;}if (!CheckSampleRate(encoder, codecCtx->sample_rate)){av_log(NULL, AV_LOG_ERROR, "[%s] Encoder does not support sample rate codecCtx->sample_rate:%d -- line:%d\n", __FUNCTION__, codecCtx->sample_rate, __LINE__);goto _end;}if (!CheckChannelLayout(encoder, codecCtx->channel_layout)){av_log(NULL, AV_LOG_ERROR, "[%s] Encoder does not support sample channel_layout %lu -- line:%d\n", __FUNCTION__, codecCtx->channel_layout, __LINE__);goto _end;}av_log(NULL, AV_LOG_INFO, "\n[%s] ------------------------ Audio encode config ------------------------ line:%d \n", __FUNCTION__, __LINE__);av_log(NULL, AV_LOG_INFO, "[%s] codecCtx->bit_rate: %ld kbps -- line:%d\n", __FUNCTION__, codecCtx->bit_rate / 1024, __LINE__);av_log(NULL, AV_LOG_INFO, "[%s] codecCtx->sample_rate: %d -- line:%d\n", __FUNCTION__, codecCtx->sample_rate, __LINE__);av_log(NULL, AV_LOG_INFO, "[%s] codecCtx->sample_fmt: %s -- line:%d\n", __FUNCTION__, av_get_sample_fmt_name(codecCtx->sample_fmt), __LINE__);av_log(NULL, AV_LOG_INFO, "[%s] codecCtx->channels: %d -- line:%d\n", __FUNCTION__, codecCtx->channels, __LINE__);// frame_size 是在 av_coedc_open2后进行关联av_log(NULL, AV_LOG_INFO, "[%s] Before frame size %d -- line:%d\n", __FUNCTION__, codecCtx->frame_size, __LINE__);if (avcodec_open2(codecCtx, encoder, NULL) < 0){av_log(NULL, AV_LOG_ERROR, "[%s] Could not open codec -- line:%d\n", __FUNCTION__, __LINE__);goto _end;}av_log(NULL, AV_LOG_INFO, "[%s] Once frame_size %d -- line:%d\n\n", __FUNCTION__, codecCtx->frame_size, __LINE__); // 决定每次送多少个采样点AVPacket *packet = av_packet_alloc();if (!packet){av_log(NULL, AV_LOG_ERROR, "[%s] packet alloc error! -- line:%d \n", __FUNCTION__, __LINE__);goto _end;}AVFrame *frame = av_frame_alloc();if (!frame){av_log(NULL, AV_LOG_ERROR, "[%s] Could not allocate audio frame -- line:%d\n", __FUNCTION__, __LINE__);goto _end;}frame->nb_samples = codecCtx->frame_size;frame->format = codecCtx->sample_fmt;frame->channel_layout = codecCtx->channel_layout;frame->channels = av_get_channel_layout_nb_channels(frame->channel_layout);av_log(NULL, AV_LOG_INFO, "[%s] frame nb_samples: %d -- line:%d\n", __FUNCTION__, frame->nb_samples, __LINE__);av_log(NULL, AV_LOG_INFO, "[%s] frame sample_fmt: %s -- line:%d\n", __FUNCTION__, av_get_sample_fmt_name(frame->format), __LINE__);av_log(NULL, AV_LOG_INFO, "[%s] frame channel_layout: %lu -- line:%d\n", __FUNCTION__, frame->channel_layout, __LINE__);// 为frame分配bufferint ret = av_frame_get_buffer(frame, 0);if (ret < 0){av_log(NULL, AV_LOG_ERROR, "[%s] Could not allocate audio data buffers -- line:%d\n", __FUNCTION__, __LINE__);goto _end;}// 计算出每一帧的数据 单个采样点的字节 * 通道数目 * 每帧采样点的数量size_t FrameByteSize = av_get_bytes_per_sample(frame->format) * frame->channels * frame->nb_samples;av_log(NULL, AV_LOG_INFO, "[%s] frame_bytes %ld frame->channels %d frame->nb_samples %d -- line:%d\n", __FUNCTION__, FrameByteSize, frame->channels, frame->nb_samples, __LINE__);uint8_t *pcmBuf = (uint8_t *)malloc(FrameByteSize);uint8_t *pcmBufTemp = (uint8_t *)malloc(FrameByteSize);if (!pcmBuf || !pcmBufTemp){av_log(NULL, AV_LOG_ERROR, "[%s] pcmBuf or pcmBufTemp malloc failed -- line:%d\n", __FUNCTION__, __LINE__);goto _end;}memset(pcmBuf, 0, FrameByteSize);memset(pcmBufTemp, 0, FrameByteSize);int64_t pts = 0;av_log(NULL, AV_LOG_INFO, "\n[%s] ------------------------ start enode ------------------------ line:%d \n", __FUNCTION__, __LINE__);while (1){memset(pcmBuf, 0, FrameByteSize);size_t ReadByteSize = fread(pcmBuf, 1, FrameByteSize, pcmfile);if (ReadByteSize <= 0){av_log(NULL, AV_LOG_INFO, "[%s] read file finish -- line:%d \n", __FUNCTION__, __LINE__);break;}/*确保该 frame 可写, 如果编码器内部保持了内存参数计数,则需要重新拷贝一个备份目的是新写入的数据和编码器保存的数据不能产生冲突*/ret = av_frame_make_writable(frame);if (ret != 0){av_log(NULL, AV_LOG_ERROR, "[%s] av_frame_make_writable failed!!! -- line:%d\n", __FUNCTION__, __LINE__);}if (AV_SAMPLE_FMT_S16 == frame->format){// 将读取到的PCM数据填充到frame去,但是要注意匹配格式,(planner | packet )ret = av_samples_fill_arrays(frame->data, frame->linesize, pcmBuf, frame->channels, frame->nb_samples, frame->format, 0);}else{// 将读取到的PCM数据填充到frame去,但是要注意匹配格式,(planner | packet )// 将本地的f32le packed 模式的数据转为 float palannermemset(pcmBufTemp, 0, FrameByteSize);f32leConvert2fltp((float *)pcmBuf, (float *)pcmBufTemp, frame->nb_samples);ret = av_samples_fill_arrays(frame->data, frame->linesize, pcmBufTemp, frame->channels, frame->nb_samples, frame->format, 0);}// 设置 ptspts += frame->nb_samples;frame->pts = pts; // 使用采样率作为pts的单位,具体换算成秒 pts*1/采样率ret = decodeAudioInterface(codecCtx, frame, packet, aacfile);if (ret < 0){av_log(NULL, AV_LOG_ERROR, "[%s] encode failed -- line:%d\n", __FUNCTION__, __LINE__);break;}}/*冲刷编码器*/decodeAudioInterface(codecCtx, NULL, packet, aacfile);
_end:if (aacfile){fclose(aacfile);}if (pcmfile){fclose(pcmfile);}if (pcmBuf){free(pcmBuf);}if (pcmBufTemp){free(pcmBufTemp);}if (packet){av_packet_free(&packet);}if (frame){av_frame_free(&frame);}if (codecCtx){avcodec_free_context(&codecCtx);}return ret;
}

对于 flush encoder 的操作:
编码器通常的冲洗方法:调用一次 avcodec_send_frame(NULL)(返回成功),
然后不停调用 avcodec_receive_packet() 直到其返回 AVERROR_EOF,取出所有缓存帧,
avcodec_receive_packet() 返回 AVERROR EOF 这一次是没有有效数据的,仅仅获取到一个结束标志

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

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

相关文章

【区块链 + 智慧政务】南京发改委:基于区块链的项目评审与专家管理系统 | FISCO BCOS应用案例

围绕招投标、项目评审过程中的信息化管理&#xff0c;南京市发展和改革委员会上线基于区块链的项目评审与专家管理系统&#xff0c; 规范南京市发改委专家评审&#xff08;咨询&#xff09;活动&#xff0c;健全专家库管理机制&#xff0c;提升行政决策质量和政策研究水平。该系…

HarmonyOS 状态管理(一)

1. HarmonyOS 状态管理 1.1. 说明 官方文档&#xff08;https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/arkts-state-management-V5&#xff09; 1.1.1. 状态管理&#xff08;V1稳定版&#xff09; 状态管理&#xff08;V1稳定版&#xff09;提供了多种…

【iOS】——SideTable

SideTable Side Table主要用于存储和管理对象的额外信息&#xff0c;特别是与弱引用相关的数据。Side Table的设计和使用是Objective-C运行时实现弱引用的基础&#xff0c;使得ARC&#xff08;Automatic Reference Counting&#xff09;能够正确地处理弱引用的生命周期。 新版…

【系统架构设计 每日一问】四 如何对关系型数据库及NoSql数据库选型

根据不同的业务需求和场景&#xff0c;选择适合的数据库类型至关重要。以下是一个优化后的表格展示&#xff0c;涵盖了管理型系统、大流量系统、日志型系统、搜索型系统、事务型系统、离线计算和实时计算七大类业务系统的数据库选型建议。先明确下NoSQL的分类 NoSQL数据库分类…

预训练语言模型实践笔记

Roberta output_hidden_statesTrue和last_hidden_states和pooler_output 在使用像BERT或RoBERTa这样的transformer模型时&#xff0c;output_hidden_states和last_hidden_state是两个不同的概念。 output_hidden_states: 这是一个布尔值&#xff0c;决定了模型是否应该返回所…

大数据学习之sparkstreaming

SparkStreaming idea中初步实现 Spark core: SparkContext 核心数据结构&#xff1a;RDD Spark sql: SparkSession 核心数据结构&#xff1a;DataFrame Spark streaming: StreamingContext 核心数据结构&#xff1a;DStream(底层封装了RDD)&#xff0c;遍历出其中的RDD即可进行…

ReadAgent,一款具有要点记忆的人工智能阅读代理

人工智能咨询培训老师叶梓 转载标明出处 现有的大模型&#xff08;LLMs&#xff09;在处理长文本时受限于固定的最大上下文长度&#xff0c;并且当输入文本越来越长时&#xff0c;性能往往会下降&#xff0c;即使在没有超出明确上下文窗口的情况下&#xff0c;LLMs 的性能也会随…

中文之美:荷·雅称

文章目录 引言I 荷雅称水宫仙子、六月花神水芝、水芸溪客、水旦芙蕖、菡萏朱华、红蕖风荷、静客II 与荷、莲相关的句子、诗词周敦颐李商隐李重元杨公远孟浩然刘光祖苏轼汪曾祺席慕蓉余光中引言 中文之美,美在诗词歌赋,美在绝句华章,也美在对事物名称的雅致表达。 中文对万物…

Speaker Tracking SOTA 文章翻译

AV-A-PF Abstract 在室内环境中跟踪多个移动说话者的问题受到了广泛关注。早期的技术完全基于单一模态&#xff0c;例如视觉。最近&#xff0c;多模态信息的融合已被证明在提高跟踪性能以及在像遮挡这样的具有挑战性情况下的鲁棒性方面发挥了重要作用&#xff08;由于摄像机视…

寄存器与CPU和硬盘的关系

寄存器与 CPU 之间的信息传递主要通过数据总线、地址总线和控制总线来实现&#xff1a; 1. 数据总线&#xff08;Data Bus&#xff09;&#xff1a;用于在 CPU 和寄存器之间传输数据。当 CPU 需要从寄存器中读取数据时&#xff0c;数据通过数据总线从寄存器传输到 CPU&#xff…

GPT-4o mini是什么?

今天&#xff0c;全网都知道 OpenAI 发现货了&#xff01; GPT-4o mini 取代 GPT 3.5&#xff0c;从此坐上正主之位。 从官网信息来看&#xff0c;OpenAI 最新推出的 GPT-4o mini 重新定义了 AI 成本效益的标准&#xff0c;其性能优于前代模型 GPT-3.5 Turbo&#xff0c;且成本…

ruoyi-cloud-plus

1.X项目初始化 (dromara.org)参考文档&#xff01; 可以直接参考以上链接&#xff01;我只是整理我自己需要的部分&#xff0c;方便查看使用。 nacos 服务启动顺序 必须启动基础建设: mysql redis nacos可选启动基础建设: minio(影响文件上传) seata(影响分布式事务 默认开启…

弹性伸缩:如何在Eureka中实现服务的自动扩展和收缩

弹性伸缩&#xff1a;如何在Eureka中实现服务的自动扩展和收缩 在微服务架构中&#xff0c;服务的自动扩展和收缩是实现高可用性和成本效益的关键策略。Eureka&#xff0c;作为Netflix开源的服务发现框架&#xff0c;虽然本身不直接提供自动扩展和收缩的功能&#xff0c;但我们…

[2024-7-22]面试题2

Redis的持久化机制,在真实的线上环境中需要采取什么样的策略 在真实的线上环境中&#xff0c;Redis的持久化机制主要有两种&#xff1a;RDB&#xff08;Redis DataBase&#xff09;和AOF&#xff08;Append Only File&#xff09;。每种机制都有其优点和适用场景&#xff0c;实…

Synopsys:Design Compiler的XG模式和DB模式

相关阅读 Synopsyshttps://blog.csdn.net/weixin_45791458/category_12738116.html?spm1001.2014.3001.5482 很久之前&#xff0c;Design Compiler使用的是DB模式&#xff08;包括一些其他工具&#xff0c;例如DFT Compiler, Physical Compiler和Power Compiler&#xff09;&…

二叉树基础及实现(一)

目录&#xff1a; 一. 树的基本概念 二. 二叉树概念及特性 三. 二叉树的基本操作 一. 树的基本概念&#xff1a; 1 概念 &#xff1a; 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0 &#xff09;个有限结点组成一个具有层次关系的集合。 把它叫做树是因…

数据结构之初始二叉树(4)

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a;数据结构&#xff08;Java版&#xff09; 二叉树的基本操作 二叉树的相关刷题&#xff08;上&#xff09;通过上篇文章的学习&#xff0c;我们…

queue的模拟实现【C++】

文章目录 全部的实现代码放在了文章末尾什么是适配器模式&#xff1f;准备工作包含头文件定义命名空间类的成员变量 默认成员函数emptysizefrontbackpushpop全部代码 全部的实现代码放在了文章末尾 queue的模拟实现和stack一样&#xff0c;采用了C适配器模式 queue的适配器一…

Leetcode 3229. Minimum Operations to Make Array Equal to Target

Leetcode 3229. Minimum Operations to Make Array Equal to Target 1. 解题思路2. 代码实现 题目链接&#xff1a;3229. Minimum Operations to Make Array Equal to Target 1. 解题思路 这一题其实也还蛮简单的&#xff0c;我们只需要考察一下两个数组的差值序列即可。 我…

PCI总线域与处理器域

PCI总线域 在x86处理器系统中&#xff0c;PCI总线域是外部设备域的重要组成部分。实际上在Intel的x86处理器系统中&#xff0c;所有的外部设备都使用PCI总线管理。而AMD的x86处理器系统中还存在一条HT(HyperTransport)总线&#xff0c;在AMD的x86处理器系统中还存在HT总线域。…