做了一星期了,几乎搜遍了网上所有相关的博文终于完成了这个,整理下思路给需要的朋友
首先得说下这边的环境,数据是rtmp c++过来的,公司底层已经写完,flash端已经可以流畅播放
刚开始做的时候网上搜了下关于AudioQueue的资料,想了解的朋友可以看下
http://blog.csdn.net/onlyou930/article/details/7372791
学习了基本的知识后,搜索能在内存中读buffer的ios类库
后来在这个帖子中看到了作者使用AudioFileStream实现了内存播放
http://www.cocoachina.com/bbs/read.php?tid=93226&page=1
所以在苹果官网下载了AudioFileStreamExample,改了下顺利跑起来,
再自己封装了个AudioPlayer基本实现播放器
接下来就是把rtmp过来的数据整合到AudioPlayer,这个东西卡了我将近一星期
因为快过年了,做rtmp底层的哥们回家了,
把rtmp过来的数据直接塞给AudioFileStreamParseBytes完全解析不出来,十分抓狂,在这里绕了好几天
首先直接放进去是不对的,在此之后去了解了下aac、heaac的解读方式,
一度以为ios不能直接放aac,得通过解码器解码。。。后来发现自己绕远了,回来继续思考
在这个帖子看到了格式的基本定义
http://www.cnblogs.com/caosiyang/archive/2012/07/16/2594029.html
AAC音频格式分析 AAC音频格式有ADIF和ADTS: ADIF:Audio Data Interchange Format 音频数据交换格式。这种格式的特征是可以确定的找到这个音频数据的开始,不需进行在音频数据流中间开始的解码,即它的解码必须在明确定义的开始处进行。故这种格式常用在磁盘文件中。 ADTS:Audio Data Transport Stream 音频数据传输流。这种格式的特征是它是一个有同步字的比特流,解码可以在这个流中任何位置开始。它的特征类似于mp3数据流格式。 简单说,ADTS可以在任意帧解码,也就是说它每一帧都有头信息。ADIF只有一个统一的头,所以必须得到所有的数据后解码。且这两种的header的格式也是不同的,目前一般编码后的和抽取出的都是ADTS格式的音频流。 语音系统对实时性要求较高,基本是这样一个流程,采集音频数据,本地编码,数据上传,服务器处理,数据下发,本地解码 ADTS是帧序列,本身具备流特征,在音频流的传输与处理方面更加合适。
也就是之前我在AudioFileStreamExample里直接读取的是ADIF格式的文件,那么AudioQueue能不能播放adts的呢?
经过测试答案是肯定的,我用千千静听转了一个音频,格式为heacc,并且勾上了ISO-13318-7,转码出来就是带adts头的文件了
接着开始着手读取adts头了,我在csdn下了个adts头读取的demo很好用
下载地址:http://download.csdn.net/detail/yyh520520/4877097,要积分给原作者的哦!!
这个是adts头的一些资料:http://honwsn.itpub.net/post/41648/497237
把里面的函数封装到了自己写的AudioPlayer,
用千千静听转码的HEAAC+ADTS格式的文件,用每次包的头7个字节用那个函数读取打印出来,解析正常,
接着套到rtmp流去居然发现每个包第一个字节不是0xFF,再次陷入泥潭
询问了音频编解码的哥们,他肯定说是以adts打包的,没问题!!接着问一些rtmp包相关的问题他就不涉及到,也就啥也不知道了
最后只能看rtmp底层的源代码,发现这段代码
pkt->m_body[0] = char(0xaf); pkt->m_body[1] = char(0x01);
同事发了我一片博文,我们终于研究出了其中道道
rtmp的音频数据过来,
第一帧是0xaf,0x00,.....,是告知文件的格式、码率、声道等
第二帧是0xaf,0x01,....,前面2字节是固定加的,后面是adts帧去掉头7字节后的数据
那么豁然开朗,flash中能播放是因为遵循了rtmp协议,这个协议就是这么定义的数据,
把原始的adts帧去掉头7字节,然后在最前面加上0xaf,0x01,就可以给flash 播放
那么我在ios上做的时候读取第一帧,解析出音频格式,生成adts头
然后后面的每个数据帧去掉头2字节0xaf,0x01,加上7字节adts头(根据传过来的参数生成),后面跟上音频数据,
传给AudioQueue终于出声!!!!把我给激动的呀!!!!
总结一下
问题出现在对rtmp协议的不理解,自己使劲在那里转,
现在问题解决了,终于可以过个好年了,也祝大家新春快乐,自己明年顺利,哈哈
#include <stdio.h> typedef struct adts_fixed_header { unsigned int syncword:12; unsigned char ID:1; unsigned char layer:2; unsigned char protection_absent:1; unsigned char profile:2; unsigned char sampling_frequency_index:4; unsigned char private_bit:1; unsigned char channel_configuration:3; unsigned char original_copy:1; unsigned char home:1; }adts_fixed; typedef struct adts_variable_header { unsigned char copyright_identification_bit:1; unsigned char copyright_identification_start:1; unsigned int frame_length:13; unsigned int adts_buffer_fullness:11; unsigned char number_of_raw_data_blocks_in_frame:2; }adts_variable; static int read_adts(unsigned char* adts); unsigned char adts_t[25]; unsigned char adts[7]={0xff,0xf9,0x60,0x40,0x10,0x1f,0xfc}; unsigned char adts_s[7]; static int read_adts(unsigned char* adts) { adts_fixed *fixed; adts_variable *variable; fixed = (adts_fixed *)malloc(sizeof(adts_fixed) *1); variable = (adts_variable *)malloc(sizeof(adts_variable) *1); fixed->syncword = ((adts[0]<<4) |(adts[1]>>4)); fixed->ID = ((adts[1]>>3)&0x1); fixed->layer = ((adts[1]>>1)&0x3); fixed->protection_absent = ((adts[1])&0x1); fixed->profile = ((adts[2]>>6)&0x3); fixed->sampling_frequency_index = ((adts[2]>>2)&0xF); fixed->private_bit = ((adts[2]>>1)&0x1); fixed->channel_configuration =(((adts[2]&0x1)<<2)|((adts[3]>>6)&0x3)); fixed->original_copy = ((adts[3]>>5)&0x1); fixed->home = ((adts[3]>>4)&0x1); variable->copyright_identification_bit =((adts[3]>>3)&0x1); variable->copyright_identification_start =((adts[3]>>2)&0x1); variable->frame_length =((((adts[3])&0x3)<<11)|(adts[4])<<3|((adts[5]>>5)&0x7)); variable->adts_buffer_fullness =(((adts[5]&0x1F)<<6)|((adts[6]>>2)&0x3F)); variable->number_of_raw_data_blocks_in_frame =(adts[6]&0x3); printf("***********fixed*******************************\n"); printf("fixed->syncword = 0x%x\n",fixed->syncword); printf("fixed->ID = 0x%x\n",fixed->ID); printf("fixed->layer = 0x%x\n",fixed->layer); printf("fixed->protection_absent = 0x%x\n",fixed->protection_absent); printf("fixed->profile = 0x%x\n",fixed->profile); printf("fixed->sampling_frequency_index = 0x%x\n",fixed->sampling_frequency_index); printf("fixed->private_bit = 0x%x\n",fixed->private_bit); printf("fixed->channel_configuration = 0x%x\n",fixed->channel_configuration); printf("fixed->original_copy = 0x%x\n",fixed->original_copy); printf("fixed->home = 0x%x\n",fixed->home); printf("***********variable*******************************\n"); printf("variable->copyright_identification_bit = 0x%x\n",variable->copyright_identification_bit); printf("variable->copyright_identification_start = 0x%x\n",variable->copyright_identification_start); printf("variable->frame_length = 0x%x\n",variable->frame_length); printf("variable->adts_buffer_fullness = 0x%x\n",variable->adts_buffer_fullness); printf("variable->number_of_raw_data_blocks_in_frame = 0x%x\n",variable->number_of_raw_data_blocks_in_frame); return 0; } static int write_adts(unsigned char* adts_s,int sample,int channel,int len) { adts_fixed *fixed; adts_variable *variable; memset(adts_s,0,7); fixed = (adts_fixed *)malloc(sizeof(adts_fixed) *1); variable = (adts_variable *)malloc(sizeof(adts_variable) *1); fixed->syncword = 0xfff; fixed->ID = 0x1; fixed->layer =0x0; fixed->protection_absent =0x1; fixed->profile = 0x1; fixed->sampling_frequency_index = sample ;//sample; fixed->private_bit = 0x0; fixed->channel_configuration = channel;//channel; fixed->original_copy = 0x0; fixed->home = 0x0; variable->copyright_identification_bit =0x0; variable->copyright_identification_start =0x0; variable->frame_length = len;//len; variable->adts_buffer_fullness =0x7ff; variable->number_of_raw_data_blocks_in_frame =0x0; adts_s[0] = (fixed->syncword>>4); adts_s[1] = (((fixed->syncword & 0xF)<<4)|(fixed->ID<<3)|(fixed->layer<<1)|(fixed->protection_absent)); adts_s[2] = ((fixed->profile<<6)|(fixed->sampling_frequency_index<<2)|(fixed->private_bit<<1)|((fixed->channel_configuration>>2)&0x1)); adts_s[3] = (((fixed->channel_configuration&0x3)<<6)|(fixed->original_copy<<5)|(fixed->home<<4)|(variable->copyright_identification_bit<<3)|(variable->copyright_identification_start<<2)|((variable->frame_length>>11)&0x3)); adts_s[4] =((variable->frame_length>>3)&0xff); adts_s[5] = (((variable->frame_length&0x7)<<5)|((variable->adts_buffer_fullness>>6)&0x1f)); adts_s[6] = (((variable->adts_buffer_fullness&0x3F)<<2)|(variable->number_of_raw_data_blocks_in_frame)); printf(" 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",adts_s[0],adts_s[1],adts_s[2],adts_s[3],adts_s[4],adts_s[5],adts_s[6]); printf("***********fixed*******************************\n"); printf("fixed->syncword = 0x%x\n",fixed->syncword); printf("fixed->ID = 0x%x\n",fixed->ID); printf("fixed->layer = 0x%x\n",fixed->layer); printf("fixed->protection_absent = 0x%x\n",fixed->protection_absent); printf("fixed->profile = 0x%x\n",fixed->profile); printf("fixed->sampling_frequency_index = 0x%x\n",fixed->sampling_frequency_index); printf("fixed->private_bit = 0x%x\n",fixed->private_bit); printf("fixed->channel_configuration = 0x%x\n",fixed->channel_configuration); printf("fixed->original_copy = 0x%x\n",fixed->original_copy); printf("fixed->home = 0x%x\n",fixed->home); printf("***********variable*******************************\n"); printf("variable->copyright_identification_bit = 0x%x\n",variable->copyright_identification_bit); printf("variable->copyright_identification_start = 0x%x\n",variable->copyright_identification_start); printf("variable->frame_length = 0x%x\n",variable->frame_length); printf("variable->adts_buffer_fullness = 0x%x\n",variable->adts_buffer_fullness); printf("variable->number_of_raw_data_blocks_in_frame = 0x%x\n",variable->number_of_raw_data_blocks_in_frame); return 0; } int main(int argv, char *argc[]) { //int i; write_adts(adts_t,4,2,15); read_adts( adts_t ); printf("0x%x\n",(0x14 & 0x2)); return 0; }