最近一个月,为了实现音频直播的功能,不断研究rtmp协议,以及flv和aac的封装编码的实现,俨然变身成了音频处理达人了。

    首先,服务器的选择上,FMS和AS5之类的直接就没有考虑了, 试用了crtmpserver以后发现完全算是实验产品, 没法用于生产, 于是转向了nginx-rtmp-module, 这个算很顺利。

    然后开始了漫长的客户端实现的经历。android我用了比较hack的办法,用processbuilder另开一个ffmpeg的进程,用进程间pipe的方式实现了,这个是最简单的,而且兼容性好,唯一的难点就在于ndk编译ffmpeg上,调整好configure参数,只打开需要用到的 de/muxer,de/encoder, protocol, 最终编译出了一个小于1M的可执行文件。其中有2个坑, 一个是在部分很搓的中信手机上无法执行,还有一个是aac参数需要加 -strict -2, 幸好都完美解决了。

    而写iOS代码就是一个悲剧的历程了。在ios平台不能fork进程,只能引入静态库文件.a,然后写C的code。所以第一个问题就是交叉编译出i386, armv7, armv7s的.a文件,然后lipo合到一块,这个折腾了不少时间,坑不少。然后第二个问题,因为ffmpeg在1.x以后,decode aac默认输出的是fltp,不是s16le, 因此需要从float转成2个channel的s16。播放rtmp搞定以后,开始折腾publish,由于专利原因 ffmpeg不带aac encoder的功能,需要自己编译libvo_aacenc/libaacplus/libfaac的库文件,然后再打包, 因此又重新折腾了一遍交叉编译,品尝了酸甜苦辣。打包aac的时候,又出现了adts的问题,于是加上aac_adtstoasc的filter,重新打包,在代码里面启用以后,总算能够让vlc和ffplay播放了。

    但是不完美,因为音频的pts有错, 这个花了很久的时间,google了各种代码终于用合适的方式解掉。接着,开始着手解决网页端flash player不能播放(播放没有声音)的bug,这个是一个大坑,因为没有任何错误提示和可以debug的地方,只能各种猜测错误的方向。后来实在没办法以后,决定用tcpdump抓包,对比和正常rtmp发布端的hex字节, 这样下来,已经对rtmp的协议实现了解到每个字节段的程度了。。。终于,发现了一个rtmp包区别, 简单说就是正常的rtmp是 af 00 12 10, 我的C代码是af 00, 不含有12 10这个AudioSpecificConfig, 为了让我的代码能够加入这2个字节,想了N种方法,最后尝试给ffmpeg加个patch,在 libavformat/flvenc.c 加入了一行,

 avio_wb16(pb, 0x1210 ); 

    测试OK,终于搞定。后来尝试了不用patch的路子,在AVFormatContext的extradata上做文章,填入了AudioSpecificConfig的字节,算是完美解决。

     其实整个过程还有各种坑存在,只是不断被解决。因为研究这个rtmp和ffmpeg的人不多,至少网上的“正确”的代码太少,都是各种抄文章和ffmpeg< 0.8的老代码。所以算是花了很大心思在研究上面, 以及自己写test代码不断尝试。幸好结局很满意,算是实现了ios+android+flash 的直播功能, 就等大量上用户等着并发压力的时候了。

标签: none

已有 4 条评论

  1. 小龙 小龙

    本人学生,非计算机专业,出于兴趣正在想做跟你基本一样的一套解决方案,请问有没有什么指导呢,感激不尽!

    1. Gao Jie Gao Jie

      其实主要的就是研究ffmpeg编解码了。

  2. 刘俊宏 刘俊宏

    您好,我最近在研究android上rtmp直播,但是对底层不太了解.在网上找了很多资料,的确如您所说资料很少,我试过github上javacv的demo,可以用,但是直播界面只有10多帧,请问这个怎么解决呢?

  3. [...]https://kexiao8.com/blog/index.php/2013/12/18/64.html[...]

添加新评论