音视频前处理

更新时间: 2024/08/23 10:24:52

本章节主要介绍网易云信提供的各种音视频前处理功能。前处理介于采集和编码之间,按照数据类型分类,可以分为音频前处理和视频前处理,音频前处理包括降噪回音消除人声检测自动增益耳返等等,视频前处理包括美颜磨皮设置对比度镜像水印等。网易云信移动端SDK中内置了基础款的美颜滤镜。 同时,网易云信还提供了音视频采集数据的回调功能,所以除了SDK自带的一些音视频的前处理功能,开发者可以利用音视频采集数据的回调功能,实现自定义的音视频数据前处理,包括接入第三方变声、美颜算法。

音频前处理

音频采集数据回调与发送

  • API介绍

当用户开始外部语音处理后,采集到的语音数据通过次回调通知。 用户可以对语音数据做相应的变声等不同的处理。需要通过setParameters开启语音数据处理。

  • API原型
java    /**
     * 语音数据处理接口, 不要改变数据的长度. 需要设置参数 {@link AVChatParameters#KEY_AUDIO_FRAME_FILTER}.
     *
     * @param frame 语音帧
     * @return 返回false 失败
     * @see AVChatParameters#KEY_AUDIO_FRAME_FILTER
     * @see AVChatManager#setParameter(AVChatParameters.Key, Object)
     */
    boolean onAudioFrameFilter(AVChatAudioFrame frame);
  • 参数说明
参数 说明
frame 语音帧,参考AVChatAudioFrame
  • 示例
java@Override
public boolean onAudioFrameFilter(AVChatAudioFrame frame) {}

音频耳返

  • API介绍

当主播想要从耳机中听到自己的声音时,可以开启耳返。一般使用在主播开启伴音,主播戴上耳机,随着伴奏说话唱歌,可以从耳机中实时听到融合了音乐和自己人声的声音。

  • API原型
java    /**
     * <p>开启耳返</p>
     * <p>
     * <p>在通话建立后可以打开耳返功能,打开后可以从耳机中实时听到自己的声音。</p>
     *
     * @return {@code true} 方法调用成功,{@code false} 方法调用失败
     */
    public abstract boolean startPlayCapturedAudio();


    /**
     * <p>关闭耳返</p>
     * <p>
     * <p>在成功开启耳返功能后, 可以随时关闭耳返效果。</p>
     *
     * @return {@code true} 方法调用成功,{@code false} 方法调用失败
     */
    public abstract boolean stopPlayCapturedAudio();


    /**
     * <p>设置耳返音量</p>
     * <p>
     * <p>在成功打开耳返功能后,可以实时调整耳返音量。</p>
     *
     * @param volume 播放耳返音量 [0.0f - 1.0f]
     * @return {@code true} 方法调用成功,{@code false} 方法调用失败
     */
    public abstract boolean setPlayCapturedAudioVolume(float volume);
  • 参数说明

setPlayCapturedAudioVolume参数说明:

参数 说明
volume 播放耳返数据音量[0.0f - 1.0f]

视频前处理

视频采集数据回调与发送

  • API介绍

当用户开始外部视频处理后,采集到的视频数据通过此回调通知。 用户可以对视频数据做相应的美颜等不同的处理。 需要通过setParameters开启视频数据处理,根据情况选择开启新的或者老的数据回调,推荐使用新的数据回调方式。

parameters.setBoolean(AVChatParameters.KEY_VIDEO_FRAME_FILTER, on);//开启老的视频数据回调
parameters.setBoolean(AVChatParameters.KEY_VIDEO_FRAME_FILTER_NEW, on);//开启新的视频数据回调
  • API原型1(弃用)
/**
     * 视频数据外部处理接口, 此接口需要同步执行. 操作运行在视频数据发送线程上,处理速度过慢会导致帧率过低
     *
     * @param frame          待处理数据
     * @param maybeDualInput 如果为 {@code true} 则代表需要外部输入两路数据,
     *                       {@link AVChatVideoFrame#data} 处理后的原始数据,{@link AVChatVideoFrame#dataMirror} 处理后的镜像数据。
     *                       如果为  {@code false} 则代表仅需要外部输入一路数据,仅支持 {@link AVChatVideoFrame#data}。
     *                       在实际使用过程中,用户需要根据自己需求来决定是否真正需要输入镜像数据,一般在使用到水印等外部处理时才会需要真正输入两路数据,其他情况可以忽略此参数。
     * @return 返回true成功
     */
    boolean onVideoFrameFilter(AVChatVideoFrame frame, boolean maybeDualInput);
  • 参数说明
