云存储

更新时间:2023-09-19 03:00:53下载pdf

涂鸦智能为智能摄像机(IPC)提供云存储的服务,用户可以将 IPC 设备录制的视频上传到云端存储起来。

云存储流程

  • 判断设备是否支持云存储能力,支持则继续。

  • 判断设备是否开通云存储服务,根据服务状态继续判断:

    • 如果云存储服务未开通或者已经过期,并且云视频已经被全部删除,就需要先购买云存储服务。云存储服务过期后,已经上传的云视频还会保留一段时间,通常是 7 天。

    • 如果云存储服务在有效期内,先查询有云视频的日期,然后查询指定日期的相关数据,包括云存储事件、时间轴数据、鉴权信息等。之后,用户就可以选择一个云存储事件或者一个时间点开始播放云视频了。

      服务有效
      未开通或已过期
      开始
      获取云存储状态
      是否可用
      获取云存储相关数据
      播放指定云存储事件或视频片段
      销毁
      购买云存储

支持云存储

ThingSmartCloudManager 提供了云存储 API 集合,包括判断设备是否支持云存储能力。

接口说明

+ (BOOL)isSupportCloudStorage:(NSString *)devId;

参数说明

参数 说明
devId 设备 ID

开通云存储

云存储服务开通需要使用 云存储服务 UI 业务包,该组件提供了云存储开通的 H5 页面和订单展示功能。

参数说明

参数 说明
devId 设备 ID

云存储设置

购买过云存储服务后,智能摄像机会把录制的视频上传云端。用户可以通过 SDK 播放已经上传的云视频。云存储相关功能通过 ThingSmartCameraKit 中的 ThingSmartCloudManager 类操作。

类和协议

类名(协议名) 说明
ThingSmartCloudManager 云存储服务状态,视频数据维护和云视频播放
ThingSmartCloudManagerDelegate 云视频播放,视频帧数据回调代理

初始化云存储服务

接口说明

初始化 ThingSmartCloudManager 时,需要传入设备 ID。

云视频默认是静音开始播放的,如果您需要在播放时开启声音,可在初始化时,设置静音状态NO。云视频播放时,视频帧数据和帧头信息都将通过代理方法回调。

- (instancetype)initWithDeviceId:(NSString *)devId;

开启云存储事件图片加密

开启图片加密,设置为 YES,云存储事件中携带的图片将加密。此时,您需要使用 ThingEncryptImage 组件显示图片。

接口说明

@property (nonatomic, assign) BOOL enableEncryptedImage;

云视频数据代理回调

云存储代理接口为 ThingSmartCloudManagerDelegate,只有一个代理方法,会返回每一帧视频的 YUV 数据和帧信息。如果您想要自行渲染视频,可以将 ThingSmartCloudManagerautoRender 属性设置为 NO(默认为YES),并在代理方法中查询视频帧的 YUV 数据加以渲染。

接口说明

- (void)cloudManager:(ThingSmartCloudManager *)cloudManager didReceivedFrame:(CMSampleBufferRef)frameBuffer videoFrameInfo:(ThingSmartVideoFrameInfo)frameInfo;

参数说明

参数 说明
cloudManager 播放云视频的 ThingSmartCloudManager 对象
frameBuffer 视频帧 YUV 数据
frameInfo 视频帧信息

加载云存储数据

在使用云视频播放功能前,还需要先加载云存储的相关数据。云存储数据接口会返回云存储服务当前的状态,以及加载对应的加密秘钥,鉴权信息等。

接口说明

- (void)loadCloudData:(void(^)(ThingSmartCloudState state))complete

参数说明

参数 说明
complete 加载完成回调,返回当前的云存储服务状态

ThingSmartCloudState 枚举

枚举值 说明
ThingSmartCloudStateNoService 用户未开通云存储服务
ThingSmartCloudStateNoData 用户已开通云存储服务,但是没有回放视频
ThingSmartCloudStateValidData 用户已开通云存储服务,且有回放视频
ThingSmartCloudStateExpiredNoData 用户的云存储服务已过期,且无回放视频
ThingSmartCloudStateExpiredData 用户的云存储服务已过期,但是还有可以查看的回放视频
ThingSmartCloudStateLoadFailed 云存储服务状态加载失败

