Dump Rtmp Audio Stream To AAC Formate File (从Rtmp流提取并保存AAC音频文件)
一、准备工作
参考:https://www.cnblogs.com/doudouyoutang/p/10220599.html
搭建本地rtmp服务:
https://www.cnblogs.com/doudouyoutang/p/6602430.html
获取使用到的库,openssl 和 librtmp
参考:
https://www.jianshu.com/p/b38656443e71
https://github.com/x2on/OpenSSL-for-iPhone
也可以从我的工程中直接拿 https://github.com/liqiushui/RtmpDumpAsAAC
二、关键解释:
RTMP的Message音频和视频分开发送的,音频和视频的发送类似,第一次会收到一个AAC Sequence Header,这里面包含音频格式的描述信息
Message 判断为音频之后,通过判断前两个字节可以得到后面是 AAC Sequence Header 还是 AAC裸数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | if (packet.m_packetType == RTMP_PACKET_TYPE_AUDIO) { //Audio Packet //FLV Audio Tag 原始数据,包含Tag Header, 音频Tag Header一般由一个字节定义(AAC用两个字节) //第一个字节的定义如下:音频格式 4bits | 采样率 2bits | 采样精度 1bits | 声道数 1bits| /* 看第2个字节,如果音频格式AAC(0x0A),AudioTagHeader中会多出1个字节的数据AACPacketType,这个字段来表示AACAUDIODATA的类型: 0x00 = AAC sequence header,类似h.264的sps,pps,在FLV的文件头部出现一次。 0x01 = AAC raw,AAC数据 */ //FLV Audio Tag, 完整格式,结构为:【0x08, 3字节包长度,4字节时间戳,00 00 00】,AF 01 N字节AAC数据 | 前包长度 //其中编码后AAC纯数据长度为N,3字节包长度 = N + 2 //前包长度 = 11 + 3字节包长度 = 11 + N + 2 = 13 + N。 //如果要保存AAC为流数据,需要 【ADTS头 + AACRaw数据】【ADTS头 + AACRaw数据】【ADTS头 + AACRaw数据】 写入文件 if (packet.m_nBodySize >= 2 && packet.m_body[1] == 0x00) { //AAC sequence header this ->p = new FLVAudioTagHeader(( const unsigned char *)(packet.m_body)); this ->p->parse(); this ->p->dumpHeaderInfo(); //FFMpeg 解析参考 //https://github.com/herocodemaster/rtmp-cpp/blob/3ec35590675560ac4fa9557ca7a5917c617d9999/RTMP/projects/ffmpeg/src_completo/libavcodec/mpeg4audio.c //用bit操作类https://blog.csdn.net/qll125596718/article/details/6901935 this ->p->parseAudioConfig(( const char *)(packet.m_body + 2), packet.m_nBodySize-2); } if (packet.m_nBodySize >= 2 && packet.m_body[1] == 0x01) { //AAC Raw Data unsigned char adts[7] = {0}; this ->p->aac_set_adts_head(adts, packet.m_nBodySize - 2); this ->dumpBytesToFlv(adts, 7); this ->dumpBytesToFlv(( const unsigned char *)(packet.m_body+2), packet.m_nBodySize-2); } RTMPPacket_Free(&packet); } |
RTMP的AAC Payload是 2个字节的头 + 【音频裸数据 | 或者 AAC Sequence Header】,
关于AAC Sequence Header的解析,可以参考FFMPEG
如果不解析AAC Sequence Header也是可以的,因为后面每段音频的前两个字节的头,也包含音频格式、采样率、帧率的信息
得到音频的裸数据后,如果需要播放,需要在每段数据前面加上ADTS头
感谢: https://blog.csdn.net/lichen18848950451/article/details/78266054
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | int aac_set_adts_head(unsigned char *buf, int size) { ADTSContext *acfg = & this ->ctx; unsigned char byte; if (size < ADTS_HEADER_SIZE) { return -1; } buf[0] = 0xff; buf[1] = 0xf1; byte = 0; byte |= (acfg->objecttype & 0x03) << 6; byte |= (acfg->sample_rate_index & 0x0f) << 2; byte |= (acfg->channel_conf & 0x07) >> 2; buf[2] = byte; byte = 0; byte |= (acfg->channel_conf & 0x07) << 6; byte |= (ADTS_HEADER_SIZE + size) >> 11; buf[3] = byte; byte = 0; byte |= (ADTS_HEADER_SIZE + size) >> 3; buf[4] = byte; byte = 0; byte |= ((ADTS_HEADER_SIZE + size) & 0x7) << 5; byte |= (0x7ff >> 6) & 0x1f; buf[5] = byte; byte = 0; byte |= (0x7ff & 0x3f) << 2; buf[6] = byte; return 0; } |
在追加了ADTS头,aac流就可以导入播放器进行播放了
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架