和田地网站seo/营销渠道有哪些
😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀
🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭
🤣本文内容🤣:🍭介绍 opus 编码的 Ogg 封装文件🍭
😎金句分享😎:🍭🍭
本文未经允许,不得转发!!!
opus和Ogg相关系列文章:
1、RFC3533 :Ogg封装格式版本 0(The Ogg Encapsulation Format Version 0)
2、Ogg封装格式详解——包含Ogg封装过程、数据包(packet)、页(page)、段(segment)等
3、libogg库详解介绍以及使用——附带libogg库解析.opus文件的C源码
4、RFC7845:Opus音频编解码器的Ogg封装(Ogg Encapsulation for the Opus Audio Codec)
5、opus编解码库(opus-1.4)详细介绍以及使用——附带解码示例代码
6、opus编码的Ogg封装文件详解
目录
- 🎄一、概述
- 🎄二、ID头部数据(ID Header)
- ✨2.1、ID 头部数据的介绍
- ✨2.2、.opus 文件 ID头部数据 分析
- 🎄三、注释头部数据(Comment Header)
- ✨3.1、注释头部数据的介绍
- ✨3.2、.opus 文件 注释头部数据 分析
- 🎄四、opus 编码数据包
- 🎄五、opus编码的Ogg封装文件解码C语言源码
- 🎄六、总结
🎄一、概述
前面的文章 Ogg封装格式详解 介绍了Ogg格式的封装,介绍了封装过程、Ogg的页结构、Ogg的段,但没涉及到每个段的内容,因为这跟编码有关系。本文就介绍 opus 编码在 Ogg 封装文件中是怎样存储的,同样地,从一个 opus 编码的Ogg文件去查看十六进制,最终了解 opus 编码 Ogg 封装文件的整个结构,这样就可以轻易将这类文件解码为PCM了。
opus 编码的Ogg文件结构如下图:
- 逻辑Ogg比特流中的第一个数据包必须包含ID头部数据(ID Header),该头部数据将流唯一标识为Opus音频。
- 逻辑Ogg比特流中的第二个数据包必须包含注释头部数据(Comment Header),其中包含用户提供的元数据。
- 之后的所有页面(page)都是音频数据页面。
下文分析的Ogg封装文件为 48000Hz-s16le-1ch-ChengDu.opus,下载链接:https://download.csdn.net/download/wkd_007/88492683
🎄二、ID头部数据(ID Header)
✨2.1、ID 头部数据的介绍
opus编码的逻辑Ogg比特流中,第一页必须包含ID头部数据
,其结构如下图,包括8个字段,各个字段代表的含义如下:
-
1、Magic Signature(8字节):
这是一个8位字节(64位)字段,允许编解码器识别,并且是人类可读的。它按顺序包含以下的字母:
0x4F 'O' 0x70 'p' 0x75 'u' 0x73 's' 0x48 'H' 0x65 'e' 0x61 'a' 0x64 'd'
从“Op”开始有助于将其与音频数据包区分开来,因为这是一个无效的TOC序列。
-
2、Version (1字节, unsigned):
对于此版本的封装规范,版本号必须始终为“1”。实现应该将版本号的前四位与已识别规范的版本号匹配的流视为与该规范向后兼容。也就是说,版本号可以分为“主要”和“次要”版本子字段,次要子字段的变化(在较低的四位中)表示兼容的变化。例如,本规范的实现应该接受版本号为“15”或更低的任何流,并且应该假设版本号为”16“或更高的任何流不兼容。选择初始版本“1”是为了防止实现依赖此八位字节作为“OpusHead”字符串的null终止符。 -
3、Output Channel Count ‘C’ (1字节, unsigned)
这是输出通道的数量。这可能与编码信道的数量不同,编码信道的数目可以在逐包的基础上改变。此值不得为零。最大允许值取决于通道映射族,可能大到255。详见[RFC7845]
文档的第5.1.1节。 -
4、Pre-skip (2字节, unsigned, little endian):
这是开始播放时要从解码器输出中丢弃的采样数(48 kHz),也是要从页面的颗粒位置中减去以计算其PCM采样位置的数量。当裁剪现有Ogg Opus流的开头时,建议预跳过至少3840个样本(80ms),以确保解码器完全收敛。
-
5、Input Sample Rate (4字节, unsigned, little endian):
这是原始输入(编码前)的采样率,单位为Hz。该字段不是用于播放编码数据的采样率。
Opus可以在4、6、8、12和20kHz的内部音频带宽之间切换。流中的每个数据包可以具有不同的音频带宽。不管音频带宽如何,参考解码器都支持以8、12、16、24或48kHz的采样率对任何流进行解码。传递到编码器的音频的原始采样率不被有损压缩所保留。
Ogg Opus播放器应根据以下程序选择播放采样率:
1.如果硬件支持48 kHz播放,则以48 kHz进行解码。
2.否则,如果硬件的最高可用采样率是支持的速率,则以该采样率进行解码。
3.否则,如果硬件的最高可用采样率小于48kHz,则以高于最高可用硬件速率的下一个更高的Opus支持速率进行解码并重新采样。
4.否则,以48 kHz解码并重新采样。
然而,“输入采样率”字段允许复用器将原始输入流的采样率作为元数据传递。当用户需要输出采样率来匹配输入采样率时,这是有用的。例如,当不播放输出时,将PCM格式样本写入磁盘的实现可能会选择将音频重新采样回原始输入采样率,以减少用户的意外,因为用户可能会合理地期望以相同的采样率返回文件。
零值表示“未指定”。复用器应该写入实际输入采样率或零,但使用该字段执行某些操作的实现应该注意,如果给定疯狂的值(例如,如果请求,不要实际将输出上采样到10MHz),则行为要理智。实现应支持 8kHz 和 192kHz(包括8kHz)之间的输入采样率。此范围之外的速率可以通过回落到默认速率 48kHz 来忽略。
-
6、Output Gain (2字节, signed, little endian):
这是解码时要应用的增益。它是对解码器输出进行缩放以获得所需播放量的因子的20*log10,存储在具有8个小数比特的16比特、带符号的2的补码定点值中(即Q7.8[Q-NOTATION])。
为了应用增益,实现可以使用以下内容:
sample *= pow(10, output_gain/(20.0*256))
其中“output_gain”是来自标头的原始16位值。
玩家和媒体框架应该默认应用它。如果播放器选择应用任何音量调整或增益修改,如R128_TRACK_AIN(见第5.2节),则除了此输出增益外,还必须应用该调整,以实现标准化音量的播放。
复用器应该将该字段设置为零,而不是在编码之前应用任何增益,只要这是可能的,并且不会与用户的愿望相冲突。非零输出增益表示在编码之后调整了增益,或者用户希望在保持恢复原始信号幅度的能力的同时调整增益以进行回放。
尽管输出增益具有巨大的范围(+/-128 dB,足以将听不见的声音放大到身体疼痛的阈值),但大多数应用程序只能合理地使用零附近这个范围的一小部分。大范围的部分作用是确保增益始终可以在OpusHead和R128增益标签之间无损传输(见下文)而不会饱和。
-
7、Channel Mapping Family (1字节, unsigned):
这个八位字节表示输出通道的顺序和语义。
该八位位组的每个当前指定值都指示一个映射族,该映射族定义了一组允许的通道计数,以及每个允许的通道数的有序通道名称集。详见
[RFC7845]
文档的第5.1.1节。 -
8、Channel Mapping Table:
此表定义了从编码流到输出通道的映射。其内容见
[RFC7845]
文档的第5.1.1节。ID标头中的所有字段都是必需的,但“通道映射表”除外,当通道映射族为0时,必须省略该字段,否则为必需字段。如果流包含的ID标头没有足够的数据用于这些字段,即使它包含有效的“魔术签名”,实现也应该将其视为无效。该规范的未来版本,甚至是向后兼容的版本,可能会在ID头中包含额外的字段。如果ID标头具有兼容的主版本,但具有较大的次版本,则实现不得将其视为无效,因为它包含此处未指定的其他数据,前提是它仍然在第一页上完成。
✨2.2、.opus 文件 ID头部数据 分析
现在按照上面的字段,分析opus编码的Ogg文件,用Notepad打开 48000Hz-s16le-1ch-ChengDu.opus 并查看十六进制模式:
- 前面蓝色背景的部分(包括0x13)是Ogg页头部数据,不清楚的看 上篇文章 的 4.2 节;
- 紫色框开始是opus编码的ID头部数据,内容是8个字符:
OpusHead
; - 接下去的蓝色框是版本号,目前的版本,该值为
1
; - 紧接着的蓝色框是声道数量,这里值为
1
,表示单声道; - 后面的橙色框表示 “开始播放时要从解码器输出中丢弃的采样数”,值为
0x0138
; - 接着的绿色框表示 “原始输入(编码前)的采样率”,值为
0xbb80
,对应十进制48000
; - 后面的蓝色框表示 “解码时要应用的增益”;
- 后面的黑色框表示 “表示输出通道的顺序和语义”,值为
0
,代表使用映射族0,允许的通道数:1或2,且省略通道映射表(Channel Mapping Table);
🎄三、注释头部数据(Comment Header)
✨3.1、注释头部数据的介绍
opus编码的逻辑Ogg比特流中,第二页必须包含注释头部数据
。它可能跨越多个页面(page),从逻辑流的第二页开始。无论它跨越多少页,注释头数据包都必须结束在一个完整的页面,其结构如下图,包括6个字段,各个字段代表的含义如下:
-
1、Magic Signature(8个字节):
这是一个8位字节(64位)字段,允许编解码器识别,并且是人类可读的。它按顺序包含以下神奇数字:
0x4F 'O' 0x70 'p' 0x75 'u' 0x73 's' 0x54 'T' 0x61 'a' 0x67 'g' 0x73 's'
从“Op”开始有助于将其与音频数据包区分开来,因为这是一个无效的TOC序列。
-
2、Vendor String Length (4个字节, unsigned, little endian):
此字段给出下个字段
Vendor String
的长度,单位为八位字节。它不得指示供应商字符串比数据包的其余部分长。 -
3、Vendor String (variable length, UTF-8 vector):
这是一个用于供应商信息的简单可读标签,编码为UTF-8字符串[RFC3629]。不需要终止空八位字节。
此标签旨在识别编解码器编码器和封装实现,以跟踪技术行为的差异。面向用户的应用程序可以使用“ENCODER”用户注释标记来标识自己。
-
4、User Comment List Length (4个字节, unsigned, little endian):
此字段指示用户提供的注释个数。它可能表示用户提供的注释为零,在这种情况下,数据包中没有其他字段。它不能表明有太多的注释,以至于注释字符串长度需要比数据包其余部分更多的数据。
-
5、User Comment #i String Length (4个字节, unsigned, little endian):
此字段给出下个字段
User Comment #i String
的长度,单位为八位字节。“用户评论列表长度”字段指示的每个用户评论都有一个。它不能指示字符串比数据包的其余部分长。 -
6、User Comment #i String (variable length, UTF-8 vector):
此字段包含编码为UTF-8字符串的单个用户注释[RFC3629]。“用户评论列表长度”字段指示的每个用户评论都有一个。
✨3.2、.opus 文件 注释头部数据 分析
下图是用Notepad打开 48000Hz-s16le-1ch-ChengDu.opus 并查看十六进制模式的截图,这里分析的是第二页数据:
- 前面蓝色背景的部分是Ogg页头部数据,不清楚的看 上篇文章 的 4.2 节第二页数据;
- 紫色框开始是opus编码的注释头部数据,内容是8个字符:
OpusTags
; - 接下去的红色色框的4个字节是供应商字符串长度, 此字段给出下个字段
Vendor String
的长度,这里是0x0b
; - 紧接着的红色框的11个字节就是供应商字符串,内容是
libopus 1.1
- 后面的绿色框表示 “注释个数”,值为
0x01
,表示只有一个注释 ; - 接着的蓝色框表示 “第一个注释字符串的长度”,值为
0x25
,对应十进制37
,表示后面有37个字符的注释; - 后面的橙色框表示 “注释字符串”,内容是
ENCODER=opusenc form opus-tools 0.1.8
,共37个字符;
🎄四、opus 编码数据包
在一个opus编码的Ogg格式文件中,除了一个ID头部数据包
和一个 注释头部数据包
(有时可以跨多页),剩下的都是 opus编码音频数据包
,音频数据包也是存储在Ogg格式文件的各个段(Segment)中,下面从一个实际的Ogg文件分析音频数据包。
下图是用Notepad打开 48000Hz-s16le-1ch-ChengDu.opus 并查看十六进制模式的截图,这里分析的是第三页数据:
- 图中黑色框表示该Ogg页数据中有
0x33
(十进制51)个段(Segment),但并不表示有51个opus音频数据包,因为段的长度为0xff
时,表示该段存不下一个音频数据包,下个段仍然是这个包的数据。 - 蓝色背景的
51
个字节就是各个段的长度,可以看到第一个段长度是0xff
,表示第一个音频包存储了2个段,第一个音频包的实际长度应该是0xff+0x06
;后面49个段长度中,都没有0xff
,说明每个都存储了一个音频数据包。所以这一页应该是50个音频数据包。每个数据包读取后,都可以直接送到opus-1.4
的库去解码成PCM音频数据。
🎄五、opus编码的Ogg封装文件解码C语言源码
清楚了前面的知识,就可以对opus编码的Ogg文件进行解码了,你可以使用 libogg库加上 opus-1.4 的库进行解码,那样会更简洁一点,下面给出的源码只使用了opus-1.4去解码音频包,有很大的参考价值:
opusDec.h
/*** @file opusDec.h* @author wkd_007* @date 2023-10-27 15:47:38*/
#ifndef __OPUS_DEC_H__
#define __OPUS_DEC_H__#include "opus/opus.h"#define MAX_OPUS_DEC_FRAME 48000 // opus解码最大采样点个数,如果个数时间小于120ms,可能停止解码,这里设置1000ms的个数
#define OPUS_DEC_CHANNELS 2
class COpusDec
{
public:COpusDec();~COpusDec();int CreateOpusDecoder(int sampleRate, int channels);int OpusDecode(unsigned char* in_data, int in_len, short *out_buf);private:OpusDecoder *decoder; // opus 解码器指针int sample_rate; // 采样率int channel_num; // 通道数
};
#endif// __OPUS_DEC_H__
opusDec.cpp
/*** @file opusDec.cpp* @author wkd_007* @brief opus 解码* @date 2023-10-27 15:38:43*/#include <stdio.h>
#include "opusDec.h"COpusDec::COpusDec()
{decoder = NULL;sample_rate = 0;channel_num = 0;
}COpusDec::~COpusDec()
{sample_rate = 0;channel_num = 0;if(decoder){opus_decoder_destroy(decoder);decoder = NULL;}
}int COpusDec::CreateOpusDecoder(int sampleRate, int channels)
{int err = 0;decoder = opus_decoder_create(sampleRate, channels, &err);if(err != OPUS_OK || decoder == NULL){printf("[%s %d]err=%d decoderIsNULL=%d\n",__FILE__,__LINE__,err, decoder == NULL);return -1;}opus_decoder_ctl(decoder, OPUS_SET_LSB_DEPTH(16));sample_rate = sampleRate;channel_num = channels;return err;
}int COpusDec::OpusDecode(unsigned char* in_data, int in_len, short *out_buf)
{if(decoder == NULL)return -1;int frame_size = opus_decode(decoder, in_data, in_len, out_buf, MAX_OPUS_DEC_FRAME, 0);if (frame_size < 0){printf("[%s %d] frame_size=%d in_len=%d\n",__FILE__,__LINE__, frame_size,in_len);return frame_size;}return frame_size;
}
readOggFile.c
// g++ readOggFile.c opusDec.cpp ../../opus-1.4/result_gcc/lib/libopus.a -I ../../opus-1.4/result_gcc/include/#include <stdio.h>
#include <stdlib.h>
#include <string.h>#include "opusDec.h"COpusDec g_OpusDec;// 8字节数组转成 unsigned long long
unsigned long long ToULL(unsigned char num[8], int len)
{unsigned long long ret = 0;if(len==8){ int i=0;for(i=0; i<len; i++){ret |= ((unsigned long long)num[i] << (i*8));}}return ret;
}// 4字节数组转成 unsigned int
unsigned int ToUInt(unsigned char num[4], int len)
{unsigned int ret = 0;if(len==4){int i=0;for(i=0; i<len; i++){ret |= ((unsigned int)num[i] << (i*8));}}return ret;
}int readOggPage(char *oggFile)
{typedef struct PAGE_HEADER{ char Oggs[4]; unsigned char ver;unsigned char header_type_flag;unsigned char granule_position[8];unsigned char stream_serial_num[4];unsigned char page_sequence_number[4];unsigned char CRC_checksum[4];unsigned char seg_num;unsigned char segment_table[];}PAGE_HEADER;FILE *fp=fopen(oggFile,"rb");FILE *fpout=fopen("opus_out.pcm","wb+");;while(fp!=NULL && !feof(fp)){// 1、读取 page_headerPAGE_HEADER page_header;if(1 != fread(&page_header,sizeof(page_header),1,fp))break;printf("page_num:%03u; ",ToUInt(page_header.page_sequence_number, 4));printf("Oggs:%c %c %c %c; ",page_header.Oggs[0],page_header.Oggs[1],page_header.Oggs[2],page_header.Oggs[3]);printf("type=%d, granule_position:%08llu; ", page_header.header_type_flag,ToULL(page_header.granule_position, 8));//printf("seg_num:%d \n",page_header.seg_num);// 2、读取 Segment_tableunsigned char *pSegment_table = (unsigned char *)malloc(page_header.seg_num);fread(pSegment_table,sizeof(unsigned char),page_header.seg_num,fp);// 3、计算段数据总大小unsigned int TotalSegSize = 0;int i=0;for(i=0; i<page_header.seg_num; i++){TotalSegSize += pSegment_table[i];}printf("TotalSegSize:%d \n",TotalSegSize);// 4、读取段数据unsigned char *pSegment_data = (unsigned char *)malloc(TotalSegSize);fread(pSegment_data,sizeof(unsigned char),TotalSegSize,fp);if(page_header.header_type_flag == 4)printf("Last 4 Byte: %x %x %x %x\n",pSegment_data[TotalSegSize-4],pSegment_data[TotalSegSize-3], pSegment_data[TotalSegSize-2],pSegment_data[TotalSegSize-1]);// 5、解码opusunsigned sample_pos = ToULL(page_header.granule_position, 8);if(sample_pos){short out_buf[48000*2] = {0};int decodedLen = 0; // 已经解码的长度int preSegLen =0; // 前面分段的长度for(i=0; i<page_header.seg_num; i++){if(pSegment_table[i] == 255)// 这个包延续到后面,把该段长度累加起来{preSegLen += pSegment_table[i];continue;}int decFrames = g_OpusDec.OpusDecode((unsigned char*)pSegment_data+decodedLen, (int)preSegLen+pSegment_table[i], out_buf);if(decFrames < 0){printf("decodedLen=%d TotalSegSize=%d pSegment_table[i]=%d %d %d\n",decodedLen, TotalSegSize,pSegment_table[i-1],pSegment_table[i],pSegment_table[i+1]);}else{fwrite(out_buf,decFrames * sizeof(unsigned short),1,fpout);}decodedLen += (preSegLen+pSegment_table[i]);preSegLen = 0;}}free(pSegment_data);free(pSegment_table);}fclose(fp);fclose(fpout);return 0;
}int main()
{g_OpusDec.CreateOpusDecoder(48000, 1);readOggPage((char *)"48000Hz-s16le-1ch-ChengDu.opus");return 0;
}
🎄六、总结
本文介绍了opus编码的Ogg文件的 ID数据头部、注释数据头部、opus编码数据包的结构和解析,并用一个.opus文件的十六进行带着读者理解各个数据包,最后给出了笔者的C语言代码,将opus编码Ogg格式解析为PCM。看完一定大有所获,别忘记点赞、收藏、支持一下。
如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁
相关文章:

【音视频 | opus】opus编码的Ogg封装文件详解
😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀 🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C、数据结构、音视频🍭 🤣本文内容🤣&a…...

【微信小程序】自定义组件(一)
自定义组件 组件的创建与引用1、创建组件2、引用组件3、全局引用VS局部引用4、组件和页面的区别 样式1、组件样式隔离2、组件样式隔离的注意点3、stylelsolation的可选值 数据、方法和属性1、data数据2、methods方法3、properties4、data和properties区别5、使用setData修改pr…...

如何通过一条数字人三维动画宣传片,打造出数字文旅
越来越多虚拟人,以文化挖掘者的身份通过数字人三维动画宣传片,打通次元壁,助力文化传播形式创造性转化、创新性表达,赋予文化发展新动能。 如南方都市报民间博物馆文化探寻者“岭梅香”,由一艘在南宋时期失事的沉船“南…...

【MongoDB】索引 - 数组字段的多键索引
数组字段创建索引时,MongoDB会为数组中的每个元素创建索引键(多键索引),多键索引支持数组字段的高效查询。 一、准备工作 这里准备一些数据 db.shop.insertMany([{_id: 1, name: "水果店1", fruits: ["apple&qu…...

2023.11.5 关于 Spring 创建 和 使用
目录 创建 Spring 项目 1.创建 Maven 项目 2.添加 Spring 依赖 将 Bean 对象存储到 Spring 容器中 创建 Bean 存储 Bean ApplicationContext 获取 Bean BeanFactory 获取 Bean ApplicationContext 和 BeanFactory 的区别 获取 Bean 的三种方式 根据 Bean id 获取…...

3D目标检测实战 | 图解KITTI数据集评价指标AP R40(附Python实现)
目录 1 准确率和召回率2 P-R曲线的绘制3 AP R11与AP R40标准4 实际案例 1 准确率和召回率 首先给出 T P TP TP、 F P FP FP、 F N FN FN、 T N TN TN的概念 真阳性 True Positive T P TP TP 预测为正(某类)且真值也为正(某类)的样本数,可视为 I o U > I o U t…...

制作一个ros2机器人需要学习的课本(还不全面)
1《C语言》---这个是基础200页左右 2《C》-----500-600页 3《高等数学》-----没有这个无法计算动态电路 4《电路分析》-----没有这个没法设计硬件电路 5《英语5000词汇》最少也得达到美国小学生毕业时候的词汇水平5000词汇量 6《ros1》因为ros2没有一本中文课本---有那么一…...

Qt OpenGL相机系统
文章目录 一、简介二、实现代码三、实现效果参考资料效果展示 一、简介 一直偷懒没有学习OpenGL,乘着这段有点时间重新学习一下OpenGL,做一个简单的小工具,有助于后面理解OSG。我们都知道OpenGL中存在着下面几个坐标空间:模型空间(物体空间)、世界空间、观察空间(或者称…...

英语语音识别,语言评测,语音打分实践与代码实现
项目在这:couldn/speech-evaluation-of-english 详细的可查看项目内的md文档...

【SpringBoot篇】SpringBoot整合Mybatis实战
🎊专栏【SpringBoot】 🍔喜欢的诗句:天行健,君子以自强不息。 🎆音乐分享【如愿】 🎄欢迎并且感谢大家指出小吉的问题🥰 文章目录 🌺Spring Boot和MyBatis的好处🌺创建工…...

android c++ 硬编码硬解码官方demo
参考: https://fossies.org/linux/opencv/modules/videoio/src/cap_android_mediandk.cpp 代码: // This file is part of OpenCV project.// It is subject to the license terms in the LICENSE file found in the top-level directory// of this d…...

Python之Excel数据相关
Excel Microsoft Excel是Microsoft为使用Windows和Apple Macintosh操作系统的电脑编写的一款电子表格软件。直观的界面、出色的计算功能和图表工具,再加上成功的市场营销,使Excel成为最流行的个人计算机数据处理软件。在1993年,作为Microsof…...

Ubuntu网络IP地址一直显示127.0.0.1
问题描述: 终端输入ip a显示127.0.0.1,原来类似192.168.231.1的地址不见了。 ip a 点击网络配置(ubuntu桌面版),发现无线网络模块看不见了 正常情况应该有wired 模块,就是下面标红的 解决方案:…...

Vulnhub-DC-3 靶机复现完整过程
啰嗦两句: 提权之前完成是一个月前做的,当时在提权处出了点问题就搁置了,今天才完成,所以IP地址可能会会有变化 注意:后续出现的IP地址为192.168.200.55同样是靶机IP地址,若本文能有帮助到你的地方…...

Dubbo篇---第三篇
系列文章目录 文章目录 系列文章目录一、Dubbo 容错策略二、Dubbo 动态代理策略有哪些?三、说说 Dubbo 与 Spring Cloud 的区别?一、Dubbo 容错策略 failover cluster 模式 provider 宕机重试以后,请求会分到其他的 provider 上,默认两次,可以手动设置重试次数,建 议把写…...

Redis-使用java代码操作Redis->java连接上redis,java操作redis的常见类型数据存储,redis中的项目应用
java连接上redisjava操作redis的常见类型数据存储redis中的项目应用 1.java连接上redis package com.zlj.ssm.redis;import redis.clients.jedis.Jedis;/*** author zlj* create 2023-11-03 19:27*/ public class Demo1 {public static void main(String[] args) { // …...

react 使用笔记
1.学习:https://reactjs.bootcss.com/learn 2.项目启动报错:Delete ␍ prettier/prettier 解决:https://blog.csdn.net/qq_30272167/article/details/133280165 3.访问地址配置 文件:config-overrides.js devServer: functio…...

Ubuntu下启动Apache对.htaccess 的支持步骤, 利用.htaccess绑定域名到子目录
Ubuntu下启动Apache对.htaccess 的支持步骤 1. 终端运行 sudo a2enmod 程序提示可供激活的模块名称,输入: rewrite 2. 修改/etc/apache2/sites-enabled/000-default (该链接指向的是站点配置文件) 把(默认的www目录、或者需要应用.htacc…...

C++常用格式化输出
在C语言中可以用printf以一定的格式打印字符,C当然也可以。 输入输出及命名空间还不太了解的小伙伴可以看一看C入门讲解第一篇。 在C中,可以用流操作符(stream manipulators)控制数据的输出格式,这些流操作符定义在2…...

QCC TX 音频输入切换+提示声音
QCC TX 音频输入切换提示声音 QCC蓝牙芯片(QCC3040 QCC3056 等等),AUX、I2S、USB输入 蓝牙音频输入,模拟输出是最常见的方式。 也可以再此基础上动态切换输入方式。 针对TX切换EQ,调节音量不能出提示声音问题,可以增…...

【Java】封装、继承、多态
面向对象的重要特征:封装、继承、多态; 面向对象的语言的语言并不止Java,C也是面向对象的语言; 访问限定符 public:在哪里都可以使用(公开的);private:仅在当前类可以使用…...

第九章 异常处理
系列文章目录 第一章 Python 基础知识 第二章 python 字符串处理 第三章 python 数据类型 第四章 python 运算符与流程控制 第五章 python 文件操作 第六章 python 函数 第七章 python 常用内建函数 第八章 python 类(面向对象编程) 第九章 python 异常处理 第十章 python 自定…...

(四) Python Pandas入门
一、介绍 Pandas是Python中一个强大的数据处理库,它提供了许多功能强大的数据结构和数据分析工具。在本文中,我们将介绍Pandas的基本概念和如何使用它生成一个包含今天到未来20个工作日的日期列表的Excel文件。 Pandas提供了大量的数据结构和数据分析工…...

软件测试面试最经典的5个问题
软件测试面试灵魂五问! 请做一下自我介绍?你为什么从上家公司离职?为什么转行做测试? 你对测试行业的认识?你的期望薪资是多少?最后,你要问我什么? 一、请做一下自我介绍 简历上有的可以一两…...

从公共业务提取来看架构演进——功能设置篇
1.引言 上一篇文章我们以帐号权限的提取为例,介绍了当架构跟不上业务发展时及时调整架构的一种思路。这篇文章我们以功能设置为例,进一步讨论公共业务提取这个话题。 功能设置在本文中是指产品开放给企业和用户的一些功能设置项,以视频会议…...

Java基础-015-System.java常用类
Java基础-015-System.java常用类 1、标准输入输出2、获取属性3、System.java初始化4、设置标准输出System.out java/lang/System.java 1、标准输入输出 System.in、System.out public class Test {public static void main(String[] args) {String charsetName String.valueOf…...

Flutter笔记:发布一个模块 scale_design - (移动端)设计师尺寸适配工具
Flutter笔记 发布一个模块scale_design设计师尺寸适配工具与常用组件库 作者:李俊才 (jcLee95):https://blog.csdn.net/qq_28550263 邮箱 :291148484163.com 本文地址:https://blog.csdn.net/qq_28550263/a…...

torch增加维度操作
使用none作为占位符 在Python中,None 表示空值或占位符。 在masked_pos[:, :, None]这个切片操作中,None 被用作一个占位符,以改变张量的维度。这通常用于将一维张量变为二维张量,或者改变张量的形状。 具体来说,ma…...

软件测试面试题及答案2024
1、你们的缺陷等级如何划分的?☆☆☆☆☆ 我们的缺陷一般分为四个等级,致命级,严重级,一般级和轻微级。致命级指能够导致软件程序无法使用的缺陷,比如宕机,崩溃,手机APP的闪退,数据…...

C现代方法(第18章)笔记——声明
文章目录 第18章 声明18.1 声明的语法18.2 存储类型18.2.1 变量的性质18.2.2 auto存储类型18.2.3 static存储类型18.2.4 extern存储类型18.2.5 register存储类型18.2.6 函数的存储类型18.2.7 小结 18.3 类型限定符18.4 声明符18.4.1 解释复杂声明18.4.2 使用类型定义来简化声明…...