这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 综合技术 » 电源与模拟 » 【ALINXAXU2CGB试用】使用V4L2函数库驱动USB摄像头&UDP网络摄

共1条 1/1 1 跳转至

【ALINXAXU2CGB试用】使用V4L2函数库驱动USB摄像头&UDP网络摄...

工程师
2021-07-19 12:51:17     打赏
【ALINX AXU2CGB试用】使用V4L2函数库驱动USB摄像头&UDP网络摄像头实现


       所有Linux设备,只要是有USB接口,都可以实现USB摄像头的读取,这是每一个嵌入式开发者都必须掌握的技能。
       首先是打开支持V4L2的设备,通常会被系统映射为/dev/videox设备:

读写方式同样是ioctl,非常简单:
  1.     if ((fd_video = open(filename,O_RDWR)) == -1)

  2.     {

  3.         printf("Error opening V4L interface\n");

  4.         return 1;

  5.     }


  6.     if (ioctl(fd_video,VIDIOC_QUERYCAP,&cap) == -1)

  7.     {

  8.         printf("Error opening device %s: unable to query device.\n",filename);

  9.         return 2;

  10.     }

复制代码
使用format结构体设置相关参数:
  1.     struct v4l2_format fmt;

  2.     fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

  3.     fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;

  4.     fmt.fmt.pix.height = IMAGEHEIGHT;

  5.     fmt.fmt.pix.width =  IMAGEWIDTH;

  6.     fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;


  7.     if(ioctl(fd_video,VIDIOC_S_FMT, &fmt) == -1)

  8.     {

  9.         printf("Unable to set format\n");

  10.         return 3;

  11.     }


  12.     if(ioctl(fd_video,VIDIOC_G_FMT, &fmt) == -1)

  13.     {

  14.         printf("Unable to get format\n");

  15.         return 4;

  16.     }

复制代码
使用requestbuffers结构体配置申请内存:
  1. struct v4l2_requestbuffers req;

  2.     req.count = 4;

  3.     req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

  4.     req.memory = V4L2_MEMORY_MMAP;

  5.     if(ioctl(fd_video,VIDIOC_REQBUFS,&req)==-1)

  6.     {

  7.         printf("request for buffers error\n");

  8.         return 5;

  9.     }

复制代码
抓取时,使用队列缓存进行数据搬运:
  1.         if (ioctl (fd_video,VIDIOC_QUERYBUF, &buf) == -1)

  2.         {

  3.             printf("query buffer error\n");

  4.             return(0);

  5.         }


  6.     ioctl (fd_video, VIDIOC_STREAMON, &type);


  7.     ioctl(fd_video, VIDIOC_DQBUF, &buf);


  8. int RGB888_u8_2_RGB565_u16(unsigned char * input_buffer,unsigned short output_buffer[])

  9. {

  10.     int i;

  11.     for(i = 0 ; i < 640 * 480 * 3 ; i += 3)

  12.     {

  13.         output_buffer[i/3] = (unsigned short)(((input_buffer[i] << 8) & 0xF800) |   ((input_buffer[i+1] << 3) & 0x7E0)  | input_buffer[i+2] >> 3);

  14.     }

  15.     


  16.     return 0;

  17. }

复制代码
显示到framebuffer设备需要进行格式转换,数据格式取决于开发板的GPU显示芯片所支持的格式:
  1. int LCD_Show_Buffer16(char *dev_name , int xpos , int ypos , int width , int height ,unsigned short frame_buffer16[])

  2. {

  3.     int fd_lcd,i,j,count;

  4.     fd_lcd = open(dev_name,O_RDWR);

  5.     if(fd_lcd==-1)

  6.     {

  7.             printf("open LCD failed!\n");

  8.             return -1;

  9.     }

  10.     for(i = 0 ; i < LCD_HEIGHT ; i++)

  11.     {

  12.         for(j = 0 ; j < LCD_WIDTH ; j++)

  13.         {

  14.             if(i <= height && j <= width)

  15.             {

  16.                 framebuffer_lcd[(i + ypos) * LCD_WIDTH + j + xpos] = frame_buffer16[i * width + j];

  17.             }

  18.         }

  19.     }

  20.     write(fd_lcd,framebuffer_lcd,LCD_WIDTH * LCD_HEIGHT * 2);

  21.     close(fd_lcd);

  22.     return 0;

  23. }


复制代码
  1. uint16_t ConvertRGB32_or_24_To16(uint32_t rgb)

  2. {

  3.     uint32_t red = (rgb & 0x00F80000) >> 8 ;

  4.     uint32_t green = (rgb & 0x0000FC00) >> 5 ;

  5.     uint32_t blue = (rgb & 0x000000F8) >> 3;

  6.     return red | green | blue;

  7. }

复制代码


然后是UDP传输摄像头图片的实现,需要设置目标IP和端口号:

  1. int UDP_Send_Found(socklen_t* socket_found , struct sockaddr_in *addr , char* ip , int port)

  2. {

  3. *socket_found = socket(AF_INET, SOCK_DGRAM, 0);


  4. if(*socket_found == (~0))

  5. {

  6. printf("Create udp send socket failed!\n");

  7. return -1;

  8. }


  9. addr->sin_family = AF_INET;

  10. addr->sin_addr.s_addr = inet_addr(ip);

  11. addr->sin_port = htons(port);

  12. memset(addr->sin_zero, 0, 8);

  13. return 0;

  14. }

复制代码
  1. int UDP_Send_Picture(socklen_t socket_send , struct sockaddr_in addr , char* filename)

  2. {

  3.     struct Package

  4.     {

  5.         int length;

  6.         char data[UDP_FRAME_LEN];

  7.         int fin;

  8.     }picture;


  9.     socklen_t addr_len = sizeof(struct sockaddr_in);


  10.     FILE *fp;

  11.     fp = fopen(filename, "rb+");

  12.     printf("fp = %d\n",fp);

  13.     fseek(fp, 0, SEEK_END);

  14.     int fend = ftell(fp);

  15.     fseek(fp, 0, 0);

  16.     int sendbytes;

  17.     printf("fend = %d\n",fend);

  18.     while(fend > 0)

  19.     {

  20.         memset(picture.data, 0, sizeof(picture.data));

  21.         fread(picture.data, UDP_FRAME_LEN, 1, fp);

  22.         if(fend >= UDP_FRAME_LEN)

  23.         {

  24.             picture.length = UDP_FRAME_LEN;

  25.             picture.fin = 0;

  26.         }

  27.         else

  28.         {

  29.             picture.length = fend;

  30.             picture.fin = 1;

  31.         }


  32.         //printf("sendbytes = %d \n",sendbytes);


  33.         sendbytes = sendto(socket_send, (char *)&picture, sizeof(struct Package), 0, (struct sockaddr*)&addr,addr_len);


  34.         if(sendbytes == -1)

  35.         {

  36.             printf("Send Picture Failed!d\n");

  37.             return -1;

  38.         }

  39.         else

  40.         {

  41.             fend -= UDP_FRAME_LEN;

  42.         }

  43.     }

  44.     fclose(fp);

  45.     return 0;

  46. }

复制代码

电脑端使用QT上位机搭建一个接收UDP的界面:

 

 UDPImage1.zip (24.5 MB, 下载次数: 0) 





关键词: ALINX     AXU2CGB     试用     使用V4L2         

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]