【经验分享】视频镜像相关处理

一、背景

  1. 什么是镜像?
    答: 平面镜成像缩写。自己拿手机打开相机对着自己的脸,举起左手或右手摆出yeah的姿势,屏幕上的效果就是“镜像”。 比如下面图中这样的效果。

image

现实世界中的“镜像”效果:
Picture1 Picture2

  1. 集成过程中常见的需求
    答: 我是要这样的效果(本地和远端看到的方向一致)
    image

不是这样的效果(本地和远端不一致)
image

  1. 如果我们的SDK采集+SDK渲染,不做任何处理,默认效果是怎么样的?
    答: 效果如下,本地和远端是方向相反的:
    image

二、SDK采集、SDK渲染

  1. 本地镜像 setLocalVideoMirrorMode() 这个接口怎么玩?
    答: 先来看一下这个接口说文档说明:

这个接口,只有在使用声网 sdk 渲染时才生效。 就是调用 setupLocalVideosetupRemoteVideo 时才生效。

  1. 三个参数的说明:
    a. VIDEO_MIRROR_MODE_AUTO(0)
    这个参数就是默认的情况:
    前置摄像头:
    image
    后置摄像头:
    image
    b. VIDEO_MIRROR_MODE_ENABLED(1)
    前置摄像头:
    image
    后置摄像头:
    image
    c. VIDEO_MIRROR_MODE_DISABLED(2)
    前置摄像头:
    image
    后置摄像头:
    image
  2. 远端镜像有个私有接口
setParameters(“{\”che.video.enableRemoteViewMirror\”:true}”);
[self.agoraKit setParameters:@"{“che.video.enableRemoteViewMirror”:true}"];

用法:
image

说明: 如果主播 A 和观众 B 连麦,主播 A 用前置摄像头,默认不加上面的私有接口是下面这样的效果:
image

在远端观众端,加上私有接口的效果:
前置摄像头:
image

后置摄像头:
image

说明: 上面这两个接口,实际上是在渲染端做的是否镜像的处理。实际并不太实用。

三、自采集、自渲染

  1. 安卓自采集,想改变本地渲染时的方向
    目前我们集成 FaceUnity 的 Demo 上就有这个功能(点击“切换镜像”,即可以本地渲染实现切换显示方向功能):
    image image

说明:
1). 核心代码:

public void flipFrontX() {
if (mCurrentCameraType != Camera.CameraInfo.CAMERA_FACING_FRONT) {
return;
}
    Matrix.scaleM(mvp, 0, -1, 1, 1);
}

具体代码细节,请参考:

2). 目前在 FaceUnity Demo 上仅对前置摄像头有效
3). 目前该本地镜像的功能仅对 nv21 格式的视频测试过,对于 texture 格式的视频还没有在 demo 上验证,理论上而言应该也是可以的。

  1. texture 格式视频帧进行“镜像”翻转
    该功能目前只能在自采集后的前处理来做。

处理:
{-1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
1.0f, 0.0f, 0.0f, 1.0f};
自采集是通过更改 AgoraFrame 中 rotation 矩阵以达到旋转和翻转图像的目的。
image

  1. yuv 格式实现“镜像”翻转
    该功能目前只能在自采集后的前处理来做。
    方式一: 直接在 java 层,通过变换算法来做(不太建议采用,因为这种方式比较耗 CPU 资源)
    image

方式二: yuv 格式, 通过 libyuv 的库来做镜像翻转:

在 Android 做过自定义 Camera 的朋友应该都知道,我们可以通过 public void onPreviewFrame(byte[] data, Camera camera) 回调来实现视频显示相关处理。

说明: 该方法还未经本地代码尝试, 但是理论上而言其性能消耗会比上面方式一好很多,几乎没有什么性能影响。

附录:

  1. 关于镜像,你可以了解的:
    拿出你的 iOS 和 Android 手机,打开“相机”,尝试一下相机预览和实际拍摄完生成照片的方向(只研究前置摄像头就可以)。

Android:
image

iOS:
image

常见需求 (这里只谈论自采集的情况,参考 Agora 集成 FaceUnity 的 Demo)
1)本地镜像显示,远端和本地显示一致。
image
解决方法:
本地不做变化,远端做镜像翻转(可参考第 8 点和第 9 点)

2)本地镜像显示,远端和本地不一致,和现实一致。
image
解决方法:
默认就是这个效果,不需要做任何处理。

3)本地非镜像显示,远端和本地一致。
image
解决方法:
本地做镜像翻转处理(可参考第 7 点),远端不做任何变化。

4)本地镜像显示,频道内远端、 CDN 和本地一致。
image
本地不做变化,远端做镜像翻转(可参考第 8 点和第 9 点)

5)本地镜像显示,频道内远端、 CDN 和本地不一致。
image
默认就是这个效果,不需要做任何处理。

6) 本地非镜像显示,频道内远端、 CDN 和本地一致。
image
本地做镜像翻转处理(可参考第 7 点),远端不做任何变化。