0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

全志V85x内G2D模块实现图片格式步骤方法

全志在线 来源:chhjnavy 作者:chhjnavy 2023-04-19 09:41 次阅读

G2D主要功能:

1)旋转:支持90、180、270旋转;

2)scale:放缩;

3)镜像反转:H / V;

4)透明叠加:实现两个rgb图片叠加;

5)格式转换:yuv转rgb等多种格式相互间转换;

6)矩形填充,等诸多功能;

G2D配置

源码目录

tina-v853-docker/kernel/linux-4.9/drivers/char/sunxi_g2d

make kernel_menuconfig 配置

Device Drivers > Character devices > sunxi g2d driver

5e1a49fe-ddea-11ed-bfe3-dac502259ad0.png

Device Tree 设备树配置

sun8iw21p1.dtsi路径:

tina-v853-docker/kernel/linux-4.9/arch/arm/boot/dts/sun8iw21p1.dtsi

 g2d: g2d@05410000 {
   compatible = "allwinner,sunxi-g2d";
   reg = <0x0 0x05410000 0x0 0xbffff>;
   interrupts = ;
   clocks = <&clk_g2d>;
   iommus = <&mmu_aw 3 1>;
   status = "okay";
  };

注:status 要设定为“okay” 状态。

重新编译内核

使用烧录工具PhoenixSuit 将编译打包好的img镜像烧录到开发板。

adb shell 打开控制终端查看设备节点G2D:

5e2532ce-ddea-11ed-bfe3-dac502259ad0.png

通过G2D设备节点进行操作

static int SampleG2d_G2dOpen(SAMPLE_G2D_CTX *p_g2d_ctx)
{
  int ret = 0;
  p_g2d_ctx->mG2dFd = open("/dev/g2d", O_RDWR, 0);
  if (p_g2d_ctx->mG2dFd < 0)
    {
        aloge("fatal error! open /dev/g2d failed");
        ret = -1;
    }
    return ret;
}

G2D sample具体应用

G2D sample目录

5e406972-ddea-11ed-bfe3-dac502259ad0.png

进行rotation,scale,格式转换

具体实现:将 nv21 格式的1920x1080图转换成rgb888 格式并放缩为640x360 大小。具体用到两个功能,格式转换和放缩。

首先根据1920x1080 nv21 格式以及 640x360 rgb888 格式申请虚拟地址空间以及转换成物理地址(注意:g2d 转换是在物理地址中完成的)

1920x1080 nv21 格式空间大小(输入文件):

Y 占 19201080 = 2073600 字节

UV 占 19201080 / 2 = 1036800 字节

5e45b3fa-ddea-11ed-bfe3-dac502259ad0.png

640x360 rgb888 格式空间大小(输出文件):

RGB 占 6403603 = 691200 字节

另外:虚拟地址转换成物理地址使用如下函数:

g2d_getPhyAddrByVirAddr()

申请虚拟空间并转换成物理空间完整函数如下:

