功能介绍
除了音视频 SDK 音视频模块内部默认的采集和渲染外,下面场景默认视频模块可能无法满足需求:
- 有自己的音频或者视频模块
- 希望推送非采集的视频源(如屏幕数据)
- 有自己的美颜或经过前处理后的数据
- 有自己视频采集设备管理
基于此,SDK 支持使用自定义的音视频源或渲染器,实现相关场景。
anyRTC 自采集和渲染包括 Push 和 mediaIO 两种自定义视频采集方式:
- Push 方式下,SDK 默认不会对采集传入的音频数据做消噪等处理。如有音频消噪需求,需要开发者自行实现。
- MediaIO 方式下,自定义视频源可以搭配自定义渲染器使用,实现更为丰富的场景。
Push 方式
操作步骤
自定义视频采集和播放前,请确保已实现基本的音视频功能。
-
在
joinChannel
前通过调用setExternalVideoSource
指定外部视频采集设备。 -
指定外部采集设备后,开发者自行管理视频数据采集和处理。
-
完成视频数据处理后,再通过pushExternalVideoFrame 发送给 SDK 进行后续操作。
为满足实际使用需求,你可以在将视频数据发送回 SDK 前,通过 ARVideoFrame
修改视频数据。比如,设置 rotation
为 180,使视频帧顺时针旋转 180 度。
API 时序图
参考下图时序在你的项目中自定义视频采集。
示例代码
// 首先通知 SDK 现在开始使用外部视频源
rtcEngine.setExternalVideoSource(
true, // 是否使用外部视频源
false, // 是否使用 Texture作为输出
true // true 为使用推送模式,false 为拉取模式,但目前不支持
);
// 在获得视频数据的时候调用 Push 方法将数据传送出去
rtcEngine.pushExternalVideoFrame(new ARVideoFrame(
// 在构造方法传入帧数据的参数,比如格式,宽高等
// 具体的请查看 ARVideoFrame 类的说明
));
同时,我们在 GitHub 提供一个开源的 CustomRenderAndVideoSource 示例项目。你可以前往下载,或参考 VideoActivity.java 文件中的 setVideoSource
方法的源代码。
API 参考
MediaIO 方式
通过 MediaIO 提供 IVideoSource
接口和 IVideoFrameConsumer
类,你可以通过该类设置采集的视频数据格式,并控制外部视频的采集过程。
参考如下步骤,在你的项目中使用 MediaIO 方式实现自定义视频源功能:
-
实现 IVideoSource类。通过 IVideoSource类下的各回调设置视频数据格式,并控制采集过程:
-
收到
getBufferType
回调后,在该回调的返回值中指定想要采集的视频数据格式; -
收到
onInitialize
回调后,保存该回调中的IVideoFrameConsumer
对象。AR 通过IVideoFrameConsumer
对象发送和接收自定义的视频数据; -
收到 onStart 回调后,通过 IVideoFrameConsumer对象向 SDK 发送视频帧;
为满足实际使用需求,你可以在将视频帧发送回 SDK 前,修改
IVideoFrameConsumer
中视频帧参数,如rotation
。 -
收到
onStop
回调后,停止使用IVideoFrameConsumer
对象向 SDK 发送视频帧; -
收到
onDispose
回调后,释放IVideoFrameConsumer
对象。
-
-
继承实现的
IVideoSource
类,构建一个自定义的视频源对象。 -
调用
setVideoSource
方法,将自定义的视频源对象设置给 RtcEngine。 -
根据场景需要,调用
startPreview
、joinChannel
等方法预览或发送自定义采集的视频数据。
API 时序图
参考下图时序使用 MediaIO 在你的项目中实现自定义视频采集。
示例代码
参考下文代码使用 MediaIO 在你的项目中实现自定义视频采集。
IVideoFrameConsumer mConsumer;
boolean mHasStarted;
// 先创建一个实现 VideoSource 接口的实例
VideoSource source = new VideoSource() {
@Override
public int getBufferType() {
// 返回当前帧数据的 Buffer 类型,每种数据类型在 SDK 内部会经过不同的处理,所以必须与帧数据的类型保持一致
// 若切换 VideoSource 的类型,必须重新创建另一个实例
// 有三种类型:BYTE_BUFFER(1);BYTE_ARRAY(2);TEXTURE(3)
return BufferType.BYTE_ARRAY;
}
@Override
// 初始化视频源。你需要在该方法中传入一个 IVideoFrameConsumer 对象
public boolean onInitialize(IVideoFrameConsumer consumer) {
// Consumer 是由 SDK 创建的,在 VideoSource 生命周期中注意保存它的引用
mConsumer = consumer;
}
@Override
// 启动视频源。你可以在该方法中启动视频帧捕捉。输入 true,表示自定义视频源已成功启动。
public boolean onStart() {
mHasStarted = true;
}
@Override
// 停止视频源。你可以在该方法中停止采集视频。
public void onStop() {
mHasStarted = false;
}
@Override
// 释放视频源。你可以在该方法中关闭视频源设备。同时 SDK 会销毁 IVideoFrameConsumer 对象。
public void onDispose() {
// 释放对 Consumer 的引用
mConsumer = null;
}
};
// 将输出流切换到刚创建的 VideoSource 实例
rtcEngine.setVideoSource(source);
// 在得到视频帧数据之后,可以调用 Consumer 类的方法传送数据
// 必须根据帧数据的类型来选择用不同的方法
// 假设从视频源中得到的视频为 Data, 从 Android 相机中获取的帧类型可能是 NV21,假设当前类型为 byte array,即 NV21
if (mHasStarted && mConsumer != null) {
mConsumer.consumeByteArrayFrame(data, ARVideoFrame.NV21, width, height, rotation, timestamp);
}
同时,我们在 GitHub 提供一个开源的 Custom-Media-Device-Android 示例项目。你可以前往下载,或参考 ViewSharingCapturer.java 文件中的源代码。
API 参考
相关文档
你也可以选择自己管理视频设备的生命周期,只是根据 Media Engine 的回调来打开和关闭视频帧的输入开关。对于开发者 App 之前已有自己的采集模块,需要集成 AR SDK 以获得实时通信能力的使用场景下,这种方式更简单。
自定义视频渲染器
通过 MediaIO 采集到的视频数据,还可以搭配 IVideoSink
接口使用,实现自定义渲染功能。
参考如下步骤,在你的项目中使用 MediaIO 方式实现自定义渲染器功能:
-
实现IVideoSink类。通过 IVideoSink 类下的各回调设置视频数据格式,并控制渲染过程:
- 收到
getBufferType
和getPixelFormat
回调后,在对应回调的返回值中设置你想要渲染的数据类型;
- 收到
- 根据收到的
onInitialize
、onStart
、onStop
、onDispose
、getEglContextHandle
回调,控制视频数据的渲染过程;- 实现一个对应渲染数据类型的
IVideoFrameConsumer
对象,以获取视频数据。
- 实现一个对应渲染数据类型的
-
继承实现的
IVideoSink 类
,构建一个自定义的渲染器。 -
调用
setLocalVideoRenderer
或setRemoteVideoRenderer
,用于本地渲染或远端渲染。 -
根据场景需要,调用
startPreview
、joinChannel
等方法预览或发送自定义渲染的视频数据。
API 调用时序
参考下图时序使用 MediaIO 在你的项目中实现自定义视频渲染。
示例代码
参考下文代码使用 MediaIO 在你的项目中实现自定义视频渲染。
// 先创建一个实现 IVideoSink 接口的实例
IVideoSink sink = new IVideoSink() {
@Override
// 初始化渲染器。你可以在该方法中对渲染器进行初始化,也可以提前初始化好。将返回值设为 true,表示已完成初始化
public boolean onInitialize () {
return true;
}
@Override
// 启动渲染器
public boolean onStart() {
return true;
}
@Override
// 停止渲染器
public void onStop() {
}
@Override
// 释放渲染器
public void onDispose() {
}
@Override
public long getEGLContextHandle() {
// 构造你的 Egl context
// 返回 0 代表渲染器中并没有创建 Egl context
return 0;
}
// 返回当前渲染器需要的数据 Buffer 类型
// 若切换 VideoSink 的类型,必须重新创建另一个实例
// 有三种类型:BYTE_BUFFER(1);BYTE_ARRAY(2);TEXTURE(3)
@Override
public int getBufferType() {
return BufferType.BYTE_ARRAY;
}
// 返回当前渲染器需要的 Pixel 格式
@Override
public int getPixelFormat() {
return PixelFormat.NV21;
}
// SDK 调用该方法将获取到的视频帧传给渲染器
// 根据获取到的视频帧的格式,选择相应的回调
@Override
public void consumeByteArrayFrame(byte[] data, int format, int width, int height, int rotation, long timestamp) {
// 渲染器在此渲染
}
public void consumeByteBufferFrame(ByteBuffer buffer, int format, int width, int height, int rotation, long timestamp) {
// 渲染器在此渲染
}
public void consumeTextureFrame(int textureId, int format, int width, int height, int rotation, long timestamp, float[] matrix) {
// 渲染器在此渲染
}
}
rtcEngine.setLocalVideoRenderer(sink);
同时,我们在 GitHub 提供一个开源的 Custom render 示例项目。你可以前往下载源代码。
API 参考
为了方便开发者集成和创建自定义的视频渲染器,SDK 也提供了一些辅助类和示例代码;开发者也可以直接使用这些组件,或者利用这些组件构建自定义的渲染器。
开发注意事项
-
自定义视频采集和渲染场景中,需要开发者具有采集或渲染视频的能力:
- 自定义视频采集场景中,你需要自行管理视频数据的采集和处理。
- 自定义视频渲染场景中,你需要自行管理视频数据的处理和显示。
-
自定义视频渲染场景中,当
consumeByteArrayFrame
或consumeByteBufferFrame
或consumeTextureFrame
回调报告rotation
不为 0 时,自渲染的视频会呈一定角度。该角度可能由 SDK 采集或自采集的设置引起,你需要能根据实际使用需求处理自渲染的视频角度。
相关文档
如果你还想在项目中实现自定义的音频采集和渲染功能,请参考文档自定义音频采集和播放。