Android短视频中如何实现720P磨皮美颜录制?

视频中磨皮、美颜功能已成为刚需,那么如何在Android短视频中实现720P磨皮美颜录制?本篇文章中, 网易云信资深开发工程师将向你们介绍具体的操做方法。

相关阅读推荐

短视频技术详解:Android端的短视频开发技术算法

如何快速实现移动端短视频功能?缓存

在Android上要实现一个录制功能,须要有几个方面的知识储备:自定义相机的开发、视频数据格式的了解、编码相关知识以及视频合成技术,同时若是须要美颜、磨皮等滤镜操做还须要必定的openGL的知识。若是有须要深刻音视频方面开发的同窗建议先了解下上述的基本知识点。ide

既然要实现720P、30帧,同时又要对视频数据进行滤镜处理的录制,那咱们首先就要肯定一个正确的实现方案。若是方案选错了,那即便实现了录制功能,但性能达不到30帧或是CPU消耗太大手机发烫那就很差了。工具

视频的编码录制主要是软编和硬编两种方案:

软编即采用CPU对相机采集的原始数据进行编码后再和音频一块儿合并成一个MP4等格式的文件。性能

优势是技术相对成熟,网上开源的编码以及合成库不少,实现相对较快,同时兼容性比较好。编码

缺点是CPU暂用率高,性能差的手机没法达到720P的30帧,同时引用了大量的第三方库,致使包很大。线程

软编的具体实现方案以下图所示,流程相对清晰简单:3d


硬编即采用手机提供的硬编接口,利用硬件芯片直接进行编码合成。orm

优势是速度快、效率高、CPU占用极少,即便长时间高清录制也不会发烫,同时因为使用系统API,库相对较小。cdn

缺点是某些奇葩机型须要处理兼容性问题,同时Android上的硬编跟Surface以及openGL关系比较密切,网上相关知识较少,须要本身摸索踩坑。

硬编的主要流程以下图所示,能够看到全部的数据,从采集、编码、显示以及合成都在GPU里面进行流转。


结合上面分析的两种方案咱们能够看到,在Android这类移动平台上,使用第二种硬编的方式是比较合适的。因为短视频的本地录制不像直播等场景对带宽的要求比较大,须要动态调节编码器码率帧率的状况,本地录制能够将编码器的码率设置的比较高,也不须要动态改变分辨率。所以采用硬件编码的方式既能够省CPU的性能又能够实现720P的高效编码。

肯定了方案以后,咱们就着重讲一下硬编方案的各个步骤的实现方式。

自定义相机的开发

咱们知道根据Android的系统Camera API,能够经过setPreviewDisplay接口给Camera设置一个SurfaceView的SurfaceHolder就可让Camera采集的数据显示到SurfaceView上了。这个接口的好处是系统帮咱们处理了相机采集的各类角度同时进行了绘制,若是只是简单的录制能够这么使用,但咱们须要对相机采集的数据进行滤镜处理,那这个接口就不合适了。

所以咱们须要用到另一个接口 setPreviewTexture:


经过给Camera设置一个SurfaceTexture,能够将Camera采集的数据先映射到这个SurfaceTexture上,而后咱们根据建立这个SurfaceTexture的TextureID来获取GPU上的Camera数据

滤镜以及本地绘制

咱们经过SurfaceTexture绑定的TextureID能够获取到Camera采集到GPU上的视频数据。而后能够将TextureID送给一些第三方滤镜库进行美颜滤镜或是本身编写Shader进行磨皮和美白。本身编写Shader须要opengl以及图像算法方面的知识,一般须要专门的开发人员,这里就不作详细的展开了(固然最简单的就是接入网易云短视频SDK了,里面实现了磨皮、美颜和多款滤镜)。

本地绘制主要靠openGL进行绘制,咱们须要先在Camera的采集回调线程上建立一个EGLContext以及EGLDisplay和EGLSurface, 其中EGLContext是openGL在该线程上的上下文,EGLDisplay是一块GPU中的虚拟显示区,主要用于缓存GPU上的视频数据,EGLSurface为具体显示的View到openGL上的映射,是真正绘制到View上的工具。当接受到Camera采集回调的一帧数据后,咱们先经过SurfaceTexture.updateTexImage()方法,将Camera采集的数据映射到SurfaceTexture。而后根据glsl语言将TextureID对应的数据绘制到EGLDisplay上,这里须要注意的是,Camera采集是有角度的,横竖屏下角度不一样,能够经过SurfaceTexture的getTransformMatrix方法获取角度矩阵,而后把矩阵传给EGLDisplay进行旋转。EGLDisplay旋转绘制完成后经过eglSwapBuffers方法就能够将EGLDisplay上的数据拷贝到EGLSurface上进行显示了。Android 系统中的GLSurfaceView最后就是经过eglSwapBuffers将数据显示到咱们看到的屏幕上的。

硬件编码

Android上的硬件编码主要靠MediaCodeC API实现的,下面是MediaCodeC比较经典的一张数据处理图。


从图中咱们看到,MediaCodeC主要处理流程就是:

  • 建立并配置一个 MediaCodec 对象
  • 循环直到完成:
        若是输入缓冲区就绪,读取一个输入块,并复制到输入缓冲区中
        若是输出缓冲区就绪,复制输出缓冲区的数据
  • 释放 MediaCodec 对象


从Android的官方文档咱们看到,MediaCodeC支持ByteBuffers和Surface两种输入方式,文档也指明了Surface方式能够提升编码效率,并且咱们上面的Camera数据也是采集到的SurfaceTexture,所以咱们这里使用Surface方式做为输入源。

咱们在上面显示部分提到EGLSurface是做为真正输出显示的模块,MediaCodec也是。咱们先经过MediaCodec建立一个Surface,而后将这个Surface绑定到一个EGLSurface,当Camera采集的数据回调时,咱们只要重复一次绘制模块的操做,将Camera采集到SurfaceTexture上的数据swapBuffers到EGLSurface 上就能够了。而后循环MediaCodec输出缓冲区,MediaCodec就会将编码后的数据返回给咱们了。这样作的好处就是将显示和编码彻底分离了,即便咱们没有UI View的状况下也能够进行编码,好比在不一样Activity之间切换也不会影响咱们的正常编码。

视频合成

Android上视频合成主要经过MediaMuxer API实现。MediaMuxer类相对比较简单,特别是配合MediaCodec使用。 咱们只须要经过 addTrack 来添加视频和音频通道接口。AddTrack 接口须要传入一个MediaFormat对象,MediaFormat即媒体格式类,用于描述媒体的格式参数,如视频帧率、音频采样率等。还好咱们使用了MediaCodeC,MediaCodeC会返回MediaFormat给咱们,若是是使用软编而后用MediaMuxer进行合并的话,这里有一个比较大的坑,若是手动建立MediaFormat对象的话,必定要记得设置"csd-0"和"csd-1"这两个参数:其中"csd-0"和"csd-1"对应的是视频的sps和pps,对于AAC音频的话,对应的是ADTS。不设置的话会崩溃的。 设置完这些以后,只要编码器来一帧数据,咱们送到MediaMuxer中能够出来MP4了。

最后大致的流程图就是:


以上就是在Android短视频中实现720P磨皮美颜录制的分享。

另外,想要获取更多产品干货、技术干货,记得关注网易云信博客

相关文章
相关标签/搜索