简体中文

通过AVAPIs的方式实作云存推流

云存储(VSaaS)设备端开发指南 | TUTK AV SDK 开发手册

一、核心说明

云存储采用「服务器主动取流」模式(类似实时观看):设备端触发存储需求时,调用接口通知云服务器从设备端取流,底层基于 TUTK AVAPIs 协议
设备端仅需对接 TUTK 公版实时音视频协议,无需额外开发复杂存储逻辑。
1.1 编码格式要求
图像:H264 / H265
音频:PCM、AAC、G711 等

二、云存储模块初始化

初始化时读取本地云存储配置文件(含 URL、Token),无配置则通过回调从 APP 端获取并持久化。
// 读取云存储配置文件(gVsaasInfoFilePath:本地配置文件路径)
char *vsaas_info = NULL;
FILE *vsaas_info_file_ptr = fopen(gVsaasInfoFilePath, "r");
int ret = 0;

if (vsaas_info_file_ptr == NULL) {
    // 未配置:从APP端获取(通过VsaasConfigChangedHandle回调保存)
    printf("Enable VSaaS without preload data!\n");
    ret = avEnableVSaaS(
        device_ctx,                  // 设备上下文(提前初始化)
        NULL,                        // 无预加载配置
        VsaasConfigChangedHandle,    // 配置变更回调
        VSaaSUpdateContractInfoHandle// 合约信息更新回调
    );
} else {
    // 已配置:读取本地文件初始化
    long file_size = 0;
    fseek(vsaas_info_file_ptr, 0, SEEK_END);
    file_size = ftell(vsaas_info_file_ptr);
    rewind(vsaas_info_file_ptr);

    vsaas_info = (char*)malloc(sizeof(char)*file_size);
    if (vsaas_info == NULL) {
        printf("memory alloc fail!\n");
        fclose(vsaas_info_file_ptr);
        return -1;
    }
    
    fread(vsaas_info, 1, file_size, vsaas_info_file_ptr);
    ret = avEnableVSaaS(device_ctx, vsaas_info, VsaasConfigChangedHandle, VSaaSUpdateContractInfoHandle);
    
    fclose(vsaas_info_file_ptr);
    free(vsaas_info);
    gVsaasConfigExist = true;
}

if (ret != AV_ER_NoERROR) {
    printf("avEnableVSaaS error [%d]\n", ret);
    return -1;
}
说明:device_ctx 为设备初始化后的核心句柄,需确保已正常创建

三、通知云服务器取流

支持「实时流(Live)」和「回放流(Playback)」两种模式,按参数要求构造 JSON 后调用接口。
/* 参数说明:
 * starttime:实时流填"live",回放流填时间戳(秒)
 * event_id:固定为 VSAAS_EVENT_GENERAL
 * event_file:回放流必填,指定本地录像文件路径
 * media_type:0=H264,1=H265,2=JPEG
 * channel:回放流必填,传入回放专用IOTC通道ID(避免avServStartEx超时)
 */
char att_json_str[256] = {0};
bool isLiveView = true;  // true=实时流,false=回放流
bool h264 = true;        // true=H264,false=H265
unsigned long current_time_sec = 1699999999;  // 回放起始时间戳
char *gRecordFile = "/mnt/record/20231114_100000.h264";  // 本地录像文件
int iotc_channel_id_for_playback = 1;  // 回放IOTC通道ID

if (isLiveView) {
    // 实时流模式
    sprintf(att_json_str, 
        "{\"starttime\":\"live\",\"protocol\":\"tutk\",\"event_id\":\"%d\",\"media_type\":\"%d\"}",
        VSAAS_EVENT_GENERAL,
        h264 ? 0 : 1
    );
} else {
    // 回放流模式
    sprintf(att_json_str, 
        "{\"starttime\":\"%lu\",\"protocol\":\"tutk\",\"event_id\":\"%d\",\"event_file\":\"%s\",\"media_type\":\"%d\",\"channel\":\"%d\"}",
        current_time_sec,
        VSAAS_EVENT_GENERAL,
        gRecordFile,
        h264 ? 0 : 1,
        iotc_channel_id_for_playback
    );
}

// 通知云服务器取流(超时3000ms)
Nebula_Json_Obj attr_obj = NULL;
Nebula_Json_Obj_Create_From_String(att_json_str, &attr_obj);
ret = avServNotifyCloudRecordStream(attr_obj, 3000, NULL);
printf("avServNotifyCloudRecordStream ret[%d]\n", ret);

