1、分析mmp的sample工程
注意;建立SI工程的时候注意要把外面的那个include文件夹加载进来
sample_venc的大体分析
(1)从main入手,main的传参分析
(2)几个基本概念:
H.264 H.265 MJPEG 视频编码规范标准
1080P、720P、VGA、D1 视频分辨率(清晰度)
fps(frame per second) 帧率
MMP分析查看的手册;01.software\board\document_cn\HiMPP IPC V2.0 媒体处理软件开发参考.pdf
2、图像像素格式 RGB和YUV
rawRGB和图像采集过程
(1)图像采集的过程:光照在成像物体被反射->镜头汇聚->Sensor光电转换->ADC为rawRGB
(2)sensor上每个像素只采集特定颜色的光的强度,因此sensor每个像素只能为R或G或B
(3)rawRGB和RGB都是用来描述图像的,图像采集时RGB是由rawRGB计算而来的
(4)因为图像颜色本身有一定连贯性,而且人眼是非理想的,因此图像采集和再显示给人这整个构成中有三个要素:分辨率、pitch、观看距离
(5)如果是视频,质量好坏还要加上帧率framerate
(6)图像的表达、压缩、修整等相关技术,就发生在rawRGB进来以后的各个环节
RGB和YUV详解1_2
RGB方式表示颜色
(1)RGB有RGB565和RGB888,ARGB等多种子分类;
RGB565 就是 5+6+5用16位表示的,RGB888 就是用24位表示,ARGB加上透明度
(2)RGB的本质:将所有色度分解为R、G、B三部分,然后记录下亮度数据,最后再由RGB混合成颜色,因此与灰度图兼容不友好。
(3)RGB的优势:方便数字化表达,广泛用于数字化彩色显示器,计算机编程等领域。
(4)RGB的劣势:和传统的灰度图兼容不好,表达颜色的效率不高
YUV
(1)YUV是一种色彩空间,Y表示亮度,U和V表示色度。只有Y就是黑白图像,再加上UV就是彩色图像了。YUV的一个好处就是让彩色系统和传统黑白系统很好的兼容。
(2)YUV和RGB的相同点是:都是用来表达颜色的数学方法;不同点是:对颜色的描述思路和方法不同。RGB将一个颜色拆解为3个纯色的亮度组合,YUV将一个颜色分解为一个亮度和2个色度的组合。
(3)RGB和YUV之间可以用数学方法互相换算,是个典型的浮点运算过程。
(4)YUV和YCbCr几乎可以看做一个概念,详细的区分以后再去慢慢体会。
(5)YUV分为packed和planar两种。具体参考:http://blog.csdn.net/sunnylgz/article/details/7580628
具体的区别就是YUV三个像素的组合顺序不同,packed模式是按像素打包,一个像素的YUV存储在一起 如 Y1U1V1 Y2U2V2…这样的顺序存储,而planar平面是按YUV 将几个像素的Y U V抽出来再按 Y1,Y2,Y3… U1 U2 U3…v1 v2 v3 …的顺序存储。
(6)有多种YUV相关的概念需要弄清楚
YUV
YUYV 就是 YUV422 四个像素点有四个Y,2个U,V水平两个组合一个
YUV422
YUV420(YUV411) 四个像素点有四个Y,1个U,V水平两个组合一个
YUV422 planar(YUV422P) P的存储方式为 U,V分别存放,先放U1,U2,U3…v1,v2,v3…
YUV420 Planar(YUV420P)
YUV422 semi planar(YUV422SP) SP的存储方式为一个像素 U,V一起存放,先放u1v1,u2v2
YUV420 semi Planar(YUV420SP)
参考:http://blog.csdn.net/bingqingsuimeng/article/details/50716390
和https://www.2cto.com/kf/201303/198023.html
3、MPP功能模块
海思提供的媒体处理软件平台(Media Process Platform,简称 MPP),可支持应用软件快速
开发。该平台对应用软件屏蔽了芯片相关的复杂的底层处理,并对应用软件直接提供
MPI( MPP Programe Interface)接口完成相应功能。
HiMPP IPC V2.0 媒体处理软件开发参考.pdf 手册查阅
4、视频缓冲池 VB
(1)视频的本质是多帧图片,图片的本质是RGB或rawRGB数据,要占用一段连续内存
(2)视频的裁剪、缩放、修正处理等各种操作,本质上就是对内存中的数据进行运算
(3)视频缓存池(VB, video buffer)就是一段很大,又被合理划分和管理的内存,用来做视频数据的暂存和运算场地
(4)公共视频缓存池的公共2字,可以理解为全局变量,也就是各个模块都能访问的一段内存
(5)看似视频缓存块在各个模块之间流转,实际上并没有内存复制,而是指针在传递
(6)视频缓存池的内存由MPP来维护,我们在系统启动时就把整个SDRAM分成了2部分:系统部分(由linux kernel来维护管理)和mpp部分(由mpp系统来维护管理)
(7)缓存池需要几个,每个中包含几个缓存块,每个缓存块多大,都是可以由用户程序设置好参数,然后调用MPP的相应API来向MPP申请分配的。
VB相关的数据结构和API
(1)VB_CONF_S 结构体变量定义并进行了填充
(2)HI_MPI_VB_SetConf 将结构体变量设置到MPP系统里面去,但还没有具体分配内存
(3)HI_MPI_VB_Init 设置到MPP之后,调用init才真正具体分配内存
typedef struct hiVB_CONF_S
{
//表示最多有多少个缓冲池
//VB_MAX_POOLS这个是MMP系统定义的上限
HI_U32 u32MaxPoolCnt; /* max count of pools, (0,VB_MAX_POOLS] */
//定义的公告缓冲池 即使上面图片的ABC...一共多少个这样的池
struct hiVB_CPOOL_S
{
HI_U32 u32BlkSize; 这个要与自己的一帧图片有多大有关;公共缓存池中每个缓存块的大小应根据当前图像像素格式以及图像是否压缩而有所不同。
HI_U32 u32BlkCnt;
HI_CHAR acMmzName[MAX_MMZ_NAME_LEN];
}astCommPool[VB_MAX_COMM_POOLS];//VB_MAX_COMM_POOLS 16个
} VB_CONF_S;
成员名称 描述
u32MaxPoolCnt 整个系统中可容纳的缓存池个数。
取值范围: (0, VB_MAX_POOLS]。
静态属性。
目前,固定取值 VB_MAX_POOLS。
astCommPool 公共缓存池属性结构体,成员包括公共缓存池中每个缓存块的大小(以 byte 为单位)和缓存块的个数及此缓存池在所在的MMZ 的名字。
5、VI部分的概念知识
1)常用Sensor的接口有三种:MIPI、LVDS、DC
(2)WDR宽动态 场景中特别亮的部分和特别暗的部分都能看清楚。太亮的曝光就要快一点,太暗就要曝光久一点,
宽动态手段就是让同一幅图像有不同的曝光,保证都能看清。
宽动态范围;图像能分辨最亮的亮度信号值与能分辨的最暗的亮光信号值的比值
(3)isp就是image signal process,图像信号处理。
(4)HI3518E内部的ISP单元是隶属于VI模块的。
VI模块就包含3大部分:第一部分是和Sensor对接的部分,第二部分就是ISP,第三部分就是VI dev(采集的硬件单元)和channel(采集后的图像处理传输通道)
6、VPSS部分的概念知识
VPSS( Video Process Sub-System)支持对一幅输入图像进行统一预处理,如去噪、去隔行等,然后再对各通道分别进行缩放、锐化增加清晰程度等处理,最后输出多种不同分辨率的图
像
GROUP;VPSS 对用户提供组( GROUP)的概念。各芯片的最大组数目有所不同,各 GROUP 分时复用 VPSS 硬件,因此GROUP其实就是VPSS引进的一个
虚拟化设备映射。每个 VPSS GROUP 包含多个通道。
CHANNEL;VPSS 组的通道。通道分为 2 种:物理通道和扩展通道。 VPSS 硬件提供多个物理通道,
每个通道具有缩放、裁剪等功能。扩展通道具备缩放功能,它通过绑定物理通道,将物理通道输出作为自己的输入,把图像缩放成用户设置的目标分辨率
输出。因此可以说扩展通道是借助物理通道完成工作的。
VI的Chn(和Dev)
在 VI里面也是有Dev 和Chn 其中Dev与GROUP类似,也是VI的映射,但是Chn就是绑定一个Dev的
注意VI和VPSS 的chn是没有一点关系的,在之后的数据对接,也是VI的Chn对接VPSS的GROUP的
7、venc 编码模块
这个模块因为太复杂也是海思那么封装的太好,我们这边在实践操作中不需要做什么.。创建通道,绑定,启动数据接收即可完成了。
8、sample工程解析
分析main的SAMPLE_VENC_1080P_CLASSIC分支
分析方法;绘制调用关系图谱
(1)有些函数是sample写的,有些是调用MPP的,数据结构也是2种都有,根据名称 HI_MPI就是MMP里面写的这个就不用再追了。
(2)学习重点1:全局把控熟悉整个过程全景视图
(3)学习重点2:掌握细节数据结构元素含义,和遇到的概念
(4)学习重点3:知道某些关键操作在哪里定义,哪里设置,将来需要改的时候能找到地方
第一步;根据serson获取分辨率大小,设置三路码流,设置VB的stVbConf参数
SAMPLE_COMM_VI_GetSizeBySensor 通过sensor得到将来sensor出来的图片分辨率大小
SAMPLE_COMM_SYS_CalcPicVbBlkSize 根据不同码流图片分辨率计算要申请视频缓冲池中缓冲块的大小
SAMPLE_COMM_SYS_GetPicSize 获取大小
CEILING_2_POWER 对齐
VB_PIC_HEADER_SIZE
第二步;根据第一步填充的VB的stVbConf参数 对VB系统进行设置 初始化,并且对sys也就是mmp系统也进行设置和初始化,注意两者的顺序
SAMPLE_COMM_SYS_Init
HI_MPI_SYS_Exit
HI_MPI_VB_Exit
HI_MPI_VB_SetConf
HI_MPI_VB_Init
HI_MPI_SYS_SetConf
HI_MPI_SYS_Init
第三步;开启VI部分,要分为三部分 与serson那边的参数设置,内部ISP模块参数设置和启动,VI本身dev设备和chn通道设置启动
SAMPLE_COMM_VI_StartVi
IsSensorInput(enViMode)判断是不是从sensor来的
SAMPLE_COMM_VI_StartIspAndVi(走这里)
(1)mipi configure mipi就是serson常用接口的一种,这里就是设置VI中对对接sensor的属性
SAMPLE_COMM_VI_StartMIPI
SAMPLE_COMM_VI_SetMipiAttr
(2)configure sensor and ISP (include WDR mode) 这一步是可以跳过的
SAMPLE_COMM_ISP_Init 部署安装HI3518E内部自带的ISP部件
1.sensor_register_callback 配置VI内部对sensor的注册
2.HI_MPI_AE_Register 内部ISP的自动曝光模块注册 3A注册
3.HI_MPI_AWB_Register
4.HI_MPI_AF_Register
5.HI_MPI_ISP_MemInit 自己使用内存注册
6.HI_MPI_ISP_SetWDRMode 宽动态模式
7.HI_MPI_ISP_SetPubAttr
8.HI_MPI_ISP_Init 最后初始化整个ISP的
(3)run isp thread 第二步准备参数,这步进行启动ISP
SAMPLE_COMM_ISP_Run 运行ISP模块 算法都是提供好的,我们只需要填充参数运行的
pthread_create(&gs_IspPid, &attr, (void* (*)(void*))Test_ISP_Run, NULL)
SAMPLE_COMM_ISP_Run
HI_MPI_ISP_Run
(4)config & start vicap dev
SAMPLE_COMM_VI_StartDev
HI_MPI_VI_SetDevAttr 设置VI的采集设备硬件的属性并启动设备
HI_MPI_ISP_GetWDRMode
HI_MPI_VI_SetWDRAttr
HI_MPI_VI_EnableDev
(5)onfig & start vicap chn (max 1)
SAMPLE_COMM_VI_StartChn 设置主chn属性并启动,之后可以扩展chnannel
HI_MPI_VI_SetChnAttr
HI_MPI_VI_EnableChn
第四步;完成VPSS部件的GRp启动,与VI的绑定,以及VPSS的Chn设置
SAMPLE_COMM_SYS_GetPicSize
SAMPLE_COMM_VPSS_StartGroup 创建GRP 获取参数 设置参数 开始GRP
HI_MPI_VPSS_CreateGrp
HI_MPI_VPSS_GetNRParam
HI_MPI_VPSS_SetNRParam
HI_MPI_VPSS_StartGrp
SAMPLE_COMM_VI_BindVpss 绑定VI的ch和Vpss的grp
SAMPLE_COMM_VI_Mode2Param
HI_MPI_SYS_Bind
SAMPLE_COMM_VPSS_EnableChn 每个通道都执行一遍 三条码流
HI_MPI_VPSS_SetChnAttr or HI_MPI_VPSS_SetExtChnAttr 物理通道还是扩展通道
HI_MPI_VPSS_SetChnMode or 不执行
HI_MPI_VPSS_EnableChn
第五步;完成对venc模块 chn启动 接收数据开启 和与VPSS模块的chn绑定
getchar() 选择格式
SAMPLE_COMM_VENC_Start 每个通道都执行一遍
SAMPLE_COMM_SYS_GetPicSize
(1) Create Venc Channel
HI_MPI_VENC_CreateChn
(2)Start Recv Venc Pictures
HI_MPI_VENC_StartRecvPic
SAMPLE_COMM_VENC_BindVpss
第六步;从venc模块的编码文件流存储到file中
因为主线程要等待结束,则要采用子线程方式执行
因为涉及多路码流的写入,想多与多路IO一样,则要先把要读写的venc的fb和要写入文件的fb都打开好,
再再循环里进行遍历判断,看select回来的是哪个fb从而进行写人操作
for (i = 0; i < s32ChnTotal; i++)
{
s32Ret = HI_MPI_VENC_GetChnAttr(VencChn, &stVencChnAttr);
s32Ret = SAMPLE_COMM_VENC_GetFilePostfix(enPayLoadType[i], szFilePostfix);
pFile[i] = fopen(aszFileName[i], "wb");
VencFd[i] = HI_MPI_VENC_GetFd(i);
}
while (HI_TRUE == pstPara->bThreadStart)//整个线程的循环,一直采集录像
{
s32Ret = select(maxfd + 1, &read_fds, NULL, NULL, &TimeoutVal);
//成功后
for (i = 0; i < s32ChnTotal; i++)
{
if (FD_ISSET(VencFd[i], &read_fds))//遍历判断哪路读出来的
{
s32Ret = HI_MPI_VENC_Query(i, &stStat);
stStream.pstPack = (VENC_PACK_S*)malloc(sizeof(VENC_PACK_S) * stStat.u32CurPacks);
s32Ret = HI_MPI_VENC_GetStream(i, &stStream, HI_TRUE);
s32Ret = SAMPLE_COMM_VENC_SaveStream(enPayLoadType[i], pFile[i], &stStream);//里面也是fwrite fflush
s32Ret = HI_MPI_VENC_ReleaseStream(i, &stStream);
free(stStream.pstPack);//哪里申请的哪里释放
stStream.pstPack = NULL;
}
}
}
//最后还要关闭打开的文件
for (i = 0; i < s32ChnTotal; i++)
{
fclose(pFile[i]);
}
第7步、等待操作结束应用,结束子线程开关变量,回收子线程
gs_stPara.bThreadStart = HI_FALSE;//关闭子线程
pthread_join(gs_VencPid, 0);//阻塞回收子线程
最后就是倒影式的资源回收方式了