在Hi3531上运行QT, 并对 mpp/sample/hifb/sample_hifb.c 修改

想用hi3531做Qt的开发,网上有相关的资料,但是解释就没那么清楚了,总结一下给大家分享.首先是网上已经有的文章.


http://blog.sina.com.cn/s/blog_48fba8050100y5yl.html

最近本人想要在Hi3531平台上运行QT,故有一些心得,写在这里与大家分享一下:

1.首先运行sample中的sample_hifb,以便打开fb0;但是需要对代码做一些修改:
将main函数中的 pthread_create(&phifb0,0,SAMPLE_HIFB_REFRESH,(void *)(&stInfo0));
改成   pthread_create(&phifb0,0,SAMPLE_HIFB_PTHREAD_RunHiFB,(void *)(&stInfo0));

SAMPLE_HIFB_PTHREAD_RunHiFB函数中的HI_BOOL g_bCompress = HI_TRUE;
改成  HI_BOOL g_bCompress = HI_FALSE;

在 
    bShow = HI_TRUE;
    if (ioctl(pstInfo->fd, FBIOPUT_SHOW_HIFB, &bShow) < 0)
    {
        printf("FBIOPUT_SHOW_HIFB failed!\n");
        munmap(pShowScreen, fix.smem_len);
        return HI_NULL;
    }
后面加上
if (pstInfo->ctrlkey == 0)
{
  while(1)
  sleep(5);
}
到此修改完毕,然后编译它。

2.接下来就可以试图在Hi3531上运行QT了,
现在终端运行hifb的demo:sample_hifb
然后运行QT的demo:qt/demos/chip/chip -qws
至此你就可以看到QT的demo程序出现在屏幕上了。
enjoy!



但是这时候qt 程序只显示在一个小方块上,还有其他鼠标和图片的干扰,分辨率也只有720P,而不是1080P.接下来我们做相应的修改,使其满足我们开发Qt程序的需要.

一、设置显存

在《HIFB开发指南》中讲到要给每个图形叠加层多大的显存。

2.2 参数设置
HiFB可配置其管理的叠加图形层物理显存的大小。物理显存大小决定了HiFB可使用
的最大物理显存和系统的可设置虚拟分辨率。在加载HiFB驱动时通过参数传递设置物
理显存大小,物理显存的大小一经设置就不会改变。
参数video 
video=“hifb:vram0_size:xxx, vram1_size:xxx,…” 
z  选项之间用逗号“,”隔开。
z  选项和选项值之间用冒号“:”隔开。
z  如果某个图层不配置物理显存大小,则系统默认分配为0。
z  vram0_size ~ vram6_size分别对应于叠加图形层0 ~ 叠加图形层6。
其中,vramn_size:xxx表示对叠加图形层n配置xxx K字节的物理显存。
(1)对于FB标准模式,vramn_size和虚拟分辨率的关系如下:
Vramn_size * 1024 >= xres_virtual * yres_virtual * bpp; 
其中:xres_virtual * yres_virtual是虚拟分辨率,bpp是每个像素所占字节数。
(2)对于FB扩展模式,各个图形层需要的内存大小取决于displaysize的大小、图层像
素格式以及刷新模式,具体关系如下: 

vramn_size * 1024 >= displaywidth * displayHeight * bpp * BufferMode; 
如:图形层0在1280*720 分辨率、ARGB8888格式的2 buffer模式下需要的内存
vram0_size = 1280*720*4*2 = 7200 K。
vramn_size必须是PAGE_SIZE(4K byte)的倍数,否则HiFB驱动强制将其设为PAGE_SIZE的
倍数,向上取整。

参数默认值
如果加载HiFB驱动时不带任何参数,则系统默认配置的参数值见下。
(1) Hi3531 
video="hifb:vram0_size:7200,vram1_size:7200,vram2_size:3240,vram3_size:3240,v
ram4_size:7200,vram5_size:128,vram6_size:128" softcursor="off"  

2.3 配置举例
配置HiFB管理叠加图形层的示例如下:
HiFB驱动的模块文件为hifb.ko。
z  配置HiFB管理一个叠加图形层。
如果只需要HiFB管理叠加图形层0,且最大虚拟分辨率为720 x 576,用到的象素
格式为ARGB1555,则叠加图形层0需要的最小显存为720 x 576 x 2 = 829440 = 
810K,配置参数如下:
insmod hifb.ko video="hifb:vram0_size:810, vram2_size:0"。
如果采用的是double buffer的方式,则需要乘以2,即:
insmod hifb.ko video="hifb:vram0_size:1620, vram2_size:0"。
z  配置HiFB管理多个叠加图形层。
如果需要HiFB管理叠加图形层0和叠加图形层1两个叠加层,且最大虚拟分辨率
为720 x 576,用到的像素格式为ARGB1555,则两个叠加层需要的最小显存都为
720 x 576 x 2 = 829440 = 810K,配置参数如下:
insmod hifb.ko video="hifb:vram0_size:810, vram1_size: 810" 


