当你使用 RTC 实现实时音视频通信时,RTC 默认使用内部的渲染模块进行音视频渲染。然而在一些场景下,你可能会发现内部渲染模块无法满足需求,比如:
你已经集成了 3.25 及以上版本的 RTC SDK,实现了基本的音视频通话。
将 RTC SDK 在本地采集的视频图像或远端用户的视频图像通过自定义的渲染模块进行渲染。
说明:不同平台的实现步骤相同,但接口名称、参数名称可能略有差异。以下指南以 Android RTC SDK 为例,参考对应平台的 API 文档获取更多信息。

注意:由于硬件差异,通过
onFrame收到的视频帧可能会呈一定角度。你可以调用getRotation获取该角度,并在自定义渲染器中进行相应处理。
/**通过创建 ByteRTCVideoSinkDelegate 实例,添加自定义渲染逻辑,构建自定义渲染器。*/ @interface CustomVideoRenderView : UIView <ByteRTCVideoSinkDelegate> @end @implementation CustomVideoRenderView /** * 视频帧回调 * @param pixelBuffer 视频的 PixelBuffer * @param rotation 视频旋转角度,参看 ByteRTCVideoRotation * @param contentType 视频内部类型 参看 ByteRTCVideoContentType * @param extendedData 视频解码后获得的附加数据 */ - (void)renderPixelBuffer:(CVPixelBufferRef _Nonnull)pixelBuffer rotation:(ByteRTCVideoRotation)rotation contentType:(ByteRTCVideoContentType)contentType extendedData:(NSData * _Nullable)extendedData { // 在此进行自定义视频渲染 CFRetain(pixelBuffer); dispatch_async(dispatch_get_main_queue(), ^{ imageView.image = [UIImage imageWithCIImage:[CIImage imageWithCVImageBuffer:pixelBuffer]]; imageView.contentMode = UIViewContentModeScaleAspectFill; switch (rotation) { case VideoRotation_0: imageView.transform = CGAffineTransformMakeRotation(0); break; case VideoRotation_90: imageView.transform = CGAffineTransformMakeRotation(M_PI_2); break; case VideoRotation_180: imageView.transform = CGAffineTransformMakeRotation(M_PI); break; case VideoRotation_270: imageView.transform = CGAffineTransformMakeRotation(M_PI_2 + M_PI); break; default: break; } CFRelease(pixelBuffer); }); } @end
获取到视频流信息以后,将视频流绑定到自定义渲染器。通过传入参数 requiredFormat 指定视频数据的像素格式。
调用 setLocalVideoSink 为本地媒体流指定自定义渲染器。
在开始采集之后,视频帧将通过 onFrame 传递到自渲染模块。
[self.rtcEngine startVideoCapture]; CustomVideoRenderView *renderView = [[CustomVideoRenderView alloc] init]; ByteRTCLocalVideoSinkConfig *sinkConfig = [[ByteRTCLocalVideoSinkConfig alloc] init]; sinkConfig.requiredPixelFormat = ByteRTCVideoSinkPixelFormatNV12; [self.rtcEngine setLocalVideoSink:renderView withLocalRenderConfig:sinkConfig];
调用 setRemoteVideoSink 为远端媒体流指定自定义渲染器。
绑定自定义渲染器所需的媒体流参数可以从 onFirstRemoteVideoFrameDecoded 回调获取。
用户进入房间,并订阅了远端视频流,视频帧到达后将通过 onFrame 传递到自渲染模块。
- (void)rtcEngine:(ByteRTCEngine * _Nonnull)engine onFirstRemoteVideoFrameDecoded:(NSString * _Nonnull)streamId info:(ByteRTCStreamInfo* _Nonnull)info withFrameInfo:(ByteRTCVideoFrameInfo * _Nonnull)frameInfo { ByteRTCRemoteVideoSinkConfig *sinkConfig = [[ByteRTCRemoteVideoSinkConfig alloc] init]; sinkConfig.requiredPixelFormat = ByteRTCVideoSinkPixelFormatNV12; CustomVideoRenderView *renderView = [[CustomVideoRenderView alloc] init]; [self.rtcEngine setRemoteVideoSink:streamId withSink:renderView withRemoteRenderConfig:sinkConfig]; }
调用 setWTNRemoteVideoSink 为 WTN 流指定自定义渲染器。
用户订阅了 WTN 流,视频帧到达后,将通过 onFrame 传递到自渲染模块。
更多关于 WTN 流的信息详见发布和订阅 WTN 流。
/** * 设置 WTN 流视频渲染 * @param streamId WTN 流ID */ - (void)setPublicStreamCustomVideoRender:(NSString *)streamId { ByteRTCWTNStream *stream = [self.rtcEngine getWTNStream]; if (stream != nil) { CustomVideoRenderView *renderView = [[CustomVideoRenderView alloc] init]; ByteRTCRemoteVideoSinkConfig *sinkConfig = [[ByteRTCRemoteVideoSinkConfig alloc] init]; sinkConfig.requiredPixelFormat = ByteRTCVideoSinkPixelFormatNV12; [stream setWTNRemoteVideoSink:streamID withSink:renderView withConfig:sinkConfig]; } }
调用步骤2 中提到的相应接口,将 videoSink 设置为 null。解绑之后,视频帧将通过 SDK 内部渲染器进行渲染。
/** * 解绑本地自定义渲染 */ - (void)unBindLocalCustomVideoRender { ... [self.rtcEngine setLocalVideoSink:nil withLocalRenderConfig:sinkConfig]; } /** * 解绑远端视频自定义渲染 * @param streamKey 远端视频信息 */ - (void)unBindRemoteCustomVideoRender:(NSString *)streamId { ... [self.rtcEngine setRemoteVideoSink:streamId withSink:nil withRemoteRenderConfig:sinkConfig]; } /** * 解绑 WTN 流视频自定义渲染 * @param streamId WTN 流ID */ - (void)unBindPublicStreamCustomVideoRender:(NSString *)streamId { ByteRTCWTNStream *stream = [self.rtcEngine getWTNStream]; if (stream != nil) { ... [stream setWTNRemoteVideoSink:streamID withSink:nil withConfig:sinkConfig]; } }
注:自3.60版本起,新的API:
setWTNRemoteVideoSink方法替代了原来的setPublicStreamVideoSink方法。方法参数亦有变化。以iOS端举例,原来为setPublicStreamVideoSink:withSink:withPixelFormat:,现在为setWTNRemoteVideoSink:withSink:withConfig:。