static int PrepareFrmBuff(SAMPLE_G2D_CTX *p_g2d_ctx)
{
  SampleG2dConfig *pConfig = NULL;
  unsigned int size = 0;


  pConfig = &p_g2d_ctx->mConfigPara;
  
  p_g2d_ctx->src_frm_info.frm_width = pConfig->mSrcWidth;
  p_g2d_ctx->src_frm_info.frm_height = pConfig->mSrcHeight;


  p_g2d_ctx->dst_frm_info.frm_width = pConfig->mDstWidth;
  p_g2d_ctx->dst_frm_info.frm_height = pConfig->mDstHeight;


  size = ALIGN(p_g2d_ctx->src_frm_info.frm_width, 16)*ALIGN(p_g2d_ctx->src_frm_info.frm_height, 16);
  if(pConfig->mPicFormat == MM_PIXEL_FORMAT_YVU_SEMIPLANAR_420 || pConfig->mPicFormat == MM_PIXEL_FORMAT_YUV_SEMIPLANAR_420)
  {
    p_g2d_ctx->src_frm_info.p_vir_addr[0] = (void *)g2d_allocMem(size);
    if(NULL == p_g2d_ctx->src_frm_info.p_vir_addr[0])
    {
      aloge("malloc_src_frm_y_mem_failed");
      return -1;
    }


    p_g2d_ctx->src_frm_info.p_vir_addr[1] = (void *)g2d_allocMem(size/2);
    if(NULL == p_g2d_ctx->src_frm_info.p_vir_addr[1])
    {
      g2d_freeMem(p_g2d_ctx->src_frm_info.p_vir_addr[0]);
      aloge("malloc_src_frm_c_mem_failed");  
      return -1;
    }


    p_g2d_ctx->src_frm_info.p_phy_addr[0] = (void *)g2d_getPhyAddrByVirAddr(p_g2d_ctx->src_frm_info.p_vir_addr[0]); 
    p_g2d_ctx->src_frm_info.p_phy_addr[1] = (void *)g2d_getPhyAddrByVirAddr(p_g2d_ctx->src_frm_info.p_vir_addr[1]);
  }


 if(pConfig->mDstPicFormat == MM_PIXEL_FORMAT_RGB_888)
 {
  size = p_g2d_ctx->dst_frm_info.frm_width * p_g2d_ctx->dst_frm_info.frm_height * 3;
  p_g2d_ctx->dst_frm_info.p_vir_addr[0] = (void *)g2d_allocMem(size);
  if(NULL == p_g2d_ctx->dst_frm_info.p_vir_addr[0])
  {
   if(p_g2d_ctx->src_frm_info.p_vir_addr[0] != NULL)
   {
    g2d_freeMem(p_g2d_ctx->src_frm_info.p_vir_addr[0]); 
   }
   if(p_g2d_ctx->src_frm_info.p_vir_addr[1] != NULL)
   {
    g2d_freeMem(p_g2d_ctx->src_frm_info.p_vir_addr[1]);
   }
   aloge("malloc_dst_frm_y_mem_failed");
   return -1;
  }
  p_g2d_ctx->dst_frm_info.p_phy_addr[0] = (void *)g2d_getPhyAddrByVirAddr(p_g2d_ctx->dst_frm_info.p_vir_addr[0]); 
 }


  return 0; 
}

通过fopen 传菜间两个文件句柄,fd_in fd_out 用来操作输入输出两个文件资源。

    p_g2d_ctx->fd_in = fopen(p_g2d_ctx->mConfigPara.SrcFile,"r");
    if(NULL == p_g2d_ctx->fd_in)
    {
      aloge("open src file failed");
      ret = -1;
      goto _err2;
    }
    fseek(p_g2d_ctx->fd_in, 0, SEEK_SET);


      p_g2d_ctx->fd_out = fopen(p_g2d_ctx->mConfigPara.DstFile, "wb");
      if (NULL == p_g2d_ctx->fd_out)
      {
        aloge("open out file failed");
        ret = -1;
        goto _err2;
      }
      fseek(p_g2d_ctx->fd_out, 0, SEEK_SET);

读出 1920x1080 nv21 图资放入 虚拟空间

read_len = p_g2d_ctx->src_frm_info.frm_width * p_g2d_ctx->src_frm_info.frm_height;
    if(pConfig->mPicFormat == MM_PIXEL_FORMAT_YVU_SEMIPLANAR_420|| pConfig->mPicFormat == MM_PIXEL_FORMAT_YUV_SEMIPLANAR_420)
    {
      size1 = fread(p_g2d_ctx->src_frm_info.p_vir_addr[0] , 1, read_len, p_g2d_ctx->fd_in);
      if(size1 != read_len)
      {
        aloge("read_y_data_frm_src_file_invalid");
      }
      size2 = fread(p_g2d_ctx->src_frm_info.p_vir_addr[1], 1, read_len /2, p_g2d_ctx->fd_in);
      if(size2 != read_len/2)
      {
        aloge("read_c_data_frm_src_file_invalid");
      }


      fclose(p_g2d_ctx->fd_in);


      g2d_flushCache((void *)p_g2d_ctx->src_frm_info.p_vir_addr[0], read_len);
      g2d_flushCache((void *)p_g2d_ctx->src_frm_info.p_vir_addr[1], read_len/2);
    }

打开g2d 初始化,并开始转换

ret = SampleG2d_G2dOpen(p_g2d_ctx);
  if (ret < 0)
    {
        aloge("fatal error! open /dev/g2d fail!");
        goto _err2;
    }
    ret = SampleG2d_G2dConvert(p_g2d_ctx);
    if (ret < 0)
    {
        aloge("fatal error! g2d convert fail!");
        goto _close_g2d;
    }
//具体转化函数:


static int SampleG2d_G2dConvert_scale(SAMPLE_G2D_CTX *p_g2d_ctx)
{
    int ret = 0;
    g2d_blt_h blit;
    g2d_fmt_enh eSrcFormat, eDstFormat; 
    SampleG2dConfig *pConfig = NULL;


    pConfig = &p_g2d_ctx->mConfigPara;


  ret = convert_PIXEL_FORMAT_E_to_g2d_fmt_enh(pConfig->mPicFormat, &eSrcFormat);
  if(ret!=SUCCESS)
  {
    aloge("fatal error! src pixel format[0x%x] is invalid!", pConfig->mPicFormat);
    return -1;
  }
  ret = convert_PIXEL_FORMAT_E_to_g2d_fmt_enh(pConfig->mDstPicFormat, &eDstFormat);
  if(ret!=SUCCESS)
  {
    aloge("fatal error! dst pixel format[0x%x] is invalid!", pConfig->mPicFormat);
    return -1;
  }


  //config blit
  memset(&blit, 0, sizeof(g2d_blt_h));


  if(0 != pConfig->mDstRotate)
  {
    aloge("fatal_err: rotation can't be performed when do scaling");
  }


  blit.flag_h = G2D_BLT_NONE_H;    // angle rotation used
//  switch(pConfig->mDstRotate)
//  {
//    case 0:
//      blit.flag_h = G2D_BLT_NONE_H;  //G2D_ROT_0, G2D_BLT_NONE_H
//      break;
//    case 90:
//      blit.flag_h = G2D_ROT_90;
//      break;
//    case 180:
//      blit.flag_h = G2D_ROT_180;
//      break;
//    case 270:
//      blit.flag_h = G2D_ROT_270;
//      break;
//    default:
//      aloge("fatal error! rotation[%d] is invalid!", pConfig->mDstRotate);
//      blit.flag_h = G2D_BLT_NONE_H;
//      break;
//  }
  //blit.src_image_h.bbuff = 1;
  //blit.src_image_h.color = 0xff;
  blit.src_image_h.format = eSrcFormat;
  blit.src_image_h.laddr[0] = (unsigned int)p_g2d_ctx->src_frm_info.p_phy_addr[0];
  blit.src_image_h.laddr[1] = (unsigned int)p_g2d_ctx->src_frm_info.p_phy_addr[1];
  blit.src_image_h.laddr[2] = (unsigned int)p_g2d_ctx->src_frm_info.p_phy_addr[2];
  //blit.src_image_h.haddr[] = 
  blit.src_image_h.width = p_g2d_ctx->src_frm_info.frm_width;
  blit.src_image_h.height = p_g2d_ctx->src_frm_info.frm_height;
  blit.src_image_h.align[0] = 0;
  blit.src_image_h.align[1] = 0;
  blit.src_image_h.align[2] = 0;
  blit.src_image_h.clip_rect.x = pConfig->mSrcRectX;
  blit.src_image_h.clip_rect.y = pConfig->mSrcRectY;
  blit.src_image_h.clip_rect.w = pConfig->mSrcRectW;
  blit.src_image_h.clip_rect.h = pConfig->mSrcRectH;
  blit.src_image_h.gamut = G2D_BT601;
  blit.src_image_h.bpremul = 0;
  //blit.src_image_h.alpha = 0xff;
  blit.src_image_h.mode = G2D_PIXEL_ALPHA;  //G2D_PIXEL_ALPHA, G2D_GLOBAL_ALPHA
  blit.src_image_h.fd = -1;
  blit.src_image_h.use_phy_addr = 1;


  //blit.dst_image_h.bbuff = 1;
  //blit.dst_image_h.color = 0xff;
  blit.dst_image_h.format = eDstFormat;
  blit.dst_image_h.laddr[0] = (unsigned int)p_g2d_ctx->dst_frm_info.p_phy_addr[0];
  blit.dst_image_h.laddr[1] = (unsigned int)p_g2d_ctx->dst_frm_info.p_phy_addr[1];
  blit.dst_image_h.laddr[2] = (unsigned int)p_g2d_ctx->dst_frm_info.p_phy_addr[2];
  //blit.dst_image_h.haddr[] = 
  blit.dst_image_h.width = p_g2d_ctx->dst_frm_info.frm_width;
  blit.dst_image_h.height = p_g2d_ctx->dst_frm_info.frm_height;
  blit.dst_image_h.align[0] = 0;
  blit.dst_image_h.align[1] = 0;
  blit.dst_image_h.align[2] = 0;
  blit.dst_image_h.clip_rect.x = pConfig->mDstRectX;
  blit.dst_image_h.clip_rect.y = pConfig->mDstRectY;
  blit.dst_image_h.clip_rect.w = pConfig->mDstRectW;
  blit.dst_image_h.clip_rect.h = pConfig->mDstRectH;
  blit.dst_image_h.gamut = G2D_BT601;
  blit.dst_image_h.bpremul = 0;
  //blit.dst_image_h.alpha = 0xff;
  blit.dst_image_h.mode = G2D_PIXEL_ALPHA;  //G2D_PIXEL_ALPHA, G2D_GLOBAL_ALPHA
  blit.dst_image_h.fd = -1;
  blit.dst_image_h.use_phy_addr = 1;


  ret = ioctl(p_g2d_ctx->mG2dFd, G2D_CMD_BITBLT_H, (unsigned long)&blit);
  if(ret < 0)
    {
        aloge("fatal error! bit-block(image) transfer failed[%d]", ret);
        system("cd /sys/class/sunxi_dump;echo 0x14A8000,0x14A8100 > dump;cat dump");
  }


  return ret;
}

