前言

  上一篇已经将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要成对使用。

解决方法

  

Hi3516开发笔记(十):Qt从VPSS中获取通道图像数据存储为jpg文件的更多相关文章

  1. 【Qt开发】关于Qt应用程序中的堆栈、静态存储区的使用错误

    [Qt开发]关于Qt应用程序中的堆栈.静态存储区的使用错误 标签:[Qt开发] 最近终于又碰到了这个问题,想在main函数中定义一个局部大的数组,结果运行就报错,尼玛!刚开始真的不知道到发生了什么,后 ...

  2. sitecore开发入门之如何在代码中获取SITECORE图像URL

    using Sitecore; using Sitecore.Data.Items; using Sitecore.Resources.Media; public string GetUrl() { ...

  3. Hi3516开发笔记(一):海思HI3516DV300芯片介绍,入手开发板以及Demo测试

    前言   目前主流国产芯片为RV11XX.RK33XX.Hi35XX系列,本系列开启Hi3516系列的开发教程.   Hi3516DV300芯片介绍   Hi3516DV300为专业行Smart IP ...

  4. Hi3516开发笔记(四):Hi3516虚拟机编译uboot、kernel、roofts和userdata以及分区表

    若该文为原创文章,转载请注明原文出处本文章博客地址:https://hpzwl.blog.csdn.net/article/details/121572767红胖子(红模仿)的博文大全:开发技术集合( ...

  5. Hi3516开发笔记(六):通过HiTools使用USB/串口将uboot、kernel、roofts和userdata按照分区表烧写镜像

    若该文为原创文章,转载请注明原文出处本文章博客地址:https://hpzwl.blog.csdn.net/article/details/121706033红胖子(红模仿)的博文大全:开发技术集合( ...

  6. Hi3516开发笔记(二):Hi3516虚拟机基础环境搭建之串口调试、网络连接以及sftp文件传输

    前言   搭建Hi3516的基础虚拟机,为交叉编译环境搭建前期工作.后续会编译一个基本的C语言程序Demo,在HI3516上跑.   虚拟机   开发本对虚拟机做了一些基本要求,如下图:    其实重 ...

  7. [OpenCV Qt教程] 在Qt图形界面中显示OpenCV图像的OpenGL Widget (第一部分)

    本文译自:http://www.robot-home.it/blog/en/software/tutorial-opencv-qt-opengl-widget-per-visualizzare-imm ...

  8. IOS开发数据存储篇—IOS中的几种数据存储方式

    IOS开发数据存储篇—IOS中的几种数据存储方式 发表于2016/4/5 21:02:09  421人阅读 分类: 数据存储 在项目开发当中,我们经常会对一些数据进行本地缓存处理.离线缓存的数据一般都 ...

  9. Android编程中的5种数据存储方式

    Android编程中的5种数据存储方式 作者:牛奶.不加糖 字体:[增加 减小] 类型:转载 时间:2015-12-03我要评论 这篇文章主要介绍了Android编程中的5种数据存储方式,结合实例形式 ...

随机推荐

  1. 深入解读SQL的聚集函数

    摘要:本文从基本聚集操作入手,介绍常用的SQL语法,以及一些扩展的聚集功能,同时会讲到在GaussDB(DWS)里聚集相关的一些优化思路. 本文分享自华为云社区<GaussDB(DWS) SQL ...

  2. python初识数据类型(字典、集合、元组、布尔)与运算符

    目录 python数据类型(dict.tuple.set.bool) 字典 集合 元组 布尔值 用户交互与输出 获取用户输入 输出信息 格式化输出 基本运算符 算术运算符 比较运算符 逻辑运算符 赋值 ...

  3. python基础中遇到的问题(TypeError: unhashable type: 'list')

    d20220330 #false >>> l=[{i:i+1} for i in [1,2,3]] >>> l [{1: 2}, {2: 3}, {3: 4}] & ...

  4. 使用C++的ORM框架QxORM

    QxORM中,我们用的最多的无非是这两点 官方表述是这样的: 持久性: 支持最常见的数据库,如 SQLite.MySQL.PostgreSQL.Oracle.MS SQL Server.MongoDB ...

  5. Kubebuilder简介与架构

    什么是Kubebuilder Kubebuilder是一个用Go原因构建Kubernetes APIs的框架,通过使用KubeBuilder,用户可以遵循一套简单的编程框架,使用CRD构建API.Co ...

  6. 一个bug肝一周...忍不住提了issue

    导航 Socket.IO是什么 Socket.IO的应用场景 为什么选socket.io-client-java 实战案例 参考 本文首发于智客工坊-<socket.io客户端向webserve ...

  7. NC201605 Bits

    NC201605 Bits 题目 题目描述 Nancy喜欢做游戏! 汉诺塔是一个神奇的游戏,神奇在哪里呢? 给出 \(3\) 根柱子,最开始时 \(n\) 个盘子按照大小被置于最左的柱子. 如果盘子数 ...

  8. 游戏启动后提示安装HMS Core,点击取消,未再次提示安装HMS Core(初始化失败返回907135003)

    问题描述 我们国内的华为联运游戏集成华为游戏服务SDK 之后,被审核驳回:在未安装或需要更新华为移动服务(HMS Core)的手机上,提示安装华为移动服务,点击取消,未再次提示安装HMS Core. ...

  9. Tapdata 实时数据融合平台解决方案(二):理解数据中台

    作者介绍:TJ,唐建法,Tapdata 钛铂数据 CTO,MongoDB中文社区主席,原MongoDB大中华区首席架构师,极客时间MongoDB视频课程讲师. 数据中台定义: 以打通部门或数据孤岛的统 ...

  10. throw关键字和Objects非空判断_requireNonNull方法

    作用: 可以使用throw关键字在指定的方法中抛出指定的异常 使用格式: throw new xxxException("异常产生的原因") 注意: 1.throw关键字必须写在方 ...