Chinaunix首页 | 论坛 | 博客
  • 博客访问: 208336
  • 博文数量: 32
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 850
  • 用 户 组: 普通用户
  • 注册时间: 2013-11-22 15:50
文章存档

2014年(16)

2013年(16)

分类: 嵌入式

2013-12-23 21:20:39

                    V4L2采集视频利用TCP协议远程传输
开发环境
            system : ubuntu12.04
            board   : mini2440
            arm-linux-gcc : v4.3.2

        说明:该应用将V4L2视频采集和TCP网络传输结合起来,实现了实时视频传输,分为客户端client和服务器端server两部分,客服端采集视频并进行传输,服务器穿接收视频并保存成文件。 客户端编译了arm版本和x86版本,均测试正常。
       本程序仅做学习用~~~~~~~~~~
1.    v4l2_tcp_server.c

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <unistd.h>
  6. #include <sys/types.h>
  7. #include <sys/socket.h>
  8. #include <netinet/in.h>
  9. #include <arpa/inet.h>
  10.   
  11. #define MAXLINE 1024
  12. #define     SERVER_PORT     3333

  13.   
  14. void usage(char *command)
  15. {
  16.     printf("usage :%s filename\n", command);
  17.     exit(0);
  18. }
  19. int main(int argc,char **argv)
  20. {
  21.     struct sockaddr_in serv_addr;
  22.     struct sockaddr_in clie_addr;
  23.     char buf[MAXLINE];
  24.     int sock_id;
  25.     int link_id;
  26.     int recv_len;
  27.     int write_leng;
  28.     int clie_addr_len;
  29.     FILE *fp;
  30.   
  31.     if (argc != 2) {
  32.         usage(argv[0]);
  33.     }
  34.     if ((fp = fopen(argv[1], "w")) == NULL) {
  35.         perror("Open file failed\n");
  36.         exit(0);
  37.     }
  38.     if ((sock_id = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  39.         perror("Create socket failed\n");
  40.         exit(0);
  41.     }
  42.     //memset(&serv_addr, 0, sizeof(serv_addr));
  43.     bzero(&serv_addr,sizeof(serv_addr));
  44.     serv_addr.sin_family = AF_INET;     //IPv4
  45.     serv_addr.sin_port = htons(SERVER_PORT);
  46.     serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  47.   
  48.     if (bind(sock_id, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0 ) {
  49.         perror("Bind socket failed\n");
  50.         exit(0);
  51.     }
  52.   
  53.     if (-1 == listen(sock_id, 10)) {
  54.         perror("Listen socket failed\n");
  55.         exit(0);
  56.     }
  57.     while (1) {
  58.         clie_addr_len = sizeof(clie_addr);
  59.         link_id = accept(sock_id, (struct sockaddr *)&clie_addr, (socklen_t *)&clie_addr_len);
  60.         if (-1 == link_id) {
  61.             perror("Accept socket failed\n");
  62.             exit(0);
  63.         }
  64.         bzero(buf, MAXLINE);
  65.         while ((recv_len = recv(link_id, buf, MAXLINE, 0)) != 0) {
  66.             if(recv_len < 0) {
  67.                 printf("Recieve Data From Server Failed!\n");
  68.                 break;
  69.             }
  70.             printf("#");
  71.             write_leng = fwrite(buf, sizeof(char), recv_len, fp);
  72.             if (write_leng < recv_len) {
  73.                 printf("Write file failed\n");
  74.                 break;
  75.             }
  76.             bzero(buf,MAXLINE);
  77.         }
  78.         printf("\nFinish Recieve\n");
  79.         fclose(fp);
  80.         close(link_id);
  81.     }
  82.     close(sock_id);
  83.     return 0;
  84. }
    Makefile 

点击(此处)折叠或打开

  1. all:v4l2_tcp_server

  2. v4l2_tcp_server:v4l2_tcp_server.c
  3.     gcc -Wall -o $@ $<

  4. clean:
  5.     rm -rf v4l2_tcp_server *.yuv
2.    v4l2_tcp_client.c

点击(此处)折叠或打开

  1. /*
  2.  * V4L2 video capture and tcp transformation example
  3.  * AUTHOT : WANGTISHENG
  4.  * DATA : 2013-12-18
  5.  */
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <assert.h>
  10. #include <getopt.h> /* getopt_long() */
  11. #include <fcntl.h> /* low-level i/o */
  12. #include <unistd.h>
  13. #include <errno.h>
  14. #include <sys/stat.h>
  15. #include <sys/types.h>
  16. #include <sys/time.h>
  17. #include <sys/mman.h>
  18. #include <sys/ioctl.h>
  19. #include <sys/socket.h>
  20. #include <netinet/in.h>
  21. #include <arpa/inet.h>
  22. #include <linux/videodev2.h>



  23. #define CLEAR(x) memset(&(x), 0, sizeof(x))

  24. struct buffer {
  25.         void *start;
  26.         size_t length;
  27. };

  28. static char *dev_name;
  29. static int fd = -1;        //DEVICE NUMBER
  30. struct buffer *buffers;
  31. static unsigned int n_buffers;
  32. static int frame_count = 100;
  33. FILE *fp;                                //FILE POINTOR
  34. #define CAPTURE_FILE "./frame_test.yuv"

  35. /* variables and macros for socket */
  36. int sock_id;
  37. #define        SERVER_IP        "192.168.1.121"
  38. #define        CLIENT_PORT        3333
  39. #define     MAXLINE     1024
  40. char buf[MAXLINE];


  41. static void errno_exit(const char *s)
  42. {
  43.         fprintf(stderr, "%s error %d, %s\n", s, errno, strerror(errno));
  44.         exit(EXIT_FAILURE);
  45. }

  46. static int xioctl(int fh, int request, void *arg)
  47. {
  48.         int r;
  49.         do {
  50.                 r = ioctl(fh, request, arg);
  51.         } while (-1 == r && EINTR == errno);
  52.         return r;
  53. }
  54. //处理函数
  55. static void process_image(const void *p, int size)
  56. {
  57.         int read_len;
  58.         FILE *fp_tmp;
  59.         int    send_len;
  60.     
  61.         fp_tmp = fopen(CAPTURE_FILE,"w");
  62.         fwrite(p,size, 1, fp_tmp);
  63.         fclose(fp_tmp);
  64.         //fwrite(p,size, 1, fp);
  65.         //memset(buf,0,MAXLINE);
  66.         fp_tmp = fopen(CAPTURE_FILE,"r");
  67.         while ((read_len = fread(buf, sizeof(char), MAXLINE, fp_tmp)) >0 ) {
  68.         send_len = send(sock_id, buf, read_len, 0);
  69.         if ( send_len < 0 ) {
  70.             perror("Send file failed\n");
  71.             exit(0);
  72.         }
  73.         //bzero(buf, MAXLINE);         //no use
  74.     }
  75.         fclose(fp_tmp);
  76. }

  77. static int read_frame(FILE *fp)
  78. {
  79.         struct v4l2_buffer buf;
  80.         CLEAR(buf);

  81.         buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  82.         buf.memory = V4L2_MEMORY_MMAP;
  83.         
  84.         if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf))
  85.                 errno_exit("VIDIOC_DQBUF");
  86.         
  87.         process_image(buffers[buf.index].start, buf.bytesused);

  88.         if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))
  89.             errno_exit("VIDIOC_QBUF");

  90.         return 1;
  91. }

  92. static void mainloop(void)
  93. {
  94.         unsigned int count;
  95.         count = frame_count;
  96.         while (count-- > 0) {
  97.             printf("No.%d\n",frame_count - count);        //显示当前帧数目
  98.             read_frame(fp);
  99.         }
  100.                 
  101.         printf("\nREAD AND SAVE DONE!\n");
  102. }

  103. static void stop_capturing(void)
  104. {
  105.         enum v4l2_buf_type type;

  106.         type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  107.         if (-1 == xioctl(fd, VIDIOC_STREAMOFF, &type))
  108.             errno_exit("VIDIOC_STREAMOFF");
  109. }

  110. static void start_capturing(void)
  111. {
  112.         unsigned int i;
  113.         enum v4l2_buf_type type;

  114.         for (i = 0; i < n_buffers; ++i) {
  115.                 struct v4l2_buffer buf;

  116.                 CLEAR(buf);
  117.                 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  118.                 buf.memory = V4L2_MEMORY_MMAP;
  119.                 buf.index = i;

  120.                 if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))
  121.                         errno_exit("VIDIOC_QBUF");
  122.         }
  123.         type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  124.         if (-1 == xioctl(fd, VIDIOC_STREAMON, &type))
  125.                 errno_exit("VIDIOC_STREAMON");
  126. }

  127. static void uninit_device(void)
  128. {
  129.         unsigned int i;

  130.         for (i = 0; i < n_buffers; ++i)
  131.                 if (-1 == munmap(buffers[i].start, buffers[i].length))
  132.                         errno_exit("munmap");

  133.         free(buffers);
  134. }



  135. static void init_mmap(void)
  136. {
  137.         struct v4l2_requestbuffers req;

  138.         CLEAR(req);

  139.         req.count = 4;
  140.         req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  141.         req.memory = V4L2_MEMORY_MMAP;

  142.         if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) {
  143.                 if (EINVAL == errno) {
  144.                         fprintf(stderr, "%s does not support "
  145.                                  "memory mapping\n", dev_name);
  146.                         exit(EXIT_FAILURE);
  147.                 } else {
  148.                         errno_exit("VIDIOC_REQBUFS");
  149.                 }
  150.         }

  151.         if (req.count < 2) {
  152.                 fprintf(stderr, "Insufficient buffer memory on %s\n",
  153.                          dev_name);
  154.                 exit(EXIT_FAILURE);
  155.         }

  156.         buffers = calloc(req.count, sizeof(*buffers));

  157.         if (!buffers) {
  158.                 fprintf(stderr, "Out of memory\n");
  159.                 exit(EXIT_FAILURE);
  160.         }

  161.         for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {
  162.                 struct v4l2_buffer buf;

  163.                 CLEAR(buf);

  164.                 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  165.                 buf.memory = V4L2_MEMORY_MMAP;
  166.                 buf.index = n_buffers;

  167.                 if (-1 == xioctl(fd, VIDIOC_QUERYBUF, &buf))
  168.                         errno_exit("VIDIOC_QUERYBUF");

  169.                 buffers[n_buffers].length = buf.length;
  170.                 buffers[n_buffers].start =
  171.                         mmap(NULL /* start anywhere */,
  172.                               buf.length,
  173.                               PROT_READ | PROT_WRITE /* required */,
  174.                               MAP_SHARED /* recommended */,
  175.                               fd, buf.m.offset);

  176.                 if (MAP_FAILED == buffers[n_buffers].start)
  177.                         errno_exit("mmap");
  178.         }
  179. }


  180. static void init_device(void)
  181. {
  182.         struct v4l2_capability cap;
  183.         struct v4l2_format fmt;

  184.         if (-1 == xioctl(fd, VIDIOC_QUERYCAP, &cap)) {        //测试参数
  185.                 if (EINVAL == errno) {
  186.                         fprintf(stderr, "%s is no V4L2 device\n",
  187.                                  dev_name);
  188.                         exit(EXIT_FAILURE);
  189.                 } else {
  190.                         errno_exit("VIDIOC_QUERYCAP");
  191.                 }
  192.         }

  193.         if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
  194.                 fprintf(stderr, "%s is no video capture device\n",
  195.                          dev_name);
  196.                 exit(EXIT_FAILURE);
  197.         }

  198.         if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
  199.                 fprintf(stderr, "%s does not support streaming i/o\n",
  200.                     dev_name);
  201.                 exit(EXIT_FAILURE);
  202.         }




  203.         CLEAR(fmt);
  204.         fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  205.         fmt.fmt.pix.width = 320;
  206.         fmt.fmt.pix.height = 240;
  207.         fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
  208.         fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;

  209.         if (-1 == xioctl(fd, VIDIOC_S_FMT, &fmt))        //设置格式
  210.                 errno_exit("VIDIOC_S_FMT");        
  211.         init_mmap();
  212. }

  213. static void close_device(void)
  214. {
  215.         if (-1 == close(fd))
  216.                 errno_exit("close");

  217.         fd = -1;
  218. }

  219. static void open_device(void)
  220. {
  221.         //加上O_NONBLOCK会出现如下错误
  222.         //VIDIOC_DQBUF error 11, Resource temporarily unavailable
  223.         fd = open(dev_name, O_RDWR /* required */ /*| O_NONBLOCK*/, 0);

  224.         if (-1 == fd) {
  225.                 fprintf(stderr, "Cannot open '%s': %d, %s\n",
  226.                          dev_name, errno, strerror(errno));
  227.                 exit(EXIT_FAILURE);
  228.         }
  229. }

  230. /* tcp initinalization */
  231. int tcp_init(void)    
  232. {
  233.     struct sockaddr_in serv_addr;
  234.     int                  i_ret;
  235.     //sock_id = socket(AF_INET, SOCK_DGRAM, 0);
  236.     if ((sock_id = socket(AF_INET,SOCK_STREAM,0)) < 0) {
  237.         perror("Create socket failed\n");
  238.         exit(0);
  239.     }

  240.     memset(&serv_addr, 0, sizeof(serv_addr));
  241.     serv_addr.sin_family = AF_INET;
  242.     serv_addr.sin_port = htons(CLIENT_PORT);
  243.     serv_addr.sin_addr.s_addr=inet_addr(SERVER_IP);
  244.      
  245.     /* connect the server commented by guoqingbo*/
  246.     i_ret = connect(sock_id, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr));
  247.     if (-1 == i_ret) {
  248.         printf("Connect socket failed\n");
  249.        return -1;
  250.     }
  251.     printf("Socket connected!\n");
  252.     return 0;
  253. }

  254. int main(int argc, char **argv)
  255. {
  256.         dev_name = "/dev/video0";
  257.         
  258.         //if(argc != 1)
  259.         //{
  260.         //    printf("usage :%s filename\n", argv[0]);
  261.         //    exit(0);
  262.         //}
  263.         //if ((fp = fopen(argv[1], "w")) == NULL) {
  264.         //    perror("Creat file failed");
  265.         //    exit(0);
  266.         //}
  267.         tcp_init();
  268.         open_device();
  269.         init_device();
  270.         start_capturing();
  271.         mainloop();                //主要处理均在该函数中实现
  272.         //fclose(fp);
  273.         stop_capturing();
  274.         uninit_device();
  275.         close_device();
  276.         //fprintf(stderr, "\n");
  277.         return 0;
  278. }
    Makefile: 

点击(此处)折叠或打开

  1. all:v4l2_tcp_client_x86 v4l2_tcp_client_arm

  2. v4l2_tcp_client_x86:v4l2_tcp_client.c
  3.     gcc -Wall -o $@ $<
  4. v4l2_tcp_client_arm:v4l2_tcp_client.c
  5.     arm-linux-gcc -Wall -o $@ $<
  6. clean:
  7.     rm -rf v4l2_tcp_client_x86 v4l2_tcp_client_arm
3.    编译测试
    先执行服务器端程序
        # ./v4l2_tcp_server file_receive.yuv
    执行客户端程序
        # ./v4l2_tcp_client_x86 或者
        # ./v4l2_tcp_client_arm 

阅读(5646) | 评论(0) | 转发(6) |
给主人留下些什么吧!~~