如何获取 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目录下例程前提是外部应用开启了流,即这些代码不包含启动流的初始化。

  1. 设置 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);
  1. 获取帧。
s32Ret = HI_MPI_VPSS_GetChnFrame(Grp, Chn, &stFrame, s32MilliSec);
  1. 这里保存数据需要视频存储格式为线性的,根据动态范围选择对应保存方式。
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);
}

  1. 释放获取的帧。
s32Ret = HI_MPI_VPSS_ReleaseChnFrame(Grp, Chn, &stFrame);
  1. 这里是一个外部dump工具,结束时需要还原属性。
stChnAttr.u32Depth = u32OrigDepth;
s32Ret = HI_MPI_VPSS_SetChnAttr(VpssGrp, VpssChn, &stChnAttr);
原文地址:https://www.cnblogs.com/llil/p/14552807.html