云存储服务过期后,用户已上传的云视频还会预留一段时间,通常是 7 天,具体时长需要参考云存储服务协议。如果在预留期间内没有续费,服务到期后,用户的云视频将会被删除。

查询云视频录制日期

在加载云存储数据成功返回后,如果云端有云视频回放数据,可以通过 cloudDays 属性查询有视频回放数据的日期。

接口说明

@property (nonatomic, strong, readonly) NSArray<ThingSmartCloudDayModel *> *cloudDays;

ThingSmartCloudDayModel 模型

字段 类型 说明
sumDuration NSInteger 当天云视频总长度
uploadDay NSString 日期,格式为 yyyy-MM-dd
startTime NSInteger 当天 00:00:00 的 Unix 时间戳
endTime NSInteger 当天 23:59:59 的 Unix 时间戳

查询云视频片段列表

在用户播放云视频前,您需要查询当天的云存储视频片段时间数据。

接口说明

- (void)timeLineWithCloudDay:(ThingSmartCloudDayModel *)cloudDay
                     success:(void(^)(NSArray<ThingSmartCloudTimePieceModel *> * timePieces))success
                     failure:(void(^)(NSError * error))failure;

参数说明

参数 说明
cloudDay 云视频录制日期模型
success 成功回调,返回当天所有视频片段时间数据模型的数组
failure 失败回调,error 表示错误信息

ThingSmartCloudTimePieceModel 数据模型

字段 类型 说明
startTime NSInteger 视频开始时间 Unix 时间戳
startDate NSDate 视频开始时间
endTime NSInteger 视频结束时间 Unix 时间戳
endDate NSDate 视频结束时间
aiDetectList NSArray<ThingSmartAICloudTimePieceModel *> * AI 识别到的物种 对应的片段

ThingSmartAICloudTimePieceModel 数据模型

ThingSmartAICloudTimePieceModel 继承自 ThingSmartCloudTimePieceModel

字段 类型 说明
startTime NSInteger 视频开始时间 Unix 时间戳
startDate NSDate 视频开始时间
endTime NSInteger 视频结束时间 Unix 时间戳
endDate NSDate 视频结束时间
aiCode NSString AI 事件片段 ID

查询普通云存储事件

开启云存储服务后,设备通过侦测报警上报的事件,云存储事件会和云视频关联起来。正常情况下,每一个云存储事件都会有一段对应的云视频。

云存储的 报警事件侦测报警消息 略有不同。两者的触发原因可能是一样的,但是侦测报警消息的删除不会影响到云存储事件。注意,并非所有的侦测报警消息都会触发云视频录制,例如电量警告等。

接口说明

- (void)timeEventsWithCloudDay:(ThingSmartCloudDayModel *)cloudDay
                        offset:(int)offset
                         limit:(int)limit
                       success:(void(^)(NSArray<ThingSmartCloudTimeEventModel *> * timeEvents))success
                       failure:(void(^)(NSError * error))failure;

参数说明

参数 说明
cloudDay 云视频录像日期模型
offset 偏移量,0 标示从第一个事件开始
limit 数量限制,-1 标示查询所有事件
success 成功回调,返回事件模型的数组
failure 失败回调,error 表示错误信息

ThingSmartCloudTimeEventModel 数据模型

字段 类型 说明
describe NSString 事件描述
startTime NSInteger 事件开始时间 Unix 时间戳
endTime NSInteger 事件结束时间 Unix 时间戳
snapshotUrl NSString 事件发生时,设备抓拍的实时图片

云存储事件中携带的实时截图是经过加密的,您需要通过加密图片组件 ThingEncryptImage 展示,详情请参考 加密图片

查询设备 AI 云存储设置信息

设备是否开启 AI 检测能力。

接口说明

- (void)queryAIDetectConfigSuccess:(void (^)(ThingCameraAIDetectConfigModel *model))success
                           failure:(void (^)(NSError *error))failure;

ThingCameraAIDetectConfigModel 数据模型

字段 类型 说明
isAiDevice BOOL 设备是否有 AI 检测能力
switchState NSInteger 设备 AI 检测能力是否开启
  • 1 表示开启
  • 0 表示关闭
