android音视频开发之编码封装
音视频编码
为何要对音视频进行编码?
音视频的原始数据非常庞大,难以存储和传输。要解决音视频数据的存储和传输问题,或是为了加密等。就需要对这些数据进行压缩,音视频数据压缩技术就是音视频编码
。 编码的目的就是在最小图像或音频信息丢失情况下得到最大的压缩,解码是相对编码的,其目的是最大限度的还原原始图像或声音信息。编解码的意义就是便于数据传输和存储
。
编解码种类(硬件编码,软件编码)
硬编码:
用设备GPU去实现编解码,这样可以减轻CPU的压力。
软编码:
让CPU来进行编解码,在c层代码来进行编解码,因为c/c++有很多好的编解码库。
软硬编码对比:
硬编的好处主要在于速度快,而且是系统自带的库不需要引入外部的库,但是特性支持有限,而且硬编的压缩率一般偏低,而对于软编码来说,虽然速度较慢,但是压缩率比较高,而且支持的H264特性也会比硬编码多很多,相对来说比较可控。而且硬编码会受硬件设备支持的影响。
在Android 4.1之前没有提供硬编解码的API,所以基本都是采用开源的那些库,比如著名的FFMpeg实现软编解码。但是通常情况下,同一平台同一硬件环境,硬编码的速度快于软件编码,软编码使用CPU来进行计算,会消耗一些app的运算效率。在Android4.1及以上版本可以使用MediaCodec来访问底层的媒体编解码器从而支持硬编码/硬解码。
视频编码编辑的可行性方案
-
第一个就是大家熟知的ffmpeg,将ffmpeg移植到anroid平台,编译成so文件,由jni 调用,可以实现音视频的分离、裁剪、拼合、加字幕、滤镜等功能。
-
第二个就是android 自带的MediaCodec 框架,MediaCodec框架底层调用的是StageFright库,StageFright库是默认封装在android系统里面的。
-
第三个,如果只是做视频音频混合的话,可以用这个开源工程mp4parser。
可行性方案的优缺点
-
功能多少方面:
ffmpeg 无疑排第一位,他集合了视频编解码、视频滤镜、流媒体推流、音频各种特效等等,基本上你能想到的功能都在里面。
第二位当是Android的亲儿子,MediaCodec。MediaCodec涵盖了音视频解复用、音频解码、视频解码、音频编码、视频编码、音视频合并的整个流程。跟ffmpeg相比,MediaCodec 更接近底层硬件。这个方案如果想要实现视频的滤镜、字幕、拼接等功能的话,需要自己配合OpenGL ES 来实现,另外,音视频拼接的话,要考虑到不同音频采样率的重采样问题,音频重采用问题,需要懂得傅立叶变换相关的离散信号变换方法,如果要实现音频特效,如变声、均衡器的话,也需要懂得上述信号变换方法。因此,很少公司会采用。
第三位mp4praser,可以实现音视频编解码及编辑。 -
学习门槛:如果只是做视频转码、加文字、图片特效等,ffmpeg和MediaCodec 旗鼓相当,mp4parser最低(但是基于mp4parser的资料比较少,其实也未必)。如果是要拼接视频、做音频 的变声、均衡器特效的话,MediaCodec是难度最高的,因为这一切需要你从底层原理做起。
-
运行效率:MediaCodec硬解硬编最快,ffmpeg硬解硬编方案稍慢(注意,2017年5月以后最新版ffmpeg已经整合了MediaCodec,不再慢了),mp4parser(只能软解软编)最慢。
-
稳定性: MediaCodec和ffmpeg 的硬解硬编方案旗鼓相当,mp4parser在低配的机器上可能出现卡顿的问题。
-
打包占用空间:国内最得最好的ffmpeg硬解硬编方案,其so文件在10.几M,MediaCodec由于是纯java 代码,占用空间很容易做到几百K甚至几十K。mp4parser也是纯Java,开发包同样非常小。
FFmpeg
ffmpeg 是基于C语言的著名视频编解码方案。具有非常强大的功能包括视频采集功能、视频格式转换、视频抓图、给视频加水印等。国内有也有不少的公司将ffmpeg 移植到iOS和android 平台进行视频处理,例如,美拍、秒拍等。当前众多的视频SDK中, 大都是封装ffmpeg对视频进行转码, 压缩, 裁剪的处理.优点是ffmpeg发展到现在已经相对成熟, 支持的视频格式较多。但是缺点有:
- 速度慢,用cpu来执行视频数据的处理属于软解码, 效率并不高;
- 增加包的体积,一般好的sdk(如阿里云短视频sdk) 有20m上下, 这样的sdk合入应用后, 对应用大小有一定的影响。
FFmpeg本质上可以看做是媒体处理工具的集合,包含了很多的媒体文件处理工具,例如媒体文件格式解析工具、编解码器等,这些工具实际上就是一个个的库,而FFmpeg的命令行程序实际上就是对这些库的一种包装,在调用命令行程序时也是通过底下的这些库来完成操作。这些库有的是编译时可选的,而且FFmpeg也支持一些外部的库,例如x264、MediaCodec。FFmpeg由于提供了很多的编解码器,而且它的媒体操作也很丰富,所以可以支持非常多的媒体类型,同时很多的处理功能也已经由FFmpeg提供,使用者只需要去调用即可,所以不少的编辑处理功能可以相对简单地完成开发。
适用场景:多平台使用(例如不同芯片厂商的手机),短时间摄像。
MediaCodec
MediaCodec提供的功能就相对单一,它基本上只用来完成编解码相关的功能。以整个视频转码流程举例,大致需要几个步骤:解封装->解码->滤镜处理等操作->编码->封装,MediaCodec只提供编解码功能,而其它的功能则需要其它组件,如MediaExtractor以及MediaMuxer来完成。
但是MediaCodec在编解码时提供硬件编解码功能,其好处是非常明显的,效率很高,且CPU占用大幅降低。如果不使用硬件编解码的话,很多的转码过程的时长实在长得是令人无法忍受,放到APP上简直就是无法使用的功能。毕竟一段很短的视频,转码要好几分钟,发烫还严重,体验肯定是不行的。MediaCodec的缺点就是一定程度上会依赖于设备,由于MediaCodec的硬解码实际上是由厂商所提供的,同时安卓设备的硬件相互之间差异很大,所以在硬解码实现上自然也有所差别,就导致了一样的程序,一些设备上可以正常跑,而在另一些设备上则可能会出问题,此时就需要自行提供兼容性上的支持。
适用场景:有固定的硬件方案,无需移植(例如智能家具产品),需要长时间摄像。
对比
作一个简单的比喻:FFmpeg就像一个工具箱,而MediaCodec就像一类功能强大,但是使用范围相对受限且不够灵活的工具。
- 1.FFmpeg也有对MediaCodec的支持,在编译出合适的库后,可以通过FFmpeg的api来调用MediaCodec,但只能使用解码功能。
- 2.MediaCodec并非只代表硬编解码,它事实上可以看做是一种服务,厂商将自己的编解码方案预先注册于服务中,而用户在需要时再通过服务去调用相应的编解码器来完成任务。MediaCodec支持硬件编解码以及软件编解码,可以自行选择需要使用的编解码器。
- 3.FFmpeg在使用MediaCodec时,使用的方式和JAVA调用是类似的,FFmpeg会通过JNI的callXXmethod去调用MediaCodec的方法,这个过程其实和JAVA中的调用没有区别,但是FFmpeg通过封装MediaCodec的操作,使得MediaCodec可以按照FFmpeg的编解码流程进行调用。
- 4.MediaCodec它本身并不是Codec,它是通过调用底层编解码组件具有Codec能力。
开源方案
基于ffmpeg 的免费软解软编方案在github.com有很多,例如:EpMedia,硬解硬编方案还没有看到。商业收费的方案有趣拍、美摄等。不过这些商业方案是按年收费的有点小贵。
基于MediaCodec 的免费开源方案有m4m,videotranscoder等,不过这些开源方案,表面看上去功能很强大,实际使用的时候会遇到不少坑,只适用于对MediaCodec的原理进行研究。
参考文章
微信 Android 视频编码爬过的那些坑
Android视频技术探索之旅:美团外卖商家端的实践
Android音视频开发之MediaCodec编解码
Android视频处理之MediaCodec-1-简介
Android视频处理之MediaCodec-2-使用
Android视频处理之MediaCodec-3-播放视频
Android视频处理之MediaCodec-4-视频帧转图片
Android视频处理之MediaCodec-5-生成mp4视频
Android视频处理之MediaCodec-6-给视频加水印
Android 音视频编辑经验总结及开源工程分享
Android 音视频开发学习思路
从开发小白到音视频专家
android音视频开发基础4--FFmpeg 入门