参数 说明
frame 待处理数据,参考AVChatVideoFrame
maybeDualInput 是否需要外部输入两路数据,如果为 true 则代表需要外部输入两路数据。
  • 示例
java@Override
public boolean onVideoFrameFilter(AVChatVideoFrame frame, boolean maybeDualInput)) {}
  • API原型2(推荐)
java/**
 * 视频数据外部处理接口, 此接口需要同步执行. 操作运行在视频数据发送线程上,处理速度过慢会导致帧率过低
 * @param input          待处理数据
 * @param outputFrames   {@link com.netease.nrtc.sdk.video.VideoFrame[0]} 处理后的数据,{@link com.netease.nrtc.sdk.video.VideoFrame[1]} 处理后的镜像数据。
 *                       在实际使用过程中,用户需要根据自己需求来决定是否真正需要输入镜像数据,一般在使用到水印等外部处理时才会需要真正输入两路数据,其他情况可以忽略此参数。
 * @param filterParameter 待处理数据的参数
 * @return 返回true成功
 */
boolean onVideoFrameFilter(final com.netease.nrtc.sdk.video.VideoFrame input, com.netease.nrtc.sdk.video.VideoFrame[] outputFrames, VideoFilterParameter filterParameter);
  • 参数说明
参数 说明
input 待处理数据,统一用VideoFrame封装,可能是I420/NV/Texture格式
outputFrames outputFrames[0]处理后的数据,outputFrames[1]处理后的镜像数据
filterParameter 待处理参数 ,参考 VideoFilterParameter
  • 示例
java@Override
boolean onVideoFrameFilter(final VideoFrame input, VideoFrame[] outputFrames, VideoFilterParameter filterParameter){
    ...
        if(format == VideoFrameFormat.kVideoTexture) {
            innerVideoEffect.init(getApplicationContext(), true, true);
        }else{
            innerVideoEffect.init(getApplicationContext(), true, false);
        }
    ...
         if (frame.getBuffer().getFormat() == VideoFrameFormat.kVideoTexture) {
            return  filterTextureFrame(frame,outputFrames,filterParameter);
        } else {
            return filterByteBufferFrame(frame, outputFrames, filterParameter);
        }
    ...
}

滤镜模块初始化

  • API介绍

SDK的发布包中打包有滤镜SDK,开发者可以根据需要接入滤镜功能,轻松实现磨皮、滤镜、静态水印和动态水印功能。滤镜模块的接口文档打开查阅API文档

滤镜模块需要运行在GLES 3.0及以上版本的系统中,对应API版本为API >= 18

滤镜模块可以通过gradle进行依赖,如

javadependencies {
    implementation 'com.netease.nrtc:videoeffect:1.0.3'
}

如果在API < 18工程中依赖,需要在AndroidManifest.xml中申明此库支持低版本依赖,运行时需增加API >= 18才使用滤镜库逻辑

xml<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    <!--添加以下内容-->
    <uses-sdk tools:overrideLibrary="com.netease.nrtc.libvideoeffect"/>
    
    <application>...<application/>
</manifest>

接入时,需要在采集视频数据的回调方法中自定义滤镜功能,该回调需要设置对应参数才会触发。

java    boolean onVideoFrameFilter(final AVChatVideoFrame frame, final boolean maybeDualInput);

滤镜模块的功能实现由VideoEffect类提供,使用前需要通过VideoEffectFactory.getVCloudEffect创建一个对应实例。

  • API原型
java/**
 * 滤镜模块初始化前处理
 */
public void init(Context context, boolean useFilter, boolean hasGLContext);
  • 参数说明
参数 说明
context 应用上下文,建议使用ApplicationContext。
useFilter 是否使用滤镜功能。
hasGLContext 调用线程是否具有EGLContext。如果当前线程没有EGLContext,那么该接口会创建一个。后续所有的滤镜API必须保证在同一个具有GL Context的线程中调用。
  • 示例
javamVideoEffect = VideoEffectFactory.getVCloudEffect();
mVideoEffect.init(getApplicationContext(), true, false);
  • 特殊说明 滤镜的功能需要在onVideoFrameFilter方法中同步处理,因此该初始化方法也需要在该方法中进行完成调用,开发者也可以在onVideoFrameFilter中使用第三方滤镜 SDK 进行视频处理。

对视频美颜

  • API介绍

对视频美颜需要调用 VideoEffect的设置滤镜类型和滤镜强度接口。

  • API原型
