Enhanced-Rtmp支持H265

Enhanced-Rtmp支持H265

千呼万唤使出来,rtmp/flv算是有统一支持H265的国际版本。本文介绍一下:

  • 现存rtmp/flv支持H265的方式;
  • Enhanced-Rtmp协议如何支持H265;
  • ffmpeg/obs/srs/media-server各个开源的实现;
  • 国内方案与国外方案的兼容性问题;

1. rtmp/flv封装视频方式

准确的说,rtmp是传输协议,传输协议内部的封装是flv格式,其实我们所说的支持H265,是在flv封装格式里面支持H265编码数据。

flv对视频的封装格式, 原有VideoTagHeader定义如下:

------------------------------------------------------------------------------------
| FrameType(4bits) | CodecID(4bits) | AVCPacketType(8bits)| CompositionTime(24bits)|
------------------------------------------------------------------------------------

其中:

  • FrameType: 4个bits, 1: keyframe, 也就是I帧; 2: inter frame, 非I帧,B帧或P帧;
  • CodecID: 4个bits,
1: JPEG (currently unused); 
2: Sorenson H.263; 
3: Screen video; 
4: On2 VP6; 
5: On2 VP6 with alpha channel; 
6: Screen video version 2; 
7: AVC;

这里如果是H264,就是7。

  • AVCPacketType: 8个bits,也就是一个字节,0: AVC sequence header; 1: AVC NALU
  • CompositionTime: 3个字节(24bits),表示pts与dts的差值;

举例:

  • 如果视频数据是H264的sequence header(也就是包含sps/pps的Avcc Header),就应该是0x17 00;
  • 如果视频数据是H264的Iframe,就应该是0x17 01;
  • 如果视频数据是H264的非Iframe,就应该是0x27 01

flv的标准中,只设定了H264的codecId为7,之后的flv标准就没在针对video的codecId进行增加,这也就是导致后面rtmp/flv没有支持H265的标准。

1.1. 国内rtmp/flv对H265的支持

随着国内前10年移动互联网对直播需求的增加,对高清画质的需求与日俱增,支持H265直播的需求很早就在各家CDN和云厂商成为top需求。

因此,国内云厂商和CDN厂商对H265很早就支持,支持的方式比较简单,就是自定义H265的CodecID=0xC,也就是CodecID值为12。

1: JPEG (currently unused); 
2: Sorenson H.263; 
3: Screen video; 
4: On2 VP6; 
5: On2 VP6 with alpha channel; 
6: Screen video version 2; 
7: AVC;
12: H265(国内自定义H265的CodecID);

这样的自定义的好处:迅速解决了国内统一rtmp/flv支持H265的格式标准;国内的cdn厂家的服务都遵循CodecID=12来实现rtmp/flv直播服务。

举例:

  • 如果视频数据是H265的sequence header,就应该是0x1c 00;
  • 如果视频数据是H265的Iframe,就应该是0x1c 01;
  • 如果视频数据是H265的非Iframe,就应该是0x2c 01

国内的多个开源也都遵循国内的H265标准:

  • SRS
  • media-server
  • ffmpeg_rtmp_h265 自定义补丁

但是,同样有其局限性:CodecID是自定义的,并且对CodecID只有4个bits的局限性没能解决,后面对新增的编码方式无法适用,如新增VP8,VP9, AV1,或未来的H266,扩展会很难。

国外为准的流媒体开源,并未支持CodecId=12为H265,如:

  • ffmpeg: 未支持CodecId=12为H265;
  • obs: 未支持CodecId=12为H265;

2. Enhanced-Rtmp

Enhanced-Rtmp公布支持H265的标准,彻底解决在rtmp/flv支持H265的编码。

2.1 Enhanced-Rtmp规范

Enhanced-Rtmp规范: 原文

flv对视频的封装格式, 原有VideoTagHeader定义如下:

------------------------------------------------------------------------------------
| FrameType(4bits) | CodecID(4bits) | AVCPacketType(8bits)| CompositionTime(24bits)|
------------------------------------------------------------------------------------

而Enhanced-Rtmp对上面的格式进行修改:
首先FrameType第一个bit变为IsExHeader,如下

-------------------------------------
| IsExHeader(1bit)FrameType(3bits) |
-------------------------------------

也就是在原FrameType的最高位加了1bit的IsExHeader标志位,如果IsExHeader使能,表示Enhanced-Rtmp格式使能,后面的定义是Enhanced-Rtmp格式;否则还遵循之前的rtmp/flv传统规范。

