短视频业务主要包含:“视频录制”以及 “视频编辑”这两个核心功能。
其中视频录制又包括:视频采集、实时美颜、自定义码率、摄像头切换、变焦、对焦、曝光度调节以及滤镜等功能。
视频编辑包括:视频裁剪、视频拼接、混音、视频动画效果、动态贴图等功能。
Android端短视频录制的技术方案
我们先来说说视频录制:
视频录制的大致实现流程就如上图所示,先由Camera、AudioRecord进行最原始的相机画面以及声音的采集,然后将采集的数据进行滤镜、降噪等前处理,处理完成后由MediaCodec进行硬件编码,最后采用MediaMuxer生成最终的MP4文件。
这个方案的优点在于,由于全程采用了GPU以及硬件编码,基本上不涉及CPU上的操作,因此可实现在高帧率(30fps)、高分辨率(720P)以及高码率的情况下CPU暂用率也非常低,即使在性能较差的手机上也能很好的运行。但同时这个方案的难点也在于此。
做过音视频的同学都知道,通常情况下我们所说的对音视频的处理,主要是对视频的 YUV、H264 音频的PCM、AAC这类数据格式进行操作,这类操作都有相关的RFC技术也比较成熟,实现起来比较容易,出了问题也更容易定位,通常情况下在PC等设备上也都是这么处理的。
但这样的方案在对于手机端情况就不同了,虽然手机这几年的性能大大加强了,很多旗舰手机基本都是8核的CPU了,但要操作如此大量的图片数据并进行浮点运算对CPU的消耗还是很大的。CPU暂用率高就会引起手机发烫,手机发烫就会导致Camera采集的掉帧,甚至在一些小米等厂商下,手机发烫还会引起CPU降频,CPU一降频那APP所暂用的CPU比例就更高了,同时CPU暂用率高电量消耗就快。
因此上面的方案是目前Android上比较适合短视频录制的方案。
Android端短视频录制的具体实现
既然确定了技术方案,我们就来看看具体的实现。这里首先需要知道几个概念:
SurfaceTexture
我们知道在一些简单的自定义相机应用中,要实现一个相机,只需要将一个SurfaceHolder设置给Camera,Android系统就会自动的帮我们把Camera采集的数据绘制到屏幕上。但由于在短视频中我们需要对相机采集的数据进行前处理加工比如滤镜等,而且还要做到可见即所得的效果,因此必须要求我们将相机采集的数据先缓存起来,前处理完后自己再绘制到屏幕上,这时候就需要用到SurfaceTexture了。按照Android官方文档的介绍,SurfaceTexture就是这样一块用于接收Camera采集的数据,同时又不可见的画布。这块画布是存在于GPU内存中的。
TextureID
纹理ID,主要用来标识每一块纹理在GPU内存中的内存地址,类似于C语言中的内存指针。每一块GPU的纹理(可以理解为一块用于显示图片的画布)都有对应的一个TextureID进行标识。上述的SurfaceTexture在创建也同样需要绑定一个纹理ID进行唯一标识。
知道了这两个概念,我们就知道了Camera采集的数据具体存在于GPU的哪个位置了。接下来就可以对原始的数据进行前处理编码了。
这里有一个需要注意的地方,Android的camera采集到SurfaceTexture上的纹理是GL_TEXTURE_EXTERNAL_OES 类型的纹理,而目前市面的很多滤镜算法,如开源的GPUImage中很多的滤镜都是基于GL_TEXTURE_2D类型的纹理进行图像处理的。
因此在进行我们在基于开源滤镜算法或自研算法时需要先将GL_TEXTURE_EXTERNAL_OES类型的纹理转化为GL_TEXTURE_2D的纹理,或者在GPU Shader中加入 “#extension GL_OES_EGL_image_external: require” 来表明该纹理是OES纹理,同时编写基于OES纹理的图像处理算法。
目前网易这边是先将OES转化为TEXTURE_2D在进行前处理,这样便于与iOS端算法统一以及更好的接入一些开源的滤镜算法。
解决了SurfaceTexture的问题,接下来的MediaCodec以及MediaMuxer就比较容易了。Android中的MediaCodec天生支持将GPU中的纹理绘制到MediaCodec的Surface中,然后对Surface中的图像直接进行硬件编码,图像数据始终是在GPU空间中进行流转,而没有涉及到CPU。
这里需要注意的是MediaCodec以及MediaMuxer需要在API 18及以上才能使用。同时需要注意MediaCodec在不同设备上的兼容性。
Android端视频编辑功能
最后对于视频编辑的功能,目前Android上没有很好的系统API即硬件处理方式,主要还是利用ffmpeg进行相应的叠加、裁剪混音等后期处理。可以优化的一个点是,先将原始的MP4视频进行解码,然后将解码后的YUV数据映射到GPU的纹理上进行亮度、饱和度等参数的调节,做到文件编辑的所见即所得,然后将调好的参数配置为ffmpeg进行编辑处理。
文章来源:网易云社区 https://sq.163yun.com/blog/article/178364770879594496
相关阅读: