AnsweredAssumed Answered

Framebuffer data layout for YUV422P

Question asked by Julien Jemine on Mar 7, 2018

Hi,

 

I'm trying to use a framebuffer on the i.MX6QP in YUV422P.

Everything works fine when my data starts at the beginning of the buffer (fb_var_screeninfo.yoffset = 0). 

I have my Y plane, followed by my Cb and Cr planes with half the width of the Y plane.

 

However, when I try to use double-buffering with a virtual size bigger than the actual size and a non-zero yoffset, the chroma are incorrect. I would expect to have the whole plane layout shifted by yoffset * xres_virtual bytes. 

 

Where can I find documentation about the memory layout for YUV422P ?

 

Here is my code:

#include <linux/fb.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <iostream>
#include <string.h>
#include "ipu.h"     // Customized version of <linux/ipu.h>

using namespace std;

int main ()
{
   int framebuffer_device;
   struct fb_var_screeninfo var_info;
   char* buf;

   framebuffer_device = open ("/dev/fb2", O_RDWR);
   ioctl(framebuffer_device, FBIOGET_VSCREENINFO, &var_info);

   var_info.xres = 1920;
   var_info.yres = 1080;
   var_info.xres_virtual = 3000;
   var_info.yres_virtual = 3000;
   var_info.activate |= FB_ACTIVATE_FORCE;
   var_info.nonstd = IPU_PIX_FMT_YUV422P;
   int result = ioctl(framebuffer_device, FBIOPUT_VSCREENINFO, &var_info);
   cout << "FBIOPUT_VSCREENINFO: " << result << endl;
   //ioctl(framebuffer_device, FBIOBLANK, FB_BLANK_UNBLANK);

   buf = (char*)mmap(0, var_info.xres_virtual * var_info.yres_virtual * 2, PROT_READ | PROT_WRITE, MAP_SHARED, framebuffer_device, 0);
   if (buf == nullptr)
      cout << "mmap failed" << endl;

   memset(buf, 0, var_info.xres_virtual * var_info.yres_virtual * 2);

   const uint32_t lumaStride = var_info.xres_virtual;
   const uint32_t chromaStride = var_info.xres_virtual / 2;
   const uint32_t nextImageLineOffset = 1200;
   const uint32_t imageStride = var_info.xres_virtual * nextImageLineOffset;

   // Even frame - Blue: Y=128, Cb=255, Cr=96
   memset(buf, 128, lumaStride * 1080);
   memset(buf + lumaStride * 1080, 255, chromaStride * 1080);
   memset(buf + (lumaStride + chromaStride) * 1080, 96, chromaStride * 1080);

   // Odd frame - Pink: Y=255, Cb=160, Cr=192
   memset(buf + imageStride, 255, lumaStride * 1080);
   memset(buf + imageStride + lumaStride * 1080, 160, chromaStride * 1080);  
   memset(buf + imageStride + (lumaStride + chromaStride) * 1080, 192, chromaStride * 1080);

   for (int k = 0; k < 100; k++)
   {
      uint32_t lineOffset = (k % 2) ? nextImageLineOffset : 0;

      var_info.yoffset = lineOffset;
      ioctl(framebuffer_device, FBIOPAN_DISPLAY, &var_info);
      sleep(1);
   }
  
   munmap(buf, var_info.xres_virtual * var_info.yres_virtual * 2);
   close(framebuffer_device);
   return 0;
}

Outcomes