结合 Agora SDK 在 Android 端实现实时视频的美颜

作者:声网Agora 资深软件开发工程师 戚敏明

如今越来越多的用户开始对美颜/道具这一功能产生越来越大的需求,尤其是在泛娱乐场景下。而现如今市场上有许多第三方的美颜 SDK 可以供开发者选择使用,那么这些第三方的美颜 SDK 是否可以与 Agora RTC SDK 进行结合从而实现实时视频泛娱乐这一应用场景呢?答案当然是肯定的。

本文的目的就是要帮助大家快速了解如何使用。默认情况下,Agora RTC SDK 提供端到端的整体方案,Agora RTC SDK 负责采集音视频,前处理,然后将数据发送到对端进行渲染,这种运行模式通常能满足大多数开发者的需求。但如果开发者希望对采集到的数据进行二次处理(比如美颜等),建议通过 setVideoSource(IVideoSourcevideoSource) 调用自定义视频数据源来实现。在这种情况下,整个过程的数据流如下图所示:

1. 从相机采集视频数据

2. 将采集到的数据传递给 FaceUnity SDK 进行二次处理,并进行渲染

3. 将处理过的数据传递给 Agora RTC SDK

4. Agora RTC SDK 将处理过的数据编码通过 SD-RTN 传输到对端,对端进行解码并渲染

本文将以 Android 平台代码 为例子来具体讲解如何实现。

1. 设置 Agora RTC SDK 视频源为自定义视频源

在本示例程序中,使用了 TextureSource 类,该类是 Agora RTC SDK 提供的适用于纹理类型(texture)视频源的预定义实现。当实例化了该类后,可调用 setVideoSource 接口来设置视频源,具体用法如下:

2. 采集数据

本示例程序中,使用到的自定义视频源为相机,视频数据采集在示例程序中完成,具体做法如下:

其中 openCamera 方法主要是对相机做了一些参数配置,例如预览尺寸,显示方向,对焦模式等,而 cameraStartPreview 方法则主要调用了 setPreviewTexture 方法来指定相机预览数据所需要输出到的 SurfaceTexture。另外本示例程序中还重载了 onPreviewFrame 回调接口,该接口主要用来接收相机返回的预览数据,其中入参 byte[]data 就是相机所捕捉到的预览数据,当得到该数据后本例会调用 mGLSurfaceView.requesetRender() 方法来请求绘制图像。

如此一来,相机的预览数据就保存在了 mCameraNV21Byte 数组和 mSurfaceTexture 中。

3. 初始化 FaceUnity SDK

在使用 FaceUnity 提供的 SDK 之前,必须进行初始化工作,具体做法如下:

4. 对采集到的原始数据进行美颜处理

在第 2 步中,我们已经得到了相机的原始数据,那么下面我们就要调用相应的美颜 API 来对该数据进行二次处理,具体做法如下:

此处的 onDrawFrame 方法调用由第 2 步中 mGLSurfaceView.requesetRender() 调用触发,其中的 mCameraNV21Byte mCameraTextureId 就是我们得到的相机原始数据,在 onDrawFrame 中我们进行了 mOnCameraRendererStatusListener.onDrawFrame 的回调,而该回调接口的实现如下:

可以看到,该回调接口又调用了 mFURenderer.onDrawFrame 方法,而该方法中主要调用了如下 FaceUnity 的 API 来对原始数据做美颜处理:

其中 img tex 是我们传入的原始数据, mItemsArray 则是需要用到的美颜效果数组,当该方法返回时,得到的数据便是经过美颜处理的数据,该数据会写回到我们传入的 img 数组中,而返回的 fuTex 则是经过美颜处理的新的纹理标识。而相应的美颜效果可以通过如下方法进行调节(均在 faceunity 当中):

5. 本地对经过美颜处理的数据进行渲染显示

如果本地需要对美颜效果进行预览,则可以对进行过美颜处理的数据进行自渲染,具体做法如下:

其中 mFuTextureId 便是第 4 步中经过美颜处理返回的新的纹理标识,我们通过调用 mFullFrameRectTexture2D.drawFrame 方法在本地 GLSurfaceView.Renderer 中的 onDrawFrame 方法中进行绘制。

6. 将经过美颜处理的数据发送给对端

当拿到已经经过美颜处理的数据后,下一步要做的就是通过调用 Agora RTC SDK 提供的接口将该数据传送给对端,具体做法如下:

其中 mIVideoFrameConsume 就是我们在第 1 步中保存的 IVideoFrameConsumer 对象,通过调用该对象的 consumeByteArrayFrame 方法,我们就可以将经过美颜处理的数据发送给 Agora RTC SDK,然后通过 SD-RTN 传到对端,其中的入参 backImage 便是我们在第 4 步中得到的经过美颜处理的数据, MediaIO.PixelFormat.NV21.intValue() 为该视频数据使用的格式, cameraWidth cameraHeight 为视频图像的宽与高, mCameraOrientation 为视频图像需要旋转的角度, System.currentTimeMillis() 为当前单调递增时间,Agora RTC SDK 以此来判断每一帧数据的先后顺序。

7. 对端对收到的经过美颜处理的数据进行渲染显示

当对端收到发送过来的经过美颜处理的数据时,我们可以对其进行渲染显示(这是默认的渲染方式,当然也可以类似于自定义的视频源去实现自定义渲染,这里就不展开),具体做法如下:

其中 uid 为发送端的用户标识。

更多参考:

  • https://docs.agora.io/cn/

  • http://www.faceunity.com/#/developindex