音视频功能

更新时间:2023-05-25 06:23:52

除了实时视频直播,存储卡录像播放以外,IPC SDK 还提供了一些额外的音视频能力。

本地录制

无论是视频直播,还是录像回放,当视频成功开始播放以后,用户都可以将当前正在播放的视频录制到手机中。

接口说明

录制视频并保存到手机系统相册。

- (void)startRecord;

接口说明

录制视频保存到指定路径。

- (void)startRecordWithFilePath:(NSString *)filePath;

参数说明

参数 说明
filePath 保存视频的文件路径,视频保存为 MP4 文件,文件路径需要有 .mp4 后缀

接口说明

停止录制,并保存文件。

- (void)stopRecord;

接口说明

视频开始录制的代理回调。

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

接口说明

视频停止录制并成功保存视频文件的代理回调。

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

调用开始录制和停止录制均有可能会失败,失败后将通过代理方法 -(void)camera:didOccurredErrorAtStep: specificErrorCode:; 返回错误信息。

示例代码

Objective C:

- (void)startRecord {
    if (self.isRecording) {
        return;
    }
    // 在视频播放中才能开启录制
    if (self.previewing || self.playbacking) {
        [self.camera startRecord];
        self.recording = YES;
    }
}

- (void)stopRecord {
    if (self.isRecording) {
        [self.camera stopRecord];
        self.recording = NO;
    }
}

- (void)cameraDidStartRecord:(id<ThingSmartCameraType>)camera {
        // 已成功开启视频录制,更新 UI
}

- (void)cameraDidStopRecord:(id<ThingSmartCameraType>)camera {
        // 视频录制已停止,并且录制的视频成功保存
}

- (void)camera:(id<ThingSmartCameraType>)camera didOccurredErrorAtStep:(TYCameraErrorCode)errStepCode specificErrorCode:(NSInteger)errorCode {
    // 开启或者停止视频录制失败
    if (errStepCode == Thing_ERROR_RECORD_FAILED) {
        self.recording = NO;
    }
}

Swift:

func startRecord() {
    if self.isRecording {
        return
    }
    guard self.isPreviewing || self.isPlaybacking else {
        return;
    }
    self.camera.startRecord()
    self.isRecording = true
}

func stopRecord() {
    guard self.isRecording else {
        return
    }
    self.camera.stopRecord()
}

func cameraDidStartRecord(_ camera: ThingSmartCameraType!) {
    // 已成功开启视频录制,更新 UI
}

func cameraDidStopRecord(_ camera: ThingSmartCameraType!) {
    // 视频录制已停止,并且录制的视频成功保存
}

func camera(_ camera: ThingSmartCameraType!, didOccurredErrorAtStep errStepCode: ThingCameraErrorCode, specificErrorCode errorCode: Int) {
    // 开启或者停止视频录制失败
    if errStepCode == Thing_ERROR_RECORD_FAILED {
        self.isRecording = false
    }
}
  • 在视频录制的过程中,请不要再切换视频清晰度,开关声音及对讲。否则,可能会出现录制失败。建议在录制视频时,将切换视频清晰度、开关声音、对讲等设置为不可操作状态。
  • 由于视频播放卡顿、从开始录制时的下一个关键帧保存视频等情况的存在,实际录制保存的视频时长,可能比录制时间少。因此,录制时间仅做参考。

视频截图

同样的,无论是视频直播,还是录像回放,当视频成功开始播放以后,用户可以对当前显示的视频图像截图。IPC SDK 提供三种截图的方式,下面两种方式是 ThingSmartCameraType 对象提供的方法:

接口说明

视频截图,图片保存在手机系统相册。

- (UIImage *)snapShoot;

返回值

类型 说明
UIImage 视频截图的 UIImage 对象,返回 nil 表示图片保存失败

接口说明

视频截图,图片保存在指定文件路径。P2P 1.0 设备不支持此接口。

- (UIImage *)snapShootSavedAtPath:(NSString *)filePath thumbnilPath:(NSString *)thumbnilPath;

参数说明

参数 说明
filePath 保存图片的文件路径
thumbnilPath 保存缩略图的文件路径,如果不需要,可以传入 nil

返回值

类型 说明
UIImage 视频截图的 UIImage 对象,返回 nil 表示图片保存失败

接口说明

还有一种方式,是使用视频渲染视图 ThingSmartVideoType 的截图接口,此方法只返回一个 UIImage 对象,并不会自动保存图片。

- (UIImage *)screenshot;

返回值

类型 说明
UIImage 视频截图的 UIImage 对象,返回 nil 表示图片保存失败

示例代码

Objective C:

- (void)snapShoot {
    // 在播放视频时才可以截图
    if (self.previewing || self.playbacking) {
        if ([self.camera snapShoot]) {
            // 截图已成功保存到手机相册
        }
    }
}

