通过多线程同时获取H264和H265码流
- 软件开发
- 2025-09-13 21:39:01

目录
一.RV1126 VI采集摄像头数据并同时编码H264、H265的大概流程编辑编辑
1.1初始化VI模块:
1.2H264、H265的VENC模块初始化:
1.3VI分别绑定H264的VENC层和H265的VENC层:
1.4开启H264线程采集H264的VENC数据:
1.5开启H265线程采集H265的VENC数据:
二.代码实战:
一.RV1126 VI采集摄像头数据并同时编码H264、H265的大概流程
RV1126利用多线程同时获取H264文件、H265文件的过程一般分为上图的7步骤,分别是:VI模块的初始化、H264的VENC模块初始化、H265的VENC模块初始化、VI绑定H264的VENC模块、VI绑定H265的VENC模块,开启H264线程获取H264码流并保存、开启H265线程获取H265码流并保存。
1.1初始化VI模块:VI模块的初始化实际上就是对VI_CHN_ATTR_S的参数进行设置、然后调用RK_MPI_VI_SetChnAttr设置VI模块并使能RK_MPI_VI_EnableChn,伪代码如下:
VI_CHN_ATTR_S vi_chn_attr;
。。。。。。。。。。。。。。。(这里是设置VI的属性)
ret = RK_MPI_VI_SetChnAttr(CAMERA_ID, 0, &vi_chn_attr);
ret |= RK_MPI_VI_EnableChn(CAMERA_ID, 0);
1.2H264、H265的VENC模块初始化:VENC_CHN_ATTR_S h264_venc_chn_attr;
..................................
RK_MPI_VENC_CreateChn(H264_VENC_CHN, &h264_venc_chn_attr);
VENC_CHN_ATTR_S h265_venc_chn_attr;
..................................
RK_MPI_VENC_CreateChn(H265_VENC_CHN, &h265_venc_chn_attr);
注意:这里需要创建两个编码器层,分别是H264编码器和H265编码器。
1.3VI分别绑定H264的VENC层和H265的VENC层:VI节点分别绑定H264的VENC节点和H265节点,伪代码如下:
//VI模块节点的设置
MPP_CHN_S vi_chn_s;
vi_chn_s.enModId = RK_ID_VI;
vi_chn_s.s32ChnId = 0;
//H264的VENC模块节点设置
MPP_CHN_S h264_venc_chn_s;
h264_venc_chn_s.enModId = RK_ID_VENC;
h264_venc_chn_s.s32ChnId = H264_VENC_CHN;
ret = RK_MPI_SYS_Bind(&vi_chn_s, &h264_venc_chn_s);
//H265的VENC模块节点设置
MPP_CHN_S h265_venc_chn_s;
h265_venc_chn_s.enModId = RK_ID_VENC;
h265_venc_chn_s.s32ChnId = H265_VENC_CHN;
ret = RK_MPI_SYS_Bind(&vi_chn_s, &h265_venc_chn_s);
1.4开启H264线程采集H264的VENC数据:开启一个线程去采集每一帧H264的VENC模块数据,使用的API是RK_MPI_SYS_GetMediaBuffer, 模块ID是RK_ID_VENC,通道号ID是H264 VENC创建的ID号。这个API伪代码如下:
while(1)
{
.........................
mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VENC, H264_VENC_CHN, -1);
fwrite(RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb), 1, h264_file);
.......................
}
1.5开启H265线程采集H265的VENC数据:开启一个线程去采集每一帧H265的VENC模块数据,使用的API是RK_MPI_SYS_GetMediaBuffer, 模块ID是RK_ID_VENC,通道号ID是H265 VENC创建的ID号。这个API伪代码如下:
while(1)
{
.........................
mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VENC, H265_VENC_CHN, -1);
fwrite(RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb), 1, h265_file);
.......................
}
二.代码实战: #include <assert.h> #include <fcntl.h> #include <getopt.h> #include <pthread.h> #include <signal.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <time.h> #include <unistd.h> // #include "common/sample_common.h" #include "rkmedia_api.h" #define CAMERA_PATH "rkispp_scale0" #define CAMERA_ID 0 #define CAMERA_CHN 0 #define H264_VENC_CHN 0 #define H265_VENC_CHN 1 //创建线程获取H264码流数据并保存 void * get_h264_stream_thread(void * args) { pthread_detach(pthread_self()); FILE * h264_file = fopen("test_camera.h264", "w+"); MEDIA_BUFFER mb ; while (1) { //获取每一帧H264编码码流 mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VENC, H264_VENC_CHN, -1); if(!mb) { printf("Get H264_Venc Buffer break....\n"); break; } fwrite(RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb), 1, h264_file); RK_MPI_MB_ReleaseBuffer(mb); } return NULL; } //创建线程获取H265码流数据并保存 void * get_h265_stream_thread(void * args) { pthread_detach(pthread_self()); FILE * h265_file = fopen("test_camera.h265", "w+"); MEDIA_BUFFER mb ; while (1) { //获取每一帧H265编码码流 mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VENC, H265_VENC_CHN , -1); if(!mb) { printf("Get H265_VENC Buffer break...\n"); break; } fwrite(RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb), 1, h265_file); RK_MPI_MB_ReleaseBuffer(mb); } return NULL; } int main(int argc, char *argv[]) { int ret; VI_CHN_ATTR_S vi_chn_attr; vi_chn_attr.pcVideoNode = CAMERA_PATH; //设置视频设备节点路径 vi_chn_attr.u32Width = 1920; //设置分辨率的宽度 vi_chn_attr.u32Height = 1080; //设置分辨率的高度 vi_chn_attr.enPixFmt = IMAGE_TYPE_NV12; //设置图像类型 vi_chn_attr.enBufType = VI_CHN_BUF_TYPE_MMAP;//设置VI获取类型 vi_chn_attr.u32BufCnt = 3; //设置缓冲数量 vi_chn_attr.enWorkMode = VI_WORK_MODE_NORMAL; //设置VI工作类型 ret = RK_MPI_VI_SetChnAttr(CAMERA_ID, CAMERA_CHN, &vi_chn_attr); if(ret) { printf("Vi Set Attr Failed.....\n"); return 0; } else { printf("Vi Set Attr Success.....\n"); } ret = RK_MPI_VI_EnableChn(CAMERA_ID, CAMERA_CHN); if(ret) { printf("Vi Enable Attr Failed.....\n"); return 0; } else { printf("Vi Enable Attr Success.....\n"); } VENC_CHN_ATTR_S h264_venc_chn_attr; //****** H264 设置VENC基础属性 ************************// h264_venc_chn_attr.stVencAttr.enType = RK_CODEC_TYPE_H264; //设置编码器类型 h264_venc_chn_attr.stVencAttr.u32PicWidth = 1920;//设置编码分辨率宽度 h264_venc_chn_attr.stVencAttr.u32PicHeight = 1080;//设置编码分辨率高度 h264_venc_chn_attr.stVencAttr.u32VirWidth = 1920;//设置编码分辨率虚宽 h264_venc_chn_attr.stVencAttr.u32VirHeight = 1080;//设置编码分辨率虚高 h264_venc_chn_attr.stVencAttr.u32Profile = 66;//设置编码等级 h264_venc_chn_attr.stVencAttr.imageType = IMAGE_TYPE_NV12;//设置编码图像类型 h264_venc_chn_attr.stVencAttr.enRotation = VENC_ROTATION_0;//设置编码的旋转角度 //********* H264 设置H264码率控制属性 *******************// h264_venc_chn_attr.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR; //设置H264的CBR码率控制模式 h264_venc_chn_attr.stRcAttr.stH264Cbr.u32Gop = 25;//设置GOP关键帧间隔 //25/1 NUM/DEN == FrameRate h264_venc_chn_attr.stRcAttr.stH264Cbr.u32SrcFrameRateDen = 1; //设置源帧率分母 h264_venc_chn_attr.stRcAttr.stH264Cbr.u32SrcFrameRateNum = 25;//设置源帧率分子 h264_venc_chn_attr.stRcAttr.stH264Cbr.fr32DstFrameRateDen = 1;//设置目标帧率分母 h264_venc_chn_attr.stRcAttr.stH264Cbr.fr32DstFrameRateNum = 25;//设置目标帧率分子 h264_venc_chn_attr.stRcAttr.stH264Cbr.u32BitRate = 8388608; //设置码率大小 ret = RK_MPI_VENC_CreateChn(H264_VENC_CHN, &h264_venc_chn_attr); if(ret) { printf("Create H264 Venc Failed .....\n"); return 0; } else { printf("Create H264 Venc Success .....\n"); } VENC_CHN_ATTR_S h265_venc_chn_attr; //****** H265 设置VENC基础属性 ************************// h265_venc_chn_attr.stVencAttr.enType = RK_CODEC_TYPE_H265;//设置编码器类型 h265_venc_chn_attr.stVencAttr.u32PicWidth = 1920;//设置编码分辨率宽度 h265_venc_chn_attr.stVencAttr.u32PicHeight = 1080;//设置编码分辨率高度 h265_venc_chn_attr.stVencAttr.u32VirWidth = 1920;//设置编码分辨率虚宽 h265_venc_chn_attr.stVencAttr.u32VirHeight = 1080;//设置编码分辨率虚高 h265_venc_chn_attr.stVencAttr.u32Profile = 77;//设置编码等级 h265_venc_chn_attr.stVencAttr.imageType = IMAGE_TYPE_NV12;//设置编码图像类型 h265_venc_chn_attr.stVencAttr.enRotation = VENC_ROTATION_0;//设置编码的旋转角度 //********* H265 VENC RCMODE Set *******************// h265_venc_chn_attr.stRcAttr.enRcMode = VENC_RC_MODE_H265CBR;//设置H265的CBR码率控制模式 h265_venc_chn_attr.stRcAttr.stH264Cbr.u32Gop = 25;//设置GOP关键帧间隔 //25/1 NUM/DEN == FrameRate h265_venc_chn_attr.stRcAttr.stH265Cbr.u32SrcFrameRateDen = 1; //设置源帧率分母 h265_venc_chn_attr.stRcAttr.stH265Cbr.u32SrcFrameRateNum = 25;//设置源帧率分子 h265_venc_chn_attr.stRcAttr.stH265Cbr.fr32DstFrameRateDen = 1;//设置目标帧率分母 h265_venc_chn_attr.stRcAttr.stH265Cbr.fr32DstFrameRateNum = 25;//设置目标帧率分子 h265_venc_chn_attr.stRcAttr.stH265Cbr.u32BitRate = 8388608; //设置码率大小 ret = RK_MPI_VENC_CreateChn(H265_VENC_CHN, &h265_venc_chn_attr); if(ret) { printf("Create H265 Venc Failed .....\n"); return 0; } else { printf("Create H265 Venc Success .....\n"); } //VI_CHN MPP_CHN_S vi_chn_s; vi_chn_s.enModId = RK_ID_VI; vi_chn_s.s32ChnId = CAMERA_CHN; //H264_VENC_CHN MPP_CHN_S h264_chn_s; h264_chn_s.enModId = RK_ID_VENC; h264_chn_s.s32ChnId = H264_VENC_CHN; //H265_VENC_CHN MPP_CHN_S h265_chn_s; h265_chn_s.enModId = RK_ID_VENC; h265_chn_s.s32ChnId = H265_VENC_CHN; //VI Bind H264_VENC ret = RK_MPI_SYS_Bind(&vi_chn_s, &h264_chn_s); if(ret) { printf("Vi Bind H264_Venc Failed .....\n"); } else { printf("Vi Bind H264_Venc Success .....\n"); } //VI Bind H265_VENC ret = RK_MPI_SYS_Bind(&vi_chn_s, &h265_chn_s); if(ret) { printf("Vi Bind H265_Venc Failed .....\n"); } else { printf("Vi Bind H265_Venc Success .....\n"); } pthread_t h264_pid, h265_pid; pthread_create(&h264_pid, NULL, get_h264_stream_thread, NULL);//创建线程获取H264码流数据并保存 pthread_create(&h265_pid, NULL, get_h265_stream_thread, NULL);//创建线程获取H265码流数据并保存 while (1) { sleep(1); } RK_MPI_SYS_UnBind(&vi_chn_s, &h264_chn_s); RK_MPI_SYS_UnBind(&vi_chn_s, &h265_chn_s); RK_MPI_VI_DisableChn(0, 0); RK_MPI_VENC_DestroyChn(0); RK_MPI_VENC_DestroyChn(1); return 0; }通过多线程同时获取H264和H265码流由讯客互联软件开发栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“通过多线程同时获取H264和H265码流”
下一篇
Linux系统管理操作