Android MediaCodec API实现的音视频编解码

音视频编解码思路

主要借自己开发音视频编解码的经验谈谈思路,希望可以帮助刚接触音视频编解码的猿们:

  • 音视频的原始数据格式
  • YUV数据之间的转换
  • MediaCodec 将原始音视频数据编码
  • 音视频两者之间的封装
  • 推流协议的一些说明

音视频的原始数据格式

经过自己长达两个多月的摸索,现在大体明白了音视频数据的在每一步之间的格式是什么了!首先,Android调用本地的摄像头以及麦克风采集的原始数据,视频是YUV或者RGB格式的。这种格式的数据量是十分庞大的,所以这就说明了为什么需要后面的音视频编码压缩等问题了,目的就是节约空间,提高传输速率;音频经过麦克风采集后是PCM格式的。这是采集的最原始的数据。

使用时记得在清单文件添加需要的权限就可以:


视频最原始的数据获取是十分简单地.此时数据格式:视频:NV21,音频:PCM

YUV数据之间的转换

起初,我也一直不明白,我的是原格式是NV21的,怎么又换成YUV420SP的了?当时真的一头雾水,无奈只能自己继续摸索。在YUV这个大家族里,为了简单,我分成两大类:yuv xxx p和yuv xxx sp。xxx可以呀444,422,420替换过来,官方的文档是十分复杂的,相信你们很难看下去的。在这里,我把我自己的经验分享出来。一切是为了简单。Y是控制亮度的,U和V是控制色度的;大家可以通过这一特点简单地判断一些颜色的问题,如果红色的和蓝色出现对调了,可能就是U和V出现了调换。如果是顶层编码写反了就需要NDK重新编译生成新的.so文件了!如果你运气好代码就在程序中,简单地调换一下位置就可把问题解决。在这里主要介绍一下YUV420P和YUV420SP的存储模式(如果你希望深入学习的话,建议你还是去官方分析相应的代码):

YUV420P(I420和YU12) 可以理解是平面模式的,在这种模式之下:是先存储Y数据,然后是U数据,最后是V数据 就像这样:以下是模拟的数组存储 (Y00 Y01 Y10 Y11共用U00 V00)

        Y00  Y01  Y02  Y03
        Y10  Y11  Y10  Y13
        ...
        U00  U01
        U10  U11
        ...
        V00  V01
        V10  V11       

YUV420SP(NV12和NV21) two-plane模式,即Y和UV分为两个plane UV交错存储

        Y00  Y01  Y02  Y03
        Y10  Y11  Y10  Y13
            ...
        U00  V00  U01  V01
        U10  V10  U11  V11
            ...

采集到原始的数据Android默认是NV21的,当然你可以作为修改。当时我自己的项目默认是NV21的,然后又出来一个I420格式的,因为这些格式完全乱了套。前面说过,原始的音视频数据量太大,不方便进行传输,所以我们需要编码压缩处理。我看到过网上有人说H.264编码的输入数据必须是I420标准的格式。这样所有的问题都解决了。原始数据NV21(YUV420SP),在我的程序了首先将其转换成了I420(YUV420P),这样就可以继续利用MediaCodec API将原始数据进行编码了。此时数据格式:视频:I420,音频:PCM

MediaCodec 将原始音视频数据编码

视频编码
这里的代码我就不贴了,这里的信息在API中一查就有了,而且网上的开源的不开源的代码也有很多,稍作分析就可以了,你只需要设置相关的参数就可以了。这个API 还是蛮强大的,就是更新有点快了,让学习Android的同学学起来比较吃力。在这里有许多的参数需要设置,在这里我简单贴几个常用的配置参数设置:我的程序了设置的是H.264格式

        适合家用DVD播放的媒体文件(此DVD需要支持MP4文件播放功能)

代表含义 设置值
设置音频流编码格式 LAME MP3
设置音频流采样率 44100Hz
设置音频流取样声道 默认即可
设置音频流编码具体方式 ABR
设置音频流转换后的声道 Auto
设置音频流转换码率 96 kbps或128kbps
设置视频流具体编码方式 Bitrate-based
设置视频流转换码率 400 kbps或500 kbps
设置视频编码格式 Xvid
设置封装容器 AVI
设置转换后的文件的分辨率 400x-3
设置转换后的文件的帧率 24

        适合支持大部分PDA、智能手机播放的媒体文件,低速CPU机型适用(CPU速度低于400MHz的)