Swift:

func snapShoot() {
    guard self.isPreviewing || self.isPlaybacking else {
        return;
    }
    if let _ = self.camera.snapShoot() {
        // 截图已成功保存到手机相册
    }
}

在使用上面的录制或者截图方法时,请确保 App 已获得手机相册的访问权限,否则会导致 App 崩溃。

视频声音

无论是视频直播,还是录像回放,当视频成功开始播放以后,用户都可以开启视频声音,默认声音是关闭状态。

接口说明

视频声音开关。

- (void)enableMute:(BOOL)mute forPlayMode:(ThingSmartCameraPlayMode)playMode;

参数说明

参数 说明
mute 是否静音:
  • YES:关闭声音。
  • NO:打开声音。
playMode 当前的播放模式

接口说明

视频声音开关结果代理回调。

- (void)camera:(id<ThingSmartCameraType>)camera didReceiveMuteState:(BOOL)isMute playMode:(ThingSmartCameraPlayMode)playMode;

参数说明

参数 说明
camera 开关声音的 Camera 对象
isMute 当前的静音状态
playMode 当前的播放模式

接口说明

扬声器和听筒模式的切换,返回值不为 0 表示切换失败。P2P 1.0 设备不支持此接口。

- (int)enableSpeaker:(BOOL)enabled;

参数说明

参数 说明
enabled
  • YES:切换成扬声器播放。
  • NO:切换成听筒播放。

接口说明

获取当前声音播放模式,返回 YES 表示扬声器播放,NO 为听筒播放,P2P 1.0 设备不支持此接口。

- (BOOL)speakerEnabled;

播放模式在视频直播和录像回放之间切换后,IPC SDK 内部不会保留前一个播放模式的静音状态。即如果:

  • 打开视频直播声音后,切换到了录像回放的模式,声音还是打开的。
  • 这时关闭声音,再次切换到视频直播模式,声音还是关闭的。

所以切换播放模式后,您需要同步一下期望的声音开关状态。

视频码率

视频出流成功后,可以获取实时的视频码率。

接口说明

获取实时的视频码率。

- (double)getVideoBitRateKBPS;

实时对讲

在 P2P 连接成功后,可以开启与设备的实时通话功能,在开始对讲前,需要确保 App 已获得手机麦克风的访问权限。

查询是否支持对讲

设备支持扬声器,代表支持单向对讲。设备同时支持扬声器和拾音器,代表视频有声音,即支持双向对讲。您可通过查询 设备能力,确认设备是否支持扬声器和拾音器。

双向对讲

在实时视频直播时,打开视频声音,播放的声音即为摄像机实时采集的人声与环境声音。此时,打开 App 到摄像机的声音通道,即可实现双向对讲功能。

部分摄像机可能没有扬声器或拾音器,此类摄像机无法实现双向对讲。

单向对讲

单向对讲功能需要开发者来实现控制。在开启对讲的时候,关闭视频声音,关闭对讲后,再打开视频声音即可。

接口说明

开启 App 到摄像机的声音通道。

- (void)startTalk;

接口说明

关闭 App 到摄像机的声音通道。

- (void)stopTalk;

接口说明

App 到摄像机的声音通道成功开启代理回调。

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

接口说明

App 到摄像机的声音通道成功关闭的代理回调。

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

示例代码

下文以单向对讲为例,展示声音开关与实时对讲接口的用法。

Objective C:

- (void)startTalk {
    [self.camera startTalk];
    // 如果不是静音状态,关闭声音
    if (!self.isMuted) {
        [self.camera enableMute:YES forPlayMode:ThingSmartCameraPlayModePreview];
    }
}

- (void)stopTalk {
    [self.camera stopTalk];
}

- (void)cameraDidBeginTalk:(id<ThingSmartCameraType>)camera {
        // 对讲已成功开启
}

- (void)cameraDidStopTalk:(id<ThingSmartCameraType>)camera {
        // 对讲已停止
        // 如果是静音状态,打开声音
    if (self.isMuted) {
        [self.camera enableMute:NO forPlayMode:ThingSmartCameraPlayModePreview];
    }
}

- (void)camera:(id<ThingSmartCameraType>)camera didReceiveMuteState:(BOOL)isMute playMode:(ThingSmartCameraPlayMode)playMode {
        // 收到静音状态的变化,更新 UI
        self.isMuted = isMute;
}

- (void)camera:(id<ThingSmartCameraType>)camera didOccurredErrorAtStep:(ThingCameraErrorCode)errStepCode specificErrorCode:(NSInteger)errorCode {
    if (errStepCode == Thing_ERROR_START_TALK_FAILED) {
            // 开启对讲失败,重新打开声音
                if (self.isMuted) {
                [self.camera enableMute:NO forPlayMode:ThingSmartCameraPlayModePreview];
            }
    }
    else if (errStepCode == Thing_ERROR_ENABLE_MUTE_FAILED) {
                // 设置静音状态失败
    }
}

