这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界» 论坛首页» 综合技术» 电源与模拟» 【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. return 0;

  16. }

复制代码
显示到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 跳转至

回复

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