互动视频
  • iOS : Objective-C
  • Android
  • macOS
  • Windows
  • Linux
  • Web
  • 小程序
  • Electron
  • 概述
  • 限制说明
  • SDK 下载
  • 快速开始
  • 常用功能
  • 推拉流进阶
  • 视频进阶
  • 音频进阶
  • 其他功能
  • 废弃接口
  • API 文档
  • 常见错误码
  • 常见问题
  • AI教育
  • KTV 合唱
  • 视频直播
  • 视频通话
  • 游戏直播
  • 直播答题
  • 娃娃机
  • 文档中心
  • 互动视频
  • 视频进阶
  • 视频外部采集

视频外部采集

更新时间:2023-04-28 10:07

1 常用场景

当开发者业务中出现以下情况时,我们推荐使用 SDK 的外部采集功能:

  1. 普通摄像头的采集无法满足需求。例如,包含了大量的原有业务。
  2. 直播过程中,开发者需要使用摄像头完成的额外功能和 SDK 的默认逻辑有冲突,导致摄像头无法正常使用。例如,直播到一半,需要录制短视频。
  3. 直播非摄像头数据。例如需要将视频播放的数据推流出去。
  4. 开发者可以使用外部采集来做自定义美颜等视频预处理。

2 使用步骤

相关功能的 Demo 源码,请联系 ZEGO 技术支持获取。

特别说明

考虑到设备的独占问题,SDK 的视频外部采集采用的是面向对象的设计,帮助用户把原有采集代码封装成外部采集设备。

开发者通过实现 ZegoVideoCaptureFactoryZegoVideoCaptureDevice 协议,可以把外部采集的数据传给 SDK 进行编码推流:

  1. ZegoVideoCaptureFactory 是外部采集的入口,定义了创建、销毁 ZegoVideoCaptureDevice 的接口,向 SDK 提供管理 ZegoVideoCaptureDevice 生命周期的能力。需要调用 setVideoCaptureFactory 的地方必须实现该接口。
  2. ZegoVideoCaptureDevice 定义基本的组件能力,包括 allocateAndStartstopAndDeAllocatestartCapturestopCapturezego_supportBufferType,方便 SDK 在直播流程中进行交互。

请注意,SDK 会在适当的时机创建和销毁 ZegoVideoCaptureDevice ,开发者无需担心生命周期不一致的问题。

使用视频外部采集的简要使用步骤:

  • 1.实现外部采集设备
  • 2.实现外部采集工厂
  • 3.设置外部采集工厂
  • 4.初始化 SDK
  • 5.推流

外部采集的接口调用流程如下图所示:

/Pics/iOS/ZegoLiveRoom/ZegoLiveRoom-ExternalCapture/call_flow_iOS.png

2.1 外部采集工厂创建外部采集设备

在 SDK 回调 zego_create 时,创建并返回 ZegoVideoCaptureDevice 实例。在zego_destroy 回调销毁ZegoVideoCaptureDevice 实例。

下述代码,ZGDemoExternalVideoCaptureFactory.m自身实现了 ZegoVideoCaptureDevice ,所以zego_create 方法返回 self

ZGDemoExternalVideoCaptureFactory.m

#pragma mark - ZegoVideoCaptureFactory

- (nonnull id<ZegoVideoCaptureDevice>)zego_create:(nonnull NSString*)deviceId {
    return self;
}

- (void)zego_destroy:(nonnull id<ZegoVideoCaptureDevice>)device {
    [self destoryResource];
}

@end

请注意:

  1. 大部分情况下,ZegoVideoCaptureFactory 会缓存 ZegoVideoCaptureDevice 实例,开发者需避免创建新的实例,造成争抢独占设备(例如摄像头)。
  2. 开发者必须保证 ZegoVideoCaptureDevice 在采集工厂 zego_createzego_destroy 之间是可用的,请勿直接销毁对象。

2.2 外部采集设备实现

实现 ZegoVideoCaptureDevice 协议,协议的方法有:

zego-api-external-video-capture-oc.h

/** 视频外部采集设备接口 */
@protocol ZegoVideoCaptureDevice <NSObject, ZegoSupportsVideoCapture>

@required

/**
 初始化采集使用的资源(例如启动线程等)回调

 @param client SDK 实现回调的对象,一定要保存
 @discussion 第一次调用开始预览/推流/拉流时调用
 */
- (void)zego_allocateAndStart:(nonnull id<ZegoVideoCaptureClientDelegate>) client;

/**
 停止并且释放采集占用的资源

 @discussion 在此之后,不能再调用 client 对象的接口
 */
- (void)zego_stopAndDeAllocate;

/**
 启动采集,采集的数据通过 [client -onIncomingCapturedData:withPresentationTimeStamp:] 通知 SDK

 @return 0 表示成功,其他是错误
 @discussion 一定要实现,不要做丢帧逻辑,SDK内部已经包含了丢帧策略
 */