格式的具体逻辑如下,UB代表bit的站位符(举例: UB[4]表示站位4bits)

IsExHeader = (UB[4] & 0b1000 != 0) ? true : false;
FrameType = UB[4] & 0b0111; //1 = key frame, 2 = inter frameif (IsExHeader == 0)
{//如果IsExHeader未使能, 还遵循之前的rtmp/flv传统规范CodecId = UB[4];//4bits的codecId,H264的值为7.AVCPacketType = UB[8];//8bits的AVCPacketType, 0: sequence header; 1: NALUCompositionTime = UB[24];//24bits的CompositionTime,表示pts与dts的差值DATA = [H264 NALU]; //后续数据为常规的视频数据
}
else // IsExHeader使能,表示Enhanced-Rtmp格式使能
{PacketType = UB[4];// 0 = PacketTypeSequenceStart// 1 = PacketTypeCodedFrames// 2 = PacketTypeSequenceEnd// 3 = PacketTypeCodedFramesX// 4 = PacketTypeMetadata// 5 = PacketTypeMPEG2TSSequenceStartFourCC = UB[32];// 4字节的FourCC,如下字符表示对应的视频CodecId// AV1 = { 'a', 'v', '0', '1' }// VP9 = { 'v', 'p', '0', '9' }// HEVC = { 'h', 'v', 'c', '1' }, 也就是h265// 如果类型是HEVC, 也就是H265,后续规范如下if (FourCC == HEVC){if (PacketType == PacketTypeSequenceStart){//如果PacketType是PacketTypeSequenceStart,表示后续H265的数据内容是DecoderConfigurationRecord,也就是常说的sequence header;DATA = [HEVCDecoderConfigurationRecord]}else if (PacketType == PacketTypeCodedFrames || PacketType == PacketTypeCodedFramesX){if (PacketType == PacketTypeCodedFrames){//如果PacketType是PacketTypeCodedFrames,就是pts与dts有差值CompositionTime = UB[24];//24bits,表示pts与dts的差值}else //如果PacketType是PacketTypeCodedFramesX{//无CompositionTime,节省3字节的空间}//随后是正常的H265数据DATA = [HEVC NALU]}}
}

2.2 ffmpeg6.1实现Enhance Rtmp

ffmpeg在version6.1中正式支持enhance rtmp,以此支持H265 in rtmp/flv。这里介绍其对应的实现。

首先下载对应的ffmpeg6.1版本源码:

git clone https://git.ffmpeg.org/ffmpeg.git ffmpeg
cd ffmpeg
git fetch origin release/6.1
git checkout release/6.1

flv封装的实现,对应文件: libavformat/flvenc.c

static int flv_write_packet(AVFormatContext *s, AVPacket *pkt) {//......// 如果编码格式是H265, 使用如下的实现if (par->codec_id == AV_CODEC_ID_HEVC) {// 如果报文pts和dts不一样,packettype为PacketTypeCodedFrames;// 否则packettype为PacketTypeCodedFramesXint pkttype = (pkt->pts != pkt->dts) ? PacketTypeCodedFrames : PacketTypeCodedFramesX;// 第一个字节,最高bit位写入FLV_IS_EX_HEADER;// 第一个字节,最高的第3, 4bits写入FLV_FRAME_KEY或FLV_FRAME_INTER// 第一个字节,最低2bits位,写入PacketTypeCodedFramesX或PacketTypeCodedFramesavio_w8(pb, FLV_IS_EX_HEADER | pkttype | frametype); // ExVideoTagHeader mode with PacketTypeCodedFrames(X)// 后4个字节,写入FourCC,写入4个字符: "hvc1"avio_write(pb, "hvc1", 4);// pkttype为PacketTypeCodedFrames,写入3个字节的pts与dts的差值if (pkttype == PacketTypeCodedFrames)avio_wb24(pb, pkt->pts - pkt->dts);}// 写入H264的数据avio_write(pb, pkt->data, pkt->size);// ......
}

2.3 OBS实现Enhance Rtmp

OBS在Release 29版本正式支持Enhance Rtmp,实现H265 in rtmp/flv的直播推流。
获取版本:

git clone git@github.com:obsproject/obs-studio.git
cd obs-studio
git fetch origin release/29.1
git checkout release/29.1

具体实现在: plugins/obs-outputs/rtmp-stream.c