java //设置滤镜类型,可设置为`FilterType`枚举类中的一种
 public abstract void setFilterType(FilterType type);

 //设置滤镜强度,有效值为(0-1)
 public abstract void setFilterLevel(float level);
  • 参数说明
参数 说明
FilterType 滤镜类型。
level 滤镜强度,有效值为(0-1)。
  • 示例
javamVideoEffect.setFilterType(VideoEffect.FilterType.nature);
mVideoEffect.setFilterLevel(0.5f);

设置磨皮强度

  • API介绍

对视频进行磨皮需要调用 VideoEffect的设置磨皮强度接口。

  • API原型
java/** 设置磨皮强度
 * 参数:
 * level - (0-5)*/
public abstract void setBeautyLevel(int level)

  • 参数说明
参数 说明
level 磨皮强度,有效值为(0-5)。
  • 示例
javamVideoEffect.setBeautyLevel(5);

设置静态水印

  • API介绍

设置静态水印需要调用 VideoEffect的设置静态水印接口。

  • API原型
java/**添加水印(只需要调用一次)
 * 参数:
 * bitmap - 水印图片
 * rect - 水印具体位置(上下左右中四个基本位置)
 * x - 距离 rect 的 x 坐标
 * y - 距离 rect 的 y 坐标 */
public void addWaterMark(android.graphics.Bitmap bitmap,
                         VideoEffect.Rect rect,
                         int x,
                         int y)

  • 参数说明
参数 说明
bitmap 水印图片。
rect 水印具体位置(上下左右中四个基本位置)。
x 距离 rect 的 x 坐标。
y 距离 rect 的 y 坐标。
  • 示例
javamVideoEffect.addWaterMark(mWaterMaskBitmapStatic, frame.width / 2, frame.height / 2);

设置动态水印

  • API介绍

设置动态水印需要调用 VideoEffect的设置动态水印接口。

  • API原型
java/**添加水印(只需要调用一次)
 * 添加动态水印(只需要调用一次)
 * 参数:
 * bitmapArray - 水印图片
 * rect - 水印具体位置(上下左右中四个基本位置)
 * x - 距离 rect 的 x 坐标
 * y - 距离 rect 的 y 坐标
 * fps - 动态水印的帧率
 * cameraFps - 相机采集的帧率
 * looped - 是否循环播放 */
public void addDynamicWaterMark(android.graphics.Bitmap[] bitmapArray,
                                VideoEffect.Rect rect,
                                int x,
                                int y,
                                int fps,
                                int cameraFps,
                                boolean looped)
  • 参数说明
参数 说明
bitmapArray 水印图片。
rect 水印具体位置(上下左右中四个基本位置)。
x 距离 rect 的 x 坐标。
y 距离 rect 的 y 坐标。
fps 动态水印的帧率。
cameraFps 相机采集的帧率。
looped 是否循环播放。
  • 示例
java	  mVideoEffect.closeDynamicWaterMark(false);
      mVideoEffect.addDynamicWaterMark(null, frame.width / 2, frame.height / 2, 23, AVChatVideoFrameRate.FRAME_RATE_15, true);
      mVideoEffect.addDynamicWaterMark(mWaterMaskBitmapDynamic, frame.width / 2, frame.height / 2, 23, AVChatVideoFrameRate.FRAME_RATE_15, true);

滤镜处理

  • ByteBuffer的滤镜API介绍

对图片原始数据进行滤镜处理,并返回RGBA格式的数据,如果开启了滤镜,则每一帧都需要调用该方法.采用GPU对buffer数据进行滤镜处理,必须在具有EGLContext的线程上进行调用。

  • API原型
java/**采用GPU对buffer数据进行滤镜处理(必须在具有EGLContext的线程上进行调用)
 * 参数:
 * format - 数据类型
 * data - 原始数据
 * width - 图像宽
 * height - 图像高
 * 返回:
 * RGBA图像数组 */
public abstract byte[] filterBufferToRGBA(VideoEffect.DataFormat format,
                                          byte[] data,
                                          int width,
                                          int height)
  • 参数说明
参数 说明
format 数据类型。
data 原始数据。
width 图像宽。
height 图像高。
  • 示例
java            byte[] intermediate = mVideoEffect.filterBufferToRGBA(format, frame.data, frame.width, frame.height);
  • Texture的滤镜API介绍

对图片原始数据进行滤镜处理,并2D的纹理ID,如果开启了滤镜,则每一帧都需要调用该方法.采用GPU对纹理数据进行滤镜处理,必须在具有EGLContext的线程上进行调用。

  • API原型
