相芯美颜
更新时间: 2024/03/15 17:20:41
NERTC SDK 支持接入相芯等第三方专业美颜滤镜厂商,实现美颜、美妆、滤镜、贴纸等美颜特效。在娱乐社交、在线教育等场景中,您可以快速构建具备美颜特效能力的应用,让用户在进行视频通话或直播时,呈现更良好的肌肤状态和精神面貌。
相芯美颜(Faceunity Nama SDK,下文简称 Nama SDK)的详细功能介绍请参见人脸特效。
准备工作
- 下载相芯美颜 SDK(推荐使用 V8.3.0 版本)。
- 获取相芯美颜 SDK 的证书,具体请联系网易云信商务经理。
- 获取相芯美颜资源文件,具体请联系网易云信商务经理。
- 集成 NERTC SDK,推荐使用 NERTC V4.6.50 及以后版本,V4.6.50 版本对相芯美颜进行了优化。
功能原理
-
NERTC SDK 提供了
setVideoCallback
采集数据回调的接口,将采集到的视频图像数据通过该接口回调出来。 -
Nama SDK 通过回调获取视频图像数据,进行美颜处理后,通过参数返回给 NERTC SDK。
-
NERTC SDK 将美颜后的数据进行编码和传输。
基本概念
- 纹理(Texture):纹理指的是一张二维的图片,把它像贴纸一样贴在图元上面,让图元看起来像贴纸所要表现的效果那样。
- NV21:NV21是 YUV420SP 图像编码的一种类型。根据 YUV 来定义图像的颜色,其中Y 表示明亮度,U 和 V 分别表示色调和饱和度。Android 系统的相机默认的图像格式是 NV21 。它比 RGB 模型的图像更省存储空间和带宽。
- 双输入:纹理+ YUV 双份数据输入。
注意事项
- 美颜相关方法返回值为 false 时,表示方法调用失败。
- 调用
enableLocalVideo
开启本地视频采集时,请设置streamType
为kNERtcVideoStreamTypeMain
,否则美颜效果不会生效。
集成相芯美颜
-
将证书文件
authpack.java
放到本地项目的faceunity/com/faceunity/fulivedemo
目录下。 -
将所需的美颜模型和道具放到本地项目的
assets
目录下,例如/app/src/main/assets/Resource
。 -
通过 Gradle 集成相芯美颜 SDK。详细步骤请参见Faceunity Nama官网文档。
在项目对应模块的
build.gradle
中加入以下行。// allprojects配置 allprojects { repositories { ... maven { url 'http://maven.faceunity.com/repository/maven-public/' } ... } } // dependencies导入依赖 dependencies { ... implementation "com.faceunity:nama:8.3.0 ... }
视频图像处理
根据不同的视频数据格式,分别介绍纹理渲染、NV21 渲染和双输入三种场景的视频图像处理,并提供相应的示例代码。
方案一:纹理渲染
-
设置 NERTC 的视频属性
调用
setLocalVideoConfig
方法的videoConfig
参数,设置视频的分辨率、图像的数据格式。在本示例中,视频的分辨率为 640 x 360 px,帧率为 15 fps,图像数据格式
colorFormat
为TEXTURE
。示例代码如下:// NERtcSDK默认设置,可以不调用 NERtcVideoConfig videoConfig = new NERtcVideoConfig(); config.width = 640; config.height = 360; videoConfig.colorFormat = NERtcConstants.VideoColorFormat.TEXTURE; //在纹理渲染的场景中,请设置为 TEXTURE config.frameRate = NERtcVideoConfig.NERtcVideoFrameRate.FRAME_RATE_FPS_15; NERtcEx.getInstance().setLocalVideoConfig(videoConfig);
-
初始化相芯美颜 SDK
初始化时,
setInputTextureType
设置的图像数据格式需要和 NERTC 中设置的图像数据格式(colorFormat)保持一致。在本示例中,都采用 TEXTURE 渲染。FURenderer.setup(this); mFURenderer = new FURenderer.Builder(this) .setInputTextureType(FURenderer.INPUT_TEXTURE_EXTERNAL_OES) //在纹理渲染的场景中,指定输入格式为 TEXTURE .setCameraFacing(mCameraFacing) .setInputImageOrientation(CameraUtils.getCameraOrientation(mCameraFacing)) .setRunBenchmark(true) .setOnDebugListener(new FURenderer.OnDebugListener() { @Override public void onFpsChanged(double fps, double callTime) { final String FPS = String.format(Locale.getDefault(), "%.2f", fps); Log.i(TAG, "onFpsChanged: FPS " + FPS + " callTime " + String.format(Locale.getDefault(), "%.2f", callTime)); runOnUiThread(new Runnable() { @Override public void run() { if (mTvFps != null) { mTvFps.setText("FPS: " + FPS); } } }); } }).build();
-
在成功加入房间后,调用 NERTC 的
enableLocalVideo
接口,开启本地视频采集,请设置streamType
为kNERtcVideoStreamTypeMain
,否则美颜效果不会生效。 -
调用 NERTC 的
setVideoCallback
接口,设置摄像头采集数据的回调。在onVideoCallback
回调中,将原始的视频图像数据发给相芯美颜 SDK,美颜 SDK 将美颜处理后的数据返回给 NERTC SDK,NERTC SDK 对美颜后的数据进行预览以及编码发送。NERtcEx.getInstance().setVideoCallback(new NERtcVideoCallback() { @Override public boolean onVideoCallback(NERtcVideoFrame neRtcVideoFrame) { long start = System.nanoTime(); int texId = 0; texId = mFURenderer.onDrawFrameSingleInput(neRtcVideoFrame.textureId, neRtcVideoFrame.width, neRtcVideoFrame.height); long renderTime = System.nanoTime() - start; neRtcVideoFrame.textureId = texId; neRtcVideoFrame.format = NERtcVideoFrame.Format.TEXTURE_RGB; //在纹理渲染的场景中,请设置输出格式为 TEXTURE_RGB return true; } }, false);
方案二:NV21 渲染
-
设置 NERTC 的视频属性
调用
setLocalVideoConfig
方法的videoConfig
参数,设置视频的分辨率、图像的数据格式。在本示例中,视频的分辨率为 640 x 360 px,帧率为 15 fps,图像数据格式
colorFormat
为NV21
。示例代码如下:NERtcVideoConfig videoConfig = new NERtcVideoConfig(); config.width = 640; config.height = 360; videoConfig.colorFormat = NERtcConstants.VideoColorFormat.NV21; config.frameRate = NERtcVideoConfig.NERtcVideoFrameRate.FRAME_RATE_FPS_15; NERtcEx.getInstance().setLocalVideoConfig(videoConfig);
-
初始化相芯美颜 SDK
在 NV21 渲染的场景中,
setInputTextureType
时不需要指定渲染模式,设置了也不起作用。FURenderer.setup(this); mFURenderer = new FURenderer.Builder(this) .setCameraFacing(mCameraFacing) .setInputImageOrientation(CameraUtils.getCameraOrientation(mCameraFacing)) .setRunBenchmark(true) .setOnDebugListener(new FURenderer.OnDebugListener() { @Override public void onFpsChanged(double fps, double callTime) { final String FPS = String.format(Locale.getDefault(), "%.2f", fps); Log.i(TAG, "onFpsChanged: FPS " + FPS + " callTime " + String.format(Locale.getDefault(), "%.2f", callTime)); runOnUiThread(new Runnable() { @Override public void run() { if (mTvFps != null) { mTvFps.setText("FPS: " + FPS); } } }); } }).build();
-
在成功加入房间后,调用 NERTC 的
enableLocalVideo
接口,开启本地视频采集,请设置streamType
为kNERtcVideoStreamTypeMain
,否则美颜效果不会生效。 -
调用 NERTC 的
setVideoCallback
接口,设置摄像头采集数据的回调。在onVideoCallback
回调中,将原始的视频图像数据发给相芯美颜 SDK,美颜 SDK 将美颜处理后的数据返回给 NERTC SDK,NERTC SDK 对美颜后的数据进行预览以及编码发送。Java NERtcEx.getInstance().setVideoCallback(new NERtcVideoCallback() { @Override public boolean onVideoCallback(NERtcVideoFrame neRtcVideoFrame) { long start = System.nanoTime(); int texId = 0; texId = mFURenderer.onDrawFrameSingleInput(neRtcVideoFrame.data, neRtcVideoFrame.width, neRtcVideoFrame.height, IFURenderer.INPUT_FORMAT_NV21_BUFFER); //设置输入格式为 NV21 long renderTime = System.nanoTime() - start; neRtcVideoFrame.textureId = texId; neRtcVideoFrame.format = NERtcVideoFrame.Format.TEXTURE_RGB; //设置输出格式为 TEXTURE_RGB return true; } }, false);
方案三:双输入
在双输入模式中,您可以 1 路采用 I420 格式用于人脸检测,1 路采用纹理格式用于美颜。
-
设置 NERTC 的视频属性
调用
setLocalVideoConfig
方法的videoConfig
参数,设置视频的分辨率、图像的数据格式。在本示例中,视频的分辨率为 640 x 360 px,帧率为 15 fps,图像数据格式
colorFormat
为TEXTURE
。示例代码如下:NERtcVideoConfig videoConfig = new NERtcVideoConfig(); config.width = 640; config.height = 360; videoConfig.colorFormat = NERtcConstants.VideoColorFormat.TEXTURE; //在双输入模式下,推荐输入的格式为 TEXTURE config.frameRate = NERtcVideoConfig.NERtcVideoFrameRate.FRAME_RATE_FPS_15; NERtcEx.getInstance().setLocalVideoConfig(videoConfig);
-
初始化相芯美颜 SDK
初始化时,
setInputTextureType
设置的图像数据格式需要和 NERTC 中设置的图像数据格式(colorFormat)保持一致。在本示例中,都采用 TEXTURE 渲染。FURenderer.setup(this); mFURenderer = new FURenderer.Builder(this) .setInputTextureType(FURenderer.INPUT_TEXTURE_EXTERNAL_OES) //在双输入场景中,指定输入格式为 TEXTURE .setCameraFacing(mCameraFacing) .setInputImageOrientation(CameraUtils.getCameraOrientation(mCameraFacing)) .setRunBenchmark(true) .setOnDebugListener(new FURenderer.OnDebugListener() { @Override public void onFpsChanged(double fps, double callTime) { final String FPS = String.format(Locale.getDefault(), "%.2f", fps); Log.i(TAG, "onFpsChanged: FPS " + FPS + " callTime " + String.format(Locale.getDefault(), "%.2f", callTime)); runOnUiThread(new Runnable() { @Override public void run() { if (mTvFps != null) { mTvFps.setText("FPS: " + FPS); } } }); } }).build();
在 FuRenderer.java 中修改如下代码,设置输入格式。
private int createFlags() { int inputTextureType = mInputTextureType; int flags = inputTextureType | mInputImageFormat; if (mCameraFacing != CAMERA_FACING_FRONT) { flags |= faceunity.FU_ADM_FLAG_FLIP_X; flags |= faceunity.FU_ADM_FLAG_TEXTURE_AND_READBACK_BUFFER_OPPOSITE_Y; } flags |= faceunity.FU_ADM_FLAG_EXTERNAL_OES_TEXTURE | faceunity.FU_ADM_FLAG_ENABLE_READBACK; return flags; }
-
在成功加入房间后,调用 NERTC 的
enableLocalVideo
接口,开启本地视频采集,请设置streamType
为kNERtcVideoStreamTypeMain
,否则美颜效果不会生效。 -
调用 NERTC 的
setVideoCallback
接口,设置摄像头采集数据的回调。通过onVideoCallback
回调,将原始的视频图像数据发给相芯美颜 SDK,美颜 SDK 将美颜处理后的数据返回给 NERTC SDK,NERTC SDK 对美颜后的数据进行预览以及编码发送。Java NERtcEx.getInstance().setVideoCallback(new NERtcVideoCallback() { @Override public boolean onVideoCallback(NERtcVideoFrame neRtcVideoFrame) { long start = System.nanoTime(); int texId = 0; texId = mFURenderer.onDrawFrameDualInput(neRtcVideoFrame.data, neRtcVideoFrame.textureId, neRtcVideoFrame.width, neRtcVideoFrame.height); long renderTime = System.nanoTime() - start; //输出NV21格式:两种输出格式二选一即可 neRtcVideoFrame.format = NERtcVideoFrame.Format.NV21; //输出TEXTURE_RGB: neRtcVideoFrame.textureId = texId; neRtcVideoFrame.format = NERtcVideoFrame.Format.TEXTURE_RGB; return true; } }, false);
设置美颜效果
美颜、美妆、滤镜、贴纸效果的具体参数设置,请参见 Faceunity Nama 相关文档。
示例项目源码
网易云信提供相芯美颜的示例项目源码,您可以参考该源码实现相芯美颜。
API 参考
方法 | 功能描述 |
---|---|
enableLocalVideo |
开启本地视频采集。 |
setVideoCallback |
设置摄像头采集数据的回调。 |
NERtcVideoCallback |
视频帧数据回调。 |
常见问题
Android 支持的最低系统版本是多少
推荐使用 V4.3 及以上版本。
是否需要设置OpenGL环境,创建EGL context
不需要,虽然 NERtcSDK 的 view 继承自 SurfaceView,不具备系统自带的 GL 环境,但是我们在 setVideoCallback
的回调中设定了 GL 环境,并创建了相应的 EGL context,生命周期同 NERtc。
FURenderer(Nama SDK)的生命周期
FURenderer 的生命周期是独立的,和 NERtc 无关,但是两者通过 setVideoCallback
共享了 EGL context 的生命周期,因此需要 FURenderer 美颜相关接口的调用在 NERtc 的 init
和 release
之间,并且确保 NERtc 在 release 之后,FURenderer 也需要释放。
1 对 1 视频通话场景中接入美颜,第一次打开本地预览正常,第二次打开本地预览画面闪一下后黑屏/花屏
排查思路:
-
先注释掉
setVideoCallback
相关代码,检查本地预览是否正常。如果预览正常,继续执行后续步骤排查接口调用逻辑。 -
如果第一次预览结束后,调用了
NERtcEx.getInstance().release()
接口去释放 NERTC SDK,则也需要调用destroyFU()
去释放相芯资源。因为 NERTC 已经被释放,EGL Context 已经失效,Nama SDK 默认丢掉前几帧画面,所以我们可以看到前面几帧没有经过相芯处理的画面一闪而过,后面的数据无法正常拿到,所以显示黑屏。
解决方案:
-
调用
release
释放 NERTC SDK 资源后,也需要调用destroyFU()
去释放Nama SDK。 -
如果没有调用
release
释放 NERTC SDK 资源,则无需每次调用destroyFU()
去释放Nama SDK,Nama SDK 与 NERTC SDK 共享EGL Context。
开启美颜后,预览画面绿屏
检查 NERtcEx.getInstance().setVideoCallback()
回调中,返回的 neRtcVideoFrame
的 format 是否正确。
Nama SDK 处理完之后的数据默认为 TEXTURE_RGB
,需要正确设置纹理为 NERtcVideoFrame.Format.TEXTURE_RGB
才能正常渲染。