RV1126+FFMPEG推流项目(5)VI和VENC模块绑定,并且开启线程采集

news/2025/1/20 21:16:37/

        回顾一下这个图,前面VI和VENC已经初始化了,现在也已经到了绑定两个模块的时候了。最后才开启线程到通道里面拿数据。 

 

        接下要完成这个两个模块,

rkmedia_assignment_manage.cpp (任务管理模块),管理 RV1126 上的各个任务。主要任务是创建并管理三个线程:
  1. 视频编码线程 (camera_venc_thread)。
  2. 音频编码线程 (audio_aenc_thread)。
  3. 音视频合成推流线程 (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; //获取idvi_channel.enModId = RK_ID_VI; //设定成VI模块,enModId 是一个枚举里面还有很多模块,这里只用到了RK_ID_VI//1.3从VI容器里面获取通道VENC_IDRV1126_VENC_CONTAINER venc_container;get_venc_container(0, &venc_container);venc_channel.s32ChnId = venc_container.venc_id;//获取idvenc_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; //获取idvi_channel.enModId = RK_ID_VI; //设定成VI模块,enModId 是一个枚举里面还有很多模块,这里只用到了RK_ID_VI//1.3从VI容器里面获取通道VENC_IDRV1126_VENC_CONTAINER venc_container;get_venc_container(0, &venc_container);venc_channel.s32ChnId = venc_container.venc_id;//获取idvenc_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");}//释放vencret = RK_MPI_VENC_DestroyChn(venc_arg->vencId);if(ret){printf("venc释放失败");return 0;}//释放viret = RK_MPI_VI_DisableChn(0,0);if(ret){printf("vI释放失败");return 0;}return NULL;
}

 

        详细的源码


http://www.ppmy.cn/news/1564753.html

相关文章

Comment(爆破+git泄漏+二次注入)

通过爆破密码的后三位&#xff0c;获得账号为&#xff1a;zhangwei666 F12查看控制台 使用bugscanteam的githack工具&#xff0c;下载泄漏的源码&#xff0c;根据控制台的提示&#xff0c;完整源码还在历史的commit中 git log –reflog 查看历史记录 查看最新的提交记录&#…

@Scope(“prototype“)

Scope("prototype") 是 Spring 框架中用于定义 Bean 作用域的注解之一&#xff0c;它的主要作用是将一个 Bean 定义成 原型作用域&#xff08;Prototype Scope&#xff09;。在原型作用域下&#xff0c;每次从 Spring 容器中请求这个 Bean 时&#xff0c;都会创建一个…

Windows蓝牙驱动开发-蓝牙 IOCTL

蓝牙驱动程序堆栈为配置文件驱动程序提供了多个 IOCTL&#xff0c;来收集有关以下内容的信息&#xff1a; 本地蓝牙无线电和系统&#xff1b; 远程蓝牙设备&#xff1b; 会使即插即用 (PnP) 管理器加载配置文件驱动程序的设备&#xff1b; 为收集有关本地蓝牙无线电和系统的…

Ceph与RAID在存储中的协同工作过程

本文将结合架构图&#xff0c;详细讲解Ceph与RAID如何在存储环境中相互配合&#xff0c;共同提供高效且可靠的存储服务。 架构概述 从上图中可以看到&#xff0c;Ceph的架构主要分为四个层次&#xff1a; 客户端和服务接口层&#xff1a;这一层包括客户端访问存储应用的接口…

【深度学习】Pytorch:CUDA 模型训练

在深度学习中&#xff0c;GPU 的强大计算能力能极大地提升模型训练的速度。PyTorch 提供了对 CUDA&#xff08;Compute Unified Device Architecture&#xff09;的原生支持&#xff0c;使得在 GPU 上运行深度学习模型变得简单高效。本文将详细讲解如何使用 PyTorch 在 CUDA 上…

BERT详解

1.背景结构 1.1 基础知识 BERT(Bidirectional Encoder Representations from Transformers)是谷歌提出,作为一个Word2Vec的替代者,其在NLP领域的11个方向大幅刷新了精度,可以说是前几年来自残差网络最优突破性的一项技术了。论文的主要特点以下几点: 使用了双向Transfo…

.NET8.0多线程编码结合异步编码示例

1、创建一个.NET8.0控制台项目来演示多线程的应用 2、快速创建一个线程 3、多次运行程序&#xff0c;可以得到输出结果 这就是多线程的特点 - 当多个线程并行执行时&#xff0c;它们的具体执行顺序是不确定的&#xff0c;除非我们使用同步机制&#xff08;如 lock、信号量等&am…

CTTSHOW-WEB入门-信息搜集11-20

web11 1. 题目&#xff1a; 2. 解题步骤及思路&#xff1a;本题的flag已经给出&#xff0c;主要考点是考察域名的查询&#xff0c;通过查询有时候也可以得到一些有用的信息。 3. 相关知识点&#xff1a;查询域名可以使用nslookup命令使用方法如下&#xff1a;&#xff08;windo…