通过多线程分别获取高分辨率和低分辨率的H264码流
- 软件开发
- 2025-09-14 06:30:01

目录
一.RV1126 VI采集摄像头数据并同时获取高分辨率码流和低分辨率码流流程
编辑
1.1初始化VI模块:
1.2初始化RGA模块:
1.3初始化高分辨率VENC编码器、 低分辨率VENC编码器:
1.4 VI绑定高分辨率VENC编码器,VI绑定RGA模块,伪代码如下:
1.5 创建多线程获取高分辨率编码数据:
1.6 创建多线程获取低分辨率数据并传输到编码器:
1.7.创建多线程获取低分辨率编码数据:
三.运行的效果:
一.RV1126 VI采集摄像头数据并同时获取高分辨率码流和低分辨率码流流程
RV1126利用多线程同时获取高分辨率编码文件、低分辨率编码文件,一般要分为上图8个步骤:VI模块初始化、RGA图像模块初始化、高分辨率编码器的初始化、低分辨率编码器的初始化、VI绑定高分辨率VENC编码器、创建多线程获取高分辨率编码数据、创建多线程获取低分辨率数据并传输到编码器、创建多线程获取低分辨率编码数据。
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.2初始化RGA模块:RGA主要的作用是缩放VI模块的分辨率,比方说:VI模块的分辨率1920 * 1080,经过RGA缩放后分辨率为1280 * 720,并利用RK_MPI_RGA_CreateChn创建RGA模块,伪代码如下:
RGA_ATTR_S rga_attr;
rga_attr.stImgIn.u32Width = 1920;
rga_attr.stImgIn.u32Height = 1080;
。。。。。。。。。
rga_attr.stImgOut.u32Width = 1280;
rga_attr.stImgOut.u32Height = 720;
。。。。。。。。。。。
RK_MPI_RGA_CreateChn(RGA_CHN_ID, &rga_attr);
这段代码的核心是输入图像(输入分辨率是原分辨率和VI模块一致)和输出分辨率(输出分辨率是自己设置的分辨率)的设置。比方说输入的分辨率是 : 1920*1080,那stImgIn.u32Width = 1920 、stImgIn.u32Height = 1080,输出图像成:1280 * 720,stImgOut.u32Width = 1280、stImgOut.u32Height = 720。
1.3初始化高分辨率VENC编码器、 低分辨率VENC编码器:高分辨率编码器的初始化
VENC_CHN_ATTR_S high_venc_chn_attr;
high_venc_chn_attr.stVencAttr.u32PicWidth = 1920;
high_venc_chn_attr.stVencAttr.u32PicHeight = 1080;
high_venc_chn_attr.stVencAttr.u32VirWidth = 1920;
high_venc_chn_attr.stVencAttr.u32VirHeight = 1080;
................................
RK_MPI_VENC_CreateChn(HIGH_VENC_CHN, &high_venc_chn_attr);
低分辨率编码器的初始化
VENC_CHN_ATTR_S low_venc_chn_attr;
low_venc_chn_attr.stVencAttr.u32PicWidth = 1280;
low_venc_chn_attr.stVencAttr.u32PicHeight = 720;
low_venc_chn_attr.stVencAttr.u32VirWidth = 1280;
low_venc_chn_attr.stVencAttr.u32VirHeight = 720;
................................
RK_MPI_VENC_CreateChn(HIGH_VENC_CHN, &low_venc_chn_attr);
高分辨率和低分辨率最核心的设置就是分辨率的设置,高分辨率u32PicWidth = 1920、u32PicHeight = 1920,低分辨率u32PicWidth = 1280、u32PicHeight = 720
1.4 VI绑定高分辨率VENC编码器,VI绑定RGA模块,伪代码如下://VI模块绑定RGA模块
MPP_CHN_S vi_chn_s;
vi_chn_s.enModId = RK_ID_VI;
vi_chn_s.s32ChnId = CAMERA_CHN;
MPP_CHN_S rga_chn_s;
rga_chn_s.enModId = RK_ID_RGA;
rga_chn_s.s32ChnId = RGA_CHN_ID;
RK_MPI_SYS_Bind(&vi_chn_s, &rga_chn_s);
//VI模块绑定高分辨率VENC模块
MPP_CHN_S high_venc_chn_s;
high_venc_chn_s_s.enModId = RK_ID_VENC;
high_venc_chn_s_s.s32ChnId = HIGH_VENC_ID;
RK_MPI_SYS_Bind(&vi_chn_s, &high_venc_chn_s);
1.5 创建多线程获取高分辨率编码数据:开启一个线程去采集每一帧高分辨率的VENC模块数据,使用的API是RK_MPI_SYS_GetMediaBuffer, 模块ID是RK_ID_VENC,通道号ID是高分辨率VENC创建的ID号:
while(1)
{
.........................
mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VENC, HIGH_VENC_ID, -1);
fwrite(RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb), 1,high_venc_id);
.......................
}
1.6 创建多线程获取低分辨率数据并传输到编码器:开启一个线程去采集每一帧RGA低分辨率的数据,使用的API是RK_MPI_SYS_GetMediaBuffer, 模块ID是RK_ID_RGA,通道号ID是RGA的通道ID,采集完每一帧RGA数据则使用RK_MPI_SYS_SendMediaBuffer传输到低分辨率编码器。这个API伪代码如下:
while (1)
{
.........................................
mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_RGA, 0, -1);
RK_MPI_SYS_SendMediaBuffer(RK_ID_VENC, LOW_VENC_ID, mb);
................................
}
下面我们来看看RK_MPI_SYS_SendMediaBuffer的具体实现:
RK_S32 RK_MPI_SYS_SendMediaBuffer(MOD_ID_E enModID, RK_S32 s32ChnID, MEDIA_BUFFER buffer);
enModID:开发者需要传输的目的模块的ID号,比方说VI模块的数据传输到VENC模块,那么目的模块就是VENC,ID号就是RK_ID_VENC;比方说VI模块的数据传输到RGA模块,那么目的模块就是RGA,ID号就是RK_ID_RGA。
s32ChnID:目的模块的通道号
buffer:缓冲区数据MediaBuffer
1.7.创建多线程获取低分辨率编码数据:开启一个线程去采集每一帧低分辨率的编码数据,使用的API是RK_MPI_SYS_GetMediaBuffer, 模块ID是RK_ID_VENC,通道号ID是低分辨率VENC创建的ID号。这个API伪代码如下:
while (1)
{
.........................................
mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VENC, LOW_VENC_ID, -1);
fwrite(RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb), 1, low_venc_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 PIPE_ID 0 #define VI_CHN_ID 0 #define RGA_CHN_ID 0 #define HIGH_VENC_CHN 0 #define LOW_VENC_CHN 1 //创建多线程获取高分辨率的编码码流 void *get_high_venc_thread(void *args) { pthread_detach(pthread_self()); FILE *high_venc_file = fopen("test_high_venc.h264", "w+"); MEDIA_BUFFER mb; while (1) { //获取每一帧高分辨率编码码流数据 mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VENC, HIGH_VENC_CHN, -1); if (!mb) { printf("Get High Venc break.....\n"); } printf("Get High Venc Success.....\n"); fwrite(RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb), 1, high_venc_file); RK_MPI_MB_ReleaseBuffer(mb); } return NULL; } //创建多线程获取RGA码流并发送到低分辨率编码器 void *rga_handle_thread(void *args) { pthread_detach(pthread_self()); MEDIA_BUFFER mb; while (1) { //获取每一帧RGA码流数据 mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_RGA, RGA_CHN_ID, -1); if (!mb) { printf("Get RGA break.....\n"); } printf("Get RGA Success.....\n"); //发送每一帧RGA数据到低分辨率编码器 RK_MPI_SYS_SendMediaBuffer(RK_ID_VENC, LOW_VENC_CHN, mb); RK_MPI_MB_ReleaseBuffer(mb); } return NULL; } //创建多线程获取低分辨率编码码流 void *get_low_venc_thread(void *args) { pthread_detach(pthread_self()); MEDIA_BUFFER mb; FILE * low_venc_file = fopen("test_low_venc.h264", "w+"); while (1) { //获取每一帧低分辨率编码码流 mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VENC, LOW_VENC_CHN, -1); if (!mb) { printf("Get LOW VENC break.....\n"); } printf("Get LOW VENC Success.....\n"); fwrite(RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb), 1, low_venc_file); RK_MPI_MB_ReleaseBuffer(mb); } return NULL; } int main(int argc, char *argv[]) { int ret; RK_MPI_SYS_Init(); // VI Init...... VI_CHN_ATTR_S vi_chn_attr; vi_chn_attr.pcVideoNode = "rkispp_scale0";//设置视频设备节点路径 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(PIPE_ID, VI_CHN_ID, &vi_chn_attr); if (ret) { printf("VI_CHN_ATTR Set Failed.....\n"); return -1; } else { printf("VI_CHN_ATTR Set Success.....\n"); } ret = RK_MPI_VI_EnableChn(PIPE_ID, VI_CHN_ID); if (ret) { printf("VI_CHN_ATTR Enable Failed.....\n"); return -1; } else { printf("VI_CHN_ATTR Enable Success.....\n"); } // RGA RGA_ATTR_S rga_info; /**Image Input ..............*/ rga_info.stImgIn.u32Width = 1920;//设置RGA输入分辨率宽度 rga_info.stImgIn.u32Height = 1080;//设置RGA输入分辨率高度 rga_info.stImgIn.u32HorStride = 1920;//设置RGA输入分辨率虚宽 rga_info.stImgIn.u32VirStride = 1080;//设置RGA输入分辨率虚高 rga_info.stImgIn.imgType = IMAGE_TYPE_NV12;//设置ImageType图像类型 rga_info.stImgIn.u32X = 0;//设置X坐标 rga_info.stImgIn.u32Y = 0;//设置Y坐标 /**Image Output......................*/ rga_info.stImgOut.u32Width = 1280;//设置RGA输出分辨率宽度 rga_info.stImgOut.u32Height = 720;//设置RGA输出分辨率高度 rga_info.stImgOut.u32HorStride = 1280;//设置RGA输出分辨率虚宽 rga_info.stImgOut.u32VirStride = 720;//设置RGA输出分辨率虚高 rga_info.stImgOut.imgType = IMAGE_TYPE_NV12;//设置输出ImageType图像类型 rga_info.stImgOut.u32X = 0;//设置X坐标 rga_info.stImgOut.u32Y = 0;//设置Y坐标 // RGA Public Parameter rga_info.u16BufPoolCnt = 3;//缓冲池计数 rga_info.u16Rotaion = 0;// rga_info.enFlip = RGA_FLIP_H;//水平翻转 rga_info.bEnBufPool = RK_TRUE; ret = RK_MPI_RGA_CreateChn(RGA_CHN_ID, &rga_info); if (ret) { printf("RGA Set Failed.....\n"); } else { printf("RGA Set Success.....\n"); } // High Venc Parameter VENC_CHN_ATTR_S high_venc_attr; high_venc_attr.stVencAttr.enType = RK_CODEC_TYPE_H264;//设置编码器类型 high_venc_attr.stVencAttr.imageType = IMAGE_TYPE_NV12;//设置编码图像类型 high_venc_attr.stVencAttr.u32PicWidth = 1920;//设置编码分辨率宽度 high_venc_attr.stVencAttr.u32PicHeight = 1080;//设置编码分辨率高度 high_venc_attr.stVencAttr.u32VirWidth = 1920;//设置编码分辨率虚宽 high_venc_attr.stVencAttr.u32VirHeight = 1080;//设置编码分辨率虚高 high_venc_attr.stVencAttr.u32Profile = 66;//设置编码等级 high_venc_attr.stVencAttr.enRotation = VENC_ROTATION_0;//设置编码的旋转角度 //********* 设置码率控制属性 *******************// high_venc_attr.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR;//设置H264的CBR码率控制模式 high_venc_attr.stRcAttr.stH264Cbr.u32Gop = 25;//设置GOP关键帧间隔 high_venc_attr.stRcAttr.stH264Cbr.u32SrcFrameRateNum = 25;//设置源帧率分子 high_venc_attr.stRcAttr.stH264Cbr.u32SrcFrameRateDen = 1;//设置源帧率分母 high_venc_attr.stRcAttr.stH264Cbr.fr32DstFrameRateNum = 25;//设置目标帧率分子 high_venc_attr.stRcAttr.stH264Cbr.fr32DstFrameRateDen = 1;//设置目标帧率分母 high_venc_attr.stRcAttr.stH264Cbr.u32BitRate = 8388608;//设置码率大小 ret = RK_MPI_VENC_CreateChn(HIGH_VENC_CHN, &high_venc_attr); if (ret) { printf("Set High Venc Attr Failed.....\n"); } else { printf("Set High Venc Attr Success.....\n"); } // Low Venc Parameter VENC_CHN_ATTR_S low_venc_attr; low_venc_attr.stVencAttr.enType = RK_CODEC_TYPE_H264;//设置编码器类型 low_venc_attr.stVencAttr.imageType = IMAGE_TYPE_NV12;//设置编码图像类型 low_venc_attr.stVencAttr.u32PicWidth = 1280;//设置编码分辨率宽度 low_venc_attr.stVencAttr.u32PicHeight = 720;//设置编码分辨率高度 low_venc_attr.stVencAttr.u32VirWidth = 1280;//设置编码分辨率虚宽 low_venc_attr.stVencAttr.u32VirHeight = 720;//设置编码分辨率虚高 low_venc_attr.stVencAttr.u32Profile = 66;//设置编码等级 low_venc_attr.stVencAttr.enRotation = VENC_ROTATION_0;//设置编码的旋转角度 //********* 设置码率控制属性 *******************// low_venc_attr.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR;//设置H264的CBR码率控制模式 low_venc_attr.stRcAttr.stH264Cbr.u32Gop = 25;//设置GOP关键帧间隔 low_venc_attr.stRcAttr.stH264Cbr.u32SrcFrameRateNum = 25;//设置源帧率分子 low_venc_attr.stRcAttr.stH264Cbr.u32SrcFrameRateDen = 1;//设置源帧率分母 low_venc_attr.stRcAttr.stH264Cbr.fr32DstFrameRateNum = 25;//设置目标帧率分子 low_venc_attr.stRcAttr.stH264Cbr.fr32DstFrameRateDen = 1;//设置目标帧率分母 low_venc_attr.stRcAttr.stH264Cbr.u32BitRate = 8388608;//设置码率大小 ret = RK_MPI_VENC_CreateChn(LOW_VENC_CHN, &low_venc_attr); if (ret) { printf("Set Low Venc Attr Failed.....\n"); } else { printf("Set Low Venc Attr Success.....\n"); } MPP_CHN_S vi_chn_s; vi_chn_s.enModId = RK_ID_VI; vi_chn_s.s32ChnId = VI_CHN_ID; MPP_CHN_S high_chn_s; high_chn_s.enModId = RK_ID_VENC; high_chn_s.s32ChnId = HIGH_VENC_CHN; //VI绑定高分辨率VENC模块 ret = RK_MPI_SYS_Bind(&vi_chn_s, &high_chn_s); if (ret) { printf("VI Bind High Venc Failed.....\n"); return -1; } else { printf("VI Bind High Venc Success.....\n"); } MPP_CHN_S rga_chn_s; rga_chn_s.enModId = RK_ID_RGA; rga_chn_s.s32ChnId = RGA_CHN_ID; //VI绑定RGA模块 ret = RK_MPI_SYS_Bind(&vi_chn_s, &rga_chn_s); if (ret) { printf("VI Bind RGA Failed.....\n"); return -1; } else { printf("VI Bind RGA Success.....\n"); } pthread_t high_venc_pid; pthread_t rga_pid; pthread_t low_venc_pid; pthread_create(&high_venc_pid, NULL, get_high_venc_thread, NULL); //创建多线程获取高分辨率的编码码流 pthread_create(&rga_pid, NULL, rga_handle_thread, NULL);//创建多线程获取RGA码流并发送到低分辨率编码器 pthread_create(&low_venc_pid, NULL, get_low_venc_thread, NULL);//创建多线程获取低分辨率编码码流 while (1) { sleep(1); } RK_MPI_SYS_UnBind(&vi_chn_s, &high_chn_s); RK_MPI_SYS_UnBind(&vi_chn_s, &rga_chn_s); RK_MPI_RGA_DestroyChn(RGA_CHN_ID); RK_MPI_VENC_DestroyChn(HIGH_VENC_CHN); RK_MPI_VENC_DestroyChn(LOW_VENC_CHN); RK_MPI_VI_DisableChn(PIPE_ID, VI_CHN_ID); return 0; } 三.运行的效果:分别用ffplay播放器分别播出高分辨率H264文件(test_high_venc.h264),低分辨率(test_rga_venc.h264)
ffplay test_high_venc.h264
ffplay test_rga_venc.h264
通过多线程分别获取高分辨率和低分辨率的H264码流由讯客互联软件开发栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“通过多线程分别获取高分辨率和低分辨率的H264码流”