海思Hi3518EV200 SDK分析筆記
===========================================================================================================
1.
/* We just coyp this value of payload type from RTP/RTSP definition */
typedef enum
{
PT_PCMU = 0,
....... ....
PT_H265 = 265,
PT_MAX = 266,
/* add by hisilicon */
PT_AMR = 1001,
PT_MJPEG = 1002,
PT_AMRWB = 1003,
PT_BUTT
} PAYLOAD_TYPE_E;
#海思原始碼中,列舉型別都是以大寫字母加下劃線構成,並以E結尾,結構體是以S結尾
#這裡面PT就是PAYLOAD_TYPE,PAYLOAD簡單理解為載體或者載荷,可以這麼理解,假設你在傳輸一個視訊,你傳輸的這個視訊是個什麼型別的
#這就是這個視訊的PAYLOAD_TYPE,你把RTSP視訊傳輸看成是用餃子皮把餃子餡包起來運走,這個PAYLOAD_TYPE就是問你這個餃子是什麼餡的。
#通過RTSP不僅能傳H.264型別的,還可以傳其他型別的,都列在列舉裡面
#RTP/RTSP本來就是用來傳輸音視訊的一些東西,音視訊的編碼種類特別多,那你傳輸的是怎樣一種編碼,你要用PAYLOAD_TYPE告訴別人
#PT_BUTT是結尾識別符號,不能用
===========================================================================================================
2.
PAYLOAD_TYPE_E enPayLoad[3]= {PT_H264, PT_H264,PT_H264};
#這個變數enPayLoad以en打頭就告訴你這個是enum型別的
#從這個陣列有三個變數來看,要編3路視訊
#三路都是H.264的,這裡只是一個初始化,後面再去填充
===========================================================================================================
3.
VPSS_GRP_ATTR_S stVpssGrpAttr;
#以st打頭的就是結構體變數,前的VPSS_GRP_ATTR_S就是一個結構體,全部大寫,下劃線分開,S結尾
===========================================================================================================
4.
typedef enum hiPIC_SIZE_E
{
PIC_QCIF = 0, //176*144
PIC_CIF, //352*288
PIC_2CIF,
PIC_HD1,
PIC_D1, //704*576
PIC_960H,
PIC_QVGA, /* 320 * 240 */
PIC_VGA, /* 640 * 480 */
PIC_XGA, /* 1024 * 768 */
PIC_SXGA, /* 1400 * 1050 */
PIC_UXGA, /* 1600 * 1200 */
PIC_QXGA, /* 2048 * 1536 */
PIC_WVGA, /* 854 * 480 */
PIC_WSXGA, /* 1680 * 1050 */
PIC_WUXGA, /* 1920 * 1200 */
PIC_WQXGA, /* 2560 * 1600 */
PIC_HD720, /* 1280 * 720 */
PIC_HD1080, /* 1920 * 1080 */
PIC_2304x1296, /* 3M:2304 * 1296 */
PIC_2592x1520, /* 4M:2592 * 1520 */
PIC_5M, /* 2592 * 1944 */
PIC_UHD4K, /* 3840 * 2160 */
PIC_12M, /* 4000 * 3000 */
PIC_BUTT
} PIC_SIZE_E;
#圖片解析度的
=============================================================================================================
5.
VB_CONF_S;定義了模型,點菜
HI_MPI_VB_SetConf; 把模型告訴了VB,點好菜交給服務員
HI_MPI_VB_Init;VB真正去執行分配了,服務員把點好的選單交給後廚開始做菜
#順序不能搞錯
#可以有多個緩衝池,每個緩衝池又分多個快取塊
=============================================================================================================
6.
step 6: stream venc process -- get stream, then save it to file.
#可以把這個碼流打包成一個MP4儲存到你的硬盤裡面去,這就是錄影。
#也可以分包,分成一個一個的視訊包通過RTSP傳出去。
#也可以作為一個裸流直接丟到流檔案裡面。這個裸流檔案必須通過像VLC這些可以解析流檔案的播放器才可以觀看。
#裸流是開發過程中的半成品,沒有檔案頭,就得花時間去檢測一下這幅圖是多大,正常情況不會給別人提供裸流的
#正常的視訊去解析度都是直接從檔案中提取的
=============================================================================================================
7.
step 1: init sys variable 指的是初始化MMP這個系統的變數
=============================================================================================================
8.
typedef struct hiVB_CONF_S
{
HI_U32 u32MaxPoolCnt; /* max count of pools, (0,VB_MAX_POOLS] */
struct hiVB_CPOOL_S
{
HI_U32 u32BlkSize; /*what the size of each block. */
HI_U32 u32BlkCnt; /*How many blocks of each pool*/
HI_CHAR acMmzName[MAX_MMZ_NAME_LEN];
}astCommPool[VB_MAX_COMM_POOLS];
} VB_CONF_S;
#u32BlkSize一幀影象的大小決定了一個緩衝塊的大小
#u32BlkCnt 緩衝塊的數量按道理來說越多越好,要適量分配,避免浪費。記憶體大你就多給點避免不夠用的情況出現,記憶體不多就要合理安排
#step 1: init sys variable這一步是根據我們的實際來核算各路快取池的BlkSize,BlkCnt,不是隨便給的,
#在這一步整個MPP系統還沒有啟動
=============================================================================================================
9.
SAMPLE_COMM_VI_GetSizeBySensor(&enSize[0]);
#填充變數,命令表明函式的位置在sample/common目錄下,意思是通過sensor來算得到的影象大小
#我們這裡的SENSOR是720p的,這個函數出來後就變成720p了
#剛開始初始化時PIC_SIZE_E enSize[3] = {PIC_HD1080, PIC_VGA,PIC_QVGA};給的是這三路碼流,經過我們初始化後的到一路720p了
=============================================================================================================
10.
SAMPLE_VI_MODE_E enMode = SENSOR_TYPE;
#SENSOR_TYPE是在sample目錄下面Makefile.param配置的
################# select sensor type for your sample ####################
#SENSOR_TYPE ?= APTINA_9M034_DC_720P_30FPS
SENSOR_TYPE ?= SONY_IMX222_DC_1080P_30FPS
#SENSOR_TYPE ?= SONY_IMX222_DC_720P_30FPS
#SENSOR_TYPE ?= APTINA_AR0130_DC_720P_30FPS
#SENSOR_TYPE ?= PANASONIC_MN34222_MIPI_1080P_30FPS
#SENSOR_TYPE ?= APTINA_AR0230_HISPI_1080P_30FPS
#SENSOR_TYPE ?= OMNIVISION_OV9712_DC_720P_30FPS
#SENSOR_TYPE ?= OMNIVISION_OV9732_DC_720P_30FPS
#SENSOR_TYPE ?= OMNIVISION_OV9750_MIPI_720P_30FPS
#SENSOR_TYPE ?= OMNIVISION_OV9752_MIPI_720P_30FPS
#SENSOR_TYPE ?= OMNIVISION_OV2718_MIPI_1080P_25FPS
##########################################################################
===========================================================================================================
11.
if (PIC_HD1080 == enSize[0])
{
enSize[1] = PIC_VGA;
s32ChnNum = 2;
}
else if (PIC_HD720 == enSize[0])
{
enSize[1] = PIC_VGA;
enSize[2] = PIC_QVGA;
s32ChnNum = 3;
}
else
{
printf("not support this sensor\n");
return HI_FAILURE;
}
#最後我們得到的是720p,三路碼流,enSize[0]=PIC_HD720 enSize[1] = PIC_VGA enSize[2] = PIC_QVGA
#PIC_HD720是主碼流,PIC_VGA,PIC_QVGA是子碼流,子碼流的意思是通過對主碼流裁剪,縮放等操作後得到的。
#子碼流一般是通過手機來觀看,手機螢幕畢竟小,沒必要HD720,而且還流暢,節省頻寬。
============================================================================================================
12.
stVbConf.u32MaxPoolCnt = 128;
#視訊快取池的個數是我們自己根據資源估算設定的,128是一個經驗值
#不是實際設定了128個,而是設定了一個上限
============================================================================================================
13.
/*video buffer*/
if(s32ChnNum >= 1)
{
u32BlkSize = SAMPLE_COMM_SYS_CalcPicVbBlkSize(gs_enNorm,\
enSize[0], SAMPLE_PIXEL_FORMAT, SAMPLE_SYS_ALIGN_WIDTH);
stVbConf.astCommPool[0].u32BlkSize = u32BlkSize;
stVbConf.astCommPool[0].u32BlkCnt = g_u32BlkCnt;
} \\返回一幀影象所要的記憶體大小即u32VbSize,這個值就是block的大小-----第一路碼流的公共快取池
if(s32ChnNum >= 2)
{
u32BlkSize = SAMPLE_COMM_SYS_CalcPicVbBlkSize(gs_enNorm,\
enSize[1], SAMPLE_PIXEL_FORMAT, SAMPLE_SYS_ALIGN_WIDTH);
stVbConf.astCommPool[1].u32BlkSize = u32BlkSize;
stVbConf.astCommPool[1].u32BlkCnt =g_u32BlkCnt;
} \\---第二路碼流的公共快取池
if(s32ChnNum >= 3)
{
u32BlkSize = SAMPLE_COMM_SYS_CalcPicVbBlkSize(gs_enNorm,\
enSize[2], SAMPLE_PIXEL_FORMAT, SAMPLE_SYS_ALIGN_WIDTH);
stVbConf.astCommPool[2].u32BlkSize = u32BlkSize;
stVbConf.astCommPool[2].u32BlkCnt = g_u32BlkCnt;
} \\---第三路碼流的公共快取池
#各路快取池的BlkSize,BlkCnt是不一樣的
#一個緩衝池其實就對應一路碼流,
#為什麼要這麼分呢,是因為不同的碼流解析度不一樣,耗費的記憶體的塊block也不一樣,這是為了避免浪費記憶體空間
#enSize[0]目前為PIC_HD720,
#SAMPLE_PIXEL_FORMAT為畫素格式,比如RGB888,RGB565就不一樣,RGB888 24b佔三個位元組,RGB565 16b佔兩個位元組
#SAMPLE_SYS_ALIGN_WIDTH對齊
=============================================================================================================
14.
((PIXEL_FORMAT_YUV_SEMIPLANAR_422 == enPixFmt)?2:1.5));
#這裡指的是平均一個畫素佔幾個位元組
#YUV422 4+2+2=8位元組,4個畫素一共佔了8個位元組,那一個畫素平均佔多少個位元組8/4=2位元組
#YUV420 4+2=6位元組,4個畫素一共佔了6個位元組,那一個畫素平均佔多少個位元組6/4=1.5位元組
=============================================================================================================
15.
u32VbSize += u32HeaderSize;
#最後還要加上頭資訊
=============================================================================================================
16.
VB_PIC_HEADER_SIZE(stSize.u32Width, stSize.u32Height, enPixFmt, u32HeaderSize);
u32VbSize += u32HeaderSize;
return u32VbSize;
#返回u32VbSize就知道考慮了所有的的餘量之後一幀影象要多大記憶體
=============================================================================================================
17.
/******************************************
step 2: mpp system init.
******************************************/
s32Ret = SAMPLE_COMM_SYS_Init(&stVbConf);
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT("system init failed with %d!\n", s32Ret);
goto END_VENC_1080P_CLASSIC_0;
}
#s32Ret = SAMPLE_COMM_SYS_Init(&stVbConf);把引數&stVbConf傳進來,stVbConf是一個結構體
#函式內部用了兩個API
#這兩個API分別為 s32Ret = HI_MPI_VB_SetConf(pstVbConf); s32Ret = HI_MPI_VB_Init();
=============================================================================================================
18.
/******************************************************************************
* function : vb init & MPI system init
******************************************************************************/
HI_S32 SAMPLE_COMM_SYS_Init(VB_CONF_S *pstVbConf)
{
MPP_SYS_CONF_S stSysConf = {0};
HI_S32 s32Ret = HI_FAILURE;
HI_MPI_SYS_Exit();
HI_MPI_VB_Exit();
if (NULL == pstVbConf)
{
SAMPLE_PRT("input parameter is null, it is invaild!\n");
return HI_FAILURE;
}
s32Ret = HI_MPI_VB_SetConf(pstVbConf);
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT("HI_MPI_VB_SetConf failed!\n");
return HI_FAILURE;
}
s32Ret = HI_MPI_VB_Init();
#HI_MPI_SYS_Exit(); 和HI_MPI_VB_Exit(); 打掃場地用的,注意呼叫順序,釋放是SYS在前,VB在後
#建立的時候是先VB後SYS
#其實VB的引數要操點心,pstVbConf自己去算好,餘下的都是模式化,
================================================================================================================
19.
//SAMPLE_PRT("w:%d, u32AlignWidth:%d\n", CEILING_2_POWER(stSize.u32Width,u32AlignWidth), u32AlignWidth);
u32VbSize = (CEILING_2_POWER(stSize.u32Width, u32AlignWidth) * \
CEILING_2_POWER(stSize.u32Height,u32AlignWidth) * \
((PIXEL_FORMAT_YUV_SEMIPLANAR_422 == enPixFmt)?2:1.5));
#CEILING_2_POWER(stSize.u32Width, u32AlignWidth) 這個巨集的意思是stSize.u32Width向u32AlignWidth對齊
#怎麼對齊,stSize.u32Width向上取整,u32AlignWidth是64,stSize.u32Width為1280,往上數,一直數到夠第一個夠64整除的數,意思就是往上留點餘量
================================================================================================================
20.
PIXEL_FORMAT_YUV_SEMIPLANAR_420
#是怎麼定成YUV420的
#其實是寫APP的人用巨集定義直接定義出來的,他怎麼知道把它定成YUV420?
#define VB_PIC_HEADER_SIZE(Width, Height, Type, size)\
do{\
if (PIXEL_FORMAT_YUV_SEMIPLANAR_422 == Type || PIXEL_FORMAT_RGB_BAYER == Type )\
{\
size = VB_HEADER_STRIDE * (Height) * 2;\
}\
else if(PIXEL_FORMAT_YUV_SEMIPLANAR_420 == Type)\
{\
size = (VB_HEADER_STRIDE * (Height) * 3) >> 1;\
}\
else if(PIXEL_FORMAT_YUV_400 == Type)\
{\
size = VB_HEADER_STRIDE * (Height);\
}\
}while(0)
#PIXEL_FORMAT_RGB_BAYER指的是rawRGB,後面轉成RGA,再到YUV,為什麼不直接用RGB呢?
#是因為YUV這種方式表達顏色更加科學,所以最後不管你sensor這邊出來是什麼格式,一律轉成YUV格式
#你想變成YUV422還是YUV420都可以,自己來定
#很明顯YUV422的顏色分量會多一些,將來出來的色彩的還原度會高一些,但有比較浪費記憶體,所以自己來權衡顏色分量和記憶體佔用情況
#行業內YUV420用得比較多
=================================================================================================================
21.
/******************************************
step 3: start vi dev & chn to capture
******************************************/
stViConfig.enViMode = SENSOR_TYPE;
stViConfig.enRotate = ROTATE_NONE;
stViConfig.enNorm = VIDEO_ENCODING_MODE_AUTO;
stViConfig.enViChnSet = VI_CHN_SET_NORMAL;
stViConfig.enWDRMode = WDR_MODE_NONE;
s32Ret = SAMPLE_COMM_VI_StartVi(&stViConfig);
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT("start vi failed!\n");
goto END_VENC_1080P_CLASSIC_1;
}
#MPP裡面的函式我們追不進去
#HI_MPI_VI_SetDevAttr MPI代表MPP interface
#常用senso介面,MIPI,LVDS,DC(並口)
#stViConfig.enRotate = ROTATE_NONE;影象出來要旋轉的話在這裡設定
#stViConfig.enNorm = VIDEO_ENCODING_MODE_AUTO;影象制式的標準有PAL和NTSC兩種,對於這種數字介面的sensor來說,不重要。
#stViConfig.enViChnSet = VI_CHN_SET_NORMAL; 影象映象,翻轉在這裡設定
#stViConfig.enWDRMode = WDR_MODE_NONE;寬動態,這種技術需要sensor硬體支援。動態範圍:在一幅影象中,能看到最亮與最暗的比例
#動態範圍的模式有如下幾種
typedef enum hiWDR_MODE_E
{
WDR_MODE_NONE = 0,
WDR_MODE_BUILT_IN,
WDR_MODE_2To1_LINE,
WDR_MODE_2To1_FRAME,
WDR_MODE_2To1_FRAME_FULL_RATE,
WDR_MODE_3To1_LINE,
WDR_MODE_3To1_FRAME,
WDR_MODE_3To1_FRAME_FULL_RATE,
WDR_MODE_4To1_LINE,
WDR_MODE_4To1_FRAME,
WDR_MODE_4To1_FRAME_FULL_RATE,
WDR_MODE_BUTT,
} WDR_MODE_E;
#sensor執行需要驅動
HI_S32 SAMPLE_COMM_VI_SetMipiAttr(SAMPLE_VI_CONFIG_S* pstViConfig)
{
HI_S32 fd;
combo_dev_attr_t *pstcomboDevAttr = NULL;
/* mipi reset unrest */
fd = open("/dev/hi_mipi", O_RDWR);
if (fd < 0)
{
printf("warning: open hi_mipi dev failed\n");
return -1;
}
printf("=============SAMPLE_COMM_VI_SetMipiAttr enWDRMode: %d\n", pstViConfig->enWDRMode);
if ( pstViConfig->enViMode == APTINA_AR0230_HISPI_1080P_30FPS )
{
pstcomboDevAttr = &HISPI_4lane_SENSOR_AR0230_12BIT_ATTR;
}
if ( pstViConfig->enViMode == PANASONIC_MN34222_MIPI_1080P_30FPS )
{
pstcomboDevAttr = &MIPI_2lane_SENSOR_MN34222_12BIT_NOWDR_ATTR;
}
if ( (pstViConfig->enViMode == OMNIVISION_OV9752_MIPI_720P_30FPS)
|| (pstViConfig->enViMode == OMNIVISION_OV9750_MIPI_720P_30FPS) )
{
pstcomboDevAttr = &MIPI_2lane_SENSOR_OV9752_12BIT_NOWDR_ATTR;
}
if ( pstViConfig->enViMode == OMNIVISION_OV2718_MIPI_1080P_25FPS )
{
pstcomboDevAttr = &MIPI_4lane_SENSOR_OV2718_12BIT_NOWDR_ATTR;
}
if ( (pstViConfig->enViMode == APTINA_9M034_DC_720P_30FPS)
|| (pstViConfig->enViMode == APTINA_AR0130_DC_720P_30FPS)
|| (pstViConfig->enViMode == SONY_IMX222_DC_1080P_30FPS)
|| (pstViConfig->enViMode == SONY_IMX222_DC_720P_30FPS)
|| (pstViConfig->enViMode == OMNIVISION_OV9712_DC_720P_30FPS)
|| (pstViConfig->enViMode == OMNIVISION_OV9732_DC_720P_30FPS) )
{
pstcomboDevAttr = &MIPI_CMOS3V3_ATTR;
}
if (NULL == pstcomboDevAttr)
{
printf("Func %s() Line[%d], unsupported enViMode: %d\n", __FUNCTION__, __LINE__, pstViConfig->enViMode);
close(fd);
return HI_FAILURE;
}
if (ioctl(fd, HI_MIPI_SET_DEV_ATTR, pstcomboDevAttr))
{
printf("set mipi attr failed\n");
close(fd);
return HI_FAILURE;
}
close(fd);
return HI_SUCCESS;
#sensor驅動裝載完後會生成/dev/hi_mipi這樣的一個裝置檔案,開啟,開啟後準備好相應的引數,不同的sensor填充的引數是不一樣的
#填充完以後通過一個ioctl(fd, HI_MIPI_SET_DEV_ATTR, pstcomboDevAttr),HI_MIPI_SET_DEV_ATTR是3518E給sensor做屬性設定的命令,傳參的標準都是海思定義好的一個結構體,
#但是這個結構體在不用的sensor裡面是不一樣的,
#ioctl是驅動對應用開放的介面
#SAMPLE_COMM_VI_SetMipiAttr功能就是在應用層對sensor做一個初始化
combo_dev_attr_t HISPI_4lane_SENSOR_AR0230_12BIT_ATTR =
{
/* input mode */
.input_mode = INPUT_MODE_HISPI,
{
.lvds_attr =
{
.img_size = {1920, 1080},
HI_WDR_MODE_NONE,
LVDS_SYNC_MODE_SOL,
RAW_DATA_12BIT,
LVDS_ENDIAN_LITTLE,
LVDS_ENDIAN_LITTLE,
.lane_id = {0, 1, 2, 3, -1, -1, -1, -1},
.sync_code =
{
{{0x003, 0x007, 0x001, 0x005},
{0x003, 0x007, 0x001, 0x005},
{0x003, 0x007, 0x001, 0x005},
{0x003, 0x007, 0x001, 0x005}},
{{0x003, 0x007, 0x001, 0x005},
{0x003, 0x007, 0x001, 0x005},
{0x003, 0x007, 0x001, 0x005},
{0x003, 0x007, 0x001, 0x005}},
{{0x003, 0x007, 0x001, 0x005},
{0x003, 0x007, 0x001, 0x005},
{0x003, 0x007, 0x001, 0x005},
{0x003, 0x007, 0x001, 0x005}},
{{0x003, 0x007, 0x001, 0x005},
{0x003, 0x007, 0x001, 0x005},
{0x003, 0x007, 0x001, 0x005},
{0x003, 0x007, 0x001, 0x005}},
{{0x003, 0x007, 0x001, 0x005},
{0x003, 0x007, 0x001, 0x005},
{0x003, 0x007, 0x001, 0x005},
{0x003, 0x007, 0x001, 0x005}},
{{0x003, 0x007, 0x001, 0x005},
{0x003, 0x007, 0x001, 0x005},
{0x003, 0x007, 0x001, 0x005},
{0x003, 0x007, 0x001, 0x005}},
{{0x003, 0x007, 0x001, 0x005},
{0x003, 0x007, 0x001, 0x005},
{0x003, 0x007, 0x001, 0x005},
{0x003, 0x007, 0x001, 0x005}},
{{0x003, 0x007, 0x001, 0x005},
{0x003, 0x007, 0x001, 0x005},
{0x003, 0x007, 0x001, 0x005},
{0x003, 0x007, 0x001, 0x005}}
}
}
}
};
===============================================================================================================================
22.
/******************************************
step 2: configure sensor and ISP (include WDR mode).
note: you can jump over this step, if you do not use Hi3516A interal isp.
******************************************/
s32Ret = SAMPLE_COMM_ISP_Init(pstViConfig->enWDRMode);
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT("%s: Sensor init failed!\n", __FUNCTION__);
return HI_FAILURE;
}
#ISP image signal process 是一種技術,就是做一下數學運算,3518e內部的一個硬體單元
#這個ISP硬體單元就是專門用來做ISP的,這個模組在MPP裡面被封裝成了API
#SAMPLE_COMM_ISP_Init功能就是把這個ISP的執行緒執行起來
#ISP裡面處理比如3A
#也可以專門加一個ISP晶片,不用3518e裡面這個ISP模組單元,不啟動就行,預設就是關閉的
/******************************************************************************
* funciton : ISP init
******************************************************************************/
HI_S32 SAMPLE_COMM_ISP_Init(WDR_MODE_E enWDRMode)
{
ISP_DEV IspDev = 0;
HI_S32 s32Ret;
ISP_PUB_ATTR_S stPubAttr;
ALG_LIB_S stLib;
#if 0
/* 0. set cmos iniparser file path */
s32Ret = sensor_set_inifile_path("configs/");
if (s32Ret != HI_SUCCESS)
{
printf("%s: set cmos iniparser file path failed with %#x!\n", \
__FUNCTION__, s32Ret);
return s32Ret;
}
#endif
/* 1. sensor register callback */
s32Ret = sensor_register_callback();
if (s32Ret != HI_SUCCESS)
{
printf("%s: sensor_register_callback failed with %#x!\n", \
__FUNCTION__, s32Ret);
return s32Ret;
}
/* 2. register hisi ae lib */
stLib.s32Id = 0;
strcpy(stLib.acLibName, HI_AE_LIB_NAME);
s32Ret = HI_MPI_AE_Register(IspDev, &stLib);
if (s32Ret != HI_SUCCESS)
{
printf("%s: HI_MPI_AE_Register failed!\n", __FUNCTION__);
return s32Ret;
}
/* 3. register hisi awb lib */
stLib.s32Id = 0;
strcpy(stLib.acLibName, HI_AWB_LIB_NAME);
s32Ret = HI_MPI_AWB_Register(IspDev, &stLib);
if (s32Ret != HI_SUCCESS)
{
printf("%s: HI_MPI_AWB_Register failed!\n", __FUNCTION__);
return s32Ret;
}
/* 4. register hisi af lib */
stLib.s32Id = 0;
strcpy(stLib.acLibName, HI_AF_LIB_NAME);
s32Ret = HI_MPI_AF_Register(IspDev, &stLib);
if (s32Ret != HI_SUCCESS)
{
printf("%s: HI_MPI_AF_Register failed!\n", __FUNCTION__);
return s32Ret;
}
/* 5. isp mem init */
s32Ret = HI_MPI_ISP_MemInit(IspDev);
if (s32Ret != HI_SUCCESS)
{
printf("%s: HI_MPI_ISP_Init failed!\n", __FUNCTION__);
return s32Ret;
}
/* 6. isp set WDR mode */
ISP_WDR_MODE_S stWdrMode;
stWdrMode.enWDRMode = enWDRMode;
s32Ret = HI_MPI_ISP_SetWDRMode(0, &stWdrMode);
if (HI_SUCCESS != s32Ret)
{
printf("start ISP WDR failed!\n");
return s32Ret;
}
/* 7. isp set pub attributes */
/* note : different sensor, different ISP_PUB_ATTR_S define.
if the sensor you used is different, you can change
ISP_PUB_ATTR_S definition */
switch(SENSOR_TYPE)
{
case APTINA_9M034_DC_720P_30FPS:
case APTINA_AR0130_DC_720P_30FPS:
stPubAttr.enBayer = BAYER_GRBG;
stPubAttr.f32FrameRate = 30;
stPubAttr.stWndRect.s32X = 0;
stPubAttr.stWndRect.s32Y = 0;
stPubAttr.stWndRect.u32Width = 1280;
stPubAttr.stWndRect.u32Height = 720;
break;
case SONY_IMX222_DC_1080P_30FPS:
stPubAttr.enBayer = BAYER_RGGB;
stPubAttr.f32FrameRate = 30;
stPubAttr.stWndRect.s32X = 200;
stPubAttr.stWndRect.s32Y = 20;
stPubAttr.stWndRect.u32Width = 1920;
stPubAttr.stWndRect.u32Height = 1080;
break;
case SONY_IMX222_DC_720P_30FPS:
stPubAttr.enBayer = BAYER_RGGB;
stPubAttr.f32FrameRate = 30;
stPubAttr.stWndRect.s32X = 200;
stPubAttr.stWndRect.s32Y = 20;
stPubAttr.stWndRect.u32Width = 1280;
stPubAttr.stWndRect.u32Height = 720;
break;
case APTINA_AR0230_HISPI_1080P_30FPS:
stPubAttr.enBayer = BAYER_GRBG;
stPubAttr.f32FrameRate = 30;
stPubAttr.stWndRect.s32X = 0;
stPubAttr.stWndRect.s32Y = 0;
stPubAttr.stWndRect.u32Width = 1920;
stPubAttr.stWndRect.u32Height = 1080;
break;
case PANASONIC_MN34222_MIPI_1080P_30FPS:
stPubAttr.enBayer = BAYER_GRBG;
stPubAttr.f32FrameRate = 30;
stPubAttr.stWndRect.s32X = 0;
stPubAttr.stWndRect.s32Y = 0;
stPubAttr.stWndRect.u32Width = 1920;
stPubAttr.stWndRect.u32Height = 1080;
break;
case OMNIVISION_OV9712_DC_720P_30FPS:
stPubAttr.enBayer = BAYER_BGGR;
stPubAttr.f32FrameRate = 30;
stPubAttr.stWndRect.s32X = 0;
stPubAttr.stWndRect.s32Y = 0;
stPubAttr.stWndRect.u32Width = 1280;
stPubAttr.stWndRect.u32Height = 720;
break;
case OMNIVISION_OV9732_DC_720P_30FPS:
stPubAttr.enBayer = BAYER_BGGR;
stPubAttr.f32FrameRate = 30;
stPubAttr.stWndRect.s32X = 0;
stPubAttr.stWndRect.s32Y = 0;
stPubAttr.stWndRect.u32Width = 1280;
stPubAttr.stWndRect.u32Height = 720;
break;
case OMNIVISION_OV9750_MIPI_720P_30FPS:
case OMNIVISION_OV9752_MIPI_720P_30FPS:
stPubAttr.enBayer = BAYER_BGGR;
stPubAttr.f32FrameRate = 30;
stPubAttr.stWndRect.s32X = 0;
stPubAttr.stWndRect.s32Y = 0;
stPubAttr.stWndRect.u32Width = 1280;
stPubAttr.stWndRect.u32Height = 720;
break;
case OMNIVISION_OV2718_MIPI_1080P_25FPS:
stPubAttr.enBayer = BAYER_BGGR;
stPubAttr.f32FrameRate = 25;
stPubAttr.stWndRect.s32X = 0;
stPubAttr.stWndRect.s32Y = 0;
stPubAttr.stWndRect.u32Width = 1920;
stPubAttr.stWndRect.u32Height = 1080;
break;
default:
stPubAttr.enBayer = BAYER_GRBG;
stPubAttr.f32FrameRate = 30;
stPubAttr.stWndRect.s32X = 0;
stPubAttr.stWndRect.s32Y = 0;
stPubAttr.stWndRect.u32Width = 1920;
stPubAttr.stWndRect.u32Height = 1080;
break;
}
s32Ret = HI_MPI_ISP_SetPubAttr(IspDev, &stPubAttr);
if (s32Ret != HI_SUCCESS)
{
printf("%s: HI_MPI_ISP_SetPubAttr failed with %#x!\n", __FUNCTION__, s32Ret);
return s32Ret;
}
/* 8. isp init */
s32Ret = HI_MPI_ISP_Init(IspDev);
if (s32Ret != HI_SUCCESS)
{
printf("%s: HI_MPI_ISP_Init failed!\n", __FUNCTION__);
return s32Ret;
}
gbIspInited = HI_TRUE;
return HI_SUCCESS;
}
#sensor_register_callback() IQ除錯相關
#這個函式在sensor驅動裡面Z:\Hi3518E_V200R001C01SPC030\Hi3518E V200R001C01SPC030\
#01.software\board\Hi3518E_SDK_V1.0.3.0\package\mpp\component\isp\sensor\ar0130目錄的ar0130_cmos.c裡面
/* 2. register hisi ae lib */
stLib.s32Id = 0;
strcpy(stLib.acLibName, HI_AE_LIB_NAME);
s32Ret = HI_MPI_AE_Register(IspDev, &stLib);
if (s32Ret != HI_SUCCESS)
{
printf("%s: HI_MPI_AE_Register failed!\n", __FUNCTION__);
return s32Ret;
}
#自動曝光
/* 3. register hisi awb lib */
stLib.s32Id = 0;
strcpy(stLib.acLibName, HI_AWB_LIB_NAME);
s32Ret = HI_MPI_AWB_Register(IspDev, &stLib);
if (s32Ret != HI_SUCCESS)
{
printf("%s: HI_MPI_AWB_Register failed!\n", __FUNCTION__);
return s32Ret;
}
#自動白平衡
/* 4. register hisi af lib */
stLib.s32Id = 0;
strcpy(stLib.acLibName, HI_AF_LIB_NAME);
s32Ret = HI_MPI_AF_Register(IspDev, &stLib);
if (s32Ret != HI_SUCCESS)
{
printf("%s: HI_MPI_AF_Register failed!\n", __FUNCTION__);
return s32Ret;
}
#自動對焦
#註冊一下3A單元
/* 5. isp mem init */
s32Ret = HI_MPI_ISP_MemInit(IspDev);
if (s32Ret != HI_SUCCESS)
{
printf("%s: HI_MPI_ISP_Init failed!\n", __FUNCTION__);
return s32Ret;
}
#給ISP單元分配記憶體,傳這個引數IspDev就可以了,內部自動會去分配記憶體
/* 6. isp set WDR mode */
ISP_WDR_MODE_S stWdrMode;
stWdrMode.enWDRMode = enWDRMode;
s32Ret = HI_MPI_ISP_SetWDRMode(0, &stWdrMode);
if (HI_SUCCESS != s32Ret)
{
printf("start ISP WDR failed!\n");
return s32Ret;
}
#設定寬動態
switch(SENSOR_TYPE)
{
case APTINA_9M034_DC_720P_30FPS:
case APTINA_AR0130_DC_720P_30FPS:
stPubAttr.enBayer = BAYER_GRBG;
stPubAttr.f32FrameRate = 30;
stPubAttr.stWndRect.s32X = 0;
stPubAttr.stWndRect.s32Y = 0;
stPubAttr.stWndRect.u32Width = 1280;
stPubAttr.stWndRect.u32Height = 720;
#stPubAttr.enBayer = BAYER_GRBG; RGB原始訊號的排列序列,查sensor的datasheet
# stPubAttr.stWndRect.s32X = 0;
# stPubAttr.stWndRect.s32Y = 0; 影象區域的起始點(0,0)
#ISP初始化以後ISP就已經準備好了
/* 8. isp init */
s32Ret = HI_MPI_ISP_Init(IspDev);
if (s32Ret != HI_SUCCESS)
{
printf("%s: HI_MPI_ISP_Init failed!\n", __FUNCTION__);
return s32Ret;
}
#3518E內部ISP單元是隸屬於VI模組的
#VI模組就包括3大部分,第一部分是與sensor對接的部分,第二部分是就是ISP,第三部分就是VI dev和channel部分。
#VI dev是採集影象的硬體單元,channel是與後端連線的多個出口,也是一個硬體單元。每一個出口就是一個channel。
#填充完後就設定進去HI_MPI_VI_SetDevAttr
s32Ret = HI_MPI_VI_SetDevAttr(ViDev, &stViDevAttr);
if (s32Ret != HI_SUCCESS)
{
SAMPLE_PRT("HI_MPI_VI_SetDevAttr failed with %#x!\n", s32Ret);
return HI_FAILURE;
}
#獲取WDR模式HI_MPI_ISP_GetWDRMode
if ( (SAMPLE_VI_MODE_BT1120_1080P != enViMode)
&&(SAMPLE_VI_MODE_BT1120_720P != enViMode) )
{
s32Ret = HI_MPI_ISP_GetWDRMode(s32IspDev, &stWdrMode);
if (s32Ret != HI_SUCCESS)
{
SAMPLE_PRT("HI_MPI_ISP_GetWDRMode failed with %#x!\n", s32Ret);
return HI_FAILURE;
}
#使能dev
s32Ret = HI_MPI_VI_EnableDev(ViDev);
if (s32Ret != HI_SUCCESS)
{
SAMPLE_PRT("HI_MPI_VI_EnableDev failed with %#x!\n", s32Ret);
return HI_FAILURE;
}
#dev迴圈了一次,因為u32DevNum=1
/******************************************************
step 4 : config & start vicap dev
******************************************************/
for (i = 0; i < u32DevNum; i++)
{
ViDev = i;
s32Ret = SAMPLE_COMM_VI_StartDev(ViDev, enViMode);
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT("%s: start vi dev[%d] failed!\n", __FUNCTION__, i);
return HI_FAILURE;
}
}
VPSS(Video Process Sub-System)
#支援對一幅影象進行統一預處理,如去噪,去隔行等。
#什麼是去隔行,就是把隔行轉成逐行,因為以前的技術有隔行掃描,不過現在的大多數的sensor都是逐行掃描的了。
#然後再對各通道分別進行縮放,銳化等處理,最後輸出多種不同解析度的影象。
#從這句話可以看出,VI到VPSS是當通道輸入,多通道輸出是從VPSSz這裡出去的。擴充套件通道是從VPSS這裡出來的。
#具體的功能包括FRC(Frame Rate Control)、Crop、NR(Noise Reduce)、LDC(Lens Distortion Correction)
#Rotate、Cover/Overlay、Scale、Mirror/Flip、FishEye
#通過呼叫SYS模組的繫結介面這句話的意思,SYS模組就是MPP,繫結介面就是s32Ret = HI_MPI_SYS_Bind(&stSrcChn, &stDestChn);
#stSrcChn源頭通道是VI,目的通道stDestChn是VPSS
#group是VPSS硬體在軟體上的對映,如果只有一個group那就是VPSS硬體的1:1的對映,不用複用了
#group裡面分了好多個channel;
#VI裡面的channel和group裡面的channel是不同的東西
#是VI這裡的channel去繫結VPSS的gruop的
/*** enSize[0] **/
if(s32ChnNum >= 1)
{
VpssGrp = 0;
VpssChn = 0;
VencChn = 0;
s32Ret = SAMPLE_COMM_VENC_Start(VencChn, enPayLoad[0],\
gs_enNorm, enSize[0], enRcMode,u32Profile);
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT("Start Venc failed!\n");
goto END_VENC_1080P_CLASSIC_5;
}
s32Ret = SAMPLE_COMM_VENC_BindVpss(VencChn, VpssGrp, VpssChn);
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT("Start Venc failed!\n");
goto END_VENC_1080P_CLASSIC_5;
}
}
#Profile指的是H.264編碼的清晰度,分為baseline mainprofile hightprofile
/******************************************
step 1: Create Venc Channel
******************************************/
stVencChnAttr.stVeAttr.enType = enType;
switch(enType)
{
case PT_H264:
{
stH264Attr.u32MaxPicWidth = stPicSize.u32Width;
stH264Attr.u32MaxPicHeight = stPicSize.u32Height;
stH264Attr.u32PicWidth = stPicSize.u32Width;/*the picture width*/
stH264Attr.u32PicHeight = stPicSize.u32Height;/*the picture height*/
stH264Attr.u32BufSize = stPicSize.u32Width * stPicSize.u32Height;/*stream buffer size*/
stH264Attr.u32Profile = u32Profile;/*0: baseline; 1:MP; 2:HP; 3:svc_t */
stH264Attr.bByFrame = HI_TRUE;/*get stream mode is slice mode or frame mode?*/
stH264Attr.u32BFrameNum = 0;/* 0: not support B frame; >=1: number of B frames */
stH264Attr.u32RefNum = 1;/* 0: default; number of refrence frame*/
memcpy(&stVencChnAttr.stVeAttr.stAttrH264e, &stH264Attr, sizeof(VENC_ATTR_H264_S));
#stH264Attr.u32MaxPicWidth,stH264Attr.u32MaxPicHeight編碼通道的最大寬和高,如果給到通道里面的影象比這個大就會被壓縮,如果小就丟棄
#所有影象的寬高stH264Attr.u32PicWidth,stH264Attr.u32PicHeight就應該和最大寬和高設定一樣大,這樣是最好的,不用處理直接編碼
#stH264Attr.u32BufSize過程中的一個buffer,以畫素為單位
#svc_t是h.264的一個補充標準
================================================================================================================
pstPara = (SAMPLE_VENC_GETSTREAM_PARA_S*)p;
s32ChnTotal = pstPara->s32Cnt;
#s32Cnt告訴你有幾路,我們目前有三路
/******************************************
step 1: check & prepare save-file & venc-fd
******************************************/
if (s32ChnTotal >= VENC_MAX_CHN_NUM)
{
SAMPLE_PRT("input count invaild\n");
return NULL;
}
#總的通道數大於最大通道提醒輸入無效
for (i = 0; i < s32ChnTotal; i++)
{
/* decide the stream file name, and open file to save stream */
VencChn = i;
s32Ret = HI_MPI_VENC_GetChnAttr(VencChn, &stVencChnAttr);
if(s32Ret != HI_SUCCESS)
{
SAMPLE_PRT("HI_MPI_VENC_GetChnAttr chn[%d] failed with %#x!\n", \
&nbs