RTMP协议实现IOS播放HEAAC思路

做了一星期了,几乎搜遍了网上所有相关的博文终于完成了这个,整理下思路给需要的朋友


首先得说下这边的环境,数据是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;
}



  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 18
    评论
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值