音视频通话 2.0
Android

相芯美颜

更新时间: 2023/10/24 16:58:14

NERTC SDK 支持接入相芯等第三方专业美颜滤镜厂商,实现美颜、美妆、滤镜、贴纸等美颜特效。在娱乐社交、在线教育等场景中,您可以快速构建具备美颜特效能力的应用,让用户在进行视频通话或直播时,呈现更良好的肌肤状态和精神面貌。

相芯美颜(Faceunity Nama SDK,下文简称 Nama SDK)的详细功能介绍请参见人脸特效

准备工作

  1. 下载相芯美颜 SDK(推荐使用 V8.3.0 版本)
  2. 获取相芯美颜 SDK 的证书,具体请联系网易云信商务经理。
  3. 获取相芯美颜资源文件,具体请联系网易云信商务经理。
  4. 集成 NERTC SDK,推荐使用 NERTC V4.6.50 及以后版本,V4.6.50 版本对相芯美颜进行了优化。

功能原理

相芯美颜原理.png

  1. NERTC SDK 提供了 setVideoCallback 采集数据回调的接口,将采集到的视频图像数据通过该接口回调出来。

  2. Nama SDK 通过回调获取视频图像数据,进行美颜处理后,通过参数返回给 NERTC SDK。

  3. NERTC SDK 将美颜后的数据进行编码和传输。

基本概念

  • 纹理(Texture):纹理指的是一张二维的图片,把它像贴纸一样贴在图元上面,让图元看起来像贴纸所要表现的效果那样。
  • NV21:NV21是 YUV420SP 图像编码的一种类型。根据 YUV 来定义图像的颜色,其中Y 表示明亮度,U 和 V 分别表示色调和饱和度。Android 系统的相机默认的图像格式是 NV21 。它比 RGB 模型的图像更省存储空间和带宽。
  • 双输入:纹理+ YUV 双份数据输入。

注意事项

  • 美颜相关方法返回值为 false 时,表示方法调用失败。
  • 调用 enableLocalVideo 开启本地视频采集时,请设置 streamTypekNERtcVideoStreamTypeMain,否则美颜效果不会生效。

集成相芯美颜

  1. 将证书文件 authpack.java 放到本地项目的 faceunity/com/faceunity/fulivedemo 目录下。

  2. 将所需的美颜模型和道具放到本地项目的 assets 目录下,例如 /app/src/main/assets/Resource

  3. 通过 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 渲染和双输入三种场景的视频图像处理,并提供相应的示例代码。

方案一:纹理渲染

  1. 设置 NERTC 的视频属性

    调用setLocalVideoConfig 方法的 videoConfig 参数,设置视频的分辨率、图像的数据格式。

    在本示例中,视频的分辨率为 640 x 360 px,帧率为 15 fps,图像数据格式colorFormatTEXTURE。示例代码如下:

    // 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);
    
  2. 初始化相芯美颜 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();
    
    
  3. 在成功加入房间后,调用 NERTC 的 enableLocalVideo 接口,开启本地视频采集,请设置 streamTypekNERtcVideoStreamTypeMain,否则美颜效果不会生效。

  4. 调用 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 渲染

  1. 设置 NERTC 的视频属性

    调用setLocalVideoConfig 方法的 videoConfig 参数,设置视频的分辨率、图像的数据格式。

    在本示例中,视频的分辨率为 640 x 360 px,帧率为 15 fps,图像数据格式colorFormatNV21。示例代码如下:

    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);
    
  2. 初始化相芯美颜 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();
    
    
  3. 在成功加入房间后,调用 NERTC 的 enableLocalVideo 接口,开启本地视频采集,请设置 streamTypekNERtcVideoStreamTypeMain,否则美颜效果不会生效。

  4. 调用 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 路采用纹理格式用于美颜。

  1. 设置 NERTC 的视频属性

    调用setLocalVideoConfig 方法的 videoConfig 参数,设置视频的分辨率、图像的数据格式。

    在本示例中,视频的分辨率为 640 x 360 px,帧率为 15 fps,图像数据格式colorFormatTEXTURE。示例代码如下:

    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);
    
  2. 初始化相芯美颜 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;
    }
    
  3. 在成功加入房间后,调用 NERTC 的 enableLocalVideo 接口,开启本地视频采集,请设置 streamTypekNERtcVideoStreamTypeMain,否则美颜效果不会生效。

  4. 调用 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 的 initrelease之间,并且确保 NERtc 在 release 之后,FURenderer 也需要释放

1 对 1 视频通话场景中接入美颜,第一次打开本地预览正常,第二次打开本地预览画面闪一下后黑屏/花屏

排查思路:

  1. 先注释掉 setVideoCallback 相关代码,检查本地预览是否正常。如果预览正常,继续执行后续步骤排查接口调用逻辑。

  2. 如果第一次预览结束后,调用了 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才能正常渲染。

此文档是否对你有帮助?
有帮助
去反馈
  • 准备工作
  • 功能原理
  • 基本概念
  • 注意事项
  • 集成相芯美颜
  • 视频图像处理
  • 方案一:纹理渲染
  • 方案二:NV21 渲染
  • 方案三:双输入
  • 设置美颜效果
  • 示例项目源码
  • API 参考
  • 常见问题
  • Android 支持的最低系统版本是多少
  • 是否需要设置OpenGL环境,创建EGL context
  • FURenderer(Nama SDK)的生命周期
  • 1 对 1 视频通话场景中接入美颜,第一次打开本地预览正常,第二次打开本地预览画面闪一下后黑屏/花屏
  • 开启美颜后,预览画面绿屏