Swift:

// 当前在实时视频播放状态
func startTalk() {
    self.camera.startTalk()
    guard self.isMuted else {
        self.camera.enableMute(true, for: .preview)
        return
    }
}

func stopTalk() {
    self.camera.stopTalk()
}

func cameraDidBeginTalk(_ camera: ThingSmartCameraType!) {
    // 对讲已成功开启
}

func cameraDidStopTalk(_ camera: ThingSmartCameraType!) {
    // 对讲已停止
    if self.isMuted {
        self.camera.enableMute(false, for: .preview)
    }
}

func camera(_ camera: ThingSmartCameraType!, didReceiveMuteState isMute: Bool, playMode: ThingSmartCameraPlayMode) {
    self.isMuted = isMute
    // 收到静音状态的变化,更新 UI
}

func camera(_ camera: ThingSmartCameraType!, didOccurredErrorAtStep errStepCode: ThingCameraErrorCode, specificErrorCode errorCode: Int) {
    if errStepCode == Thing_ERROR_START_TALK_FAILED {
        // 开启对讲失败,重新打开声音
        self.camera.enableMute(false, for: .preview)
    }else if errStepCode == Thing_ERROR_ENABLE_MUTE_FAILED {
        // 设置静音状态失败
    }
}

切换清晰度

在实时视频直播时,可以切换清晰度。目前只有高清和标清两种清晰度,且只有实时视频直播时才支持。少数摄像机只支持一种清晰度。存储卡视频录像在录制时,只保存了一种清晰度的视频流。

接口说明

获取当前视频图像的清晰度,结果通过代理方法返回。

- (void)getHD;

接口说明

切换视频清晰度,YES 是高清,NO 是标清。

- (void)enableHD:(BOOL)hd;

参数说明

参数 说明
hd 是否高清:
  • YES:高清。
  • NO:标清。

接口说明

视频清晰度状态变化代理回调。

- (void)camera:(id<ThingSmartCameraType>)camera didReceiveDefinitionState:(BOOL)isHd;

参数说明

参数 说明
camera 清晰度变化的 Camera 对象
isHd 当前的清晰度状态:
  • YES:高清。
  • NO:标清。

以上三个接口在 3.20.0 版本 SDK 中已废弃,但 P2P 1.0 设备可以继续使用。您可以使用以下三个接口替代,但注意 P2P 1.0 设备不支持这些接口。

接口说明

获取视频清晰度。

- (void)getDefinition;

接口说明

设置视频清晰度。

- (void)setDefinition:(ThingSmartCameraDefinition)definition;

接口说明

视频清晰度状态变化代理回调。

- (void)camera:(id<ThingSmartCameraType>)camera definitionChanged:(ThingSmartCameraDefinition)definition;

ThingSmartCameraDefinition 枚举

描述
ThingSmartCameraDefinitionProflow 省流量
ThingSmartCameraDefinitionStandard 标清
ThingSmartCameraDefinitionHigh 高清
ThingSmartCameraDefinitionSuper 超清
ThingSmartCameraDefinitionSSuper 超超清

不同的清晰度,需要设备端支持,目前普遍设备只支持标清和高清两种清晰度。

示例代码

Objective C:

- (void)changeHD {
        ThingSmartCameraDefinition definition = self.HD ? ThingSmartCameraDefinitionStandard : ThingSmartCameraDefinitionHigh;
        [self.camera setDefinition:definition];
}

// 视频分辨率改变的代理方法,实时视频直播或者录像回放刚开始时也会调用
- (void)camera:(id<ThingSmartCameraType>)camera resolutionDidChangeWidth:(NSInteger)width height:(NSInteger)height {
        // 获取当前的清晰度
        [self.camera getDefinition];
}

// 清晰度状态代理方法
- (void)camera:(id<ThingSmartCameraType>)camera definitionChanged:(ThingSmartCameraDefinition)definition {
    self.HD = definition >= ThingSmartCameraDefinitionHigh;
}

- (void)camera:(id<ThingSmartCameraType>)camera didOccurredErrorAtStep:(TYCameraErrorCode)errStepCode specificErrorCode:(NSInteger)errorCode {
    if (errStepCode == Thing_ERROR_ENABLE_HD_FAILED) {
                // 切换视频清晰度失败
    }
}

Swift:

func changeHD() {
    let definition = self.isHD ? ThingSmartCameraDefinition.standard : ThingSmartCameraDefinition.high
    self.camera.setDefinition(definition)
}

// 视频分辨率改变的代理方法,实时视频直播或者录像回放刚开始时也会调用
func camera(_ camera: ThingSmartCameraType!, resolutionDidChangeWidth width: Int, height: Int) {
    // 获取当前的清晰度
    self.camera.getDefinition()
}