aiItemList NSArray 支持检测的 AI 物种数据信息

ThingCameraAIDetectEventModel 数据模型

字段 类型 说明
aiCode NSString AI 标识符
aiCodeIcon NSString AI 模型图标
aiCodeDesc NSString AI 描述信息
configState NSInteger 当前模型是否开启
  • 1 表示开启
  • 0 表示关闭
orderValue NSInteger 当前模型排序值

示例代码

 [self.cloudManager queryAIDetectConfigSuccess:^(ThingCameraAIDetectConfigModel *model) {
            //
} failure:^(NSError *error) {
            //
 }];

更新 AI 检测开关状态

开启、关闭设备 AI 检测功能

接口说明

- (void)enableAIDetect:(BOOL)enable
               success:(void (^)(BOOL result))success
               failure:(void (^)(NSError * error))failure;

参数说明

参数 说明
enable 是否开启 AI 检测功能
success 成功回调
failure 失败回调

更新 AI 检测事件类型

接口说明

- (void)enableAIDetectEventType:(NSString *)aiCode
                         enable:(BOOL)enable
                        success:(void (^)(BOOL result))success
                        failure:(void (^)(NSError *error))failure;

参数说明

参数 说明
aiCode AI 事件 标识 ID
enable 是否可用
success 成功回调
failure 失败回调

示例代码

[self.cloudManager enableAIDetect:YES success:^(BOOL result) {
            //
} failure:^(NSError *error) {
            //
 }];

查询 AI 云存储事件

开启 AI 云存储服务后,设备通过侦测报警上报的事件,AI 算法能够精准识别到上报事件中是否包含用户设置的物种,目前支持设置的物种有人形、宠物、车辆、包裹。

AI 云存储的 报警事件侦测报警消息 和 普通云存储的逻辑一致

接口说明

- (void)timeEventsWithCloudDay:(ThingSmartCloudDayModel *)cloudDay
                        offset:(int)offset
                         limit:(int)limit
                       aiCodes:(NSString *)aiCodes
                       success:(void(^)(NSArray<ThingSmartCloudTimeEventModel *> * timeEvents))success
                       failure:(void(^)(NSError * error))failure;

参数说明

参数 说明
cloudDay 云视频录像日期模型
offset 偏移量,0 标示从第一个事件开始
limit 数量限制,-1 标示查询所有事件
aiCodes AI 事件 ID,例如 ai_package,ai_human。查询所有 AI 事件信息请填写 all
success 成功回调,返回事件模型的数组
failure 失败回调,error 表示错误信息

ThingSmartCloudTimeEventModel 数据模型

字段 类型 说明
describe NSString 事件描述
startTime NSInteger 事件开始时间 Unix 时间戳
endTime NSInteger 事件结束时间 Unix 时间戳
snapshotUrl NSString 事件发生时,设备抓拍的实时图片
aiDetectList NSArray<ThingSmartAIEventModel *> * 事件发生时,AI 识别到的数据列表

ThingSmartAIEventModel 数据模型

字段 类型 说明
aiCode NSString AI 事件 ID
startTime NSInteger 事件开始时间 Unix 时间戳
endTime NSInteger 事件结束时间 Unix 时间戳
aiCodeIcon NSString AI 算法识别到的物种图标
orderValue NSInteger AI 算法识别到的物种排序值

示例代码

ThingSmartCloudDayModel *model = [ThingSmartCloudDayModel new];
[self.cloudManager timeEventsWithCloudDay:model offset:1 limit:15 aiCodes:@"all" success:^(NSArray<ThingSmartCloudTimeEventModel *> * timeEvents)) {
            //
} failure:^(NSError *error) {
            //
 }];

AI 云存储事件中携带的实时截图是经过加密的,您需要通过加密图片组件 ThingEncryptImage 展示,详情请参考 加密图片

播放云视频

播放云视频时,您需要指定开始播放的时间,结束时间,和是否是播放云存储事件。您还可以设置声音开关、本地视频录制、截图等。