java/**
 * 采用GPU对Camera采集的OES Texture进行滤镜处理 (必须在具有EGLContext的线程上进行调用)
 *
 * @param texture OES Texture
 * @param width   采集图像宽
 * @param height  采集图像高
 * @return 2D texture纹理,可以对这个texture做后续操作,如硬编、预览
*/
public abstract int filterTexture(int texture, int width, int height);
  • 参数说明
参数 说明
texture 数据类型。
height 图像宽。
height 图像高。
  • 示例
java int filtedTextureId = mVideoEffect.filterTexture(textureId, width, height);

水印和涂鸦处理

  • ByteBuffer API介绍

该方法将输入的原始视频数据转为YUV格式数据,同时会根据autoEffect配置是否为true自动进行水印、涂鸦、旋转等操作。

方法会返回两路数据,但只有第一路数据是始终有效的,并需要将之拷贝至AVChatVideoFrame.data中去。

仅当needMirrorDatatrue时,第二路数据有效,并需要将第二路数据拷贝至AVChatVideoFrame.dataMirror中,并设置AVChatVideoFrame.dualInputtrue

  • API原型
java/**原始视频数据转YUV,同时会根据配置进行水印、涂鸦、旋转等操作,保证输出的是正的YUV数据
 * 参数:
 * src - 原始视频数据
 * dataFormat - 原始视频数据的色彩空间类型
 * inWidth - 输入视频宽
 * inHeight - 输入视频高
 * cameraRotation - 相机拍摄调度
 * displayOrientation - 计算后的显示角度
 * outWidth - 输出视频宽
 * outHeight - 输出视频高
 * needMirrorData - 是否需要镜像后的数据(主要用于前置摄像头下水印、涂鸦等本地镜像显示和编码数据的区别)
 * autoEffect - 是否自动添加上水印、涂鸦等
 * 返回:
 * 具有水印、涂鸦等正的YUV数据*/
public VideoEffect.YUVData[] TOYUV420(byte[] src,
                                      VideoEffect.DataFormat dataFormat,
                                      int inWidth,
                                      int inHeight,
                                      int cameraRotation,
                                      int displayOrientation,
                                      int outWidth,
                                      int outHeight,
                                      boolean needMirrorData,
                                      boolean autoEffect)

  • 参数说明
参数 说明
src 原始视频数据。
dataFormat 原始视频数据的色彩空间类型。
width 视频宽。
height 视频高。
cameraRotation 相机拍摄调度。
displayOrientation 计算后的显示角度。
outWidth 输出视频宽。
outHeight 输出视频高。
needMirrorData 是否需要镜像后的数据。
autoEffect 是否自动添加上水印、涂鸦等。
  • 示例
java       result = mVideoEffect.TOYUV420(intermediate, VideoEffect.DataFormat.RGBA, frame.width, frame.height, frame.rotation, 90, frame.width, frame.height, needMirrorData, true);
  • Texture API介绍

    添加水印前,先将纹理做完滤镜,通过旋转或者镜像等处理,将纹理处理成正的方向。不然后续再做旋转,水印方向就会有问题。

方法会返回两路数据,但只有第一路数据是始终有效的,并需要将之拷贝至AVChatVideoFrame.data中去。

仅当needMirrorDatatrue时,第二路数据有效,并需要将第二路数据拷贝至AVChatVideoFrame.dataMirror中,并设置AVChatVideoFrame.dualInputtrue

  • 纹理添加水印 API原型
java    /**
     * 手动水印
     * @param data - 纹理格式的数据,包括纹理ID,纹理的byte[]数据,纹理长,纹理宽等。
     * @param needI420Data - 是否需要I420数据。
     * @param waterCount - 需要添加水印的纹理数。比如镜像过和未镜像过的两个纹理。
     * @return TextureData - 包括纹理ID,纹理的byte[]数据,纹理长,纹理宽等。
     */
    public TextureData effectWater(TextureData data,boolean needI420Data, int waterCount){}
  • 参数说明
参数 说明
data 纹理格式的数据,包括纹理ID,纹理长,纹理宽等
needI420Data 是否需要I420数据。
waterCount 需要添加水印的纹理数。比如镜像过和未镜像过的两个纹理。
  • 示例
java     //////给未镜像数据加水印
VideoEffect.TextureData textureDataW = mVideoEffect.effectWater(textureData, false,1);
  • 纹理旋转 API原型
java  /**
     * 原始纹理数据进行旋转
     * @param textureType 输入纹理类型 GLES11Ext.GL_TEXTURE_EXTERNAL_OES、GLES20.GL_TEXTURE_2D
     * @param textureId 输入纹理ID
     * @param srcWidth 输入宽
     * @param srcHeight 输入高
     * @param rotation  对纹理的旋转角度
     * @return 旋转后的纹理信息
     */
    public TextureData rotateTexture(int textureType,int textureId, int srcWidth, int srcHeight, int rotation){}
  • 参数说明
参数 说明
textureType 输入纹理类型 GLES11Ext.GL_TEXTURE_EXTERNAL_OES、GLES20.GL_TEXTURE_2D
textureId 输入纹理ID
srcWidth 输入宽
srcHeight 输入高
rotation 对纹理的旋转角度
  • 示例
java VideoEffect.TextureData textureDataR = mVideoEffect.rotateTexture(GLES20.GL_TEXTURE_2D, filtedTextureId, width, height, rotation);
  • 纹理镜像 API原型
java    /**
     * 原始纹理数据镜像处理
     *
     * @param textureType 输入纹理类型 GLES11Ext.GL_TEXTURE_EXTERNAL_OES、GLES20.GL_TEXTURE_2D
     * @param textureId 输入纹理ID
     * @param srcWidth 输入宽
     * @param srcHeight 输入高
     * @return 镜像后的纹理信息
     */
    public TextureData mirrorTexture(int textureType,int textureId, int srcWidth, int srcHeight){}
  • 参数说明
参数 说明
textureType 输入纹理类型 GLES11Ext.GL_TEXTURE_EXTERNAL_OES、GLES20.GL_TEXTURE_2D
textureId 输入纹理ID
srcWidth 输入宽
srcHeight 输入高
  • 示例
javaVideoEffect.TextureDatatextureData = mVideoEffect.mirrorTexture(GLES20.GL_TEXTURE_2D, textureDataR.textureId, textureDataR.width, textureDataR.height);

销毁滤镜模块

  • API介绍

销毁滤镜模块,需要在init方法调用的线程中调用

  • API原型
java//销毁滤镜
public void unInit()
  • 示例
javamVideoEffect.unInit();
mVideoEffect = null;

设置视频预览镜像

  • API介绍

设置视频预览镜像是通过setParameters或者setParameter接口进行设置的,参数名称在AVChatParameters中的KEY_VIDEO_LOCAL_PREVIEW_MIRROR

  • API原型
java    /**
     * 前置摄像头本地预览镜像
     *
     * >当使用前置摄像头时,本地预览画面是否镜像。 默认前置摄像头画面镜像处理。
     */
    public static final Key<Boolean> KEY_VIDEO_LOCAL_PREVIEW_MIRROR = new Key<>(RtcParameters.KEY_VIDEO_LOCAL_PREVIEW_MIRROR, Boolean.class);
  • 参数说明
参数 说明
value true 镜像,false 不镜像。
  • 示例
javaboolean mirror = AVChatManager.getInstance().getParameter(AVChatParameters.KEY_VIDEO_LOCAL_PREVIEW_MIRROR);
AVChatManager.getInstance().setParameter(AVChatParameters.KEY_VIDEO_LOCAL_PREVIEW_MIRROR, !mirror);

设置视频编码镜像

  • API介绍

设置视频预览镜像是通过setParameters或者setParameter接口进行设置的,参数名称在AVChatParameters中的KEY_VIDEO_TRANSPORT_MIRROR

  • API原型
java    /**
     * 前置摄像头发送数据预览镜像
     *
     * 当使用前置摄像头时,本地发送画面是否镜像。 默认前置摄像头发送画面不镜像处理。
     *
    public static final Key<Boolean> KEY_VIDEO_TRANSPORT_MIRROR = new Key<>(RtcParameters.KEY_VIDEO_TRANSPORT_MIRROR, Boolean.class);

  • 参数说明
参数 说明
value true 镜像,false 不镜像。
  • 示例
javaboolean mirror = AVChatManager.getInstance().getParameter(AVChatParameters.KEY_VIDEO_TRANSPORT_MIRROR);
AVChatManager.getInstance().setParameter(AVChatParameters.KEY_VIDEO_TRANSPORT_MIRROR, !mirror);

此文档是否对你有帮助?
有帮助
去反馈
  • 音频前处理
  • 音频采集数据回调与发送
  • 音频耳返
  • 视频前处理
  • 视频采集数据回调与发送
  • 滤镜模块初始化
  • 对视频美颜
  • 设置磨皮强度
  • 设置静态水印
  • 设置动态水印
  • 滤镜处理
  • 水印和涂鸦处理
  • 销毁滤镜模块
  • 设置视频预览镜像
  • 设置视频编码镜像