enum packet_type_t {PACKETTYPE_SEQ_START = 0, //表示报文序列开始PACKETTYPE_FRAMES = 1,    //表示该帧dts与pts有差值PACKETTYPE_SEQ_END = 2,   //flv文件最后一帧
#ifdef ENABLE_HEVCPACKETTYPE_FRAMESX = 3,   //表示该帧dts == pts
#endifPACKETTYPE_METADATA = 4
};//函数flv_packet_ex的最后一个参数type为packet_type_t的取值范围
void flv_packet_ex(struct encoder_packet *packet, enum video_id_t codec_id,int32_t dts_offset, uint8_t **output, size_t *size, int type)
{
// ........// packet ext header// 第一个字节,最高bit位写入1, FRAME_HEADER_EX = 8 << 4;// 第一个字节,最高的第3, 4bits写入FLV_FRAME_KEY或FLV_FRAME_INTER// 第一个字节,最低2bits位,写入PacketTypeCodedFramesX或PacketTypeCodedFrames, dts与pts相等或不等;//                       或写入PACKETTYPE_SEQ_START,或PACKETTYPE_SEQ_ENDs_w8(&s,FRAME_HEADER_EX | type | (packet->keyframe ? FT_KEY : FT_INTER));// 后4个字节,写入FourCC,写入4个字符: "hvc1"s_w4cc(&s, codec_id);#ifdef ENABLE_HEVC// hevc composition time offsetif (codec_id == CODEC_HEVC && type == PACKETTYPE_FRAMES) {// PacketType为PACKETTYPE_FRAMES,写入3个字节的pts与dts的差值s_wb24(&s, get_ms_time(packet, packet->pts - packet->dts));}
#endif// 写入h265的帧数据s_write(&s, packet->data, packet->size);
}

2.4 SRS实现Enhance Rtmp

SRS是国内最流行的流媒体服务器,支持多种直播协议rtmp, httpflv, hls,支持webrtc,也支持安放协议28181。SRS也率先支持Enhance Rtmp,服务端能够接受Enhance Rtmp的推流,同时也兼容国内CodecId=12的H265的rtmp方案。

但是在rtmp或httpflv拉流方向,是应用国内CodecId=12的H265的rtmp方案。

SRS的github地址: https://github.com/ossrs/srs.git, 当前支持分支develop。

实现主要在srs_kernel_codec.cpp这个文件中。

srs_error_t SrsFormat::video_avc_demux(SrsBuffer* stream, int64_t timestamp) {uint8_t frame_type = stream->read_1bytes();bool is_ext_header = frame_type & 0x80;//判断Rtmp Enhance是否支持,从而获取到编码类型if (!is_ext_header) {// 如果不是Rtmp Enhance,用传统的方式判断codec_id = (SrsVideoCodecId)(frame_type & 0x0f);frame_type = (frame_type >> 4) & 0x0f;} else {// 如果使能Rtmp Enhance,获取packet_type和frame_typepacket_type = (SrsVideoAvcFrameTrait)(frame_type & 0x0f);frame_type = (frame_type >> 4) & 0x07;// 读取4个字节的FourCC,判断是否是HEVC.uint32_t four_cc = stream->read_4bytes();if (four_cc == 0x68766331) { // 'hvc1'=0x68766331codec_id = SrsVideoCodecIdHEVC;}}//判断Rtmp Enhance是否支持,从而获取到composition_time(dts与pts的差值)if (!is_ext_header) {// 如果是传统的Rtmp,读取1个字节的packet_type,和3个字节的composition_timepacket_type = (SrsVideoAvcFrameTrait)stream->read_1bytes();composition_time = stream->read_3bytes();} else {// 如果使能Rtmp Enhance,当packet_type==1的时候,dts才与pts不一致,才读取3个字节的composition_time,// 否则没有composition_time字段;if (packet_type == 1) {composition_time = stream->read_3bytes();}}
}

2.5 media-server实现Enhance Rtmp

media-server是国内开源库中实现音视频格式和流媒体类型最全的开源之一,支持flv, mp4, mkv, hls, mpeg, rtmp, rtp, rtsp, sip等音视频格式和流媒体协议,并且在各种封装中支持的codec非常丰富,如H264, H265, AV1, H266都有支持。其采用C语言开发,兼容性好,同时适合服务器和嵌入式的开发。

media-server的github地址: https://github.com/ireader/media-server

media-server的Flv模块同时支持demuxer和muxer,对Enhance Rtmp支持比较全,同时支持AV1, H265, H266。(居然还支持H266,并且有H266 annexb to mp4和H266 mp4 to annexb的代码)

