基于AVAPIs模块开发网络摄像机-APP端
更新日期:2025/2/13
目录
相关sdk demo路径说明
| 平台 | 例子 |
|---|---|
| android | SDK目录\Sample\Android\Sample_AVAPIs_Client |
| ios | SDK目录\Sample\iOS\Sample_AVAPIs |
| windows | SDK目录\Sample\Windows\Sample_AVAPIs_Client |
| mac | SDK目录\Sample\MAC\Sample_AVAPIs |
常见的配网方式
可以参考:常见的配网方式实作纲要
连线和数据传输
主要使用的API: IOTCAPIs+AVAPIs
流程图:

连线
连线先使用IOTC_Get_SessionID获取一个空闲的sid,然后调用IOTC_Connect_ByUIDEx去连线设备。
// 获取会话ID
tmpSID = IOTC_Get_SessionID();
if (tmpSID < 0) {
printf("[%s:%d]IOTC_Get_SessionID failed ret[%d]\n",
__FUNCTION__, __LINE__, tmpSID);
pthread_exit(0);
}
printf("[%s:%d]IOTC_Get_SessionID tmpSID[%d]\n",
__FUNCTION__, __LINE__, tmpSID);
// 配置连接参数
IOTCConnectInput connect_input;
connect_input.cb = sizeof(connect_input);
connect_input.authentication_type = AUTHENTICATE_BY_KEY;
connect_input.timeout = 20; // 连线超时时间(秒)
// 复制认证密钥
memcpy(connect_input.auth_key,
gDemoConfig.iotc_auth_key,
IOTC_AUTH_KEY_LENGTH);
// 建立IOTC连接
SID = IOTC_Connect_ByUIDEx(uid, tmpSID, &connect_input);IOTC_Connect_ByUIDEx连线成功(即 >= 0),则返回本次连线的session ID,失败则返回相关报错,常见为-90,-42,-19等。
【其他】参考:IOTC_Connect_ByUID_Parallel,IOTC_Connect_Stop_BySID,IOTC_Session_Close
创建传输通道
因为IOTCAPIs通道为不可靠传输,所以通常会创建一个AV通道,专门用以可靠传输音视频和信令数据。创建方法可参考:
// 初始化AV客户端配置结构体
AVClientStartInConfig avClientInConfig;
AVClientStartOutConfig avClientOutConfig;
// 清空输入配置结构体
memset(&avClientInConfig, 0, sizeof(avClientInConfig));
// 配置输入参数
avClientInConfig.cb = sizeof(AVClientStartInConfig);
avClientInConfig.iotc_channel_id = 0; // AV通道需使用的IOTC通道ID,范围[0,31]
avClientInConfig.iotc_session_id = SID;// 关联的会话ID(参考上一步连线)
avClientInConfig.timeout_sec = 30;
avClientInConfig.resend = 1; // 1=开启重传,0=关闭重传
// 配置安全模式
if (ENABLE_DTLS) {
avClientInConfig.security_mode = AV_SECURITY_DTLS; // 使用DTLS加密
} else {
avClientInConfig.security_mode = AV_SECURITY_SIMPLE;// 使用TUTK加密
}
// 配置认证方式
if (AUTH_BY_TOKEN) {
// 使用Token验证(可传输更长的验证数据)
avClientInConfig.account_or_identity = gDemoConfig.av_identity;
avClientInConfig.password_or_token = gDemoConfig.av_token;
avClientInConfig.auth_type = AV_AUTH_TOKEN;
} else {
// 使用密码验证(验证数据较短)
avClientInConfig.account_or_identity = gDemoConfig.av_account;
avClientInConfig.password_or_token = gDemoConfig.av_password;
avClientInConfig.auth_type = AV_AUTH_PASSWORD;
}
// 配置输出参数
avClientOutConfig.cb = sizeof(AVClientStartOutConfig);
// 开启AV通道
avIndex = avClientStartEx(&avClientInConfig, &avClientOutConfig);【其他】参考:avClientStart,avClientStart2,avServStop,avServExit。
数据传输
AVAPIs提供了透传的通道,针对不同的数据类型,提供了不同的传输API对。
- 图像:avSendFrameData / avRecvFrameData2
- 声音:avSendAudioData / avRecvAudioData
- IO控制:avSendIOCtrl / avRecvIOCtrl //io指令的定义,可以参考SDK Readme.html的AV Module Reference of AV IO Control部分,也可以自定义格式
接收视频:
APP先发送指令,再开线程接收视频:
// 初始化AV流控制消息结构体
SMsgAVIoctrlAVStream ioMsg;
memset(&ioMsg, 0, sizeof(SMsgAVIoctrlAVStream));
// 发送AV流控制指令(启动IPCAM流)
int ret = avSendIOCtrl(
avIndex,
IOTYPE_USER_IPCAM_START,
(char*)&ioMsg,
sizeof(SMsgAVIoctrlAVStream)
);
if (ret < 0) {
printf("start_ipcam_stream failed[%d]\n", ret);
return 0;
}接收视频主要代码:
unsigned int frmNo;
int outBufSize = 0;
int outFrmSize = 0;
int outFrmInfoSize = 0;
bool need_key_frame = false;
int video_buf_size = VIDEO_BUF_SIZE;
char* buf = new char[VIDEO_BUF_SIZE];
FRAMEINFO_t frameInfo;
// 循环接收视频帧数据
while (1) {
// 接收AV帧数据
int ret = avRecvFrameData2(
avIndex,
buf,
video_buf_size,
&outBufSize,
&outFrmSize,
(char*)&frameInfo,
sizeof(FRAMEINFO_t),
&outFrmInfoSize,
&frmNo
);
// 处理接收结果
if (ret <= 0) {
// 数据未准备好,短暂等待后继续
if (ret == AV_ER_DATA_NOREADY) {
usleep(5 * 1000); // 5ms延迟
continue;
}
// 帧丢失或不完整
else if (ret == AV_ER_LOSED_THIS_FRAME || ret == AV_ER_INCOMPLETE_FRAME) {
printf("Recv video, Lost video frame NO[%d]\n", frmNo);
need_key_frame = true; // 标记需要等待I帧
}
// 缓冲区大小不足
else if (ret == AV_ER_BUFPARA_MAXSIZE_INSUFF) {
printf("Video buffer is too small to store frame[%d]\n", frmNo);
// 提示:需增大视频缓冲区或帧信息缓冲区
resizeVideoBuffer(); // 或调用resizeFrameInfoBuffer()
need_key_frame = true; // 标记需要等待I帧
continue;
}
// 其他错误,退出循环
else {
printf("Recv video, error code[%d], will break;\n", ret);
break;
}
}
// 处理关键帧需求
if (need_key_frame) {
// 检查是否为I帧
if (frameInfo.flags == IPC_FRAME_FLAG_IFRAME) {
need_key_frame = false; // 已获取I帧,清除标记
} else {
continue; // 跳过非I帧
}
}
// 实际接收的帧大小:ret
// 数据处理逻辑:
// 1. 把数据拷贝到解码队列
// 2. 初始化播放器
// 3. 解码并显示图像
// 注意:第一帧需要从I帧开始处理,否则会解码失败
}
// 释放资源
delete[] buf;
buf = NULL;接收音频:
APP先发送指令,再开线程接收声音:
// 发送AV流控制指令(启动IPCAM音频流)
int ret = avSendIOCtrl(
avIndex,
IOTYPE_USER_IPCAM_AUDIOSTART,
(char*)&ioMsg,
sizeof(SMsgAVIoctrlAVStream)
);
if (ret < 0) {
printf("start_ipcam_audio_stream failed[%d]\n", ret);
return 0;
}接收声音的主要代码:
// 音频缓冲区和帧信息结构体
char buf[AUDIO_BUF_SIZE];
FRAMEINFO_t frameInfo;
unsigned int frmNo; // 补充帧号变量定义
// 循环接收音频数据
while (1) {
// 接收音频帧数据
int ret = avRecvAudioData(
avIndex,
buf,
AUDIO_BUF_SIZE,
(char*)&frameInfo,
sizeof(FRAMEINFO_t),
&frmNo
);
// 处理接收结果
if (ret <= 0) {
// 数据未准备好,短暂等待后继续
if (ret == AV_ER_DATA_NOREADY) {
usleep(5 * 1000); // 5ms延迟
continue;
}
// 帧丢失或不完整
else if (ret == AV_ER_LOSED_THIS_FRAME || ret == AV_ER_INCOMPLETE_FRAME) {
printf("Recv audio, Lost audio frame NO[%d]\n", frmNo);
#if _ENABLE_FILL_LAST_FRAME_
// 音频线性特性允许使用上一帧填充丢失帧
memcpy(dst_audio_buf, last_audio_frame, last_audio_size);
#else
continue; // 不填充丢失帧,直接跳过
#endif
}
// 其他错误,退出循环
else {
printf("Recv audio, error code[%d], will break;\n", ret);
break;
}
}
// 实际接收的帧大小:ret
// 数据处理逻辑:
// 1. 把数据拷贝到解码队列
// 2. 初始化播放器
// 3. 解码并播放声音
}需要注意的问题:
- 视频和音频的接收需要分开不同线程处理,以免互相影响。
- 接收和解码播放需要分开不同线程处理,以免互相影响。
- 视频第一帧需从I帧开始处理,如果中途丢帧,需要等下一个I帧才继续处理。
对讲:
可以参考:基于AVAPIs的对讲实现
常见问题以及处理
| 问题 | 说明 | 处理举措 |
|---|---|---|
| AV_ER_INVALID_ARG/-20000 | 参数错误,常见的是结构体参数没有合理赋值,其他情况也能是avIndex被关闭了。 | 检查结构体参数是否填写合理,检查avIndex是否已被关闭。 |
| AV_ER_INVALID_SID/-20010 | 传入的Session id无效,或者连接已被关闭 | 检查参数是否正确,如果是连接已被关闭,则释放资源。 |
| AV_ER_EXCEED_MAX_SIZE/-20006 | 设备端缓存区已满 | 清缓存,降码率 |
| AV_ER_IOTC_CHANNEL_IN_USED/-20027 | avClientStartEx或者avServStartEx里面使用的iotc channel id已经被占用 | 换其他的iotc channel id |
| AV_ER_SESSION_CLOSE_BY_REMOTE/-20015 | 对端已经关闭连接 | 停止收发数据,关闭通道,关闭连接 |
| AV_ER_TIMEOUT/-20011 | 超时 |
根据不同API,做不同处理。 avClientStartEx/avServStartEx出现此报错,则需要关闭连接。 avRecvIOCtrl出现此报错,continue即可。 |
相关头文件说明
| 头文件 | 说明 |
|---|---|
| AVFRAMEINFO.h | 帧信息定义 |
| AVIOCTRLDEFs.h | IO控制指令定义 |
| TUTKGlobalAPIs.h | 全局的设定 |
| IOTCClient.h | 客户端连线相关专用接口定义 |
| IOTCCommon.h | 通用接口,默认值,错误码定义 |
| IOTCDevice.h | 设备端连线相关专用接口定义 |
| AVClient.h | 客户端数据发送相关接口定义 |
| AVCommon.h | 通用接口,默认值,错误码定义 |
| AVServer.h | 设备端数据发送相关接口定义 |
| VSaaS.h | 云存储相关接口定义 |
| DASA.h | 码流自适应接口定义 |
其他文章:
