录像本地存储

更新时间:2024-08-14 09:07:42下载pdf

本地存储是智能摄像机 IPC 的基础功能。该功能负责管理 SD 卡,将音视频和图片等数据按特定目录和文件结构存储到 SD 卡上的通用文件系统,并支持数据的检索、回放、下载、删除等操作。

功能描述

本地存储提供将实时流视频存储到本地 SD 卡的能力,可设置 事件录制模式全时段录像模式。SD 卡储存空间达到上限后,采用循环覆盖的写入模式,并提供按时间索引的视频回放接口。

开发指导

运行环境

  • 开发框架

    IPC 开发框架的通用功能。

  • 关联组件

    svc_local_storage

SD 卡管理

SD 卡管理包括热插拔监测、格式化、状态维护等。为保证足够读写性能,建议选用主流品牌、class10 以上的 SD 卡。

  • 热插拔监测:

    • SD 卡插入时,识别文件系统并挂载,以供数据的读写。
    • SD 卡拔出时,停止数据的录像、回放等操作,并卸载文件系统。
  • SD 卡状态:包含卡不存在、卡正常工作、卡异常。

    卡异常的主要导致原因有无文件系统、文件系统不支持、文件系统损坏、坏卡等。

  • SD 卡格式化:由用户在手机 App 上触发,会清空卡数据、使卡处于正常工作的状态。SD 卡格式化的流程图如下:

    DPSDKSD 卡pb_stop_all, set mode none to SDKformatingget status errstop writingget status errget status err periodyformat ok, make status okget status okwhen status ok, SDK will get mode form cfgstart writingDPSDKSD 卡

目录和文件结构

IPC 本地存储,采用通用文件系统,以私有格式文件存储音视频和索引、JPG 格式存储图片,按多级目录、特定文件名组织文件以加速检索。

目录分为录像、本地相册 2 大类,业务上彼此独立。具体如下:

DCIM                                       // 涂鸦存储目录,位于 SD 卡的文件系统的顶层目录
    ├── CHAN0                              // 单通道 IPC 或多通道 IPC 的第一个通道的录像存储目录
    │   └── 2022
    │       └── 10
    │           └── 14
    │               ├── 1665732067_0014    // 事件文件夹,记录 utc 时间开始的录像,时长 14 秒
    │               │   ├── 0000.media     // 音视频文件,采用涂鸦私有格式,从第 0 秒开始
    │               │   ├── 0010.media     // 从第 10 秒
    │               │   ├── 1665732067.jpg // 事件封面图
    │               │   └── .info          // 录像括视频格式、事件类型
    │               └── day_idx.bin        // .info 文件的索引
    ├── CHAN1
    │           ...                        //多通道 IPC 的第二个通道的录像存储目录,内部结构同

录像

录像记录

  • 录像模式有 3 种:

    • 不录像(任何时候不录像)

    • 连续录像(7*24 小时持续录像)

    • 事件录像(仅在有事件发生时录像,支持预录)

      预录,是指事件发生前 N 秒的视频,也能存到 SD 卡。N 最大值受限于 ringBuff 时长,例如 ringBuff 有 10 秒,N 最大可为 9 秒。

  • 循环覆盖,存储空间不足 500MB 时,程序自动删除时间最老的录像,为新录像留出存储空间。每次仅删除一个事件文件夹。

录像检索

  • 按月历检索,检索该月哪些天有录像。
  • 进度条检索,检索 SD 卡中某天的录像时间的分布。

录像回放

读取 SD 卡中的音视频数据,按照一定速率、有选择地传输给客户端做显示。

  • 录像回放,支持回放状态控制、进度条跳转、倍速等特性。
  • 回放状态控制,有开始、暂停、恢复、结束。
  • 倍速回放,加快或减慢数据读取和显示的速度,支持的倍速有 0.5、2、4、8 倍。

录像下载

读取 SD 卡中的音视频数据,尽量快地传给 App 等客户端。

录像删除

按天删除,由用户在 App 上触发,删除某一天的录像。

数据结构

初始化参数

