做了一星期了,几乎搜遍了网上所有相关的博文终于完成了这个,整理下思路给需要的朋友
首先得说下这边的环境,数据是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);
这头2个字节是干么的呢?
同事发了我一片博文,我们终于研究出了其中道道
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;
}