前言
上一篇已经将himpp套入qt的基础上进行开发。那么qt中拿到frame则是很关键的交互,这是qt与海思可能编解码交叉开发的关键步骤。
受限制
因为直接配置sample的vi比较麻烦,确实是困难的,其实就是配置驱动,所以我们只能从开发板的demo入手,去在相等条件下探测可能的留,从vpss中拿取后,进行软编码。
当然,如果不用qt还有一种方式,也就是大量开发海思人员使用的方式,是基于sample写一个编码程序,然后使用本地socket交互,其实绝大部分海思开发者都是这样开发的,但是他们不涉及与qt的深入交互。
前提条件
需要移植ffmpeg到海思平台,可参考博文《FFmpeg开发笔记(十):ffmpeg在ubuntu上的交叉编译移植到海思HI35xx平台》。
Demo演示
从vpss中获取一帧图像,如下图:
相关的API
(原本整理了一大半自己的习惯格式,后续海思看多了,觉得海思文档也还行,就是争对性的开发,无用信息有点多,所以此处还是用海思的文档,但是只提取涉及的部分,海思文档是个庞大的体系,需要动手,光看是很难理解的)。
HI_MPI_VPSS_GetChnFrame:从通道获取一帧处理完的数据
用户从通道获取一帧处理完成的图像,必须与HI_MPI_VPSS_ReleaseChnFrame()配对使用。
函数原型
HI_S32 HI_MPI_VPSS_GetChnFrame(VPSS_GRP VpssGrp, VPSS_CHN VpssChn, VIDEO_FRAME_INFO_S *pstVideoFrame, HI_S32 s32MilliSec);
- 参数一:VpssGrou,通道组号,海思芯片通道号,
取值[0, VPSS_MAX_GRP_NUM]; - 参数二:VpssChn,通道号,通道组下的通道号,
取值[0, VPSS_MAX_CHN_NUM]; - 参数三:pstVideoFrame,帧数据的结构体,要取的数据就在这个帧里面,这
是很关键的结构体,稍后是会深入讲解的重点; - 参数四:s32MilliSec,阻塞时间,跟其他阻塞有点区别,-1为阻塞,0为直
接获取,其他整数位等待的超时时间。
返回值
其他注意
HI_MPI_VPSS_ReleaseChnFrame:释放一帧图像
释放之前通过HI_MPI_VPSS_GetChnFrame获取获取的图像。
函数原型
HI_S32 HI_MPI_VPSS_ReleaseChnFrame (VPSS_GRP VpssGrp, VPSS_CHN VpssChn, const VIDEO_FRAME_INFO_S *pstVideoFrame);
- 参数一:VpssGrou,通道组号,海思芯片通道号,
取值[0, VPSS_MAX_GRP_NUM],之前获取使用的是哪个就哪个; - 参数二:VpssChn,通道号,通道组下的通道号,
取值[0, VPSS_MAX_CHN_NUM];之前获取使用的是哪个就哪个; - 参数三:pstVideoFrame,帧数据的结构体,要取的数据就在这个帧里面,这
是很关键的结构体,稍后是会深入讲解的重点;
返回值
其他注意
相关的结构体
VIDEO_FRAME_INFO_S:定义视频图像帧信息结构体
结构体原型
typedef struct hiVIDEO_FRAME_INFO_S{ VIDEO_FRAME_S stVFrame; // 视频图像帧 HI_U32 u32PoolId; // 视频缓存池ID MOD_ID_E enModId; // 当前帧数据是由哪一个硬件逻辑模块写出的} VIDEO_FRAME_INFO_S;
VIDEO_FRAME_S:定义视频原始图像帧结构体
结构体原型
typedef struct hiVIDEO_FRAME_S{ HI_U32 u32Width; // 图像宽度 HI_U32 u32Height; // 图像高度 VIDEO_FIELD_E enField; // 帧场模式 PIXEL_FORMAT_E enPixelFormat; // 视频图像像素格式 VIDEO_FORMAT_E enVideoFormat; // 视频图像格式 COMPRESS_MODE_E enCompressMode; // 视频压缩模式 DYNAMIC_RANGE_E enDynamicRange; // 动态范围 COLOR_GAMUT_E enColorGamut; // 色域范围 HI_U32 u32HeaderStride[3]; // 图像压缩头跨距 HI_U32 u32Stride[3]; // 图像数据跨距 HI_U32 u32ExtStride[3]; // 10bit数据位宽的图像,部分格式分开存 HI_U64 u64HeaderPhyAddr[3]; // 压缩头物理地址 HI_U64 u64HeaderVirAddr[3]; // 压缩头虚拟地址,内核态虚拟地址 HI_U64 u64PhyAddr[3]; // 图像数据物理地址 HI_U64 u64VirAddr[3]; // 图像数据虚拟地址,内核态虚拟地址 HI_U64 u64ExtPhyAddr[3]; // 10bit数据位宽度的图像,部分格式分开存 HI_U64 u64ExtVirAddr[3]; // 10bit数据位宽度的图像,部分格式分开存 HI_S16 s16OffsetTop; // 图像顶部剪裁宽度 HI_S16 s16OffsetBottom; // 图像底部剪裁宽度 HI_S16 s16OffsetLeft; // 图像左侧剪裁宽度 HI_S16 s16OffsetRight; // 图像右侧剪裁宽度 HI_U32 u32MaxLuminance; // 显示图像的最大亮度 HI_U32 u32MinLuminance; // 显示图像的最小亮度 HI_U32 u32TimeRef; // 图像帧序列号 HI_U64 u64PTS; // 图像时间戳 HI_U64 u64PrivateData; // 私有数据 HI_U32 u32FrameFlag; // 当前帧的标记,使用FRAME_FLAG_E标记 VIDEO_SUPPLEMENT_S stSupplement; // 图像的补充信息} VIDEO_FRAME_S;
其他注意
相关枚举
VIDEO_FIELD_E:帧场模式
PIXEL_FORMAT_E:视频图像像素格式
VIDEO_FORMAT_E:视频图像格式
COMPRESS_MODE_E:视频压缩模式
DYNAMIC_RANGE_E:动态范围
COLOR_GAMUT_E:色域范围
VIDEO_SUPPLEMENT_S:图像的补充信息
Demo
void HiMppManager::testGetVPssFrame(){ VIDEO_FRAME_INFO_S videoFrameInfoS;#if 0 // 搜索开开发板用了哪个通道(应该只有2个摄像头,绑定了vpss) // 结果:探测到开发板在snap抓图模式下在通道组0通道0下有图片 for(int groupIndex = 0; groupIndex < VPSS_MAX_GRP_NUM; groupIndex++) { for(int channelIndex = 0; channelIndex < VPSS_MAX_CHN_NUM; channelIndex++) { HI_S32 s32MilliSec = 100; HI_S32 ret = HI_MPI_VPSS_GetChnFrame(groupIndex, channelIndex, &videoFrameInfoS, s32MilliSec); if(ret == 0) { LOG << QString("Succeed to get HI_MPI_VPSS_GetChnFrame(%1, %2, &videoFrameInfoS, %3)") .arg(groupIndex) .arg(channelIndex) .arg(s32MilliSec); break;#if 0 }else{ LOG << QString("Failed to get HI_MPI_VPSS_GetChnFrame(%1, %2, &videoFrameInfoS, %3): %4") .arg(groupIndex) .arg(channelIndex) .arg(s32MilliSec) .arg(ret);#endif } } }#endif while(HI_MPI_VPSS_GetChnFrame(0, 0, &videoFrameInfoS, -1) == 0) { LOG << "get frame"; LOG << videoFrameInfoS.stVFrame.enPixelFormat << "PIXEL_FORMAT_YVU_PLANAR_420:" << (int)PIXEL_FORMAT_YVU_PLANAR_420 << "PIXEL_FORMAT_YVU_SEMIPLANAR_420:" << (int)PIXEL_FORMAT_YVU_SEMIPLANAR_420; LOG << videoFrameInfoS.stVFrame.enVideoFormat; HI_MPI_VPSS_ReleaseChnFrame(0, 0, &videoFrameInfoS); LOG << "release frame"; }}
入坑
入坑一:获取vpss图像一定帧数后无法再获取
问题
使用海思sdk获取图像后,多次获取后,大概20次左右就获取失败了。
原因
海思获取图像后,需要释放,是占用了缓存区。
海思的 HI_MPI_VPSS_GetChanFrame与 Hi_MPI_VPSS_ReleaseChnFrame要成对使用。
解决方法