Enhance Rtmp的实现主要在flv-header.c这个文件中, 关键的对应代码如下:

// demuxer
int flv_video_tag_header_read(struct flv_video_tag_header_t* video, const uint8_t* buf, size_t len) {// 如果第一个bit是1,则Enhance Rtmp使能if (len >= 5 && 0 != (buf[0] & 0x80)) {video->keyframe = (buf[0] & 0x70) >> 4; //获取到是否keyframevideo->avpacket = (buf[0] & 0x0F); //获取packettypevideo->cts = 0; // defaultswitch(FLV_VIDEO_FOURCC(buf[1], buf[2], buf[3], buf[4])){case FLV_VIDEO_FOURCC_AV1:video->codecid = FLV_VIDEO_AV1;return 5;case FLV_VIDEO_FOURCC_HEVC:case FLV_VIDEO_FOURCC_VVC:{if (video->avpacket == 1) //如果packettype==1,则dts与pts的差值存在{video->cts = ((uint32_t)buf[5] << 16) | ((uint32_t)buf[6] << 8) | buf[7];}return 5;}}}//否则走传统flv的解析流程//....
}// muxer: 通过编译宏控制
int flv_video_tag_header_write(const struct flv_video_tag_header_t* video, uint8_t* buf, size_t len)
{
#ifdef FLV_ENHANCE_RTMP
buf[0] = 0x80 | (video->keyframe << 4) /*FrameType*/;buf[0] |= (0 == video->cts && FLV_AVPACKET == video->avpacket) ? FLV_PACKET_TYPE_CODED_FRAMES_X : video->avpacket;switch (video->codecid){case FLV_VIDEO_AV1:SetFourCC(&buf[1], FLV_VIDEO_FOURCC_AV1);return 5;case FLV_VIDEO_H265:SetFourCC(&buf[1], FLV_VIDEO_FOURCC_HEVC);if (len >= 8 && FLV_AVPACKET == video->avpacket && video->cts != 0){SetCTS(&buf[5], video->cts);return 8;}return 5;case FLV_VIDEO_H266:SetFourCC(&buf[1], FLV_VIDEO_FOURCC_VVC);if (len >= 8 && FLV_AVPACKET == video->avpacket && video->cts != 0){SetCTS(&buf[5], video->cts);return 8;}return 5;default:break; // fallthrough}#endif//否则走传统flv的muxer流程
}

3. 国内rtmp支持H265与Enhance rtmp的兼容性问题

因为国内之前支持H265的方案是CodecID=12,现在存在的兼容性其实有两个方向:

  • 推流方向(上行)
  • 拉流方向(下行)

3.1 推流方向

推流方向的兼容性,主要取决于服务端的兼容性,也就是说服务端必须同时能支持:

  • 国内CodecID=12的H265方案
  • Enhance Rtmp的H265方案

先说结论,上行推流方向的兼容性是没有问题,只需要在服务端做好兼容性,同时支持国内外的两种方案。

具体我们以SRS服务为例,只需要判断第一bit位是否使能,就能得知后面应该走Rtmp Enhance流程,还是走传统的Rtmp流程

    bool is_ext_header = frame_type & 0x80;//判断Rtmp Enhance是否支持,从而获取到编码类型if (!is_ext_header) {// 如果不是Rtmp Enhance,用传统的方式判断} else {// 如果使能Rtmp Enhance,获取packet_type和frame_type// 如果packet_type == 1,获取composition_time(3字节,dts与pts的差值)}

因为第一个bit位就能判断后续的代码处理流程,所以推流上行做兼容性是比较容易的;

上行解包后,形成数据结构的对象,将其传到下行拉流处,因为视频帧数据部分已经去掉flvTagHeader头,所以该对象传递到下行处理。

以下为伪码:

class SrsVideoFrame
{
public:SrsVideoAvcFrameType frame_type; // 帧类型: I/非ISrsVideoAvcFrameTrait avc_packet_type;// 是否sequenche header等类型
public:int nb_samples; // 帧个数,SrsSample samples[SrsMaxNbSamples];// 帧数组,每个SrsSample是一个视频帧数据
};

SrsVideoFrame中的SrsSample数据,是去掉flvTagHeader的视频帧数据,这样传递到下行后,可以根据需要再次打包flvTagHeader,下行可以再次打包成传统的CodecId=12的H265格式,也可以打包成Enhance Rtmp格式(因为下行的兼容性问题,不推荐下行打包成Enhance Rtmp格式,下一节会说明原因)

3.2 拉流方向

拉流方向的兼容性,主要取决于客户端的兼容性,也就是rtmp或http-flv拉流播放器端的兼容性。

因为之前国内的大多数已有的播放器,都支持CodecId=12的H265方案,现存市场很多播放器是没能支持Enhanche Rtmp,也就是说即使服务端下行方向支持Enhance Rtmp,把Enhance Rtmp流推给客户端,客户端可能存在不能识别的情况。对于大量存量的Rtmp/http-flv播放器(仅仅支持CodecId=12的H265方案),向下的流推送只能继续采用CodecId=12的H265方案。

所以,当前国内大多数云服务商和CDN在下行方向,都仅仅支持CodecID=12的国内H265方案。

总结

简单一句话总结兼容性:上行推流国内外两种推流都能兼容,但是下行仅仅提供CodecID=12的国内H265方案支持。

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

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

相关文章

安卓内存机制

目录 前言一、内存 LowMemoryKiller二、常用的内存调优分析命令&#xff1a; 前言 安卓内存知识&#xff0c;不定期更新… 一、内存 LowMemoryKiller Android的设计理念之一&#xff0c;便是应用程序退出,但进程还会继续存在系统以便再次启动时提高响应时间. 这样的设计会带…

初识JDBC

1、JDBC是什么&#xff1f; Java DataBase Connectivity(Java语言连接数据库) 2、JDBC的本质是什么&#xff1f; JDBC是SUN公司制定的一套接口(interface) java.sql.*;(这个包下有很多接口) 接口都有调用者和实现者。 面向接口调用、面向接口写实现类&#xff0c;这都属于…

mysql的导入与导出

mysql表的导入与导出 导出 直接在命令行中输入&#xff08;注意不需要进入mysql&#xff09; mysqldump -u root -p my_database > C:/Users/xxx/Desktop/all.sql然后他会要求你输入数据库的密码 导入 同样也是直接在命令行中输入 mysql -u root -p my_database < …

JAVA安装linux环境安装maven

linux安装java 下载java8,地址为&#xff1a; https://www.oracle.com/cn/java/technologies/downloads/#java8&#xff0c;下载后缀为tar.gz的解压 tar -zxvf jdk-8u381-linux-x64.tar.gz移动 mv jdk1.8.0_381/ /usr/local/环境变量 export JAVA_HOME/usr/local/jdk1.8.0_38…

【Osek网络管理测试】[TG3_TC6]等待总线睡眠状态_2

&#x1f64b;‍♂️ 【Osek网络管理测试】系列&#x1f481;‍♂️点击跳转 文章目录 1.环境搭建2.测试目的3.测试步骤4.预期结果5.测试结果 1.环境搭建 硬件&#xff1a;VN1630 软件&#xff1a;CANoe 2.测试目的 验证DUT在满足进入等待睡眠状态的条件时是否进入该状态 …

17 内核开发-内核内部内联汇编学习

​ 17 内核开发-内核内部内联汇编学习 课程简介&#xff1a; Linux内核开发入门是一门旨在帮助学习者从最基本的知识开始学习Linux内核开发的入门课程。该课程旨在为对Linux内核开发感兴趣的初学者提供一个扎实的基础&#xff0c;让他们能够理解和参与到Linux内核的开发过程中…

英伟达推出视觉语言模型:VILA

NVIDIA和MIT的研究人员推出了一种新的视觉语言模型(VLM)预训练框架&#xff0c;名为VILA。这个框架旨在通过有效的嵌入对齐和动态神经网络架构&#xff0c;改进语言模型的视觉和文本的学习能力。VILA通过在大规模数据集如Coy0-700m上进行预训练&#xff0c;采用基于LLaVA模型的…

VBA编程之条件语句

上一篇我们讲述了条件语句以及分支。文章的最后用到了逻辑运算符“And“那么今天我们来聊一聊逻辑运算符和Select……Case结构。 在学习前我们先来了解一下&#xff0c;在生活中我们经常说”这个包括那个“&#xff0c;”你或者他“&#xff0c;”不是“等等。而这里”包括“和…

面对对象之封装

Python面向对象之封装 【一】什么是封装&#xff0c;为什么要封装 封装就是指&#xff0c;把数据与功能都整合到一起 就是将某些地方隐藏起来&#xff0c;在程序外部看不到&#xff0c;其他程序无法调用 封装最主要的原因就是为了保护隐私&#xff0c;将不想让用户看到的功能…

esp32+mqtt协议+paltformio+vscode+微信小程序+温湿度检测

花费两天时间完成了这个项目&#xff08;不完全是&#xff0c;属于是在resnet模型训练和温湿度检测两头跑......模型跑不出来&#xff0c;又是第一次从头到尾独立玩硬件&#xff0c;属于是焦头烂额了......&#xff0c;完成这个项目后&#xff0c;我的第一反应是写个csdn&#…

[每日AI·0506]巴菲特谈 AI,李飞飞创业,苹果或将推出 AI 功能,ChatGPT 版搜索引擎

AI 资讯 苹果或将推出 AI 功能&#xff0c;随 iPhone 发布2024 年巴菲特股东大会&#xff0c;巴菲特将 AI 类比为核技术 巴菲特股东大会 5 万字实录消息称 OpenAI 将于 5 月 9 日发布 ChatGPT 版搜索引擎路透社消息&#xff0c;斯坦福大学 AI 领军人物李飞飞打造“空间智能”创…

切比雪夫滤波器

切比雪夫滤波器&#xff0c;也被称为车比雪夫滤波器&#xff0c;是一种在通带或阻带上频率响应幅度等波纹波动的滤波器。它基于切比雪夫多项式的理论&#xff0c;并且是以俄罗斯数学家巴夫尼提列波维其切比雪夫&#xff08;Пафнутий Лвович Чебышёв&#…

论文辅助笔记:Tempo 之 model.py

0 导入库 import math from dataclasses import dataclass, asdictimport torch import torch.nn as nnfrom src.modules.transformer import Block from src.modules.prompt import Prompt from src.modules.utils import (FlattenHead,PoolingHead,RevIN, )1TEMPOConfig 1.…

【C++】 认识多态 + 多态的构成条件详细讲解

前言 C 目录 1. 多态的概念2 多态的定义及实现2 .1 虚函数&#xff1a;2 .2 虚函数的重写&#xff1a;2 .2.1 虚函数重写的两个例外&#xff1a; 2 .3 多态的两个条件&#xff08;重点&#xff09;2 .4 析构函数为啥写成虚函数 3 新增的两个关键字3.1 final的使用&#xff1a;3…

09_电子设计教程基础篇(电阻)

文章目录 前言一、电阻原理二、电阻种类1.固定电阻1、材料工艺1、线绕电阻2、非线绕电阻1、实心电阻1、有机实心电阻2、无机实心电阻 2、薄膜电阻&#xff08;常用&#xff09;1、碳膜电阻2、合成碳膜电阻3、金属膜电阻4、金属氧化膜电阻5、玻璃釉膜电阻 3、厚膜电阻&#xff0…

vue2实现生成二维码和复制保存图片功能(复制的同时会给图片加文字)

<template><divstyle"display: flex;justify-content: center;align-items: center;width: 100vw;height: 100vh;"><div><!-- 生成二维码按钮和输入二维码的输入框 --><input v-model"url" placeholder"输入链接" ty…

智能家居1 -- 实现语音模块

项目整体框架: 监听线程4&#xff1a; 1. 语音监听线程:用于监听语音指令&#xff0c; 当有语音指令过来后&#xff0c; 通过消息队列的方式给消息处理线程发送指令 2. 网络监听线程&#xff1a;用于监听网络指令&#xff0c;当有网络指令过来后&#xff0c; 通过消息队列的方…

SpringSecurity6 学习

学习介绍 网上关于SpringSecurity的教程大部分都停留在6以前的版本 但是&#xff0c;SpringSecurity6.x版本后的内容进行大量的整改&#xff0c;网上的教程已经不能够满足 最新的版本使用。这里我查看了很多教程 发现一个宝藏课程&#xff0c;并且博主也出了一个关于SpringSec…

【python】条件语句与循环语句

目录 一.条件语句 1.定义 2.条件语句格式 &#xff08;1&#xff09;if &#xff08;2&#xff09;if-else &#xff08;3&#xff09;elif功能 &#xff08;4&#xff09;if嵌套使用 3.猜拳游戏 二.循环语句 1. while循环 2.while嵌套 3.for循环 4.break和conti…

被问了n遍的小程序地理位置权限开通方法

小程序地理位置接口有什么功能&#xff1f; 在平时我们在开发小程序时&#xff0c;难免会需要用到用户的地理位置信息的功能&#xff0c;小程序开发者开放平台新规要求如果没有申请开通微信小程序地理位置接口( getLocation )&#xff0c;但是在代码中却使用到了相关接口&#…