RV1126+FFMPEG推流项目(9)AI和AENC模块绑定,并且开启线程采集
前面两篇已经交代AI和AENC模块的配置,这篇就让这两个模块绑定起来,绑定的原因是,Aenc从Ai模块拿到采集的原始数据进行编码。
使用 RK_MPI_SYS_Bind 把 AI 节点和 AENC 进行绑定,其中 enModId 是模块 ID 号选择的是 RK_ID_AI、s32ChnId 是通道号,通道号则从容器 AENC 容器获取。开启 AENC 线程采集每一帧视频编码数据并存储到音频队列。
绑定的函数是有rv1126通过的, RK_MPI_SYS_Bind,先来认识一下这个数据结构。
看到RK_MPI_SYS_Bind的参数是两个需要绑定模块,这两个数据结构,在之前说视频模块绑定的时候,已经说过了这两个参数。这里我偷懒一下,不说了。
{
//1.VI和VENC绑定
//1.1定义出AI和AENC模块
MPP_CHN_S ai_channel;
MPP_CHN_S aenc_channel;
//1.2先把容器里面的id获取出来
RV1126_AI_CONTAINER ai_container;
get_ai_container(0, &ai_container);
RV1126_AENC_CONTAINER aenc_container;
get_aenc_container(0, &aenc_container);
ai_channel.s32ChnId = ai_container.ai_id;
ai_channel.enModId = RK_ID_AI; //这里用的AI模块,选AI
aenc_channel.s32ChnId = aenc_container.aenc_id;
aenc_channel.enModId = RK_ID_AENC;//这里用的AENC模块,选AENC
//AI和VENC绑定
ret = RK_MPI_SYS_Bind(&ai_channel, &aenc_channel);
if(ret != 0)
{
printf("AI和VENC绑定失败\n");
}
else
{
printf("AI和VENC绑定成功\n");
}
}
绑定之后就开启线程,开始获取一帧一帧数据包。
//线程参数
AENC_PROC_PARAM * aenc_proc_param = (AENC_PROC_PARAM*)malloc(sizeof(AENC_PROC_PARAM));
aenc_proc_param->aenc_id = aenc_channel.s32ChnId;
//2.创建AENC线程,获取音频编码数据
pthread_t a_pid;
ret = pthread_create(&a_pid, NULL,audio_aenc_thread, (void*)aenc_proc_param);
线程处理流程:
//获取编码数据的线程
void* audio_aenc_thread(void* args)
{
int ret;
//线程分离,自己回收资源
pthread_detach(pthread_self());
MEDIA_BUFFER mb = NULL;定义一个媒体缓存区,用于接受编码器的输出数据
AENC_PROC_PARAM* aenc_arg = static_cast<AENC_PROC_PARAM*> (args);
free(args);
//一直循环在这里拿数据
while(1)
{
//获取音频编码器的数据
mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_ADEC, aenc_arg->aenc_id, -1);
if(!mb)
{
printf("获取编码器数据失败\n");
break; //推出循环
}
//获取成功
printf("获取编码器数据成功\n");
//为音频包分配一个内存
audio_data_packet_t *audio_packet =(audio_data_packet_t*) malloc(sizeof(audio_data_packet_t));
if(!audio_packet)
{
perror("音频包分配内存失败\n");
}
memset(&audio_packet, 0, sizeof(audio_packet)); //清空内存
//把拿到的音频编码数据拷贝packet包里面去
memcpy(audio_packet, RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb));
//把包的长度拷贝进去
audio_packet->audio_frame_size = RK_MPI_MB_GetSize(mb);
//把packet放到队列里面去
audio_queue->putAudioPacketQueue(audio_packet);
//释放缓存区,方便下一个包使用
RK_MPI_MB_ReleaseBuffer(mb);
}
//到这里就是获取缓存区失败,或者编码器里面没有内容了
//释放绑定的接口,和释放AI和AENC模块
MPP_CHN_S ai_channel;
MPP_CHN_S aenc_channel;
ai_channel.enModId = RK_ID_AI;
ai_channel.s32ChnId = 0 ; //我只有一个是通道,如果有多个通道可以把ai的通道号一起传进来
aenc_channel.enModId = RK_ID_AENC;
aenc_channel.s32ChnId = aenc_arg->aenc_id; //AI的通道号已经被传了进来,所以不用在容器里面拿
ret = RK_MPI_SYS_UnBind(&ai_channel, &aenc_channel);
if(ret != 0 )
{
printf("解绑失败\n");
}
printf("解绑成功\n");
ret = RK_MPI_AENC_DestroyChn(aenc_arg->aenc_id);
if(ret != 0 )
{
printf("AENC销毁失败\n");
}
printf("AENC销毁成功\n");
ret = RK_MPI_AI_DisableChn( 0 );
if(ret != 0)
{
printf("关闭AI模块势能失败\n");
}
printf("关闭AI模块势能成功\n");
return nullptr;
}