视频直播

更新时间:2024-06-17 07:52:42下载pdf

涂鸦 IPC SDK 提供智能摄像机的实时视频播放、设备存储卡录像播放、对当前正在播放的视频截图、录制视频,与摄像机实时通话等基础能力。此外,还提供视频帧解码后的 YUV 数据,您可以对视频裸流数据进行二次开发。

播放流程

在创建 ThingSmartCameraType 实例对象后,就可以开始播放实时视频了。视频数据的传输和命令交互基于 P2P 通道实现。整体流程如下图所示:

视频直播

连接 P2P 通道

在开始播放视频之前,您需要先连接 P2P 通道。P2P 的连接状态需要您自行维护,IPC SDK 会负责下发命令和接收摄像机响应结果。

接口说明

开始连接 P2P 通道,参数可以指定优先选择的连接模式,通过局域网连接或者通过外网连接。如果指定局域网连接优先,但是 App 和设备没有在同一个局域网内建立 TCP 连接,或者设备不支持局域网连接优先,IPC SDK 会自动使用外网连接模式。

- (void)connectWithMode:(ThingSmartCameraConnectMode)mode;

ThingSmartCameraType 实例对象相关的方法要保证在同一个线程调用,否则会出现异常。

参数说明

参数 说明
mode 优先使用的连接模式

ThingSmartCameraConnectMode

枚举值 说明
ThingSmartCameraConnectAuto 自动选择
ThingSmartCameraConnectFromInternet 外网连接优先
ThingSmartCameraConnectFromLocal 局域网连接优先

接口说明

断开 P2P 通道

- (void)disConnect;

代理回调

  • SDK 初始化失败:

    - (void)cameraInitFailed:(ThingSmartCameraErrorCode)errorCode;
    
  • P2P 通道成功连接:

    - (void)cameraDidConnected:(id<ThingSmartCameraType>)camera;
    
  • P2P 通道已断开,被动断开时(如网络环境较差,或者设备主动断开连接)才会调用,具体原因请参考 错误码

    - (void)cameraDisconnected:(id<ThingSmartCameraType>)camera specificErrorCode:(NSInteger)errorCode
    

播放实时视频

P2P 通道连接成功以后,就可以开始播放实时视频了。

接口说明

  • 开始播放实时视频,并指定清晰度:

    - (void)startPreviewWithDefinition:(ThingSmartCameraDefinition)definition;
    
  • 停止播放实时视频:

    - (void)stopPreview;
    
  • 获取视频渲染视图,推荐自定义:

    - (UIView<ThingSmartVideoViewType> *)videoView;
    
  • 获取本地视频渲染视图,推荐自定义:

    - (UIView<ThingSmartVideoViewType> *)localVideoView;
    
  • 绑定自定义视频渲染视图:

    - (void)registerVideoRenderView:(UIView<ThingSmartVideoViewType> *)videoView;
    
  • 解绑自定义视频渲染视图:

    - (void)uninstallVideoRenderView:(UIView<ThingSmartVideoViewType> *)videoView;
    
  • 绑定自定义本地视频渲染视图:

    - (void)bindLocalVideoView:(UIView<ThingSmartVideoViewType> *)videoView;
    
  • 解绑自定义本地视频渲染视图:

    - (void)unbindLocalVideoView:(UIView<ThingSmartVideoViewType> *)videoView;
    

以上两对绑定和解绑视频渲染视图必须成对调用,否则会出现功能异常。

代理回调

  • 视频直播已经成功开始播放:

    - (void)cameraDidBeginPreview:(id<ThingSmartCameraType>)camera;
    
  • 视频直播已经成功停止播放:

    - (void)cameraDidStopPreview:(id<ThingSmartCameraType>)camera;
    

视频渲染

视频成功播放后,IPC SDK 收到视频流将会自动渲染。您可以通过 camera 对象的 - (UIView<ThingSmartVideoViewType> *)videoView 方法获取渲染视图,将其添加到屏幕上,并设置布局属性。

协议说明

协议名 说明
ThingSmartVideoViewType 视频渲染器协议,根据摄像机实现方案不同,视频渲染的具体实现也有不同。

接口说明

  • 图像缩放属性:

    • 默认是 NO,如果视图的宽高比和视频图像的宽高比不一样,则会在图像的上下或者左右两侧留有黑边。
    • 设置为 YES,图像会拉伸铺满整个视图,可能会造成图像变形。

    IPC SDK 暂不提供全屏播放的能力。将 scaleToFill 属性设置为 YES 进行全屏模式时,横竖屏的旋转和布局的变化等请您自行维护。

    @property (nonatomic, assign) BOOL scaleToFill;
    
  • 清除当前的图像和缓存的视频帧:

    - (void)thing_clear;
    
  • 对当前渲染的图像截图:

    - (UIImage *)screenshot;
    

ThingSmartCameraType 对象提供了一个 autoRender 属性,默认是 YES,表示 IPC SDK 会自动渲染视频图像。如果您不希望自动渲染视频,可将此属性设置为 NO,然后可以从代理方法中获取到每一帧视频的 YUV 数据,并自主开发视频渲染,详细的接口在 裸流数据 章节中介绍。

错误回调

摄像机操作失败的所有错误反馈都将通过代理方法回调。

接口说明

- (void)camera:(id<ThingSmartCameraType>)camera didOccurredErrorAtStep:(ThingCameraErrorCode)errStepCode specificErrorCode:(NSInteger)errorCode;

下面方法新增扩展错误信息,可以获取细化错误码,优先回调此方法。

- (void)camera:(id<ThingSmartCameraType>)camera didOccurredErrorAtStep:(ThingCameraErrorCode)errStepCode specificErrorCode:(NSInteger)errorCode extErrorCodeInfo:(id<ThingSmartCameraExtErrorCodeInfo>)extErrorCodeInfo;

参数说明

参数 说明
camera 发生错误的摄像机对象。
errStepCode 发生错误的操作。
errorCode 错误码,表示失败的原因,详情请参考 错误码 章节。

ThingCameraErrorCode 枚举

枚举值 说明
Thing_ERROR_NONE
Thing_ERROR_CONNECT_FAILED P2P 连接失败
Thing_ERROR_START_PREVIEW_FAILED 实时视频播放失败
Thing_ERROR_START_PLAYBACK_FAILED 存储卡视频播放失败
Thing_ERROR_PAUSE_PLAYBACK_FAILED 暂停存储卡视频播放失败
Thing_ERROR_RESUME_PLAYBACK_FAILED 恢复存储卡视频播放失败
Thing_ERROR_ENABLE_MUTE_FAILED 视频声音开关失败
Thing_ERROR_START_TALK_FAILED 开启对讲失败
Thing_ERROR_RECORD_FAILED 视频录制失败
Thing_ERROR_ENABLE_HD_FAILED 设置视频清晰度失败
Thing_ERROR_GET_HD_FAILED 获取视频清晰度失败
Thing_ERROR_QUERY_RECORD_DAY_FAILED 存储卡视频回放日期查询失败
Thing_ERROR_QUERY_TIMESLICE_FAILED 存储卡视频片段查询失败

示例代码

Objective-C:

#define kThingSmartIPCConfigAPI @"thing.m.ipc.config.get"
#define kThingSmartIPCConfigAPIVersion @"2.0"

- (void)startStream {
    if (self.connected) {
        [self.camera startPreview];
        return;
    }
    id p2pType = [self.deviceModel.skills objectForKey:@"p2pType"];
    self.camera = [ThingSmartCameraFactory cameraWithP2PType:p2pType deviceId:self.deviceModel.devId delegate:self];
    [self.camera connectWithMode:ThingSmartCameraConnectAuto];
}

#pragma mark - ThingSmartCameraDelegate

- (void)cameraDidConnected:(id<ThingSmartCameraType>)camera {
    self.connected = YES;
    // 需要 P2P 连接成功后再开始预览
        [camera startPreview];
}

- (void)cameraDisconnected:(id<ThingSmartCameraType>)camera specificErrorCode:(NSInteger)errorCode {
    // P2P 连接被动断开,一般为网络波动导致
    self.connected = NO;
    self.previewing = NO;
}

- (void)cameraDidBeginPreview:(id<ThingSmartCameraType>)camera {
        // 实时视频开始播放
    self.previewing = YES;
    // 将视频渲染视图添加到屏幕上
        [self.view addSubview:camera.videoView];
}

- (void)cameraDidStopPreview:(id<ThingSmartCameraType>)camera {
        // 实时视频停止播放
    self.previewing = NO;
}

// 错误回调
- (void)camera:(id<ThingSmartCameraType>)camera didOccurredErrorAtStep:(ThingCameraErrorCode)errStepCode specificErrorCode:(NSInteger)errorCode extErrorCodeInfo:(id<ThingSmartCameraExtErrorCodeInfo>)extErrorCodeInfo {
        if (errStepCode == Thing_ERROR_CONNECT_FAILED) {
        // P2P 连接失败
        self.connected = NO;
    }
    else if (errStepCode == Thing_ERROR_START_PREVIEW_FAILED) {
        // 实时视频播放失败
        self.previewing = NO;
    }
}

Swift:

func startStream() {
    if self.isConnected {
        self.camera.startPreview()
        return
    }
    let p2pType = self.deviceModel.skills["p2pType"]!
    self.camera = ThingSmartCameraFactory.camera(withP2PType: p2pType, deviceId: self.deviceModel.devId, delegate: self)
    self.camera.connect(withMode:ThingSmartCameraConnectAuto)
}

func cameraDidConnected(_ camera: ThingSmartCameraType!) {
    self.isConnected = true
    // 需要 P2P 连接成功后再开始预览
    camera.startPreview()
}

func cameraDisconnected(_ camera: ThingSmartCameraType!, specificErrorCode: Int) {
    // P2P 连接被动断开,一般为网络波动导致
    self.isConnected = false
    self.isPreviewing = false
}

func cameraDidBeginPreview(_ camera: ThingSmartCameraType!) {
    // 实时视频开始播放
    self.isPreviewing = true;
    // 将视频渲染视图添加到屏幕上
    self.view.addSubview(camera.videoView())
}

func cameraDidStopPreview(_ camera: ThingSmartCameraType!) {
    // 实时视频停止播放
    self.isPreviewing = false
}

func camera(_ camera: ThingSmartCameraType!, didOccurredErrorAtStep errStepCode: ThingCameraErrorCode, specificErrorCode errorCode: Int, extErrorCodeInfo: ThingSmartCameraExtErrorCodeInfo!) {
    if errStepCode == Thing_ERROR_CONNECT_FAILED {
        // P2P 连接失败
        self.isConnected = false
    }else if errStepCode == Thing_ERROR_START_PREVIEW_FAILED {
        // 实时视频播放失败
        self.isPreviewing = false
    }
}

App 进入后台的时候,需要停止视频播放。因为视频数据使用硬件解码 OpenGL 渲染,在后台的时候,继续播放,可能会造成 App 崩溃。另外,涂鸦摄像机一般最多支持同时连接 5 路 P2P 通道,即支持 5 个手机同时连接。因此建议 App 在后台停留一段时间后,主动断开 P2P 连接,以释放资源。