朱老师,3518e系列,第二季
第一节, mpp sample 的总体分析。
对于摄像头,是需要实时显示的,这就需要 frambuffer 显示 摄像头的内容。
但是我的 3516cv610 没有这个例子, 因为 我的板子就没有 显示接口。
sdk 提供 Mpp 的api 手册。
h264, h265, mjpeg 都是编码的规范。
我这里的源码就是用它的 3518e ..
解压完成。
VGA是一个分辨率,不是 显示器。
第二节,图像格式理解一 + 理解二。
图像的采集过程。
小孔成像---->sensor 光电转换---->adc--->rawrgb。
sensor 的作用是 将 光信号转换成电信号。
sensor 有像素的概念。
sensor 自带 adc 将模拟电信号,转成 数字电信号。
sensor 上的每个像素 ,只能转换一种 RGB 光。
rawrgb 怎么得到rgb 呢,是从 周围的 rgb 的像素的值 ,算出来的。
第三节, YUV 与RGB
RGB : 有 RGB565 , RGB888 ,
它数据量大, 并且兼容 黑白图 效果不好,因为, 红绿蓝, 上来就是颜色,单色数值的不同表示的是亮度的不同。
透明度应该是 表示的3D,感觉。
YUV, Y表示亮度,UV表示颜色, 能够兼容黑白图,直接将UV 置零。
YUV与 RGB的转换, 这个转化不看了。
YUV 与Ycbcr 是一样的概念。
YUV packed 与 planar 的区别。
就是 数据的存放的方式的问题。
实际中用到的最多的是 planer 的,而不是 packed .
然后 是 planer 与semi planar 的区别。
可以看到, semi planar 就是 Y 是跟 planar 一样的,但是 U V , 就跟 packed 一样了。
YUV420 sp 与 YUV420 p 只是在 排列方式上有区别。
都是 一个像素对应一个 Y, 但是 四个像素对应一个 UV。
如图:
YUV422 就是 一个像素还是 对应一个 Y,但是, 一个UV 表示 两个 像素点了, 420 是表示4个。
至于 YUV422p 与YUV422 的区别与 YUV420 是一样的。
总结一下:
YUV 指的是 packed
YUVp 指的是 planar
YUVsp 指的是 semi planar
第六节+第七节, mpp 的功能模块,视频缓存池。
对于视频来说, VI , VPSS , Venc 都是有对视频做处理的。
接下来就是分析代码了。
首先是 这个函数。
这里 enpayload 就是 视频在传输的时候的 载体, 就是使用的什么协议。
海思的编码 在 枚举定义的时候, 会有 E的标识 , 比如 PAYLOAD_TYPE_E
在 实例化的时候, 命令 也有 枚举的标志, 比如, enPayLoad.
对与结构体也是一样的,比如 , SAMPLE_VI_CONFIG_s, stViConfig.
总结:
1 视频缓存就是 图像的暂时存储 + 图像运算的暂时存储 场地。
总结 ;
1 缓存池 可以有多个,
2 缓存池 可以分成 缓存块。
首先 从 缓存池中拿一个缓存块,然后 进入VI, 处理后 进入VPSS, 处理后,进入 VENC ,处理完之后, 释放缓存块。 但是处理之后的 内容放到哪里 没说。
感觉 缓存池中的内容应该是 摄像头放进去的。
VB_CONF_S 定义了 关于 VB的 结构体。
使用举例:
总结:
1 设置结构体。
2 xxxx_SetConfig , 有点挂接的意思。
3 xxx_Init , 初始化。
在具体的代码中是 分开设置的。
sample_comm_sys_init = setconf + init.
第8节+第九节 , mpp 初始化分析。
首先是大致的结构的梳理。
首先是 初始化 变量。
然后是 对MPP 进行初始化。
然后是 初始化 VI。
然后是 初始化 VPSS。
然后是 开始 编码 。
然后是 编码完 之后 开始保存。
然后就是 退出了。
接下来是关于 函数 SAMPLE_COMM_VI_GetSizeBySensor 的分析。
这里的 SENSOR_TYPE 是在 makefile 中进行设置的。
也就是说 这里是手动设置的,并不是从sensor 中读取的。
34 /******************************************************************************33 * funciton : Get enSize by diffrent sensor32 ******************************************************************************/31 HI_S32 SAMPLE_COMM_VI_GetSizeBySensor(PIC_SIZE_E *penSize)30 {29 HI_S32 s32Ret = HI_SUCCESS;28 SAMPLE_VI_MODE_E enMode = SENSOR_TYPE;2726 if (!penSize)25 {24 return HI_FAILURE;23 }2221 switch (enMode)20 {19 case APTINA_AR0130_DC_720P_30FPS:18 case APTINA_9M034_DC_720P_30FPS:17 case SONY_IMX222_DC_720P_30FPS:16 case OMNIVISION_OV9712_DC_720P_30FPS:15 case OMNIVISION_OV9732_DC_720P_30FPS:14 case OMNIVISION_OV9750_MIPI_720P_30FPS:13 case OMNIVISION_OV9752_MIPI_720P_30FPS:12 *penSize = PIC_HD720;11 break;10 case APTINA_AR0230_HISPI_1080P_30FPS:9 case SONY_IMX222_DC_1080P_30FPS:8 case PANASONIC_MN34222_MIPI_1080P_30FPS:7 case OMNIVISION_OV2718_MIPI_1080P_25FPS:6 *penSize = PIC_HD1080;5 break;43 default:2 printf("not support this sensor\n");1 break;3121 }12 return s32Ret;3 }4
这里 默认是 Imx22
那么我的 hi3516cv610 呢,
看来默认就是 sc4336p
这里 设置了 三路的视频, 并且设置了三路的分辨率。
然后就是 SAMPLE_COMM_SYS_CalcPicVbBlkSize 用于计算 block 的 大小的。
37 /******************************************************************************36 * function : calculate VB Block size of picture.35 ******************************************************************************/34 HI_U32 SAMPLE_COMM_SYS_CalcPicVbBlkSize(VIDEO_NORM_E enNorm, PIC_SIZE_E enPicSize, PIXEL_FORMAT_E enPixFmt, HI_U32 u32AlignWidth)33 {32 HI_S32 s32Ret = HI_FAILURE;31 SIZE_S stSize;30 HI_U32 u32VbSize;29 HI_U32 u32HeaderSize;2827 s32Ret = SAMPLE_COMM_SYS_GetPicSize(enNorm, enPicSize, &stSize);26 if (HI_SUCCESS != s32Ret)25 {24 SAMPLE_PRT("get picture size[%d] failed!\n", enPicSize);23 return HI_FAILURE;22 }2120 if (PIXEL_FORMAT_YUV_SEMIPLANAR_422 != enPixFmt && PIXEL_FORMAT_YUV_SEMIPLANAR_420 != enPixFmt)19 {18 SAMPLE_PRT("pixel format[%d] input failed!\n", enPixFmt);17 return HI_FAILURE;16 }1514 if (16!=u32AlignWidth && 32!=u32AlignWidth && 64!=u32AlignWidth)13 {12 SAMPLE_PRT("system align width[%d] input failed!\n",\11 u32AlignWidth);10 return HI_FAILURE;9 }8 //SAMPLE_PRT("w:%d, u32AlignWidth:%d\n", CEILING_2_POWER(stSize.u32Width,u32AlignWidth), u32AlignWidth);7 u32VbSize = (CEILING_2_POWER(stSize.u32Width, u32AlignWidth) * \6 CEILING_2_POWER(stSize.u32Height,u32AlignWidth) * \5 ((PIXEL_FORMAT_YUV_SEMIPLANAR_422 == enPixFmt)?2:1.5));43 VB_PIC_HEADER_SIZE(stSize.u32Width, stSize.u32Height, enPixFmt, u32HeaderSize);2 u32VbSize += u32HeaderSize;1177 return u32VbSize;1 }
得到 图片的分辨率。
然后计算VB的大小。
最后加上个头信息。
然后就是这个了。
40 /******************************************************************************39 * function : vb init & MPI system init38 ******************************************************************************/37 HI_S32 SAMPLE_COMM_SYS_Init(VB_CONF_S *pstVbConf)36 {35 MPP_SYS_CONF_S stSysConf = {0};34 HI_S32 s32Ret = HI_FAILURE;3332 HI_MPI_SYS_Exit();31 HI_MPI_VB_Exit();3029 if (NULL == pstVbConf)28 {27 SAMPLE_PRT("input parameter is null, it is invaild!\n");26 return HI_FAILURE;25 }2423 s32Ret = HI_MPI_VB_SetConf(pstVbConf);22 if (HI_SUCCESS != s32Ret)21 {20 SAMPLE_PRT("HI_MPI_VB_SetConf failed!\n");19 return HI_FAILURE;18 }1716 s32Ret = HI_MPI_VB_Init();15 if (HI_SUCCESS != s32Ret)14 {13 SAMPLE_PRT("HI_MPI_VB_Init failed!\n");12 return HI_FAILURE;11 }109 stSysConf.u32AlignWidth = SAMPLE_SYS_ALIGN_WIDTH;8 s32Ret = HI_MPI_SYS_SetConf(&stSysConf);7 if (HI_SUCCESS != s32Ret)6 {5 SAMPLE_PRT("HI_MPI_SYS_SetConf failed\n");4 return HI_FAILURE;3 }21 s32Ret = HI_MPI_SYS_Init();368 if (HI_SUCCESS != s32Ret)1 {2 SAMPLE_PRT("HI_MPI_SYS_Init failed!\n");3 return HI_FAILURE;4 }56 return HI_SUCCESS;7 }8
这两个函数 是关于 VB的。
HI_MPI_VB_SetConf
HI_MPI_VB_Init
这两个函数是关于 sys 的。
HI_MPI_SYS_SetConf
HI_MPI_SYS_Init
接下俩就是关于 VI的部分了。
解析来绘制 关于 VI 的 调用关系图。
mainSAMPLE_VENC_1080P_CLASSIC()step 1: init sys variableSAMPLE_COMM_VI_GetSizeBySensorstep 2: mpp system initSAMPLE_COMM_SYS_InitHI_MPI_VB_SetConfHI_MPI_VB_InitHI_MPI_SYS_SetConfHI_MPI_SYS_Initstep 3: start vi dev & chn to captureSAMPLE_COMM_VI_StartViSAMPLE_COMM_VI_StartIspAndViSAMPLE_COMM_VI_StartMIPISAMPLE_COMM_VI_SetMipiAttrfd = open("/dev/hi_mipi", O_RDWR)ioctl(fd, HI_MIPI_SET_DEV_ATTR, pstcomboDevAttr)SAMPLE_COMM_ISP_Initsensor_register_callbackHI_MPI_AE_RegisterHI_MPI_AWB_RegisterHI_MPI_AF_RegisterHI_MPI_ISP_MemInitHI_MPI_ISP_SetWDRModeHI_MPI_ISP_SetPubAttrHI_MPI_ISP_InitSAMPLE_COMM_ISP_Runpthread_create(&gs_IspPid, &attr, (void* (*)(void*))Test_ISP_Run, NULL))HI_MPI_ISP_RunSAMPLE_COMM_VI_StartDevHI_MPI_VI_SetDevAttrHI_MPI_ISP_GetWDRModeHI_MPI_VI_SetWDRAttrHI_MPI_VI_EnableDevSAMPLE_COMM_VI_StartChnHI_MPI_VI_SetChnAttrHI_MPI_VI_SetRotateHI_MPI_VI_EnableChnstep 4: start vpss and vi bind vpssSAMPLE_COMM_SYS_GetPicSizeSAMPLE_COMM_VPSS_StartGroupSAMPLE_COMM_VI_BindVpssSAMPLE_COMM_VI_Mode2ParamHI_MPI_SYS_BindSAMPLE_COMM_VPSS_EnableChnSAMPLE_COMM_SYS_GetPicSizeSAMPLE_COMM_VPSS_EnableChnSAMPLE_COMM_SYS_GetPicSizeSAMPLE_COMM_VPSS_EnableChnstep 5: start stream vencSAMPLE_COMM_VENC_StartHI_MPI_VENC_CreateChnHI_MPI_VENC_StartRecvPicSAMPLE_COMM_VENC_BindVpssHI_MPI_SYS_Bindstep 6: stream venc process -- get stream, then save it to file.SAMPLE_COMM_VENC_StartGetStreampthread_create(&gs_VencPid, 0, SAMPLE_COMM_VENC_GetVencStreamProc, (HI_VOID*)&gs_stPara);HI_MPI_VENC_GetStreamSAMPLE_COMM_VENC_SaveStreamstep 7: exit processSAMPLE_COMM_VENC_StopGetStream
然后来看看 VI的部分。
这几个 参数就是 在设置 mipi 相机。
enViMode 是 相机的型号。
enRotate 是 是否旋转。
enViChnset 是 , 是否镜像。
enWDRMode , 指是否 宽动态,宽动态 就是让 图片上的 最暗的地方亮一点,让最亮的地方暗一点。
然后 sensor 的驱动已经 注册进去了。 这里填写好参数之后 ,直接以打开文件的方式, 使用 ioctl 的方式传递进去。
什么是ISP呢?
是 芯片内部的关于 图像处理的单元,也可以不用,使用外扩的 进行处理
自动曝光,
自动对焦。
自动白平衡。
接下俩分析这个函数。
sensor_register_callback 这个函数 在 ISP 的目录下。
这些函数 是关于自动对焦 , 自动白平衡的内容。
HI_MPI_AE_Register
HI_MPI_AWB_Registe
HI_MPI_AF_Register
这是在 为 ISP 申请内存。
HI_MPI_ISP_MemInit
这是在设置宽动态
HI_MPI_ISP_SetWDRMode
HI_MPI_ISP_SetPubAttr 这个函数是在设置 ISP的属性。
f32FrameRate 是帧率。
VI 模块 大致分为三个部分, 一是 与 摄像头对接, 一是 ISP , 一是 device + channel .
device 不理解,但是 他的作用,基本上就是, 将一路图像 产生 3路输出图像。
具体的函数就不看了。
接下来就是关于 VPSS了。
看来 , AI 与 venc 是 两条通路。
group 就是 对VPSS 的控制的抽象。
可以看到 VI 与 VPSS, 以及 与 后面的处理模块是通过 sys 模块进行控制的。
但是 不理解 VPSS的 通道的含义。
来分析一下代码。
感兴趣的是 bind 函数,看一下。
这里设置了 vi 源, 以及 vpss 的输出通道。
所以看来, vpss 会输出 压缩的 三路图像,而不是 vi.
但是 怎么跟 保存联系起来的呢?
原来在这里, 也就是 说 venc 将 每一路的 vpss 的 通道 都绑定了。
手册中 有对 各个通道的说明。
第十六节, 视频压缩的原理。
空间压缩
时间压缩
第十七节, mpp 手册的解读。
REGION 就是 添加的 OSD
编码通道 对 图像 有限制。
码率控制: 编码的压缩比。
CBR: 固定码率
VBR: 可变的 码率。
FIXQP: 固定图像质量。
第18节 , 关于 venc 的讲解。
首先是 start venc
这里就将 spss 的通道与 venc 的通道 相联系了。
然后就是 获取流。
对每个 venc 的 通道 都去保存
接下来 就是 分析这个函数。
HI_S32 SAMPLE_COMM_VENC_Start(VENC_CHN VencChn, PAYLOAD_TYPE_E enType, VIDEO_NORM_E enNorm, PIC_SIZE_E enSize, SAMPLE_RC_E enRcMode,HI_U32 u32Profile)
这个函数 主要是 , profile . 它代表着 清晰度。
然后就是 关于 保存的流程了。
这个函数就是 在设置 文件的 后缀名。
这个函数就是 得到 venc 编码好的 东西。 这里 做成了一个文件的形式。
这里 有一个 select 函数。 可以 测试 一下 select 函数
到这里 这一期就 完毕了。