if (ret != AV_ER_NoERROR) {
    // 错误处理(例:-20043=用户未购买云存储方案)
    printf("通知取流失败,错误码:%d\n", ret);
}
通知成功后,云服务器会发起 IOTC 连线,通过 P2P 协议取流(设备端将收到 0x1ff、0x351 拉流指令)。

四、关键回调函数实现

4.1 配置变更回调(保存APP端下发的URL和Token)
APP 端将云存储配置(URL、Token)以 JSON 格式下发,设备端需保存到本地文件,供下次初始化使用。
static void VsaasConfigChangedHandle(const char *vsaas_config)
{
    printf("Enter %s\n", __func__);
    printf("收到云存储配置:\n%s\n", vsaas_config);

    // 保存配置到本地文件
    FILE *vsaas_info_file_ptr = fopen(gVsaasInfoFilePath, "w+");
    if (vsaas_info_file_ptr == NULL) {
        printf("%s:打开配置文件失败!路径:%s\n", __func__, gVsaasInfoFilePath);
        return;
    }

    fwrite(vsaas_config, 1, strlen(vsaas_config), vsaas_info_file_ptr);
    fclose(vsaas_info_file_ptr);
    gVsaasConfigExist = true;  // 标记已配置
}
4.2 合约信息更新回调(适配云存储方案限制)
云存储合约变更时触发(如分辨率、码率、帧率限制),设备端需按合约调整录像参数。
// 全局变量:存储云存储合约信息
VSaaSContractInfo gVsaasContractInfo = {0};

static void VSaaSUpdateContractInfoHandle(const VSaaSContractInfo *contract_info)
{
    printf("Enter %s\n", __func__);
    // 打印合约信息
    printf("合约类型:%u\n", contract_info->contract_type);
    printf("最大录制时长:%d秒\n", contract_info->event_recording_max_sec);
    printf("最大帧率:%d fps\n", contract_info->video_max_fps);
    printf("最大码率:%d kbps\n", contract_info->recording_max_kbps);
    printf("最大分辨率:%dx%d\n", contract_info->video_max_width, contract_info->video_max_high);

    // 保存合约信息(设备端需按此调整录像参数)
    memcpy(&gVsaasContractInfo, contract_info, sizeof(VSaaSContractInfo));
}
说明:需包含 VSaaSContractInfo 结构体定义头文件(参考SDK文档)

五、注意事项

公版 Kalay APP 适配:需修改密码验证回调,增加对账号 "vsaas" 的支持(云服务器取流时使用该账号认证)。
int ExPasswordAuthCallBackFn(const char *account, char *pwd, unsigned int pwd_buf_size)
{
    // 允许设备默认账号和 "vsaas" 账号认证
    if (strcmp(account, gAvAccount) != 0 && strcmp(account, "vsaas") != 0) {
        return -1;  // 账号不匹配
    }

    // 密码缓冲区长度校验
    if (pwd_buf_size <= strlen(gAvPassword)) {
        return -1;  // 缓冲区不足
    }

    // 填充密码
    strcpy(pwd, gAvPassword);
    return 0;  // 认证成功
}
说明:gAvAccount、gAvPassword 为设备端默认音视频认证账号密码

六、优化策略(实时流模式)

实时流默认云端拉取 30s 流,设备端可通过智能算法(如人形识别、宠物识别)动态调整存储时长,节省云存储空间。
示例场景:10:00:00 侦测到人形→通知云端取流;10:00:10 人形消失→停止送流→关闭连接(最终存储10s)。
设备端操作步骤
1. 识别连接来源:判断 IOTC 连线是否为云服务器发起(通过账号 "vsaas" 区分);
2. 标记 avIndex:记录该连接对应的音视频流索引(avIndex);
3. 动态停止存储:检测到无需继续存储时,停止向该 avIndex 推送音视频数据;
4. 安全关闭连接:等待 avIndex 中缓存的流全部发送完成后,关闭连接。

七、参考资源

即刻开启您的物联网之旅

联系解决方案专家
Kalay App
资讯安全白皮书
全球专利布局
解决方案
新闻动态
公司动态
行业资讯
媒体报道
永续发展
经营者的话
社会参与
环境永续
公司治理

+86 755 27702549

7×24小时服务热线

法律声明 隐私权条款

关注“TUTK”

TUTK服务尽在掌握

© 2022 物联智慧科技(深圳)有限公司版权所有粤ICP备14023641号
在线咨询
扫一扫

TUTK服务尽在掌握

全国免费服务热线
+86 755 27702549

返回顶部