如何获取 VPSS 图像数据
数据结构
视频图像帧信息
typedef struct hiVIDEO_FRAME_INFO_S
{
VIDEO_FRAME_S stVFrame; //视频图像帧
...
} VIDEO_FRAME_INFO_S;
原始图像帧
typedef struct hiVIDEO_FRAME_S
{
HI_U32 u32Width; //图像宽度
HI_U32 u32Height; //图像高度
...
PIXEL_FORMAT_E enPixelFormat; //视频图像像素格式
VIDEO_FORMAT_E enVideoFormat; //视频图像格式
...
DYNAMIC_RANGE_E enDynamicRange;//动态范围枚举
...
HI_U32 u32Stride[3]; //图像数据跨距
...
HI_U64 u64PhyAddr[3]; //图像数据物理地址
HI_U64 u64VirAddr[3]; //图像数据虚拟地址(内核态)
...
} VIDEO_FRAME_S;
enPixelFormat
:像素存储格式决定怎么取获取和保存图片,如:yuv、rgb...
enVideoFormat
:这里获取帧数据时要保证格式为VIDEO_FORMAT_LINEAR
线性存储的视频格式.
enDynamicRange
:动态范围主要分为 8bit数据 和10bit 数据,它们的保存图片方法存在差异。
u32Stride
:通常图像分配空间大小使用跨距计算。如YUV_400格式:u32Size = u32Stride[0] * u32Height。
u64VirAddr
:这个虚拟地址是内核态的,用户不操作。
u64PhyAddr
:用户要操作图像数据一般将这个物理地址HI_MPI_SYS_Mmap
后使用。
结构还包含其他一些成员,如:帧场模式、压缩模式、色域范围、压缩头信息、10bit数据分开存储信息、裁剪信息、亮度信息、帧号、时间、私有数据标记、补充信息等。
参考流程
源码路径 mpp/tools/vpss_chn_dump.c
,值得注意的是tools
目录下例程前提是外部应用开启了流,即这些代码不包含启动流的初始化。
- 设置 VPSS 物理通道属性
VPSS_CHN_ATTR_S
的队列长度u32Depth
。当队列长度为0时取不到帧。
s32Ret = HI_MPI_VPSS_GetChnAttr(Grp, Chn, &stChnAttr);
stChnAttr.u32Depth = 2;
s32Ret = HI_MPI_VPSS_SetChnAttr(Grp, Chn, &stChnAttr);
- 获取帧。
s32Ret = HI_MPI_VPSS_GetChnFrame(Grp, Chn, &stFrame, s32MilliSec);
- 这里保存数据需要视频存储格式为线性的,根据动态范围选择对应保存方式。
if (VIDEO_FORMAT_LINEAR != stFrame.stVFrame.enVideoFormat)
{
return;
}
if (DYNAMIC_RANGE_SDR8 == stFrame.stVFrame.enDynamicRange)
{
sample_yuv_8bit_dump(&stFrame.stVFrame, pfd);
}
以8bit数据的获取图像过程为例。首先需要计算图像帧占字节数,然后将这个大小的物理地址映射到虚拟空间,再把这块空间的数据写到文件,最后解除映射。
sample_yuv_8bit_dump(VIDEO_FRAME_S *pVBuf, FILE *pfd)
{
//计算大小
if (PIXEL_FORMAT_YUV_400 == pVBuf->enPixelFormat)
u32Size = (pVBuf->u32Stride[0]) * (pVBuf->u32Height);
//内存映射
pUserPageAddr[0] = (HI_CHAR *)HI_MPI_SYS_Mmap(phy_addr, u32Size);
//操作数据
for (h = 0; h < pVBuf->u32Height; h++)
{
pMemContent = pUserPageAddr[0] + h * pVBuf->u32Stride[0];
fwrite(pMemContent, pVBuf->u32Width, 1, pfd);
}
//解除映射
HI_MPI_SYS_Munmap(pUserPageAddr[0], u32Size);
}
- 释放获取的帧。
s32Ret = HI_MPI_VPSS_ReleaseChnFrame(Grp, Chn, &stFrame);
- 这里是一个外部dump工具,结束时需要还原属性。
stChnAttr.u32Depth = u32OrigDepth;
s32Ret = HI_MPI_VPSS_SetChnAttr(VpssGrp, VpssChn, &stChnAttr);