更新时间:2025-04-02 09:03:52下载pdf
本地存储是智能摄像机 IPC 的基础功能。该功能负责管理 SD 卡,将音视频和图片等数据按特定目录和文件结构存储到 SD 卡上的通用文件系统,并支持数据的检索、回放、下载、删除等操作。
本地存储提供将实时流视频存储到本地 SD 卡的能力,可设置 事件录制模式 或 全时段录像模式。SD 卡储存空间达到上限后,采用循环覆盖的写入模式,并提供按时间索引的视频回放接口。
开发框架
IPC 开发框架的通用功能
关联组件
svc_local_storage
SD 卡管理包括热插拔监测、格式化、状态维护等。为保证足够读写性能,建议选用主流品牌、class10 以上的 SD 卡。
热插拔监测:
SD 卡状态:包含卡不存在、卡正常工作、卡异常。
卡异常的主要导致原因有无文件系统、文件系统不支持、文件系统损坏、坏卡等。
SD 卡格式化:由用户在手机 App 上触发,会清空卡数据、使卡处于正常工作的状态。SD 卡格式化的流程图如下:
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 秒。
循环覆盖,存储空间不足 500 MB 时,程序自动删除时间最老的录像,为新录像留出存储空间。每次仅删除一个事件文件夹。
读取 SD 卡中的音视频数据,按照一定速率、有选择地传输给客户端做显示。
读取 SD 卡中的音视频数据,尽量快地传给 App 等客户端。
按天删除,由用户在 App 上触发,删除某一天的录像。
在使能存储,选择连续录像或事件录像后,内部自动将音视频流记录到存储卡中。默认的存储格式为涂鸦私有格式,因此在存储卡中保存的录像文件不能被常规播放器打开并播放。只能通过涂鸦 App 回放中观看。满足了一定的安全等级要求。
为满足更高的安全等级要求,在私有格式的基础上增加了存储数据的加密功能,可通过相关 API 开启或关闭。打开加密后,在保存码流数据过程中,将对数据进行加密操作,然后再写入到存储卡。
加密后的录像只可以在录像时使用的设备中回放观看,存储卡放入其他设备后,将不能正常回放加密录像。如:在 A 设备中录制的加密录像,在 B 设备中将无法正常回放观看。
MP4 文件格式是数码多媒体容器格式,广泛用于存储视频、音频、字幕以及照片等数据。MP4,全称为MPEG-4 Part 14,是基于 ISO/IEC 14496-12 标准的一种格式。它是一种高度兼容的视频格式,支持多种编码标准。
当前最新版本的 SDK 支持的 MP4 视频编码包括 H.264 和 H.265,而音频支持 PCM 和 G711 两种。
开启 MP4 存储后,与私有格式录像不再兼容。同时不再支持录像加密功能。
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 卡状态变化通知回调
INT_T stor_format; //0:默认值,私有格式存储;1:MP4 格式存储(不支持加密)
INT_T encrypt_mode; // 1:使能加密
INT_T security_level; // 加密等级,可不填写
UINT_T skills; // 0 表示支持所有能力,参考 TUYA_IPC_SKILL_BASIC | TUYA_IPC_SKILL_DOWNLOAD
TUYA_IPC_ALBUM_INFO_T album_info; // 相册功能初始化参数
INT_T max_event_duration; // 事件最大时长,0 为默认值 10 分钟
UINT_T write_card_period_s; // 录像数据写入周期,默认为 0 表示 6s 写入一次数据
TUYA_IPC_STORAGE_WORKING_PATH_NAME_T path_name; // 录像存储自定义路径命名
TUYA_IPC_AOV_STORAGE_INFO_T aov_info; // AOV 存储参数
} 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;
初始化存储通道,该操作会执行缓存空间的创建和初始化,初始化成功会返回 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 write 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: the playback and search index, used for simultaneous search from different clients
* @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);
tuya_ipc_ss_init
初始化本地存储时,设置加密使能参数。/**
* @brief set the encryption mode
*
* @param[in] encrypt_enable: turn encryption on or off
*
* @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
*/
OPERATE_RET tuya_ipc_ss_set_encrypt_mode(IN CONST BOOL_T encrypt_enable)
本地存储 tuya_ipc_ss_init
初始化的入参 stor_format
参数填入 1
,即可开启 MP4 格式存储。
开启后存储的路径与私有格式的路径不同,因此回放时不再支持原有私有格式的录像。
在首次识别到正常的 SD 卡后,会申请录像缓存内存,在本存模组反初始化时释放。
内存大小:N 秒 *(1 秒视频主码流大小+1 秒音频主码流大小),N 为可配置,默认为 6。
对于多通道录像,每通道各一份内存。
音视频文件采用涂鸦私有格式存储音视频数据,以 .media
作为后缀,后续版本会新增对 MP4 格式的支持。
涂鸦提供了标准化的存储实现,如果开发者需要有自定义的存储逻辑,如不同的目录结构、不同的文件大小和格式、不同的文件读写方案等,可以选择不启用该模块,使用自有的存储方案程序。但是需要按照标准协议对接录像回放、下载等功能。
事件产生时调用 tuya_ipc_ss_start_event
后,不能立即调用 tuya_ipc_ss_stop_event
。
调用 tuya_ipc_ss_start_event
时,如果本地初始化未完成,内部会缓存事件标记,然后等初始化完成后,根据事件标记再开始录像。但是,如果在此期间调用了 tuya_ipc_ss_stop_event
, 标记会被清除,最终事件录像将不会产生。
调用 tuya_ipc_ss_start_event
或 tuya_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
后,存储目录初始化才能完成。
回放界面的 下载 和 删除 按钮需要通过 tuya_ipc_upload_skills
上传对应能力位才可开启。能力标记位可通过 tuya_ipc_ss_init
的入参 skills
按位设置。对应值在 tuya_ipc_stream_storage.h
中可找到,检索 TUYA_IPC_SKILL_DOWNLOAD
即可。但需要注意:
tuya_ipc_ss_init
需要在调用 tuya_ipc_upload_skills
之前进行,否则存储的能力标记无法上传。tuya_ipc_upload_skills
需要在联网后调用,否则能力标记无法上传。不调用 tuya_ipc_ss_init
即可。如果需要开启回放的下载、删除等功能,需要单独上传对应的能力标记位。可调用 tuya_ipc_skill_enable
单独设置能力标记,如下所示:
TUYA_IPC_SKILL_PARAM_U skill_param = { .value = TUYA_IPC_SKILL_BASIC | TUYA_IPC_SKILL_DOWNLOAD | TUYA_IPC_SKILL_DELETE_BY_DAY};
tuya_ipc_skill_enable(TUYA_IPC_SKILL_LOCALSTG, &skill_param);
如自行实现了存储码流等功能,同时需要回放功能,可参考 Demo 中对应的信令处理流程。回放交互有以下信令:
MEDIA_STREAM_PLAYBACK_QUERY_MONTH_SIMPLIFY
,返回值参考 Demo 的实现。MEDIA_STREAM_PLAYBACK_QUERY_DAY_TS
或 MEDIA_STREAM_PLAYBACK_QUERY_DAY_TS_WITH_ENCRYPT
,返回值类型参考 Demo 的实现。MEDIA_STREAM_PLAYBACK_START_TS
,该信令接收后,需要立即返回,需要实现定位新的播放位置和发送音视频的操作。
tuya_ipc_media_playback_send_video_frame_with_encrypt
和 tuya_ipc_media_playback_send_audio_frame_with_encrypt
的上下文。MEDIA_STREAM_PLAYBACK_PAUSE
MEDIA_STREAM_PLAYBACK_RESUME
MEDIA_STREAM_PLAYBACK_MUTE
MEDIA_STREAM_PLAYBACK_UNMUTE
MEDIA_STREAM_PLAYBACK_SET_SPEED
,需要配合发送线程,且大于 4 倍速的回放建议只发送 I 帧。MEDIA_STREAM_PLAYBACK_STOP
MEDIA_STREAM_DOWNLOAD_START
tuya_imm_p2p_app_download_data
。tuya_imm_p2p_app_download_status
设置发送完成标记。MEDIA_STREAM_DOWNLOAD_STOP
MEDIA_STREAM_DOWNLOAD_PAUSE
MEDIA_STREAM_DOWNLOAD_RESUME
MEDIA_STREAM_DOWNLOAD_CANCLE
此现象与回放音视频数据发送的参数有关。 需要特别注意的是,在 MP4 方案中,使用 tuya_ipc_media_playback_send_video_frame_with_encrypt
发送视频帧数据时,接口入参中视频帧的编码参数 media.video.video_codec
、media.video.video_width
和 media.video.video_height
需要自行设置后 APP 端才能正常解析。
此问题大多和上层实现的 VOID tuya_ipc_sd_get_capacity(UINT_T *p_total, UINT_T *p_used, UINT_T *p_free)
的有关。
此接口会在 SDK 中调用,实时获取卡剩余容量,并进入对应的策略。SDK 中录像循环覆盖的逻辑有以下两种:1. 卡剩余空间小于 512MB ,会进入循环删除覆盖的逻辑 2.剩余空间小于20MB,停止任何录像。
该内容对您有帮助吗?
是意见反馈该内容对您有帮助吗?
是意见反馈