1.1. 音视频功能
除了实时视频直播,存储卡录像播放以外,Camera SDK 还提供了一些额外的音视频能力。
1.1.1. 本地录制
当视频成功开始播放以后(可以是视频直播,也可以是录像回放),可以将当前正在播放的视频录制到手机中。
接口说明
录制视频并保存到手机系统相册
- (void)startRecord;
接口说明
录制视频保存到指定路径
- (void)startRecordWithFilePath:(NSString *)filePath;
参数说明
参数 | 说明 |
---|---|
filePath | 保存视频的文件路径 |
接口说明
停止录制,并保存文件
- (void)stopRecord;
接口说明
视频开始录制的代理回调
- (void)cameraDidStartRecord:(id<TuyaSmartCameraType>)camera;
接口说明
视频停止录制并成功保存视频文件的代理回调
- (void)cameraDidStopRecord:(id<TuyaSmartCameraType>)camera;
调用开始录制和停止录制均有可能会失败,失败后将通过代理方法
-(void)camera:didOccurredErrorAtStep: specificErrorCode:;
返回错误信息。
示例代码
ObjC
- (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<TuyaSmartCameraType>)camera {
// 已成功开启视频录制,更新 UI
}
- (void)cameraDidStopRecord:(id<TuyaSmartCameraType>)camera {
// 视频录制已停止,并且录制的视频成功保存
}
- (void)camera:(id<TuyaSmartCameraType>)camera didOccurredErrorAtStep:(TYCameraErrorCode)errStepCode specificErrorCode:(NSInteger)errorCode {
// 开启或者停止视频录制失败
if (errStepCode == TY_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: TuyaSmartCameraType!) {
// 已成功开启视频录制,更新 UI
}
func cameraDidStopRecord(_ camera: TuyaSmartCameraType!) {
// 视频录制已停止,并且录制的视频成功保存
}
func camera(_ camera: TuyaSmartCameraType!, didOccurredErrorAtStep errStepCode: TYCameraErrorCode, specificErrorCode errorCode: Int) {
// 开启或者停止视频录制失败
if errStepCode == TY_ERROR_RECORD_FAILED {
self.isRecording = false
}
}
在视频录制的过程中,请不要再切换视频清晰度,开关声音及对讲。
1.1.2. 视频截图
同样的,当视频成功开始播放以后(可以是视频直播,也可以是录像回放),可以对当前显示的视频图像截图,Camera SDK 提供三种截图的方式。下面两种方式是TuyaSmartCameraType
对象提供的方法:
接口说明
视频截图,图片保存在手机系统相册
- (UIImage *)snapShoot;
返回值
类型 | 说明 |
---|---|
UIImage | 视频截图的 UIImage 对象,返回 nil 表示图片保存失败 |
接口说明
视频截图,图片保存在指定文件路径
- (UIImage *)snapShootSavedAtPath:(NSString *)filePath thumbnilPath:(NSString *)thumbnilPath;
参数说明
参数 | 说明 |
---|---|
filePath | 保存图片的文件路径 |
thumbnilPath | 保存缩略图的文件路径,如果不需要,可以传入 nil |
返回值
类型 | 说明 |
---|---|
UIImage | 视频截图的 UIImage 对象,返回 nil 表示图片保存失败 |
接口说明
还有一种方式,是使用视频渲染视图TuyaSmartVideoType
的截图接口,此方法只返回一个 UIImage
对象,并不会自动保存图片。
- (UIImage *)screenshot;
返回值
类型 | 说明 |
---|---|
UIImage | 视频截图的 UIImage 对象,返回 nil 表示图片保存失败 |
示例代码
ObjC
- (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 崩溃。
1.1.3. 视频声音
当视频成功开始播放以后(可以是视频直播,也可以是录像回放),可以开启视频声音,默认声音是关闭状态。
接口说明
视频声音开关
- (void)enableMute:(BOOL)mute forPlayMode:(TuyaSmartCameraPlayMode)playMode;
参数说明
参数 | 说明 |
---|---|
mute | 是否静音,YES :关闭声音;NO :打开声音 |
playMode | 当前的播放模式 |
接口说明
视频声音开关结果代理回调
- (void)camera:(id<TuyaSmartCameraType>)camera didReceiveMuteState:(BOOL)isMute playMode:(TuyaSmartCameraPlayMode)playMode;
参数说明
参数 | 说明 |
---|---|
camera | 开关声音的 Camera 对象 |
isMute | 当前的静音状态 |
playMode | 当前的播放模式 |
播放模式切换后(视频直播和录像回放之间切换), Camera SDK 内部不会保留前一个播放模式的静音状态。即如果视频直播打开声音后,切换到了录像回放的模式,声音还是打开的,这时关闭声音,再次切换到视频直播模式,声音还是关闭的。所以切换模式后,需要同步一下期望的声音开关状态。
1.1.4. 实时对讲
在 p2p 连接成功后,可以开启与设备的实时通话功能,在开始对讲前,需要确保 App 已获得手机麦克风的访问权限。
接口说明
开启 App 到摄像机的声音通道
- (void)startTalk;
接口说明
关闭 App 到摄像机的声音通道
- (void)stopTalk;
接口说明
App 到摄像机的声音通道成功开启代理回调
- (void)cameraDidBeginTalk:(id<TuyaSmartCameraType>)camera;
接口说明
App 到摄像机的声音通道成功关闭的代理回调
- (void)cameraDidStopTalk:(id<TuyaSmartCameraType>)camera;
双向对讲
在实时视频直播时,打开视频声音,此时播放的声音即为摄像机实时采集的人声与环境声音,此时打开 App 到摄像机的声音通道,即可实现双向对讲功能。
部分摄像机可能没有扬声器或者拾音器,此类摄像机无法实现双向对讲。
单向对讲
单向对讲功能需要开发者来实现控制。在开启对讲的时候,关闭视频声音,关闭对讲后,再打开视频声音即可。
示例代码
下面以单向对讲为例来展示声音开关与实时对讲接口的用法。
ObjC
- (void)startTalk {
[self.camera startTalk];
// 如果不是静音状态,关闭声音
if (!self.isMuted) {
[self.camera enableMute:YES forPlayMode:TuyaSmartCameraPlayModePreview];
}
}
- (void)stopTalk {
[self.camera stopTalk];
}
- (void)cameraDidBeginTalk:(id<TuyaSmartCameraType>)camera {
// 对讲已成功开启
}
- (void)cameraDidStopTalk:(id<TuyaSmartCameraType>)camera {
// 对讲已停止
// 如果是静音状态,打开声音
if (self.isMuted) {
[self.camera enableMute:NO forPlayMode:TuyaSmartCameraPlayModePreview];
}
}
- (void)camera:(id<TuyaSmartCameraType>)camera didReceiveMuteState:(BOOL)isMute playMode:(TuyaSmartCameraPlayMode)playMode {
// 收到静音状态的变化,更新 UI
self.isMuted = isMute;
}
- (void)camera:(id<TuyaSmartCameraType>)camera didOccurredErrorAtStep:(TYCameraErrorCode)errStepCode specificErrorCode:(NSInteger)errorCode {
if (errStepCode == TY_ERROR_START_TALK_FAILED) {
// 开启对讲失败,重新打开声音
if (self.isMuted) {
[self.camera enableMute:NO forPlayMode:TuyaSmartCameraPlayModePreview];
}
}
else if (errStepCode == TY_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: TuyaSmartCameraType!) {
// 对讲已成功开启
}
func cameraDidStopTalk(_ camera: TuyaSmartCameraType!) {
// 对讲已停止
if self.isMuted {
self.camera.enableMute(false, for: .preview)
}
}
func camera(_ camera: TuyaSmartCameraType!, didReceiveMuteState isMute: Bool, playMode: TuyaSmartCameraPlayMode) {
self.isMuted = isMute
// 收到静音状态的变化,更新 UI
}
func camera(_ camera: TuyaSmartCameraType!, didOccurredErrorAtStep errStepCode: TYCameraErrorCode, specificErrorCode errorCode: Int) {
if errStepCode == TY_ERROR_START_TALK_FAILED {
// 开启对讲失败,重新打开声音
self.camera.enableMute(false, for: .preview)
}else if errStepCode == TY_ERROR_ENABLE_MUTE_FAILED {
// 设置静音状态失败
}
}
1.1.5. 清晰度切换
在实时视频直播时,可以切换清晰度(少数摄像机只支持一种清晰度),目前只有高清和标清两种清晰度,且只有实时视频直播时才支持。存储卡视频录像在录制时只保存了一种清晰度的视频流。
接口说明
获取当前视频图像的清晰度,结果通过代理方法返回
- (void)getHD;
接口说明
切换视频清晰度,YES
是高清,NO
是标清
- (void)enableHD:(BOOL)hd;
参数说明
参数 | 说明 |
---|---|
hd | 是否高清,YES :高清;NO :标清 |
接口说明
视频清晰度状态变化代理回调
- (void)camera:(id<TuyaSmartCameraType>)camera didReceiveDefinitionState:(BOOL)isHd;
参数说明
参数 | 说明 |
---|---|
camera | 清晰度变化的 Camera 对象 |
isHd | 当前的清晰度状态,YES :高清,NO :标清 |
示例代码
ObjC
- (void)changeHD {
[self.camera enableHD:!self.HD];
}
// 视频分辨率改变的代理方法,实时视频直播或者录像回放刚开始时也会调用
- (void)camera:(id<TuyaSmartCameraType>)camera resolutionDidChangeWidth:(NSInteger)width height:(NSInteger)height {
// 获取当前的清晰度
[self.camera getHD];
}
// 清晰度状态代理方法
- (void)camera:(id<TuyaSmartCameraType>)camera didReceiveDefinitionState:(BOOL)isHd {
self.HD = isHd;
}
- (void)camera:(id<TuyaSmartCameraType>)camera didOccurredErrorAtStep:(TYCameraErrorCode)errStepCode specificErrorCode:(NSInteger)errorCode {
if (errStepCode == TY_ERROR_ENABLE_HD_FAILED) {
// 切换视频清晰度失败
}
}
Swift
func changeHD() {
self.camera.enableHD(true)
}
// 视频分辨率改变的代理方法,实时视频直播或者录像回放刚开始时也会调用
func camera(_ camera: TuyaSmartCameraType!, resolutionDidChangeWidth width: Int, height: Int) {
// 获取当前的清晰度
self.camera.getHD()
}
func camera(_ camera: TuyaSmartCameraType!, didReceiveDefinitionState isHd: Bool) {
self.isHD = isHd
}
func camera(_ camera: TuyaSmartCameraType!, didOccurredErrorAtStep errStepCode: TYCameraErrorCode, specificErrorCode errorCode: Int) {
if errStepCode == TY_ERROR_ENABLE_HD_FAILED {
// 切换视频清晰度失败
}
}
1.1.6. 裸流数据
Camera SDK 提供访问视频裸流数据的代理回调方法,此方法返回视频帧的 YUV 数据,颜色编码格式为 YUV 420sp,iOS 中,对应于 kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange
格式。
接口说明
视频帧裸流数据代理回调
- (void)camera:(id<TuyaSmartCameraType>)camera ty_didReceiveVideoFrame:(CMSampleBufferRef)sampleBuffer frameInfo:(TuyaSmartVideoFrameInfo)frameInfo;
参数说明
参数 | 说明 |
---|---|
camera | 接收到视频数据的 Camera 对象 |
sampleBuffer | 视频帧 YUV 数据 |
frameInfo | 视频帧信息 |
TuyaSmartVideoFrameInfo 结构体
字段 | 类型 | 描述 |
---|---|---|
nWidth | int | 视频图像宽度 |
nHeight | int | 视频图像高度 |
nFrameRate | int | 视频帧率 |
nTimeStamp | unsigned long long | 视频帧时间戳 |
nDuration | unsigned long long | 播放报警消息中视频附件时,视频的总长度,单位是毫秒 |
nProgress | unsigned long long | 播放报警消息中视频附件时,视频帧的时间点,单位是毫秒 |
如果你想要自己渲染视频图像,或者需要对视频图像做特殊处理,可以将TuyaSmartCameraType
对象的autoRender
属性设置为 NO
,然后实现此代理方法,此时 Camera SDK 将不会自动渲染视频图像。
可以将sampleBuffer
直接强转为CVPixelBufferRef
,如果你想要异步处理视频帧数据,请记得先 retain,否则此代理方法执行完成后,视频帧数据将会被释放,异步处理时会发生野指针异常。
示例代码
ObjC
- (void)camera:(id<TuyaSmartCameraType>)camera ty_didReceiveVideoFrame:(CMSampleBufferRef)sampleBuffer frameInfo:(TuyaSmartVideoFrameInfo)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: TuyaSmartCameraType!, ty_didReceiveVideoFrame sampleBuffer: CMSampleBuffer!, frameInfo: TuyaSmartVideoFrameInfo) {
// 处理并渲染视频数据
}