func camera(_ camera: ThingSmartCameraType!, definitionChanged definition: ThingSmartCameraDefinition) {
        self.isHD = definition.rawValue >= ThingSmartCameraDefinition.high.rawValue
}

func camera(_ camera: ThingSmartCameraType!, didOccurredErrorAtStep errStepCode: ThingCameraErrorCode, specificErrorCode errorCode: Int) {
    if errStepCode == Thing_ERROR_ENABLE_HD_FAILED {
        // 切换视频清晰度失败
    }
}

裸流数据

IPC SDK 提供访问视频裸流数据的代理回调方法,此方法返回视频帧的 YUV 数据,颜色编码格式为 YUV 420sp。iOS 中,对应于 kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange 格式。

接口说明

视频帧裸流数据代理回调。

- (void)camera:(id<ThingSmartCameraType>)camera thing_didReceiveVideoFrame:(CMSampleBufferRef)sampleBuffer frameInfo:(ThingSmartVideoFrameInfo)frameInfo;

参数说明

参数 说明
camera 接收到视频数据的 Camera 对象
sampleBuffer 视频帧 YUV 数据
frameInfo 视频帧信息

ThingSmartVideoFrameInfo 结构体

字段 类型 描述
nWidth int 视频图像宽度
nHeight int 视频图像高度
nFrameRate int 视频帧率
nTimeStamp unsigned long long 视频帧时间戳
nDuration unsigned long long 播放报警消息中视频附件时,视频的总长度,单位是 毫秒
nProgress unsigned long long 播放报警消息中视频附件时,视频帧的时间点,单位是 毫秒

如果您想要自行渲染视频图像,或者需要对视频图像做特殊处理,可以将 ThingSmartCameraType 对象的 autoRender 属性设置为 NO,然后实现此代理方法。此时,IPC SDK 将不会自动渲染视频图像。

您可以将 sampleBuffer 强行转换为 CVPixelBufferRef,如果您想要异步处理视频帧数据,请记得先 retain。否则,此代理方法执行完成后,视频帧数据将会被释放,异步处理时会发生野指针异常。

示例代码

Objective C:

- (void)camera:(id<ThingSmartCameraType>)camera thing_didReceiveVideoFrame:(CMSampleBufferRef)sampleBuffer frameInfo:(ThingSmartVideoFrameInfo)frameInfo {
    CVPixelBufferRef pixelBuffer = (CVPixelBufferRef)sampleBuffer;
    // retain pixelbuffer,防止提前释放
    CVPixelBufferRetain(pixelBuffer);
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // 处理并渲染 pixelBuffer
        // ...
        // 最后,请务必释放
        CVPixelBufferRelease(pixelBuffer);
    });
}

Swift:

func camera(_ camera: ThingSmartCameraType!, thing_didReceiveVideoFrame sampleBuffer: CMSampleBuffer!, frameInfo: ThingSmartVideoFrameInfo) {
        // 处理并渲染视频数据
}

智能画框

开启智能画框功能后,在视频直播的过程中,如果设备检查到移动物体,会在对应的物体上画一个白色的矩形框。

首先,您需要开启设备的智能画框功能。开启后,设备会随着视频帧发送移动物体的坐标,通过 DP 点 “198” 开启设备端的智能画框功能。

if ([self.dpManager isSupportDP:@"198"]) {
    [self.dpManager setValue:@(YES) forDP:@"198" success:nil failure:nil];
}

在设备端智能画框功能开启的前提下,直播视频播放时,需要打开 IPC SDK 的智能画框功能。SDK 会根据设备发送的移动物体坐标,在视频图像上绘制矩形框。

接口说明

智能画框功能开关。

- (void)setOutLineEnable:(BOOL)enable;

参数说明

参数 说明
enable 是否开启智能画框

设备能力

ThingSmartCameraAbility类,可以解析设备的配置信息,从而获取设备的一些基础能力。

属性 说明
defaultDefinition 实时视频播放的默认清晰度
videoNum 设备支持的码流数,
  • 值为 1 表示设备只支持一种清晰度,通过defaultDefinition 属性获取,而且无法切换清晰度
  • 值为 2 表示支持标清和高清两种清晰度
isSupportSpeaker 设备是否支持扬声器,如果设备支持扬声器,则可以开启讲话
isSupportPickup 设备是否支持拾音器,如果设备支持拾音器,则 App 端查看视频流时可以开启声音
rowData P2P config 原始数据

接口说明

根据设备数据模型创建设备能力类对象,需要在连接 P2P 之后调用。第一次 P2P 连接后,本地沙盒中会缓存此数据。

+ (instancetype)cameraAbilityWithDeviceModel:(ThingSmartDeviceModel *)deviceModel;