我使用的是fb0设备,分辨率为1080P=1920*1080, 1920*1080=2073600=2025k 这个应该是最小的内存数,我在 load3531中设置的参数为

insmod hifb.ko video="hifb:vram0_size:20000,vram1_size:7200,vram2_size:3240,vram3_size:3240,\
                vram4_size:7200,vram5_size:128,vram6_size:128" softcursor="off" u32VcmpBufNum=2\
                apszLayerMmzNames="mmzname0","mmzname1",,"graphics",,"mmzname0"

hifb:vram0_size:20000,20M肯定够了。


二、打开HDMI接口,设置屏幕分辨率、屏幕起始坐标,透明度等

下面修改 sample_hifb.c 文件.里面有打开HDMI接口,设置屏幕分辨率、屏幕起始坐标等

参考文档: 《HiFB 开发指南》,《HiFB API参考》,《HiMPP 媒体处理软件开发参考》


1. main 函数

VO_PUB_ATTR_S 
【说明】
定义视频输出公共属性结构体。
【定义】
typedef struct hiVO_PUB_ATTR_S 

HI_U32 u32BgColor; /* 设备背景色RGB表示*/ 
VO_INTF_TYPE_E enIntfType; /* Vo 接口类型*/ 
VO_INTF_SYNC_E enIntfSync; /* Vo接口时序类型*/ 
VO_SYNC_INFO_S stSyncInfo; /* Vo接口时序信息*/ 
HI_BOOL bDoubleFrame; /* 是否需要倍帧*/ 
} VO_PUB_ATTR_S; 


u32BgColor  设备背景色,表示方法RGB888。 


分辨率修改为1080P,这个最后才找到。

stPubAttr.enIntfSync = VO_OUTPUT_1080P50;


只用一个线程phifb0设置屏幕分辨率和phifb1设置画布起始点 就行了,所以可以把phifb2 的pthread_create, pthread_join 函数注释掉。线程0的参数如下

/*start hifb                       */    
    stInfo0.layer   =  0;
    stInfo0.fd      = -1;
    stInfo0.ctrlkey =  0;

   pthread_create(&phifb0,0,SAMPLE_HIFB_REFRESH,(void *)(&stInfo0));


2. 函数HI_VOID *SAMPLE_HIFB_REFRESH(void *pData) 里包含了设置屏幕分辨率的部分.先用FBIOGET_VSCREENINFO:获取屏幕可变信息,再用 FBIOPUT_VSCREENINFO:设置屏幕可变信息 。


