共计 2238 个字符,预计需要花费 6 分钟才能阅读完成。
在《如何快速实现移动端短视频功能?》中,我们主要介绍了当前短视频的大热趋势以及开发一个短视频应用所涉及到的功能和业务。在本篇文章中,我们主要谈一谈短视频在 Android 端上的具体实现技术。推荐阅读《视频私有云实战:基于 Docker 构建点播私有云平台》
《如何快速实现移动端短视频功能》
短视频业务主要包含:“视频录制”以及“视频编辑”这两个核心功能。
其中视频录制又包括:视频采集、实时美颜、自定义码率、摄像头切换、变焦、对焦、曝光度调节以及滤镜等功能。
视频编辑包括:视频裁剪、视频拼接、混音、视频动画效果、动态贴图等功能。
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 进行编辑处理。
想要获取更多产品干货、技术干货,记得关注网易云信博客。