typedef struct {
    CHAR_T base_path[SS_BASE_PATH_LEN]; /* 视频存储的根路径 */
    UINT_T max_event_per_day;           /* 每天的最大事件数,此限制应基于 Soc 能力,查询并在可接受的时间内返回播放信息 */
                                        /* 如果事件数超过此限制,将拒绝查询消息 */
    SS_SD_STATUS_CHANGED_CB sd_status_changed_cb; /* SD 卡状态变化通知回调 */
    UINT_T skills;                     /* 0 表示支持所有能力,参考 TUYA_IPC_SKILL_BASIC | TUYA_IPC_SKILL_DOWNLOAD */
    TUYA_IPC_ALBUM_INFO_T album_info;   /* 相册信息 */
} TUYA_IPC_STORAGE_VAR_T;

回调参数

SD 状态回调通知。

typedef OPERATE_RET (*SS_SD_STATUS_CHANGED_CB)(SD_STATUS_E status);

参数说明

typedef enum {
    SD_STATUS_UNKNOWN = 0,
    SD_STATUS_NORMAL,
    SD_STATUS_ABNORMAL,
    SD_STATUS_LACK_SPACE,
    SD_STATUS_FORMATING,
    SD_STATUS_NOT_EXIST,
    SD_STATUS_MAX
} SD_STATUS_E;

API 说明

初始化通道

初始化存储通道,该操作会执行缓存空间的创建和初始化,初始化成功会返回 OPRT_OK

/**
 * @brief 初始化本地存储
 *
 * @param[in] p_storage_var: pointer
 *
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tuya_ipc_ss_init(IN TUYA_IPC_STORAGE_VAR_T *p_storage_var);

释放本地存储

执行反初始化,释放缓存资源。

/**
 * @brief uninit tuya stream storage, free used resource, memory e.g.
 *
 * @param VOID
 *
 * @return VOID
 */
VOID tuya_ipc_ss_uninit(VOID);

判断是否启动了本地存储

/**
 * @brief if stream storage is inited
 *
 * @param VOID
 *
 * @return TRUE/FALSE
 */
BOOL_T tuya_ipc_ss_is_inited(VOID);

设置本地存储模式

/**
 * @brief set wtote mode of stream storage
 *
 * @param[in] write_mode
 *
 * @return OPERATE_RET
 */
OPERATE_RET tuya_ipc_ss_set_write_mode(IN CONST STREAM_STORAGE_WRITE_MODE_E write_mode);

获取本地存储模式

/**
* @brief get current stream storage write mode
*
* @param VOID
*
* @return STREAM_STORAGE_WRITE_MODE_E
*/
STREAM_STORAGE_WRITE_MODE_E tuya_ipc_ss_get_write_mode(VOID);

判断是否启用本地储存写入模式

/**
 * @brief if stream storage write mode is enabled
 *
 * @param VOID
 *
 * @return TRUE/FALSE
 */
BOOL_T tuya_ipc_ss_write_mode_is_enabled(VOID);

按通道启动录像存储

