当你使用 RTC 实现实时音视频通信时,RTC 会使用默认的音视频模块进行视频采集和渲染。在一些场景下,你可能会发现默认模块无法满足需求,比如:
在这些场景下,你可以参考本文,将自定义设备采集的视频源,交由 RTC 进行编码和传输。
你已经集成了 3.33 及以上版本的 RTC SDK,实现了基本的音视频通话。
使用 setVideoSourceType
指定自定义视频源。你需要使用自采集模块驱动采集设备对视频进行采集,采集的视频帧通过 pushExternalVideoFrame
发送给 SDK。
自定义视频采集的数据流转如下图:
API 调用时序可以参考下图:
- 以下代码基于 3.33+,此版本下,视频封装类为
VideoFrame
。- 3.32 到 3.18 版本中,视频封装类为
RtcVideoFrame
,和VideoFrame
的差别仅在于名称不同。- 对于 3.18 以下的版本,视频封装类为
ExtVideoFrame
,和VideoFrame
的差别仅在于:ExtVideoFrame
中不包含buffer_type
。
通过调用 setVideoSourceType
指定自定义视频源。
iOS
[self.rtcVideo setVideoSourceType:ByteRTCVideoSourceTypeExternal WithStreamIndex:ByteRTCStreamIndexMain];
Android
mRTCVideo.setVideoSourceType(StreamIndex.STREAM_INDEX_MAIN, VIDEO_SOURCE_TYPE_EXTERNAL);
你可以参考以下示例项目中,Advance_Demo 中自定义采集工具类,创建你的视频采集模块。
你可以使用 pushExternalVideoFrame
中的 VideoFrame
参数,对采集到的视频数据进行编码前处理。比如,设置 VideoFrame
参数中的 rotation
为 180
,即可使视频帧顺时针旋转 180 度。当然,你也可以加入自行实现的其它前处理逻辑。
你必须根据自采集视频编码数据格式,使用对应的
VideoFrame
参数。
调用 pushExternalVideoFrame
将采集到的视频帧,交由 RTC 进行编码和传输。
iOS
根据所需要设置的参数,选择调用合适的 pushExternalVideoFrame
接口。参见 API 参考。
#pragma mark - AVCaptureVideoDataOutputSampleBufferDelegate /** * 在接收到摄像头视频帧回调后调用 pushExternalVideoFrame 接口向 SDK 发送视频帧数据。 */ - (void)captureOutput:(AVCaptureOutput *)output didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection { CVPixelBufferRef buffer = CMSampleBufferGetImageBuffer(sampleBuffer); CMTime timeStamp = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);//建议增加时间戳打印,便于进行异常问题的定位和排查。 [self.rtcVideo pushExternalVideoFrame:buffer time:timeStamp]; }
Android
根据您使用的视频采集设备的不同,采集输出的视频信号可能会采取不同的视频编码方式。你需要根据不同的视频编码方式,采用不同的参数。
以下代码分别展示了采集视频采用纹理方案和 RGBA 格式 raw 数据时,如何设置视频帧参数。
public void frameAvailable(SurfaceTexture texture) { // 预览渲染逻辑 ... // 设置外部视频帧 GLTextureVideoFrameBuilder builder = new GLTextureVideoFrameBuilder(VideoPixelFormat.kVideoPixelFormatTextureOES)//或 TEXTURE_2D .setEGLContext(sharedEglContext) .setTextureID(textureID) .setTextureMatrix(transformMatrix) .setWidth(videoWidth) .setHeight(videoHeight) .setRotation(VideoRotation.VIDEO_ROTATION_270)//设置旋转角度 .setTimeStampUs(System.currentTimeMillis() * TimeUnit.MILLISECONDS.toNanos(1))//设置时间戳 //继续处理后续视频帧,直到处理完最后一帧 ... // 向 SDK 推送外部视频帧 if (mVideoCallback != null && mIsPushExternalVideoSource) { mVideoCallback.pushExternalVideoFrame(builder.build()); } }
public void createRGBAFrame(byte[] RGBABuffer, ColorSpace colorSpace) { CpuBufferVideoFrameBuilder builder = new CpuBufferVideoFrameBuilder(VideoPixelFormat.kVideoPixelFormatRGBA); builder.setWidth(width) .setHeight(height) .setRotation(VideoRotation.VIDEO_ROTATION_0) .setTimeStampUs(System.currentTimeMillis() * TimeUnit.MILLISECONDS.toNanos(1))//设置时间戳 .setPlaneData(0, RGBABuffer) .setColorSpace(colorSpace) .setPlaneStride(0, width * 4); //向 SDK 推送外部视频帧 if (mInstance != null) { mInstance.pushExternalVideoFrame(builder.build()); } }
以下是各个平台的相关 API 参考: