通过多线程同时获取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;
}