此设置方式一般也适合大多数MP4播放设备。PDA、智能手机需要安装TCPMP才可以更好的支持AVI和MKV格式
代表含义 设置值
设置音频流编码格式 LAME MP3
设置音频流采样率 44100Hz
设置音频流取样声道 默认即可
设置音频流编码具体方式 ABR
设置音频流转换后的声道 Auto
设置音频流转换码率 96 kbps
设置视频流具体编码方式 Bitrate-based
设置视频流转换码率 320 kbps
设置视频编码格式 Xvid
设置封装容器 AVI
设置转换后的文件的分辨率 320x-3
设置转换后的文件的帧率 24

        适合支持大部分PDA、智能手机播放的媒体文件,高速CPU适用(CPU速度大于或等于400MHz的)

代表含义 设置值
设置音频流编码格式 CT AAC+
设置音频流采样率 44100Hz
设置音频流取样声道 默认即可
设置音频流编码具体方式 aacplus
设置音频流转换后的声道 Stereo
设置音频流转换码率 32 kbps
设置视频流具体编码方式 Bitrate-based
设置视频流转换码率 200 kbps
设置视频编码格式 H264
设置封装容器 Matroska
设置转换后的文件的分辨率 320x-3
设置转换后的文件的帧率 24

        适合保存VCD至硬盘的转换设置

设置位置 代表含义 设置值
设置音频流编码格式 CT AAC+
设置音频流采样率 44100Hz
设置音频流取样声道 默认即可
设置音频流编码具体方式 aacplus
设置音频流转换后的声道 Stereo
设置音频流转换码率 48 kbps
设置视频流具体编码方式 Quality-based
设置视频流转换码率 95
设置视频编码格式 H264
设置封装容器 Matroska
设置转换后的文件的分辨率 352x-3
设置转换后的文件的帧率 24

        适合保存DVD至硬盘的转换设置

代表含义 设置值
设置音频流编码格式 CT AAC+
设置音频流采样率 44100Hz
设置音频流取样声道 默认即可
设置音频流编码具体方式 aacplus
设置音频流转换后的声道 Stereo
设置音频流转换码率 64 kbps
设置视频流具体编码方式 Bitrate-based
设置视频流转换码率 500 kbps或600 kbps
设置视频编码格式 H264
设置封装容器 Matroska
设置转换后的文件的分辨率 640x-3
设置转换后的文件的帧率 24

音频编码
音频设置具体思路和视频是一样的 我的程序里音频格式ACC

此时的数据格式是:视频:h.264编码的码流 音频:ACC编码的码流

音视频两者之间的封装

此时的视频和音频都已经编码好了,但属于单独的两个文件数据,需要将这两部分的数据利用一个协议进行封装,这样的协议有很多例如(FLV,AVI,MP4,等等),在这里需要注意的一个问题就是视频的音频时间的同步,如果不协调就会出现画面和声音对不上的现象。这封装前将所有的数据设置好之后

        vencoder.start();
        aencoder.start();

网上有人说,这两句话写一起就可以,虽然我不太清楚,但是我相信了!直播的时候也没有出现画面和声音对不上的现象,我的程序里是将数据封装成FLV进行传输的。

此时音视频数据格式 FLV

推流协议的一些说明

推流协议我研究的不多,感觉可以用就行,但后期如果需要降低延迟,就需要好好研究一番了!我的程序了使用的是RTMP流,可能用起来比肩的简单吧!在我理解他和UDP协议差不多,不想TCP有那么麻烦的事!但人家TCP效率高啊,安全性也高啊!!!

此时 数据的格式 rtmp流。

最后总结一下关于Android视频直播的数据流程:原始数据的采集—>转换成标准的I420格式数据—>编码成标准的H.264视频码流和ACC标准的音频码流—>将音视频数据封装成FLV文件—>套上RTMP协议发送流媒体服务器。播放端则刚好反过来,需要最原始的数据,视频由视频驱动播放,音频由音频驱动播放!

同时在这里我想纪念一位英年早逝的大神—雷霄骅,大神,你一路走好!!!
他的音视频编解码说的比我详细的多,我只是说了九牛一毛。权当抛砖引玉吧!!!
这是大神的博客 小弟在此转载,权作纪念!!!

你可能感兴趣的:(Android直播实战笔记)