自定义视频渲染

更新时间:2025-03-21 07:20:26

自定义音频播放是用户有一定的研发能力的情况,希望自己控制播放来实现某些需求,因此ARTC提供了相关的功能方便用户实现这些需求。

前提条件

ARTC内置了经过市场检验的视频渲染模块,因此一般情况下建议客户使用ARTC内置的视频渲染模块,如果有特殊需求,客户有自己完善的视频渲染模块或特殊需求,可以使用自己的视频渲染模块处理和回放视频。

技术原理

因为iOSAndroid端设备的视频渲染API存在差异,接下来我们分两部分介绍iOS端和Android端视频渲染的功能设计。

iOS端功能设计

远端视频渲染
image
本地视频渲染-Buffer
image
本地视频渲染-textureID
image

Android端功能设计

远端视频渲染
image
本地视频渲染-Buffer
image
本地视频渲染-textureID
image

iOS端实现方案

1.通过extra字段开启外部渲染

通过extra字段开启外部视频播放功能,开启该功能之后,RTC会启用虚拟render来渲染。

NSString *extras = @"{\"user_specified_use_external_video_render\":\"TRUE\"}";

/* 如果需要回调 cvPixelBuffer 需要增加这个选项*/
NSString * extras = @"{\"user_specified_use_external_video_render\":\"TRUE\",\"user_specified_native_buffer_observer\":"TRUE"}";


_engine = [AliRtcEngine sharedInstance:nil extras:extras];

2.设置回调

cvPixelBuffer/I420:
[_engine registerVideoSampleObserver];

textureID:
[_engine registerLocalVideoTexture];

3.处理回调

I420/cvPixelBuffer

/*
* 在AliRtcEngine::registerVideoSampleObserver之后触发
*/

- (AliRtcVideoFormat)onGetVideoFormatPreference {
    return AliRtcVideoFormat_I420;
}

/**
 * @brief 订阅的本地采集视频数据回调
 * @param videoSource 视频流类型
 * @param videoSample 视频裸数据
 * @return
 * - YES: 需要写回SDK(只对I420和CVPixelBuffer(ios/mac)有效)
 * - NO: 不需要写回SDK
*/

- (BOOL)onCaptureVideoSample:(AliRtcVideoSource)videoSource videoSample:(AliRtcVideoDataSample *_Nonnull)videoSample {
  /*
   * do....
   */
   return FALSE ;
}

textureID

  • openGL context创建后回调

    /**
     * @brief OpenGL上下文创建回调
     * @param context OpenGL上下文
     * @note 该回调是在SDK内部OpenGL上下文创建的时候触发
     */
    - (void)onTextureCreate:(void *_Nullable)context {
        [[renderEngine_ shared] create:context];
    }
  • openGL 纹理变更回调

    /**
     * @brief OpenGL纹理更新回调
     * @param textureId OpenGL纹理ID
     * @param width OpenGL纹理宽
     * @param height OpenGL纹理高
     * @param videoSample 视频帧数据,详见 {@link AliRtcVideoDataSample}
     * @return OpenGL纹理ID
     * @note
     * - 该回调会在每一帧视频数据上传到OpenGL纹理之后触发,当外部注册了OpenGL纹理数据观测器,在该回调中可以对纹理进行处理,并返回处理后的纹理ID
     * - 注意该回调返回值必须为有效的纹理ID,如果不做任何处理必须返回参数textureId
     * 回调的TextureID是 AliRtcVideoFormat_Texture2D 格式
     */
    - (int)onTextureUpdate:(int)textureId width:(int)width height:(int)height videoSample:(AliRtcVideoDataSample *_Nonnull)videoSample {
        
        if ( [[renderEngine_ shared] enabled] == NO) {
            return textureId;
        }
        
        int texId = [[renderEngine_ shared] processTextureToTexture:textureId Width:width Height:height];
        
        if(texId<0) {
           texId = textureId;
        }
        return texId;
    }
  • openGL 上下文删除回调

    - (void)onTextureDestory
    {
        if (self.settingModel.chnnelType == ChannelTypePrimary) {
            [[renderEngine_ shared] destroy];
        }
        
    }

4.退出

/* I420/cvPixelBuffer */
unregisterVideoSampleObserver

/* textureID */
unregisterLocalVideoTexture

Android端实现方案

1.通过extra字段开启外部渲染

通过extra字段开启外部视频播放功能,开启该功能之后,RTC会启用虚拟render来渲染。

String extras = "{\"user_specified_use_external_video_render\":\"TRUE\"}";

/* 
   如果需要回调 textureID 需要增加这个选项,
   同时建议开启纹理硬件编码
   */
String extras = "{\"user_specified_use_external_video_render\":\"TRUE\",\"user_specified_camera_texture_capture\":"TRUE",\"user_specified_texture_encode\":"TRUE" }";

_engine = AliRtcEngine.getInstance(getApplicationContext(), extras);

2.设置回调

cvPixelBuffer/I420:
_engine.registerVideoSampleObserver();


textureID:
_engine.registerLocalVideoTextureObserver();

3.处理回调

I420/cvPixelBuffer

/**
 * @brief 订阅的本地采集视频数据回调
 * @param videoSource 视频流类型
 * @param videoSample 视频裸数据
 * @return
 * - YES: 需要写回SDK(只对I420和CVPixelBuffer(ios/mac)有效)
 * - NO: 不需要写回SDK
*/
public int onGetVideoAlignment(){
  return AliRtcVideoObserAlignment.AliRtcAlignmentDefault.getValue();
}

@Override
public boolean onLocalVideoSample(AliRtcEngine.AliRtcVideoSourceType sourceType, AliRtcEngine.AliRtcVideoSample videoSample) {
  boolean ret = false;
  /*
  * 处理本地采集的视频数据进行渲染
  */
  local_renderEngine.draw(videoSample);
    
  return ret;
}

@Override
public boolean onRemoteVideoSample(String userId, AliRtcEngine.AliRtcVideoSourceType sourceType, AliRtcEngine.AliRtcVideoSample videoSample) {
  /*
  * 处理远端数据进行渲染
  */
  remote_renderEngine.draw(userId, videoSample);
  
  return false;
}

textureID

  • openGL context创建后回调

    @Override
    public void onTextureCreate(long context) {
          context_ = context ;
          render.bind(context);
          Log.d(TAG, "texture context: "+context_+" create!") ;
    }
    
  • openGL 纹理变更回调

    /**
    @Override
    public int onTextureUpdate(int textureId, int width, int height, AliRtcEngine.AliRtcVideoSample videoSample) {
        /*
        *  进行 textureid处理
        */
        render.drawTexture(textureId);
         return textureId;
    }    
    
    
  • openGL 上下文删除回调

    @Override
    public void onTextureDestroy() {
         render.free(context_);
         Log.d(TAG, "texture context: "+context_+" destory!") ;
    }

4.退出

/* I420/cvPixelBuffer */
_engine.unregisterVideoSampleObserver();

/* textureID */
_engine.unRegisterLocalVideoTextureObserver();

  • 本页导读 (1)
  • 前提条件
  • 技术原理
  • iOS端功能设计
  • Android端功能设计
  • iOS端实现方案
  • 1.通过extra字段开启外部渲染
  • 2.设置回调
  • 3.处理回调
  • 4.退出
  • Android端实现方案
  • 1.通过extra字段开启外部渲染
  • 2.设置回调
  • 3.处理回调
  • 4.退出