s32Ret = ioctl(pstInfo->fd, FBIOGET_VSCREENINFO, &stVarInfo);
if(s32Ret < 0)
{
printf("GET_VSCREENINFO failed!\n");
return HI_NULL;


    if (ioctl(pstInfo->fd, FBIOPUT_SCREEN_ORIGIN_HIFB, &stPoint) < 0)
    {
        printf("set screen original show position failed!\n");
        return HI_NULL;
    }


//slq
maxW = 1920;
maxH = 1080;

    stVarInfo.xres = stVarInfo.xres_virtual = maxW;
    stVarInfo.yres = stVarInfo.yres_virtual = maxH;
    s32Ret = ioctl(pstInfo->fd, FBIOPUT_VSCREENINFO, &stVarInfo);
    if(s32Ret < 0)
{
printf("PUT_VSCREENINFO failed!\n");
return HI_NULL;

else
{
printf("PUT_VSCREENINFO success!\n");
}

缓存方式选择,有无缓存,单缓存,双缓存

    switch (pstInfo->ctrlkey)
{
case 0 :
{  
stLayerInfo.BufMode = HIFB_LAYER_BUF_ONE;
stLayerInfo.u32Mask = HIFB_LAYERMASK_BUFMODE;
break;
}

case 1 :
{
stLayerInfo.BufMode = HIFB_LAYER_BUF_DOUBLE;
   stLayerInfo.u32Mask = HIFB_LAYERMASK_BUFMODE;
break;
}


default:
{
stLayerInfo.BufMode = HIFB_LAYER_BUF_NONE;
stLayerInfo.u32Mask = HIFB_LAYERMASK_BUFMODE;
}

}


这部分不知道干啥的,应该是内存计算之类的吧,反正里面的1280,720改成 1920,1080不会错

for (y = 358; y < 362; y++)
{
for (x = 0; x < 1920; x++)
{
*(pBuf + y * maxW + x) = HIFB_RED_1555;
}
}
for (y = 0; y < 1080; y++)
{
for (x = 638; x < 642; x++)
{
*(pBuf + y * maxW + x) = HIFB_RED_1555;
}
}

我的主函数调用时,pstInfo->ctrlkey =0,所以只用修改 case 0 就可以了,虚拟宽度,高度和真实宽度,高度都设为1920*1080

switch(pstInfo->ctrlkey)
    {
        case 0:
        {
//slq
//window width and height

            var.xres_virtual = 1920; 
            var.yres_virtual = 1080;
            var.xres = 1920;
            var.yres = 1080;
        }
        break;
        
        case 1:
        {
            var.xres_virtual = 100;
            var.yres_virtual = 100;
            var.xres = 220;
            var.yres = 200;
        }
        break;
        
        case 2:
        {
            var.xres_virtual = SAMPLE_VIR_SCREEN_WIDTH;
            var.yres_virtual = SAMPLE_VIR_SCREEN_HEIGHT;
            var.xres = SAMPLE_IMAGE_WIDTH;
            var.yres = SAMPLE_IMAGE_HEIGHT;
        }
        break;
        case 3:
        {
            var.xres_virtual = 48;
            var.yres_virtual = 48;
            var.xres = 48;
            var.yres = 48;
        }
        break;
        default:
        {
            var.xres_virtual = 98;
            var.yres_virtual = 128;
            var.xres = 98;
            var.yres = 64;
        }
    }


3. 函数HI_VOID *SAMPLE_HIFB_PTHREAD_RunHiFB(void *pData)里包含了设置屏幕起始坐标等


/* 2. set the screen original position */
    switch(pstInfo->ctrlkey)
    {
        case 0:
        {
//slq
// window start pos
            stPoint.s32XPos= 0;
            stPoint.s32YPos = 0;
        }
        break;
        
        case 1:
        {
            stPoint.s32XPos = 150;
            stPoint.s32YPos = 350;
        }
        break;
        
        case 2:
        {
            stPoint.s32XPos = 384;
            stPoint.s32YPos = 100;
        }
        break;
        case 3:
        {
            stPoint.s32XPos = 450;
            stPoint.s32YPos = 150;
        }
break;
        default:
        {
stPoint.s32XPos = 0;
            stPoint.s32YPos = 0;
        }
    }


设置 alpha 透明度, 修改 stAlpha.u8GlobalAlpha = 0xff; 即可.

/* 3.set alpha */
    stAlpha.bAlphaEnable = HI_TRUE;
    stAlpha.bAlphaChannel = HI_TRUE;
    stAlpha.u8Alpha0 = 0xff;
    stAlpha.u8Alpha1 = 0xff;


    //slq
    //set transparent 
    stAlpha.u8GlobalAlpha = 0xff;




    if (ioctl(pstInfo->fd, FBIOPUT_ALPHA_HIFB,  &stAlpha) < 0) 
    {    
        printf("Set alpha failed!\n");
        close(pstInfo->fd);
        return HI_NULL;
    }    
    if(pstInfo->layer == HIFB_LAYER_CURSOR_0 || pstInfo->layer == HIFB_LAYER_CURSOR_1)
    {     
      stColorKey.bKeyEnable = HI_TRUE;
      stColorKey.u32Key = 0x0; 
      if (ioctl(pstInfo->fd, FBIOPUT_COLORKEY_HIFB, &stColorKey) < 0) 
      {    
        printf("FBIOPUT_COLORKEY_HIFB!\n");
        close(pstInfo->fd);
        return HI_NULL;
      }    
    }    


在上述工作完成后

退出编辑,make后在板子上运行,屏幕为绿色,分辨率设置为1920*1080

# ./sample_hifb
tw2865 0x50 set to PAL mode ok! 
tw2865 0x54 set to PAL mode ok! 
tw2865 0x52 set to PAL mode ok! 
tw2865 0x56 set to PAL mode ok! 
u32Width:1920, u32Square:2
HDMI start success.
PUT_VSCREENINFO success!
expected:two red  line!


程序运行一会就会自动结束,为了不让其自动结束,在上述工作后添加如下代码使程序一直运行,比如在设置好屏幕起始坐标后

//slq
if (pstInfo->ctrlkey == 0)
{
 while(1)
   sleep(5);
}


在后台运行 sample_hifb程序,便可再运行Qt 程序了

# ./sample_hifb &
tw2865 0x50 set to PAL mode ok! 
tw2865 0x54 set to PAL mode ok! 
tw2865 0x52 set to PAL mode ok! 
tw2865 0x56 set to PAL mode ok! 
u32Width:1920, u32Square:2
HDMI start success.
PUT_VSCREENINFO success!
expected:two red  line!


此时屏幕背景色是青绿色的,

你可能感兴趣的:(hi3531,嵌入式,Qt,linux)