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 这一次是没有有效数据的,仅仅获取到一个结束标志
相关文章:
11 - FFmpeg - 编码 AAC
Planar 模式是 ffmpeg内部存储模式,我们实际使用的音频文件都是Packed模式的。 FFmpeq解码不同格式的音频输出的音频采样格式不是一样。 其中AAC解码输出的数据为浮点型的 AV_SAMPLE_FMT_FLTP 格式,MP3 解码输出的数据为 AV_SAMPLE_FMT_S16P 格式(使用的…...
OS Copilot初体验的感受与心得
本文介绍体验操作系统智能助手OS Copilot后,个人的一些收获、体验等。 最近,抽空体验了阿里云的操作系统智能助手OS Copilot,在这里记录一下心得与收获。总体观之,从个人角度来说,感觉这个OS Copilot确实抓住了不少开发…...
Ajax学习笔记
文章目录标题 Ajax学习笔记axios使用axios请求拦截器axios响应拦截器优化axios响应结果 form-serialize插件图片上传HTTP协议请求报文相应报文接口文档 AJAX原理 - XMLHttpRequest使用XMLHttpRequestXMLHttpRequest - 查询参数查询字符串对象 XMLHttpRequest - 数据提交 事件循…...
医学深度学习与机器学习融合的随想
医学深度学习与机器学习融合的随想 近年来,深度学习(图像类)和机器学习在医学领域的应用取得了飞速发展,为医学影像分析、疾病诊断和预后预测等领域带来了革命性的变革。深度学习擅长从复杂数据中提取高层次特征,而机…...
坑人的macos tar 命令 (实际上是bsdtar)换用 gnu tar
周末 看着笔记本上好用的朗文当代高级词典(mac版)和其它两部词典,准备复制到黑苹果台式机上去。考虑到词典内容有太多小文件,普通复制传输太慢,毫无疑问用 tar 打包肯定快而且能保留原始文件的各种信息。命令如下: time tar czf …...
【SpringBoot3】全局异常处理
【SpringBoot3】全局异常处理 一、全局异常处理器step1:创建收入数字的页面step2:创建控制器,计算两个整数相除step3:创建自定义异常处理器step5:创建给用提示的页面step6:测试输入(10/0) 二、BeanValidato…...
vue-Treeselect
一、Node KeyTypeDescriptionid (required)Number | String用于标识树中的选项。其值在所有选项中必须是唯一的label (required)String用于显示选项childrennode[] | null声明一个分支节点。你可以: 1) 设置为由a组成的子选项数组。叶节点,b…...
【机器学习框架TensorFlow和PyTorch】基本使用指南
机器学习框架TensorFlow和PyTorch:基本使用指南 目录 引言TensorFlow概述 TensorFlow简介TensorFlow的基本使用 PyTorch概述 PyTorch简介PyTorch的基本使用 TensorFlow和PyTorch的对比结论 引言 随着深度学习的快速发展,机器学习框架在实际应用中起到…...
matlab 中的methods(Access = protected) 是什么意思
gpt版本 在 MATLAB 中,methods 是用于定义类方法的一部分。(Access protected) 是一种访问控制修饰符,它限制了方法的访问权限。具体来说,当你在类定义中使用 methods(Access protected) 时,你是在定义只有类本身及其子类可以访…...
【漏洞复现】Netgear WN604 downloadFile.php 信息泄露漏洞(CVE-2024-6646)
0x01 产品简介 NETGEAR WN604是一款由NETGEAR(网件)公司生产的无线接入器(或无线路由器)提供Wi-Fi保护协议(WPA2-PSK, WPA-PSK),以及有线等效加密(WEP)64位、128位和152…...
图像处理 -- ISP调优(tuning)的步骤整理
ISP调优流程培训文档 1. 硬件准备 选择合适的图像传感器:根据项目需求选择合适的传感器型号。搭建测试环境:包括测试板、光源、色彩卡和分辨率卡等。 2. 初始设置 寄存器配置:初始化传感器的寄存器设置,包括曝光、增益、白平衡…...
【中项】系统集成项目管理工程师-第4章 信息系统架构-4.2系统架构
前言:系统集成项目管理工程师专业,现分享一些教材知识点。觉得文章还不错的喜欢点赞收藏的同时帮忙点点关注。 软考同样是国家人社部和工信部组织的国家级考试,全称为“全国计算机与软件专业技术资格(水平)考试”&…...
node.js中nodemon : 无法加载和使用问题,这是由于windows安全策略影起的按如下操作即可
1、用管理员权限打开vscode 2、文件终端中打开,输入 Set-ExecutionPolicy -Scope CurrentUser 3、再输入RemoteSigned 4、使用get-ExecutionPolicy查看权限,可以看到变为了RemoteSigned 重启问题解决...
【SD】 Stable Diffusion(SD)原理详解与ComfyUI使用 2
Stable Diffusion(SD)原理详解与ComfyUI使用 Stable Diffusion(SD)原理详解与ComfyUI使用1. SD整体结构2. Clip(文本编码器)3. Unit(生成模型)4. VAE(变分自编码器&#…...
【学习笔记】无人机系统(UAS)的连接、识别和跟踪(七)-广播远程识别码(Broadcast Remote ID)
目录 引言 5.5 广播远程识别码(Broadcast Remote ID) 5.5.1 使用PC5的广播远程识别码 5.5.2 使用MBS的广播远程识别码 引言 3GPP TS 23.256 技术规范,主要定义了3GPP系统对无人机(UAV)的连接性、身份识别、跟踪及…...
VMware 虚拟机 ping 不通原因排查
目录 一、检查网络 二、重启虚拟机网络 因为最近遇到了一个比较奇怪的 ping 不通虚拟机的事,在此过程中,检查了很多的设置,故而写一篇文章记录下,如有 VMware 虚拟机 ping 不通可以尝试本文的排查方式。 下面以 VMware 虚拟机为…...
websocket状态机
websocket突破了HTTP协议单向性的缺陷,基于HTTP协议构建了双向通信的通道,使服务端可以主动推送数据到前端,解决了前端不断轮询后台才能获取后端数据的问题,所以在小程序和H5应用中被广泛使用。本文主要集合报文分析对于websocket…...
JCR一区级 | Matlab实现CPO-Transformer-LSTM多变量回归预测【2024新算法】
JCR一区级 | Matlab实现CPO-Transformer-LSTM多变量回归预测【2024新算法】 目录 JCR一区级 | Matlab实现CPO-Transformer-LSTM多变量回归预测【2024新算法】效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.【JCR一区级】Matlab实现CPO-Transformer-LSTM多变量回归预测…...
力扣3226 使两个整数相等的位更改次数
写的代码: class Solution { public:string cc(int num){string res"";while(num>0){int rnum % 2;resstatic_cast<char>(48r)res;num/2;}return res;}int minChanges(int n, int k) {int res0;string n2cc(n);string k2cc(k);int n_sizen2.siz…...
VLAN 划分案例详解
vlan 的应用在网络项目中是非常广泛的,基本上大部分的项目都需要划分 vlan,这里从基础的 vlan 的知识开始,了解 vlan 的划分原理。 为什么需要 vlan: 1、什么是 VLAN? VLAN(Virtual LAN)&…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...
Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...
rknn优化教程(二)
文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK,开始写第二篇的内容了。这篇博客主要能写一下: 如何给一些三方库按照xmake方式进行封装,供调用如何按…...
从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...
IGP(Interior Gateway Protocol,内部网关协议)
IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...
关于nvm与node.js
1 安装nvm 安装过程中手动修改 nvm的安装路径, 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解,但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后,通常在该文件中会出现以下配置&…...
屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...
Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...
CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云
目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...
