回首一下这个图,前面VI和VENC已经初始化了,现在也已经到了绑定两个模块的时候了。末了才开启线程到通道内里拿数据。
接下要完成这个两个模块,
rkmedia_assignment_manage.cpp (任务管理模块),管理 RV1126 上的各个任务。重要任务是创建并管理三个线程:
- 视频编码线程 (camera_venc_thread)。
- 音频编码线程 (audio_aenc_thread)。
- 音视频合成推流线程 (push_server_thread)。
rkmedia_data_process.cpp (数据处置惩罚模块)
- 实现了三个线程的具体功能:
- 视频编码线程:处置惩罚视频编码和数据存储。
- 音频编码线程:处置惩罚音频编码和数据存储。
- 音视频合成并推流线程:将音视频数据举行合成并推送到服务器。
今天的任务: //1.VI和VENC绑定,//2.开启线程收罗视频
- int init_rv1126_first_assignment(int protocol_type, char* network_addr)
- {
- //1.VI和VENC绑定
- //2.开启线程采集视频
- }
复制代码 第一步:VI和VENC绑定,我们先来认识一个数据结构"MPP_CHN_S"和一个函数“RK_MPI_SYS_Bind()”,这个结构体也是来自rv1126手册的。
RK_MPI_SYS_Bind() :
看到这个函数 ,有两个参数,这两个参数就是这两个模块,以是先要界说出来
- //绑定vi和venc
- //不绑定venc就无法从vi模块拿到数据进行编码
- ret = RK_MPI_SYS_Bind(&vi_channel, &venc_channel);
- if(ret != 0)
- {
- printf("绑定失败\n");
- return -1;
- }
- //成功
- printf("绑定成功");
复制代码 MPP_CHN_S:
在rv1126上面,有怎么多的模块,怎么管理的?接纳一个先描述后组织的思想,先描述:MPP_CHN_S这个是在rv1126上面描述一个模块的结构体,后组织:就是用什么把他管理起来,链表还是数组,这里没有用到先不说。
- int init_rv1126_first_assignment(int protocol_type, char* network_addr)
- {
- //1.VI和VENC绑定
- //1.1定义出VI和VENC模块
- MPP_CHN_S vi_channel;
- MPP_CHN_S venc_channel;
- //1.2从VI容器里面获取通道VI_ID
- //这里就体现出来容器的作用了,我只要放在公共的容器里面,就可以从其他文件拿到,很好的解偶
- RV1126_VI_CONTAINER vi_container;
- get_vi_container(0, &vi_container);
- vi_channel.s32ChnId = vi_container.vi_id; //获取id
- vi_channel.enModId = RK_ID_VI; //设定成VI模块,enModId 是一个枚举里面还有很多模块,这里只用到了RK_ID_VI
-
- //1.3从VI容器里面获取通道VENC_ID
- RV1126_VENC_CONTAINER venc_container;
- get_venc_container(0, &venc_container);
- venc_channel.s32ChnId = venc_container.venc_id;//获取id
- venc_channel.enModId = RK_ID_VENC;//设定成VI模块
- //绑定
-
- //2.开启线程采集视频
- }
复制代码 开启线程获取摄像头的编码数据:
先来认识几个参数,是和venc哪里拿数据有关的“RK_MPI_SYS_GetMediaBuffer”这个函数是从指定通道中获取VENC数据。假设获取数据是mb, mb数据有两部门构成,有用数据和数据的大小。
RK_MPI_SYS_GetMediaBuffer:
“RK_MPI_MB_GetPtr”获取到mb内里的有用数据,RK_MPI_MB_GetSize这个mb数据是多大
RK_MPI_MB_GetPtr:
RK_MPI_MB_GetSize:
rkmedia_assignment_manage.cpp :
- int init_rv1126_first_assignment(int protocol_type, char* network_addr){ int ret; //1.VI和VENC绑定 //1.1界说出VI和VENC模块 MPP_CHN_S vi_channel; MPP_CHN_S venc_channel; //1.2从VI容器内里获取通道VI_ID //这里就表现出来容器的作用了,我只要放在公共的容器内里,就可以从其他文件拿到,很好的解偶 RV1126_VI_CONTAINER vi_container; get_vi_container(0, &vi_container); vi_channel.s32ChnId = vi_container.vi_id; //获取id vi_channel.enModId = RK_ID_VI; //设定成VI模块,enModId 是一个枚举内里还有很多模块,这里只用到了RK_ID_VI //1.3从VI容器内里获取通道VENC_ID RV1126_VENC_CONTAINER venc_container; get_venc_container(0, &venc_container); venc_channel.s32ChnId = venc_container.venc_id;//获取id venc_channel.enModId = RK_ID_VENC;//设定成VI模块 //绑定vi和venc
- //不绑定venc就无法从vi模块拿到数据进行编码
- ret = RK_MPI_SYS_Bind(&vi_channel, &venc_channel);
- if(ret != 0)
- {
- printf("绑定失败\n");
- return -1;
- }
- //成功
- printf("绑定成功"); //2.创建VENC线程,获取摄像头编码数据 //VENC线程的参数 VENC_PROC_PARAM* venc_arg_params = ( VENC_PROC_PARAM*)malloc(sizeof( VENC_PROC_PARAM)); venc_arg_params->vencId = vi_channel.s32DevId; //保存这个通道号,内里要通过这个id号获取 pthread_t pid; ret = pthread_create(&pid, NULL, camera_venc_thread, (void*)venc_arg_params);}
复制代码 rkmedia_data_process.cpp:
- //视频编码线程,并把数据放到队列里面去
- void * camera_venc_thread(void *args)
- {
- int ret;
- pthread_detach(pthread_self());//线程分离,主线程不用等待回收了,自动释放资源
- MEDIA_BUFFER mb = NULL; //定义一个媒体缓存区,用于接受编码器的输出数据
-
- VENC_PROC_PARAM *venc_arg = static_cast< VENC_PROC_PARAM *>(args);//可以直接强转,但是最高根安全一点
- free(args); //参数解析到了,释放传入的内存
- printf("线程启动成功");
- while(1) //开始获取和处理venc数据
- {
- //从指定RK_ID_VENC模块的venc_arg->vencId通道里面拿数据, -1就是非阻塞
- mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VENC, venc_arg->vencId, -1);
- if(!mb)
- {
- printf("获取数据失败了\n");
- break;
- }
- //把取出的数据存储到一个一个的视频包里面,分配数据结构
- video_data_packet_t *video_data_packet = (video_data_packet_t* )malloc(sizeof(video_data_packet_t));
- //把数据拷贝进去视频包里面,mb数据由两部分组成,有效数据和数据的大小
- memcpy(video_data_packet->buffer, RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb) );
- //把venc视频数据缓冲区数据的大小传到video_frame_size
- video_data_packet->video_frame_size = RK_MPI_MB_GetSize(mb);
- //把视频包入到队列里面
- video_queue->putVideoPacketQueue(video_data_packet);//todo......
-
- //释放mb,重新获取下一个包
- RK_MPI_MB_ReleaseBuffer(mb);
- }
- //到这里就是没数据了,就要把资源释放
- //解绑定
- MPP_CHN_S vi_channel;
- MPP_CHN_S venc_channel;
- vi_channel.s32ChnId = 0; //摄像头通道是0,也可以把vi通道号的参数一起传进来
- vi_channel.enModId = RK_ID_VI;
-
- venc_channel.s32ChnId = venc_arg->vencId; //venc通道函数
- venc_channel.enModId = RK_ID_VENC;
-
- ret = RK_MPI_SYS_UnBind(&vi_channel, &venc_channel);
- if(ret != 0)
- {
- printf("VI和VENC解绑失败\n");
- }
- else
- {
- printf("VI和VENC解绑成功\n");
- }
- //释放venc
- ret = RK_MPI_VENC_DestroyChn(venc_arg->vencId);
- if(ret)
- {
- printf("venc释放失败");
- return 0;
- }
- //释放vi
- ret = RK_MPI_VI_DisableChn(0,0);
- if(ret)
- {
- printf("vI释放失败");
- return 0;
- }
- return NULL;
- }
复制代码
具体的源码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |