目錄
一.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");}// RGARGA_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 Parameterrga_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 ParameterVENC_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 ParameterVENC_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