录像云存储

更新时间:2025-10-22 02:00:10下载pdf

录像云存储,指的是设备将录像数据,写入第三方云服务商对象存储服务器的功能。为实现音视频数据的即时备份,涂鸦基于 环形缓存(Ring Buffer) 和云端对象存储服务,实现了录像数据的云端存储(Cloud Storage)功能。

功能特性

录像云存储从环形缓存中读取音视频数据,经过数据加密后,上传至云端对象存储服务器,实现录像数据的云端备份。结合实际的应用场景,涂鸦录像云存储支持以下功能:

  • 支持两种存储模式:
    • 事件云存储:在事件触发时上传录像。
    • 连续云存储:自动上传全时录像。
  • 支持录像预录功能,在录像上传触发的时间点,预先录取一定时长的录像。
  • 提供音频控制开关,关闭、开启音频数据的上传。
  • 隐私模式下,可以暂停录像云存储服务。

安全特性

对象云存储服务,采用通道和数据双重加密,有效保证了数据的安全性。

通道加密

录像云存储,通过 HTTPS 协议,向云端对象存储服务器发送录像数据,实现了传输通道的安全性。这里需要特别说明的是,设备会对云端对象存储服务器的 CA 证书进行校验,校验通过后,才会开始上传录像数据。

设备云端对象存储服务器获取对象存储服务器的 CA 证书返回请求访问对象存储服务器返回对象存储服务器工作证书使用 CA 证书校验工作证书是否合法,只有校验通过,才会上传录像数据。设备云端对象存储服务器

数据加密

在录像数据上传前,会对视频关键帧 I 帧和音频帧,通过 AES 算法进行加密,保证了数据和通道的双重安全性。

关联组件

svc_cloud_storage

数据结构

订单类型

typedef enum
{
    CLOUD_STORAGE_TYPE_CONTINUE,        // 连续订单类型
    CLOUD_STORAGE_TYPE_EVENT,           // 事件订单类型
    CLOUD_STORAGE_TYPE_INVALID          // 未购买订单
} CLOUD_STORAGE_TYPE_E;

API

初始化

初始化录像云存储服务。主要包括内部功能资源的初始化和录像线程的创建。

/**
 * @brief    initialize cloud storage, which will malloc all needed memory after this
 * @return   error code
 * - OPRT_OK init success
 * - Others  init failed
 */
OPERATE_RET tuya_ipc_cloud_storage_init(VOID);

反初始化

反初始化录像云存储服务。该操作主要执行缓存空间的释放和录像线程的销毁。

/**
 * @brief    uninit cloud storage, free used memory
 * @return   VOID
 */
VOID tuya_ipc_cloud_storage_uninit(VOID);

获取订单类型

该接口可以获取订单类型,判断设备是否开通录像云存储服务。订单类型可分为连续云存储、事件云存储和未购买订单类型。

/**
 * @brief    get current storage type, based on purchase order
 * @return   CLOUD_STORAGE_TYPE_E
 * - CLOUD_STORAGE_TYPE_CONTINUE  continuous record type
 * - CLOUD_STORAGE_TYPE_EVENT     event-based type, only record and store audio/video when there is event happening
 * - CLOUD_STORAGE_TYPE_INVALID   no cloud storage order exist
 */
CLOUD_STORAGE_TYPE_E tuya_ipc_cloud_storage_get_store_mode(VOID);

开始事件录像

设备发生事件时,开始一段事件录像。

/**
 * @brief    start event cloud storage
 * @return   error code
 * - OPRT_OK cloud storage start success
 * - Others cloud storage start failed
 */
OPERATE_RET tuya_ipc_cloud_storage_event_start(VOID);

结束事件录像(同步)

设备当前事件结束时,结束正在进行的事件录像。该接口为同步接口,最长阻塞 30 秒。

/**
 * @brief    stop event cloud storage, synchronous api
 * @return   error code
 * - OPRT_OK cloud storage stop success
 * - Others  cloud storage stop failed
 */
OPERATE_RET tuya_ipc_cloud_storage_event_stop(VOID);

结束事件录像(异步)

设备当前事件结束时,结束正在进行的事件录像。该接口为异步接口,不会发生阻塞。

/**
 * @brief    stop event cloud storage, asynchronous api
 * @return   error code
 * - OPRT_OK cloud storage stop success
 * - Others  cloud storage stop failed
 */
