主页 > 软件开发  > 

通过多线程同时获取H264和H265码流

通过多线程同时获取H264和H265码流

目录

一.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码流