飞凌嵌入式
直播中

donatello1996

8年用户 687经验值
擅长:MEMS/传感技术
私信 关注
[技术]

【飞凌嵌入式OKMX8MP-C 开发板试用体验】/dev/fb0 HDMI图像输出&V4L2抓取MJPEG流转化JPEG文件并显示

      飞凌嵌入式OKMX8MP-C 开发板默认将三种显示接口LVDS/MIPI/HDMI全部打开,而我要对HDMI输出编程的话需要将MIPI显示关闭,关闭方式是进入uboot菜单的Display选项进行操作:
35.JPG
在串口终端启动uboot时狂按空格键,即可进入uboot菜单:
36.JPG

uboot菜单中的Display select选项就是设置输出接口的,可以分别对这三种接口进行设置,默认情况下三个输出接口都打开,而如果要进行FrameBuffer编程的话,我经过实际测试,需要将LVDS和HDMI选项都打开,HDMI接口才能正常输出/dev/fb0外设的映射图像:
39.JPG

如果将LVDS接口关闭的话,HDMI接口输出不正常,/dev/fb0也不会生成,也就无法对FrameBuffer进行编程:
38.JPG 37.JPG
在飞凌厂商提供的文档中,已经写明了HDMI接口输出的分辨率最大为1280*800*32,这个是由HDMI输出芯片决定的,比起瑞芯微主流主控的2K/4K差了不是一点半点(RK3399/RK3568),毕竟IMX8的定位是工业控制而不是多媒体应用,图形输出性能较差也是无可厚非的,对/dev/fb0外设进行ioctl,输出的分辨率也是1280*800,32位色彩:

使用命令
  1. x11vnc -rawfb /dev/fb0 -clip 1280*800

可搭建x11vnc服务器,将FrameBuffer画面输出至vnc软件客户端,也就可以在不使用HDMI输出设备的FrameBuffer分辨率只有1280*800,意味着,V4L2相机生成的流画面,分辨率高于或等于这个数无法生成显示,甚至在实测中,低于这个数一点点也无法生成(1000*750),会提示段错误终止进程,因此我经过反复调试,最终将V4L2生成的流分辨率设置为900*675,无法对相机物尽其用(相机最大分辨率为1080P),但这是板子的Framebuffer最大支持的输出分辨率,无法再设置更大了。
  1. #define  IMAGEWIDTH    900
  2. #define  IMAGEHEIGHT   675

这次的V4L2推流,我不采用之前已经熟练掌握的V4L2生成YUYV流,而是直接生成MJPEG流,生成此流有2个好处,一是生成MJPEG流无需经过YUYV转RGB的步骤,帧生成时间更短,相比起之前生成YUYV流的方式,流畅度有非常明显的提升;二是生成MJPEG流可直接保存为JPEG文件,在确保IO读取锁无冲突的前提下,可供外部程序进行访问。要使用V4L2驱动库生成MJPEG流,初始化步骤要写对:
  1.     struct v4l2_format fmt;

  2.     fmt.type = V4L2_CAP_VIDEO_CAPTURE;
  3.     fmt.fmt.pix.width = IMAGEWIDTH;
  4.     fmt.fmt.pix.height = IMAGEHEIGHT;
  5.     fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
  6.     if (ioctl (fd_video, VIDIOC_S_FMT, &fmt) == -1)
  7.     {
  8.         perror("ERROR camera VIDIOC_S_FMT Failed.");
  9.         return -1;
  10.     }

检查写入参数是否正确:
  1.     if (ioctl (fd_video, VIDIOC_G_FMT, &fmt) == -1)
  2.     {
  3.         perror("ERROR camera VIDIOC_G_FMT Failed.");
  4.         return -1;
  5.     }

使用mmap()进行物理内存地址到用户内存地址的映射,即使用一个用户定义缓存来读取物理内存中的摄像头缓存数据:
  1.     struct v4l2_buffer v4l2_buf;
  2.     v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  3.     v4l2_buf.memory = V4L2_MEMORY_MMAP;
  4.     for(i = 0; i < 4; i++)
  5.     {
  6.         v4l2_buf.index = i;
  7.         if(ioctl(fd_video, VIDIOC_QUERYBUF, &v4l2_buf) < 0)
  8.         {
  9.             perror("Unable to query buffer.");
  10.             return -1;
  11.         }

  12.         pic.tmpbuffer[i] = (unsigned char*)mmap(NULL, v4l2_buf.length, PROT_READ, MAP_SHARED, fd_video, v4l2_buf.m.offset);
  13.         if(pic.tmpbuffer[i] == MAP_FAILED)
  14.         {
  15.              perror("Unable to map buffer.");
  16.              return -1;
  17.         }
  18.         if(ioctl(fd_video, VIDIOC_QBUF, &v4l2_buf) < 0)
  19.         {
  20.             perror("Unable to queue buffer.");
  21.             return -1;
  22.         }
  23.     }

开启捕捉:
  1.     int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  2.     if(ioctl(fd_video , VIDIOC_STREAMON , &type) < 0)
  3.     {
  4.         perror("Unable to start capture.");
  5.         return -1;
  6.     }

捕捉并生成JPEG文件,循环执行的函数:


  1. int V4l2_Grab_Mjpeg(char * filename)
{
  •     struct v4l2_buffer buff;
  •     buff.type   = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  •     buff.memory = V4L2_MEMORY_MMAP;
  •     if(ioctl(fd_video , VIDIOC_DQBUF, &buff) < 0)
  •     {
  •         printf("camera VIDIOC_DQBUF Failed.n");
  •         usleep(1000*1000);
  •         return -1;
  •     }

  •     pic.tmpbytesused[buff.index] = buff.bytesused;
  •     printf("size : %dn",pic.tmpbytesused[buff.index]);


  •     int jpg_fd = open("1.jpeg" , O_RDWR | O_CREAT , 00700);
  •     if(jpg_fd == -1)
  •     {
  •         printf("open ipg Failed!n ");
  •         return -1;
  •     }
  •     int writesize = write(jpg_fd , pic.tmpbuffer[buff.index] , pic.tmpbytesused[buff.index]);
  •     printf("Write successfully size : %dn" , writesize);
  •     close(jpg_fd);

  •     //10、Queue the buffers.
  •     if(ioctl(fd_video , VIDIOC_QBUF, &buff) < 0)
  •     {
  •         printf("camera VIDIOC_QBUF Failed.");
  •         usleep(1000*1000);
  •         return -1;
  •     }
  •     return 0;
  • }

  • 主循环运行:
    1.     while(1)
    2.     {
    3.         V4l2_Grab_Mjpeg(MJPEG_FILE_NAME);
    4.         LCD_RGB888_Show_JPG_File(FB_DEV, 0 , 0 , MJPEG_FILE_NAME);
    5.     }


    运行效果:
    40.JPG


    更多回帖

    相关帖子

    imx8
    发帖
    登录/注册
    ×
    20
    完善资料,
    赚取积分