OPERATE_RET tuya_ipc_cloud_storage_event_stop_async(VOID);

获取录像状态

获取录像状态,用于判断录像是否正在进行。

/**
 * @brief    get cloud storage status
 * @return   BOOL_T
 * - TRUE    cloud storage is uploading
 * - FALSE   cloud storage is not uploading
 */
BOOL_T tuya_ipc_cloud_storage_get_status(VOID);

设置音频开关

设置音频开关,关闭音频功能时,录像存储只从环形缓存中读取视频数据,不读取音频数据。

/**
 * @brief    set audio open/close
 * @param[in] is_audio_open
 * @ref       TRUE open audio for cloud storage
 * @ref       FALSE close audio for cloud storage
 * @return    VOID
 */
VOID tuya_ipc_cloud_storage_set_audio_stat(BOOL_T is_audio_open);

设置预录时长

设置预录时长,最大值不超过环形缓存的最大时长。该接口未设置时,默认的预录时长为 2 秒。

/**
 * @brief    set cloud storage pre record time duration
 * @param[in] pre_recode_time  pre record time duration for cloud storage
 * - OPRT_OK set pre record time success
 * - Others  set pre record time failed
 */
OPERATE_RET tuya_ipc_cloud_storage_set_pre_record_time(INT_T pre_record_time);

暂停录像

暂停录像云存储服务,录像线程暂停从环形缓存读取数据,暂停数据的上传。通常,隐私模式下,需要暂停录像。

/**
 * @brief    pause cloud storage, used in privacy mode e.g.
 * @return   VOID
 */
VOID tuya_ipc_cloud_storage_pause(VOID);

恢复录像

恢复录像云存储服务,录像线程恢复工作。通常,退出隐私模式时,需要恢复录像,与 tuya_ipc_cloud_storage_pause 配对使用。

/**
 * @brief    resume cloud storage which is paused by pause API
 * @return   VOID
 */
VOID tuya_ipc_cloud_storage_resume(VOID);

常见问题

为什么要尽可能的保证音视频帧向 ringbuf 中塞流均匀?

塞流均匀指的是:在时间维度上,向 ringbuf 中塞流的 每帧间隔时间 都是 1000ms/fps

例如:

  • 视频帧的塞入为 fps20, 即为大概每隔 50 ms 塞一帧视频数据到 ringbuf。
  • 音频帧的塞入为 fps40, 即为大概每隔 25 ms 塞一帧音频数据到 ringbuf。

内存在什么时候申请与释放,占用多大的内存?

在 SDK 获取到有效的云存储订单服务时,录像云存储 会申请连续的内存。申请后在整个运行期间不会释放或者重新申请。整体内存占用大小为,11 秒对应码率 Bitrate 的乘积。

录像云存储申请的内存空间,用于缓存加密后的音视频数据,上传至云端对象存储服务器。

录像云存储在反初始化时,释放申请的内存空间。

如何裁剪云存储占用内存?

  • SDK 中的内存占用与码率关系比较大,建议优先从降低码率入手解决。
  • 子码流的 ringbuf 使用的概率较低,只有预览时才会用到,建议将 max_buffer_seconds 设置降低到 4-6 秒。
  • 事件存储的预录在 2 秒之内的,I 帧间隔如果是 2 秒,主码流的 max_buffer_seconds 可以设置为 6 秒或 8 秒。
  • 减少主码流的 max_buffer_seconds,在网络状况比较差的环境下,会增加云存储丢失的风险。

单次事件录像,中间出现中断的原因?

  • 视频实际码率,超过设置的最大码率值。
  • 设备网络较差,录像数据上传失败。
  • 设备网络较差,录像数据上传耗时很长。
    录像数据读取和录像数据上传,在录像线程中串行进行。如果设备网络较差,录像数据上传耗时超过环形缓存最大时长时,会导致中间的录像数据缺失。

SDK 报错打印

以下为一些较明显的报错打印:

ring buffer delay too much

  • Q:为什么会出现这个打印?

  • A:之所以出现这个打印,是由于对于读取 ringbuf 的业务模块来说,当前录制模块读指针指向 ringbuf 中的数据帧节点ringbuf 中最新塞入的数据帧节点 之间的 序号差值 超过 ringbuf 最大缓存帧数的百分之 95,则认定为 delay too much

    例如, ringbuf 的 max_buffer_seconds 为 10 s,fps 为 20,那么 ringbuf 的节点数量就是 200,即最多放 200 帧。假设读帧模块当前在 ringbuf 的节点 index 为 3,但是最新的一帧数据已经为 198,此时最新一帧和当前读的 index 节点差值是 195,而最大缓存帧数的百分之 95 是:200 * 0.95 = 190。195 大于 190。

    另外还有一种极端情况,即写的比较快而读取比较慢,已经覆盖了读帧模块当前在 ringbuf 的节点 index。

  • Q:什么情况会导致 读的 node index写的 node index 落后很多?

  • A:有以下两种可能情况:

    • 网络比较差,上传一个云存储片耗时超过了 ringbuf 的最大缓存时长。例如,上传一个 11s 的云存储缓存片耗时 12s,这 12s 期间是持续塞流进 ringbuf 的,因此会出现最新塞入到 ringbuf 中的一帧和最近读出来的一帧时间差值很大。
    • 塞流不均匀。例如设备自己有一个缓存,在比较短的时间内塞入了很多的数据帧。

memory insufficient to buffer data

设备实际码率比 tuya_ipc_media_adapter_set_media_info 设置的码率要高,并导致单次事件录像中间丢失一块变成了两段。

预录时长与设置值为何不一致?

环形缓存定位预录帧,是从最新的数据帧往前 frame_num 帧起继续往前查找,直到数据帧类型为关键帧 I 帧。frame_num 对应预录时长和帧率 FPS 的乘积。

因此,预录帧的位置不是一个固定位置,实际的预录时长,与设置值存在一定差异。
如果有打印 sync stream failed,就说明往 ringbuf 塞流不均匀,这时就要排查音视频塞帧到 ringbuf 在时间维度上是否均匀。

录像云存储采用主码流,还是子码流?

录像云存储默认采用主码流,目前暂时不支持子码流录制。

为什么 tuya_ipc_cloud_storage_event_stop_async 调用后, tuya_ipc_cloud_storage_get_status 拿到的值仍为 “1”?

可能有以下两种情况及原因:

取值情况 原因
几秒钟内 tuya_ipc_cloud_storage_get_status 拿到的值是 1,几秒后是 0 tuya_ipc_cloud_storage_event_stop_async 接口是立即返回的,而且云存储录像要一直录制到 调用 tuya_ipc_cloud_storage_event_stop_async 时间点的录像 才结束,这就要额外需要一点时间将云存储录制文件上传完成

例如,在 18:31:30 调用的 tuya_ipc_cloud_storage_event_stop_async,可能当前还在录制 18:31:28 的视频,要等到 18:31:30 的视频流录像录制完成,才会真正结束
超过一分钟,tuya_ipc_cloud_storage_get_status 拿到的值仍然是 1 同上文所描述的情况,可能是设备没有一直向 ringbuf 塞流。如 18:31:30 调用 Stop 后就没有继续向 ringbuf 塞流,存储模块没有拿到 18:31:30 的视频流,因此无法认为是录制完整的,就会一直处于等待和尝试获取的状态

另外,也可能是由于网络异常,导致云存储录像文件一直没有发送完整

为什么 tuya_ipc_cloud_storage_event_stop 会出现超时未停止成功?

同上文表格中 超过一分钟拿到的值仍为 1 介绍的原因,大概率是由于调用 Stop 后,没有继续向 ringbuf 塞流。

为什么 tuya_ipc_cloud_storage_get_ready 有时返回 0,有时返回 1?

tuya_ipc_cloud_storage_get_ready 获取的是云存储是否处于准备完成的状态,设备上线后才能拿到云存储订单。

  • 如果设备开通了云存储订单:
    • 设备上线前,返回值为 0
    • 设备上线后,可以获取到云存储订单,则返回值为 1
  • 如果没有开通云存储,则返回值为 0
  • 如果启动后,没有网络连接、没有获取到云存储订单,则返回值为 0

云存储录像何时会被删除?

在录像文件过期后,云存储录像会被删除。

  • 录像文件过期时间 ≠ 云存储服务的过期时间
  • 云存储服务过期时间:仅指您购买的云存储套餐的过期时间,是服务权益的截止节点。

举例说明

设备于 2025.08.16 开通了为期一个月的 7 天事件云存储服务,那么于 2025.09.15 录制的视频,云存储删除时间为 2025.09.22,删除之前视频均可查看,不受 2025.09.16 服务到期的影响。