开始播放

  • 如果需要直接播放某个视频片段 (ThingSmartCloudTimePieceModel):
    • 开始时间传入介于 ThingSmartCloudTimePieceModelstartTimeendTime 之间的一个时间戳。
    • isEvent 传入 NO
  • 如果需要播放某个云存储事件(ThingSmartCloudTimeEventModel):
    • 开始时间传入 ThingSmartCloudTimeEventModelstartTime
    • isEvent 传入 YES
    • 结束时间传入当天的结束时间,也就是 ThingSmartCloudDayModelendTime

接口说明

- (void)playCloudVideoWithStartTime:(long)startTime
                            endTime:(long)endTime
                            isEvent:(BOOL)isEvent
                         onResponse:(void(^)(int errCode))responseCallback
                         onFinished:(void(^)(int errCode))finishedCallback;

参数说明

参数 说明
startTime 开始播放的时间
endTime 结束时间,会自动连续播放到当天所有视频结束
isEvent 是否播放的是云存储事件
responseCallback 结果回调,errCode 标示错误码,0 表示成功开始播放
finishedCallback 播放结束回调,errCode 标示结束原因,0 表示视频正常播放结束

暂停播放

接口说明

- (int)pausePlayCloudVideo;

返回值

类型 说明
int 错误码,0 表示成功

恢复播放

接口说明

- (int)resumePlayCloudVideo;

返回值

类型 说明
int 错误码,0 表示成功

停止播放

接口说明

- (int)stopPlayCloudVideo;

返回值

类型 说明
int 错误码,0 表示成功

倍数播放

在开始播放调用成功后,可以设置倍数播放。音频不支持倍数播放。

接口说明

- (int)setCloudVideoPlaySpeed:(ThingSmartCameraPlayBackSpeed)speed;

参数说明

参数 说明
speed 播放倍数,支持 1、2、4 倍数,枚举值 ThingSmartCameraPlayBackSpeed

示例代码

 int result = [self.cloudManager setCloudVideoPlaySpeed:ThingSmartCameraPlayBackSpeed_10TIMES];

示例代码

Objective C:

- (void)viewDidLoad {
    [_cloudManager downloadCloudVideoWithRange:NSMakeRange(startTime, length) filePath:videoPath success:^(NSString *filePath) {

    } progress:^(NSUInteger progress) {

    } failure:^(NSError *error) {

    }];
}

Swift:

func viewDidLoad() {
    cloudManager.downloadCloudVideo(with: NSRange(location: startTime, length: length), filePath: videoPath, success: { (filePath) in }, progress: { (progress) in }, failure: { (error) in }
}

下载云视频

开始下载

接口说明

- (void)downloadCloudVideoWithRange:(NSRange)timeRange
                           filePath:(NSString *)videoPath
                            success:(DownloadSuccess)success
                           progress:(DownloadProgress)progress
                            failure:(DownloadFailure)failure;

参数说明

参数 说明
timeRange 待下载的视频的时间范围:
  • 开始时间为 10 位时间戳
  • 长度单位为秒
videoPath 保存视频的文件路径,格式为 folderPath/fileName.mp4
success 下载成功回调
progress 下载进度回调,进度以 1 到 100 之间的整数表示
failure 下载失败回调

暂停下载

接口说明

- (void)pauseDownloadCloudVideo;

恢复下载

接口说明

- (void)resumeDownloadCloudVideo:(DownloadFailure)failure;

参数说明

参数 说明
failure 恢复下载失败回调

取消下载

接口说明

- (void)cancelDownloadCloudVideo;

删除云视频

删除一段时间的云视频

接口说明

- (void)deleteCloudVideoWithRange:(NSRange)timeRange success:(void(^)(void))success failure:(void(^)(NSError *error))failure;

参数说明

参数 说明
timeRange 待删除的视频的时间范围:
  • 开始时间为 10 位时间戳
  • 长度单位为秒
success 成功的回调
failure 失败的回调

示例代码

Objective C:

- (void)viewDidLoad {
    [_cloudManager deleteCloudVideoWithRange:NSMakeRange(startTime, length) success:^{

    } failure:^(NSError *error) {

    }];
}

Swift:

func viewDidLoad() {
    cloudManager.deleteCloudVideo(with: NSRange(location: startTime, length: length), success: {

    }, failure: { error in

    })
}

删除全天的云视频

接口说明

- (void)deleteAllDayCloudVideoWithRange:(NSRange)timeRange success:(void(^)(void))success failure:(void(^)(NSError *error))failure;

参数说明

参数 说明
timeRange 待删除的视频的全天时间范围:
  • 当天的开始时间用 10 位时间戳表示
  • 长度单位为秒
success 成功的回调
failure 失败的回调

示例代码

Objective C:

- (void)viewDidLoad {
    [_cloudManager deleteAllDayCloudVideoWithRange:NSMakeRange(startTime, length) success:^{

    } failure:^(NSError *error) {

    }];
}

Swift:

func viewDidLoad() {
    cloudManager.deleteAllDayCloudVideo(with: NSRange(location: startTime, length: length), success: {

    }, failure: { error in

    })
}

云视频效果

查询云视频渲染视图

ThingSmartCloudManager 会自动渲染云视频,通过 videoView 方法查询云视频渲染视图,并添加到屏幕上。

接口说明

- (UIView<ThingSmartVideoViewType> *)videoView;

返回值

类型 说明
UIView 云视频渲染视图

设置云视频静音状态

接口说明

- (void)enableMute:(BOOL)mute success:(void(^)(void))success failure:(void (^)(NSError * error))failure;

参数说明

参数 说明
mute 是否静音
success 成功回调
failure 失败回调,error 表示错误信息

查询云视频静音状态

接口说明

- (BOOL)isMuted;

返回值

类型 说明
BOOL 是否是静音

保存云视频

录制云视频并保存到系统相册

接口说明

- (void)startRecord;

录制云视频并保存到指定文件路径

接口说明

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

参数说明

参数 说明
filePath 视频录像文件保存的路径

录制旋转的云视频并保存到指定路径

接口说明

- (void)startRecordWithRotateDirection:(ThingSmartVideoRotateDirection)direction filePath:(NSString *)filePath;

参数说明

参数 说明
direction 录制旋转方向
filePath 视频录像文件保存的路径

停止录制并保存视频文件

接口说明

- (int)stopRecord;

返回值

类型 说明
int 错误码,0 表示视频保存成功

截图视频并保存到系统相册

接口说明

- (UIImage *)snapShoot;

返回值

类型 说明
UIImage 截图的 UIImage 对象,失败时返回 nil

截图视频并保存到指定文件路径

接口说明

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

参数说明

参数 说明
filePath 保存截图的文件路径
thumbnilPath 缩略图保存路径,如果不需要缩略图,请设置为 nil

如果您只需要查询当前截图的 UIImage 对象,则不需要自动保存。此时可以通过 videoView- (UIImage *)screenshot; 方法查询截图。

示例代码

Objective C:

// self.devId = @"xxxxx";
- (void)viewDidLoad {
     if (![ThingSmartCloudManager isSupportCloudStorage:self.devId]) {
        //不支持云存储
        return;
    }
    _cloudManager = [[ThingSmartCloudManager alloc] initWithDeviceId:self.devId];
    [_cloudManager enableMute:NO success:nil failure:nil];
    _cloudManager.delegate = self;
}

- (void)loadData {
    __weak typeof(self) weakSelf = self;
    [self.cloudManager loadCloudData:^(ThingSmartCloudState state) {
      weak_self.cloudStorageDays = weak_self.cloudManager.cloudDays;
      weak_self.selectedDay = weak_self.cloudManager.cloudDays.lastObject;
      [weakSelf checkCloudState:state];
  }];
}

- (void)requestTimelineData {
    [self.cloudManager timeLineWithCloudDay:self.selectedDay success:^(NSArray<ThingSmartCloudTimePieceModel *> *timePieces) {
        // success
    } failure:^(NSError *error) {
        // failed
    }];
}

-(void)playVideo:(ThingSmartCloudTimePieceModel *)timePiece {
    [self.cloudManager playCloudVideoWithStartTime:timePiece.startTime endTime:self.selectedDay.endTime isEvent:NO onResponse:^(int errCode) {
        if (errCode == 0) {
            // success
        }else {
                    // failed
        }
    } onFinished:^(int errCode) {
              // finished
        if (errCode != 0) {
                    // some error
        }
    }];
}

- (void)playEvent:(ThingSmartCloudTimeEventModel *)event {
    [self.cloudManager playCloudVideoWithStartTime:event.startTime endTime:self.selectedDay.endTime isEvent:YES onResponse:^(int errCode) {
        if (errCode == 0) {
            // success
        }else {
    // failed
        }
    } onFinished:^(int errCode) {
  // finished
        if (errCode != 0) {
    // some error
        }
    }];
}

- (void)pause {
    if ([self.cloudManager pausePlayCloudVideo] != 0) {
        // 暂停失败
    }
}

- (void)resume {
    if ([self.cloudManager resumePlayCloudVideo] != 0) {
        // 恢复播放失败
    }
}

- (void)stop {
        [self.cloudManager stopPlayCloudVideo];
}

- (void)muteAction {
    BOOL isMuted = [self.cloudManger isMuted];
    [self.cloudManager enableMute:!isMuted success:^{
        // success
    } failure:^(NSError *error) {
        // failed
    }];
}

- (void)recordAction {
    if (self.isRecording) {
        if ([self.cloudManager stopRecord] != 0) {
            // 录制失败
        }else {
            // 录制成功,视频已保存到系统相册
        }
          self.isRecording = NO;
    }else {
        [self.cloudManager startRecord];
            self.isRecording = YES;
    }
}

- (void)snapShoot {
    if ([self.cloudManager snapShoot]) {
        // 图片已保存到系统相册
    }else {
        // 截图失败
    }
}

Swift:

func viewDidLoad() {
     if (!ThingSmartCloudManager.isSupportCloudStorage(devId: self.devId)) {
        //不支持云存储
        return;
    }
    let cloudManager = ThingSmartCloudManager(deviceId: self.devId)
    cloudManager?.enableMute(false, success: nil, failure: nil)
    cloudManager?.delegate = self
}

func loadData() {
    self.cloudManager.loadCloudData { [weak self] (state) in
            self.cloudStorageDays = self.cloudManager.cloudDays
            self.selectedDay = self.cloudManager.cloudDays.last
            self.checkCloudState(state)
    }
}

func requestTimelineData() {
        self.cloudManager.timeLine(withCloudDay: self.selectedDay, success: { (timePieces) in
        //success
    }) { (error) in
        //failed
    }
}

func playVideo(_ timePiece: ThingSmartCloudTimePieceModel) {
    self.cloudManager.playCloudVideo(withStartTime: timePiece.startTime, endTime:self.selectedDay.endTime , isEvent: false, onResponse: { (code) in
        if code == 0 {
            //success
        } else {
            //failed
        }
    }) { (errCode) in
        //finished
        if codeCode != 0 {
            //some error
        }
    }
}

func playEvent(_ event: ThingSmartCloudTimeEventModel) {
    cloudManager.playCloudVideo(withStartTime: event.startTime, endTime: self.selectedDay.endTime, isEvent: true, onResponse: { (errCode) in
        if code == 0 {
            //success
        } else {
            //failed
        }
    }) { (errCode) in
        //finished
        if errCode != 0 {
            // some error
        }
    }
}

func pause() {
    if self.cloudManager.pausePlayCloudVideo() != 0 {
        //暂停失败
    }
}

func resume() {
    if self.cloudManager.resumePlayCloudVideo() != 0 {
        // 恢复播放失败
    }
}

func stop() {
        self.cloudManager.stopPlayCloudVideo()
}

func muteAction() {
    let isMuted = self.cloudManager.isMuted()
    self.cloudManager.enableMute(!isMuted, success: {
                // success
    }) { (error) in
        // failed
    }
}

func recordAction() {
    if self.isRecording {
        if self.cloudManager.stopRecord() != 0 {
            //录制失败
        } else {
            //录制成功,视频已保存系统相册
        }
        self.isRecording = false
    } else {
        self.cloudManager.startRecord()
        self.isRecording = true
    }
}

func snapShoot() {
    if self.cloudManager.snapShoot() {
        // 图片已保存到系统相册
    } else {
        // 截图失败
    }
}