- (int)zego_startCapture;

/**
 停止采集

 @return 0 表示成功,其它是错误
 @discussion 一定要实现
 */
- (int)zego_stopCapture;


@optional
/**
 支持的 buffer 类型

 @return 支持的 buffer 类型
 @discussion 如果不实现,则为 ZegoVideoCaptureDeviceOutputBufferTypeCVPixelBuffer
 */
- (ZegoVideoCaptureDeviceOutputBufferType)zego_supportBufferType;

2.2.1 告知 SDK 当前采集数据的类型

由于 iOS 采集的多样性,SDK 支持多种外部采集数据格式,所以开发者需要告知 SDK 当前采集设备使用何种数据类型。目前 SDK 支持的类型有:

类型定义 类型说明
ZegoVideoCaptureDeviceOutputBufferTypeCVPixelBuffer CVImageBufferRef
ZegoVideoCaptureDeviceOutputBufferTypeGlTexture2D GLuint
ZegoVideoCaptureDeviceOutputBufferTypeEncodedFrame EncodedFrame,编码后的采集数据。同时使用音频外部采集与渲染时,需要在 VideoCodecConifg 里面将 is_external_clock 设置为 true,否则会出现音画不同步的问题。

SDK 默认为 ZegoVideoCaptureDeviceOutputBufferTypeCVPixelBuffer 。如果需要使用其他数据类型,需要实现 ZegoVideoCaptureDevice 的相应方法,然后在获取视频帧数据后调用 client 对应数据类型的接收方法。

/**
 支持的 buffer 类型
 如果不实现,则为 ZegoVideoCaptureDeviceOutputBufferTypeCVPixelBuffer
*/
- (ZegoVideoCaptureDeviceOutputBufferType)zego_supportBufferType {
    return ZegoVideoCaptureDeviceOutputBufferTypeCVPixelBuffer;
}

2.2.2 初始化资源

外部采集初始化会回调 zego_allocateAndStart:,初始化资源需要在此方法中实现。

开发者在 zego_allocateAndStart: 中获取到 client 对象,client 用于向 SDK 传入外部采集的数据。SDK 会在第一次预览 / 推流 / 拉流时回调 zego_allocateAndStart:

请注意,client 实例在 zego_stopAndDeAllocate 被调用前必须一直保存,否则后续步骤中无法向 SDK 传入外部采集视频。

- (void)zego_allocateAndStart:(nonnull id<ZegoVideoCaptureClientDelegate>)client {
    dispatch_async(_clientQueue, ^{
        self.client = client;
        [self.client setFillMode:ZegoVideoFillModeCrop];
    });
}

为保证 client 对象的线程安全,此处使用了 _clientQueue串行队列来同步操作client对象。

2.2.3 向 SDK 传入外部采集视频数据

外部采集设备启动后,开发者就可以使用 client-onIncomingCapturedData:withPresentationTimeStamp:方法向 SDK 传入外部采集视频数据。

在自定义的 ZGDemoExternalVideoCaptureFactory 类中封装了 -postCapturedData:withPresentationTimeStamp:方法。

- (void)postCapturedData:(CVImageBufferRef)image withPresentationTimeStamp:(CMTime)time {
    if (!image) return;
    CVBufferRetain(image);
    dispatch_async(_clientQueue, ^{
        if (self.isCapture) {
            [self.client onIncomingCapturedData:image withPresentationTimeStamp:time];
        }
        CVBufferRelease(image);
    });
}

为保证 client 对象的线程安全,此处也使用了 _clientQueue串行队列来同步操作client对象。

2.2.4 释放资源

当不再使用外部视频采集后,退出房间或 Uninit SDK 时,会回调 zego_stopAndDeAllocate,开发者可以在该回调中释放占用的资源。

ZGDemoExternalVideoCaptureFactory.m

- (void)zego_stopAndDeAllocate {
    [self destoryResource];
}


- (void)destoryResource {
    [self stopCapture];

    // 同步_clientQueue,在 client destroy 前停止 client 向SDK继续塞数据
    dispatch_sync(_clientQueue, ^{

    });
    [self.client destroy];
    self.client = nil;
}

1.为保证 client 对象的线程安全,此处也使用了 _clientQueue串行队列来同步操作client对象。并在停止采集任务后再清理 client 对象,保证 SDK 调用zego_stopAndDeAllocate后,没有残留的异步任务,否则会导致野指针 crash。 2.请注意,销毁 client需调用destroy 方法,否则会造成内存泄漏。

2.3 设置外部采集工厂

开发者需要使用外部采集功能时,请在初始化 SDK 前设置外部采集工厂对象。