转化完成后将640x360 rgb888 图资通过fd_out句柄存储起来

if(pConfig->mDstPicFormat == MM_PIXEL_FORMAT_RGB_888)
    {
      out_len = p_g2d_ctx->dst_frm_info.frm_width * p_g2d_ctx->dst_frm_info.frm_height *3;
      g2d_flushCache((void *)p_g2d_ctx->dst_frm_info.p_vir_addr[0], out_len);


      fwrite(p_g2d_ctx->dst_frm_info.p_vir_addr[0], 1, out_len, p_g2d_ctx->fd_out);
    }


转化步骤总结

通过步骤3中的模块化分析,可以看出g2d 转化大概分为一下步骤:

为打开 iomen 初始化;

为src以及dst图资申请虚拟地址空间并转换成物理地址空间;

将src图资放入虚拟地址空间,然后自动映射到物理地址空间;

打开g2d 设备节点进行转换(最重要的一环,可以通过手册分析具体怎么转换的);

将转换好的dst图资保存起来;






审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • RGB
    RGB
    +关注

    关注

    4

    文章

    764

    浏览量

    57417
  • SRC
    SRC
    +关注

    关注

    0

    文章

    60

    浏览量

    17801
  • Shell
    +关注

    关注

    1

    文章

    358

    浏览量

    22903
  • V850
    +关注

    关注

    0

    文章

    4

    浏览量

    6662
  • ADB驱动
    +关注

    关注

    0

    文章

    13

    浏览量

    6234

原文标题:详解全志V85x内G2D模块实现图片格式步骤方法