/**
 * @brief start event stream storage by channel
 *
 * @param[in] channel: which channel, 0 for ipc
 *
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tuya_ipc_ss_start_event(IN INT_T channel);

按通道停止录像存储

/**
 * @brief stop event stream storage by channel
 *
 * @param[in] channel: which channel, 0 for ipc
 *
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tuya_ipc_ss_stop_event(IN INT_T channel);

预记录时间设置

/**
 * @brief set pre-record time, invoke this API only if needed, or it is 2 seconds by default.
 *        Should be invoked once after init and before start.
 *
 * @param[in] pre_record_second: time in second
 *
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tuya_ipc_ss_set_pre_record_time(IN UINT_T pre_record_second);

最大事件时长设置

/**
 * @brief set max event duration, invoke this API only if needed, or it is 600 seconds by default.
 *        Should be invoked onece after init and before start.
 *
 * @param[in] max_event_duration: time in second
 *
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tuya_ipc_ss_set_max_event_duration(IN UINT_T max_event_duration);

开始回放

该接口在 MEDIA_STREAM_PLAYBACK_START_TS P2P 事件上启用,详细请参考 Demo 应用。

/**
 * @brief start a new playback
 *
 * @param[in] pb_idx: playback/query index, for different client do query in the same time
 * @param[in] event_cb: callback function of playback event
 * @param[in] video_cb: callback function of getting playback video data
 * @param[in] audio_cb: callback function of getting playback audio data
 *
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tuya_ipc_ss_pb_start(IN UINT_T pb_idx, IN SS_PB_EVENT_CB event_cb, IN SS_PB_GET_MEDIA_CB video_cb, IN SS_PB_GET_MEDIA_CB audio_cb);

回调参数

typedef VOID (*SS_PB_EVENT_CB)(IN UINT_T pb_idx, IN SS_PB_EVENT_E pb_event, IN PVOID_T args);

回放事件回调

typedef VOID (*SS_PB_GET_MEDIA_CB)(IN UINT_T pb_idx, IN CONST MEDIA_FRAME_T *p_frame);

音视频接收回调参数

参数 说明
pb_idx 回放和查询索引,针对不同的客户端在同一时间进行查询
event_cb 回放事件回调
video_cb 视频数据回调
audio_cb 音频数据回调

停止回放

停止指定通道的回放。

/**
 * @brief stop an ongoing playback
 *
 * @param[in] pb_idx: playback/query index, for different client do query in the same time
 *
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tuya_ipc_ss_pb_stop(IN UINT_T pb_idx);

注意事项

  • 录像的目录,按年、月、日、事件文件夹、音视频文件的多级组织。
  • 音视频文件,单文件最多存储 10s 录像。
  • 事件文件夹,是对多个时间连续的音视频文件的包裹,最多包含 600 秒录像。
  • 事件录像模式下,一个事件文件夹一般对应一个事件持续期间的录像。
  • 连续录像模式下,事件文件夹多为 600 秒。

常见问题

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

在首次识别到正常的 SD 卡后,会申请录像缓存内存,在本存模组反初始化时释放。
内存大小:N 秒 *(1 秒视频主码流大小+1 秒音频主码流大小),N 为可配置,默认为 6。
对于多通道录像,每通道各一份内存。

SD 卡存储的视频文件是什么格式?

音视频文件采用涂鸦私有格式存储音视频数据,以 .media 作为后缀,后续版本会新增对 MP4 格式的支持。

本地存储模块是否支持自定义的格式和逻辑?

涂鸦提供了标准化的存储实现,如果开发者需要有自定义的存储逻辑,如不同的目录结构、不同的文件大小和格式、不同的文件读写方案等,可以选择不启用该模块,使用自有的存储方案程序。但是需要按照标准协议对接录像回放、下载等功能。

本地存储录像中间跳帧

  • 确保设备本机时间连续无跳变。
  • 确保音视频帧率稳定。
  • 对于低功耗产品,SD 卡挂载成功时长尽量在所设置的预录时长之内。
  • SD 卡容量越大,获取第一帧后创建事件录像文件夹的时间越长,会影响第二帧与第一帧的连续性,导致中间丢帧。

有事件上报但是没有本地录像

事件产生时调用 tuya_ipc_ss_start_event 后,不能立即调用 tuya_ipc_ss_stop_event

调用 tuya_ipc_ss_start_event 时,如果本地初始化未完成,内部会缓存事件标记,然后等初始化完成后,根据事件标记再开始录像。但是,如果在此期间调用了 tuya_ipc_ss_stop_event, 标记会被清除,最终事件录像将不会产生。

本地存储初始化失败

调用 tuya_ipc_ss_start_eventtuya_ipc_ss_set_write_mode 后日志中出现 not init 报错,说明存储模块的目录初始化还没有完成。

此现象和上层 SD_STATUS_E tuya_ipc_sd_get_status(VOID) 的实现有关。SDK 内部会调用 tuya_ipc_sd_get_status,在返回 SD_STATUS_NORMAL 后,存储目录初始化才能完成。