zego-api-external-video-capture-oc.h

@interface ZegoExternalVideoCapture : NSObject

+ (void)setVideoCaptureFactory:(nullable id<ZegoVideoCaptureFactory>)factory channelIndex:(ZegoAPIPublishChannelIndex)idx;

@end

请注意

  1. 调用 setVideoCaptureFactory 接口时,请区分 SDK 版本:
    • 2021-03-09 及之后的版本,在任何时机调用本接口都可直接使用。
    • 2020-05-122021-03-09 之间的版本,必须在“引擎启动之前”调用本接口。
    • 2020-05-12 之前版本必须在 “InitSDK” 之前调用,且需要使用外部采集功能时,该工厂对象不能为空。
  2. 如果不想再使用视频外部采集,可以在收到onAVEngineStop通知引擎关闭时,调用本接口setVideoCaptureFactory设置为 nil,否则下次引擎启动后(2020-05-12 及之后版本)或者 Init SDK 后(2020-05-12 之前版本)仍然还会使用视频外部采集

引擎启动的时机有:1、未登录房间启动预览功能;2、未登录房间使用媒体播放器;3、未登录房间使用音效播放器。 引擎关闭的时机有:1、退出房间;2、未登录房间并且预览、媒体播放器和引擎播放器都停止工作。

3 FAQ

Q1:如何访问 CVPixelBufferRef 持有的图像内存?

  答:请参考 ZegoLiveRoomApicopyPixelBufferFrom:to: 方法,然后对照苹果官方头文件。

Q2:如何使用 ZegoVideoCaptureDeviceOutputBufferTypeGlTexture2D 方式传递采集数据?

  答:选择 ZegoVideoCaptureDeviceOutputBufferTypeGlTexture2D 方式时,开发者实现 zego_supportBufferType 返回 ZegoVideoCaptureDeviceOutputBufferTypeGlTexture2D , 然后调用 clientonIncomingCapturedData:width:height:withPresentationTimeStamp: 传递数据。

Q3:如何使用 ZegoVideoCaptureDeviceOutputBufferTypeEncodedFrame 方式传递编码数据?

  答:选择 ZegoVideoCaptureDeviceOutputBufferTypeEncodedFrame 方式时,开发者实现 zego_supportBufferType 返回 ZegoVideoCaptureDeviceOutputBufferTypeEncodedFrame , 可以调用 clientonEncodedFrame:config:height:bKeyframe:withPresentationTimeStamp 传递数据。目前只支持H.264码流,关键帧间隔推荐2秒。请注意,每个IDR帧都必须携带SPS和PPS,放在最前面。

Q4:ZegoSupportsVideoCapture 的方法需要实现么?

  答:对于 ZegoSupportsVideoCapture 所包含的方法,不要求开发者实现,仅仅只是为了方便开发者在自己的采集实现和 SDK 默认的采集实现间切换,避免业务层写两套逻辑代码。

  每个方法都有对应的 SDK 接口,调用 SDK 接口时,会透传调用对应的方法。比如调用 SDK 的 startPreview 时,会透传调用 ZegoVideoCaptureDevicestartPreview 方法。

Q5:ZegoVideoCaptureFactory 的子类什么时候释放?

  答:我们推荐把工厂的实例保存为单例,仅作为 SDK 管理外部采集设备生命周期的通道,开发者可以为工厂子类添加 setter 和 getter,一起管理采集类的生命周期。

Q6:使用外部采集,本地预览的画面正常,推出去观众端看到的画面变形了?

  答:外部采集进来的图像比例和 SDK 默认设置的分辨率的比例不一致(比如外部采集进来的是 4:3 ,SDK 默认推流分辨率 360*640 是 16:9)。解决方案:

  1. 开发者将外部采集的视频分辨率比例修改为 16:9
  2. 开发者调用 setAvConfig ,将 SDK 的推流分辨率自定义为 4:3(比如480*640)

Q7:开启外部采集后,如何使用 SDK 的预览功能?

  答:开启外部采集后,默认情况下,外部采集的数据,需要用户自己渲染。如果想让 SDK 支持在开启外部视频采集的同时也能预览,需在初始化 SDK 前通过 [ZegoLiveApi setConfig:@”vcap_external_support_preview=true“] 开启,然后正常调用 setPreviewViewstartPreview 接口即可。

Q8:开启外部采集后,外部采集的帧率和拉流播放帧率不一致?

  答:通过设置SDK的帧率 setVideoFPS 和外部采集调用 OnIncomingCapturedData 的频率一致。

Q9:SDK 接收视频帧数据方法内部对传入的数据是同步处理还是异步处理?

  答:SDK 接收视频帧数据后,会先同步拷贝数据,然后再异步执行编码等操作,所以在将数据传入 SDK 后即可立即释放。

本篇目录