文章出处:【微信号:gh_79acfa3aa3e3,微信公众号:全志在线】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    【米尔-T113-i开发板试用】G2D图像处理硬件调用和测试

    /drivers/char/sunxi_g2d/g2d_bsp_v2.c 从g2d内核驱动中也可以得知,暂时没有方法g2d设置自定义的YU
    发表于 02-17 18:26

    R128 SDK HAL 模块开发指南——G2D

    G2D G2D 驱动主要实现图像旋转/数据格式/颜色空间转换, 以及图层合成功能(包括包括alpha、colorkey、rotate、mirror、rop、maskblt) 等图形加速
    发表于 04-01 13:31

    图片格式转换BMP、GIF、Icon、Jpeg、Png、Wmf、Tiff......等

    构造器节点调用Bitmap 进行图片格式转换,具体实现如下:1.C#中代码2.能转换格式类型:BMP、GIF、Icon、Jpeg、Png、Wmf、Tiff......等,3.Labvi
    发表于 02-28 10:40

    V853芯片 如何在Tina V85x平台切换sensor?

    原文链接:https://bbs.aw-ol.com/topic/1666/作者@budbool目的V85x某方案目前默认Sensor是GC2053。实际使用时若需要用到GC4663(比如wdr功能
    发表于 06-28 09:27

    每日推荐 | Tina V85x 平台E907启动方式,OpenHarmony征文活动获奖名单

    大家好,以下为电子发烧友推荐每日好帖,欢迎留言点评讨论~1、V853芯片 在Tina下RISC-V核E907启动方式的选择推荐理由:Tina V
    发表于 08-08 10:14

    V853芯片 Tina下RTSP环境搭建方法

    V85X RTSP环境搭建方法2.问题背景本FAQ主要介绍Tina V85X上搭建RTSP环境的方法。目的对于小内存的机器(不支持SD卡扩
    发表于 08-08 10:50

    [开源硬件大赛] 基于V853实现音频播放器

    一、方案说明1.设计方案思路和概况基于V85x 实现最小系统搭建,在此基础上实现codec 音频驱动,
    发表于 11-30 08:20

    V85X系列芯片PCB设计需要注意些什么?

    V85X (包括V853、V853S、V851S、V
    发表于 01-18 09:57

    V853芯片 如何在Tina V85x平台切换sensor?

    V853开发板购买链接:https://item.hqchip.com/2500386536.html目的V85x某方案目前默认Sensor是GC2053。实际使用时若需要用到GC
    发表于 02-13 11:03

    Android 10 - i.MX8MMini - g2d旋转问题求解

    禁用 g2d hwc(“启用 Opengl ES 3D 合成!”),它会按预期工作,它看起来与截屏图片完全一样。
    发表于 02-28 06:40

    V85x MPP模块概述以及编译sample步骤

    /middleware/3.编译一个MPP 模块步骤(以 sample_g2d 为例)1)make menuconfig 配置配置项,选中sample_g2d路径:Allwinner
    发表于 04-17 09:41

    V851s、V853g2d模块sample深究

    1. g2d 模块概述g2d 主要功能:1)旋转:支持90、180、270旋转;2)镜像反转:H / V;3)scale:放缩4)
    发表于 04-19 09:38

    C#教程之批量图片格式转换

    C#教程之批量图片格式转换,很好的C#资料,快来学习吧。
    发表于 04-20 11:13 8次下载

    小米官方科普什么是HEIF格式 与常见图片格式有什么不同?

    小米10系列不但配备了1亿像素后置四摄,还支持全新的HEIF图片格式,可以在相机设置里选择打开,还有温馨提醒:“高效率图片格式,可节省更多的存储空间,但部分应用可能不支持此格式。 ”
    的头像 发表于 02-17 15:59 3.5w次阅读

    如何快速完成图片格式之间的相互转换

    你还是会需要用到一些特定的格式来完成工作,比如上传个人信息身份的时候,那这个时候如果图片格式不符合要求就需要将其格式进行转换,如何快速完成各种图片格式之间的相互转换并保证质量,在本文中
    的头像 发表于 03-17 16:22 1597次阅读