zoukankan      html  css  js  c++  java
  • 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裸数据

     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

        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流就可以导入播放器进行播放了


      

  • 相关阅读:
    MiniUI 在线示例(gridview)
    数据库的事务处理和并发控制
    数据库大并发操作要考虑死锁和锁的性能问题
    c# 财务报表数字转大写的方法
    js 实现打印功能1
    js 实现打印功能
    《C++ Primer 4th》读书笔记 序
    谈谈Vim中实用又好记的一些命令
    《Unix网络编程》卷2 读书笔记 第3章- System V IPC
    《Unix网络编程》卷2 读书笔记 第2章- Posix IPC
  • 原文地址:https://www.cnblogs.com/doudouyoutang/p/10232469.html
Copyright © 2011-2022 走看看