使用avilib封装MJPEG数据应用实例

  avilib 是一个很小的封装模块,它可以将一些图片数据封装成视频格式。在一些比较差的摄像头中,他们只支持V4L2_PIX_FMT_MJPEG 输出JPEG格式数据,以这种格式输出的数据,并不是标准的JPEG图片数据。因此,如果只是把MJPEG输出的所有文件存成一个文件,那么这个文件其实并不能播放。据网上的一些资料介绍,说是缺少Huffman 表,需要自己手动插入一个Huffman表。在一些嵌入式设备中,他们直接将MPEG模式下输出的数据,然后通过JPEG解码库解码成RGB数据,然后直接丢到LCD的BUFF中就可以了(这种方法我没有测试过,只是看网上资料这么介绍)。

    本人主要开发嵌入式设备,且刚接触图形编码时间不久,暂时还没有使用一些大的图片格式转换库,库文件是在网上找的,avilib只有一个文件编译之后的大小也只有几十K,他可以直接将v4l2 MPEG模式输出的数据封装成avi格式视屏。它提供的接口有:

[objc]  view plain  copy
 print ?
  1. void AVI_set_video(avi_t *AVI, int width, int height, double fps, charchar *compressor);  
  2. void AVI_set_audio(avi_t *AVI, int channels, long rate, int bits, int format, long mp3rate);  
  3. int  AVI_write_frame(avi_t *AVI, charchar *data, long bytes, int keyframe);  
  4. int  AVI_dup_frame(avi_t *AVI);  
  5. int  AVI_write_audio(avi_t *AVI, charchar *data, long bytes);  
  6. int  AVI_append_audio(avi_t *AVI, charchar *data, long bytes);  
  7. long AVI_bytes_remain(avi_t *AVI);  
  8. int  AVI_close(avi_t *AVI);  
  9. long AVI_bytes_written(avi_t *AVI);  
  10.   
  11. avi_t *AVI_open_input_file(charchar *filename, int getIndex);  
  12. avi_t *AVI_open_fd(int fd, int getIndex);  
  13. int avi_parse_input_file(avi_t *AVI, int getIndex);  
  14. long AVI_audio_mp3rate(avi_t *AVI);  
  15. long AVI_video_frames(avi_t *AVI);  
  16. int  AVI_video_width(avi_t *AVI);  
  17. int  AVI_video_height(avi_t *AVI);  
  18. double AVI_frame_rate(avi_t *AVI);  
  19. char* AVI_video_compressor(avi_t *AVI);  
  20.   
  21. int  AVI_audio_channels(avi_t *AVI);  
  22. int  AVI_audio_bits(avi_t *AVI);  
  23. int  AVI_audio_format(avi_t *AVI);  
  24. long AVI_audio_rate(avi_t *AVI);  
  25. long AVI_audio_bytes(avi_t *AVI);  
  26. long AVI_audio_chunks(avi_t *AVI);  
  27.   
  28. long AVI_max_video_chunk(avi_t *AVI);  
  29.   
  30. long AVI_frame_size(avi_t *AVI, long frame);  
  31. long AVI_audio_size(avi_t *AVI, long frame);  
  32. int  AVI_seek_start(avi_t *AVI);  
  33. int  AVI_set_video_position(avi_t *AVI, long frame);  
  34. long AVI_get_video_position(avi_t *AVI, long frame);  
  35. long AVI_read_frame(avi_t *AVI, charchar *vidbuf, intint *keyframe);  
  36.   
  37. int  AVI_set_audio_position(avi_t *AVI, long byte);  
  38. int  AVI_set_audio_bitrate(avi_t *AVI, long bitrate);  
  39.   
  40. long AVI_read_audio(avi_t *AVI, charchar *audbuf, long bytes);  
  41.   
  42. long AVI_audio_codech_offset(avi_t *AVI);  
  43. long AVI_audio_codecf_offset(avi_t *AVI);  
  44. long AVI_video_codech_offset(avi_t *AVI);  
  45. long AVI_video_codecf_offset(avi_t *AVI);  
  46.   
  47. int  AVI_read_data(avi_t *AVI, charchar *vidbuf, long max_vidbuf,  
  48.                                charchar *audbuf, long max_audbuf,  
  49.                                longlong *len);  
  50.   
  51. void AVI_print_error(charchar *str);  
  52. charchar *AVI_strerror();  
  53. charchar *AVI_syserror();  
  54.   
  55. int AVI_scan(charchar *name);  
  56. int AVI_dump(charchar *name, int mode);  
  57.   
  58. charchar *AVI_codec2str(short cc);  
  59. int AVI_file_check(charchar *import_file);  
  60.   
  61. void AVI_info(avi_t *avifile);  
  62. uint64_t AVI_max_size();  
  63. int avi_update_header(avi_t *AVI);  
  64.   
  65. int AVI_set_audio_track(avi_t *AVI, int track);  
  66. int AVI_get_audio_track(avi_t *AVI);  
  67. int AVI_audio_tracks(avi_t *AVI);  

下面是一个简单的测试程序:

[objc]  view plain  copy
 print ?
  1. /*============================================================================= 
  2. #     FileName: main.c 
  3. #         Desc: this program aim to get image from USB camera, 
  4. #               used the V4L2 interface. 
  5. #       Author: Licaibiao 
  6. #      Version:  
  7. #   LastChange: 2016-12-10  
  8. #      History: 
  9. =============================================================================*/  
  10. #include <unistd.h>  
  11. #include <sys/types.h>  
  12. #include <sys/stat.h>  
  13. #include <fcntl.h>  
  14. #include <stdio.h>  
  15. #include <sys/ioctl.h>  
  16. #include <stdlib.h>  
  17. #include <linux/types.h>  
  18. #include <linux/videodev2.h>  
  19. #include <malloc.h>  
  20. #include <math.h>  
  21. #include <string.h>  
  22. #include <sys/mman.h>  
  23. #include <errno.h>  
  24. #include <assert.h>  
  25. #include <sys/time.h>  
  26.   
  27. #include "avilib.h"  
  28.   
  29. #define FILE_VIDEO  "/dev/video0"  
  30. #define JPG "./out/image%d.jpg"  
  31.   
  32. typedef struct{  
  33.     voidvoid *start;  
  34.     int length;  
  35. }BUFTYPE;  
  36. BUFTYPE *usr_buf;  
  37.   
  38. static unsigned int n_buffer = 0;    
  39. avi_t *out_fd = NULL;   
  40. struct timeval time;  
  41.   
  42. float get_main_time(struct timeval* start , int update)  
  43. {  
  44.     float dt;  
  45.     struct timeval now;  
  46.     gettimeofday(&now, NULL);  
  47.     dt = (float)(now.tv_sec  - start->tv_sec);  
  48.     dt += (float)(now.tv_usec - start->tv_usec) * 1e-6;  
  49.       
  50.     if (update > 0) {  
  51.         start->tv_sec = now.tv_sec;  
  52.         start->tv_usec = now.tv_usec;  
  53.     }  
  54.       
  55.     return dt;  
  56. }  
  57.   
  58.   
  59.   
  60. /*set video capture ways(mmap)*/  
  61. int init_mmap(int fd)  
  62. {  
  63.     /*to request frame cache, contain requested counts*/  
  64.     struct v4l2_requestbuffers reqbufs;  
  65.   
  66.     memset(&reqbufs, 0sizeof(reqbufs));  
  67.     reqbufs.count = 6;                              /*the number of buffer*/  
  68.     reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;      
  69.     reqbufs.memory = V4L2_MEMORY_MMAP;                
  70.   
  71.     if(-1 == ioctl(fd,VIDIOC_REQBUFS,&reqbufs))  
  72.     {  
  73.         perror("Fail to ioctl 'VIDIOC_REQBUFS'");  
  74.         exit(EXIT_FAILURE);  
  75.     }  
  76.       
  77.     n_buffer = reqbufs.count;  
  78.     printf("n_buffer = %d\n", n_buffer);  
  79.     //usr_buf = calloc(reqbufs.count, sizeof(usr_buf));  
  80.     usr_buf = calloc(reqbufs.countsizeof(BUFTYPE));/*** (4) ***<span style="font-family: Arial, Helvetica, sans-serif;">/</span> 
  81.     if(usr_buf == NULL) 
  82.     { 
  83.         printf("Out of memory\n"); 
  84.         exit(-1); 
  85.     } 
  86.  
  87.     /*map kernel cache to user process*/  
  88.     for(n_buffer = 0; n_buffer < reqbufs.count; ++n_buffer)  
  89.     {  
  90.         //stand for a frame  
  91.         struct v4l2_buffer buf;  
  92.         memset(&buf, 0sizeof(buf));  
  93.         buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  94.         buf.memory = V4L2_MEMORY_MMAP;  
  95.         buf.index = n_buffer;  
  96.           
  97.         /*check the information of the kernel cache requested*/  
  98.         if(-1 == ioctl(fd,VIDIOC_QUERYBUF,&buf))  
  99.         {  
  100.             perror("Fail to ioctl : VIDIOC_QUERYBUF");  
  101.             exit(EXIT_FAILURE);  
  102.         }  
  103.   
  104.         usr_buf[n_buffer].length = buf.length;  
  105.         usr_buf[n_buffer].start = (charchar *)mmap(NULL,buf.length,PROT_READ | PROT_WRITE,MAP_PRIVATE, fd,buf.m.offset);  
  106.   
  107.         if(MAP_FAILED == usr_buf[n_buffer].start)  
  108.         {  
  109.             perror("Fail to mmap");  
  110.             exit(EXIT_FAILURE);  
  111.         }  
  112.   
  113.     }  
  114.   
  115. }  
  116.   
  117. int open_camera(void)  
  118. {  
  119.     int fd;  
  120.     /*open video device with block */  
  121.     fd = open(FILE_VIDEO, O_RDONLY);  
  122.     if(fd < 0)  
  123.     {     
  124.         fprintf(stderr, "%s open err \n", FILE_VIDEO);  
  125.         exit(EXIT_FAILURE);  
  126.     };  
  127.     return fd;  
  128. }  
  129.   
  130. int init_camera(int fd)  
  131. {  
  132.     struct v4l2_capability  cap;    /* decive fuction, such as video input */  
  133.     struct v4l2_format      tv_fmt; /* frame format */    
  134.     struct v4l2_fmtdesc     fmtdesc;    /* detail control value */  
  135.     struct v4l2_control     ctrl;  
  136.     int ret;  
  137.       
  138.             /*show all the support format*/  
  139.     memset(&fmtdesc, 0sizeof(fmtdesc));  
  140.     fmtdesc.index = 0 ;                 /* the number to check */  
  141.     fmtdesc.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  142.   
  143.     /* check video decive driver capability */  
  144.     if(ret=ioctl(fd, VIDIOC_QUERYCAP, &cap)<0)  
  145.     {  
  146.         fprintf(stderr, "fail to ioctl VIDEO_QUERYCAP \n");  
  147.         exit(EXIT_FAILURE);  
  148.     }  
  149.       
  150.     /*judge wherher or not to be a video-get device*/  
  151.     if(!(cap.capabilities & V4L2_BUF_TYPE_VIDEO_CAPTURE))  
  152.     {  
  153.         fprintf(stderr, "The Current device is not a video capture device \n");  
  154.         exit(EXIT_FAILURE);  
  155.     }  
  156.   
  157.     /*judge whether or not to supply the form of video stream*/  
  158.     if(!(cap.capabilities & V4L2_CAP_STREAMING))  
  159.     {  
  160.         printf("The Current device does not support streaming i/o\n");  
  161.         exit(EXIT_FAILURE);  
  162.     }  
  163.       
  164.     printf("\ncamera driver name is : %s\n",cap.driver);  
  165.     printf("camera device name is : %s\n",cap.card);  
  166.     printf("camera bus information: %s\n",cap.bus_info);  
  167.   
  168.         /*display the format device support*/  
  169.     while(ioctl(fd,VIDIOC_ENUM_FMT,&fmtdesc)!=-1)  
  170.     {     
  171.         printf("\nsupport device %d.%s\n\n",fmtdesc.index+1,fmtdesc.description);  
  172.         fmtdesc.index++;  
  173.     }  
  174.   
  175.   
  176.     /*set the form of camera capture data*/  
  177.     tv_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;      /*v4l2_buf_typea,camera must use V4L2_BUF_TYPE_VIDEO_CAPTURE*/  
  178.     tv_fmt.fmt.pix.width = 320;  
  179.     tv_fmt.fmt.pix.height = 240;  
  180.     tv_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG; /*V4L2_PIX_FMT_YYUV*/  
  181.     tv_fmt.fmt.pix.field = V4L2_FIELD_NONE;         /*V4L2_FIELD_NONE*/  
  182.     if (ioctl(fd, VIDIOC_S_FMT, &tv_fmt)< 0)   
  183.     {  
  184.         fprintf(stderr,"VIDIOC_S_FMT set err\n");  
  185.         exit(-1);  
  186.         close(fd);  
  187.     }  
  188.   
  189.     init_mmap(fd);  
  190. }  
  191.   
  192. int start_capture(int fd)  
  193. {  
  194.     unsigned int i;  
  195.     enum v4l2_buf_type type;  
  196.       
  197.     /*place the kernel cache to a queue*/  
  198.     for(i = 0; i < n_buffer; i++)  
  199.     {  
  200.         struct v4l2_buffer buf;  
  201.         memset(&buf, 0sizeof(buf));  
  202.         buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  203.         buf.memory = V4L2_MEMORY_MMAP;  
  204.         buf.index = i;  
  205.   
  206.         if(-1 == ioctl(fd, VIDIOC_QBUF, &buf))  
  207.         {  
  208.             perror("Fail to ioctl 'VIDIOC_QBUF'");  
  209.             exit(EXIT_FAILURE);  
  210.         }  
  211.     }  
  212.   
  213.     type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  214.     if(-1 == ioctl(fd, VIDIOC_STREAMON, &type))  
  215.     {  
  216.         printf("i=%d.\n", i);  
  217.         perror("VIDIOC_STREAMON");  
  218.         close(fd);  
  219.         exit(EXIT_FAILURE);  
  220.     }  
  221.   
  222.     return 0;  
  223. }  
  224.   
  225.   
  226. int process_image(voidvoid *addr, int length)  
  227. {  
  228. #if 0  
  229.     FILEFILE *fp;  
  230.   
  231.     static int num = 0;  
  232.   
  233.     char image_name[20];  
  234.     sprintf(image_name, JPG, num++);  
  235.     if((fp = fopen(image_name, "w")) == NULL)  
  236.     {  
  237.         perror("Fail to fopen");  
  238.         exit(EXIT_FAILURE);  
  239.     }  
  240.     fwrite(addr, length, 1, fp);  
  241.     usleep(500);  
  242.     fclose(fp);  
  243.     return 0;  
  244. #endif  
  245.     int res = 0;  
  246.     float ret = 0;  
  247.     //ret = get_main_time(&time , 1);  
  248.     res = AVI_write_frame(out_fd, addr, length,0);  
  249.     //ret = get_main_time(&time , 1);  
  250.     //printf("AVI write time = %f\n",ret);  
  251.     if(res < 0)  
  252.     {  
  253.         perror("Fail to write frame\n");  
  254.         exit(EXIT_FAILURE);  
  255.     }  
  256.   
  257.     return 0;  
  258.   
  259. }  
  260.   
  261. int read_frame(int fd)  
  262. {  
  263.     struct v4l2_buffer buf;  
  264.     unsigned int i;  
  265.     memset(&buf, 0sizeof(buf));  
  266.     buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  267.     buf.memory = V4L2_MEMORY_MMAP;  
  268.     //put cache from queue  
  269.     if(-1 == ioctl(fd, VIDIOC_DQBUF,&buf))  
  270.     {  
  271.         perror("Fail to ioctl 'VIDIOC_DQBUF'");  
  272.         exit(EXIT_FAILURE);  
  273.     }  
  274.     assert(buf.index < n_buffer);  
  275.   
  276.     //read process space's data to a file  
  277.     process_image(usr_buf[buf.index].start, usr_buf[buf.index].length);  
  278.     if(-1 == ioctl(fd, VIDIOC_QBUF,&buf))  
  279.     {  
  280.         perror("Fail to ioctl 'VIDIOC_QBUF'");  
  281.         exit(EXIT_FAILURE);  
  282.     }  
  283.     return 1;  
  284. }  
  285.   
  286.   
  287. int mainloop(int fd)  
  288. {  
  289.     int count = 400;  
  290.     while(count-- > 0)  
  291.     {  
  292.         for(;;)  
  293.         {  
  294.             fd_set fds;  
  295.             struct timeval tv;  
  296.             int r;  
  297.   
  298.             float ret = 0;  
  299.             ret = get_main_time(&time , 1);  
  300.             FD_ZERO(&fds);  
  301.             FD_SET(fd,&fds);  
  302.   
  303.             /*Timeout*/  
  304.             tv.tv_sec = 2;  
  305.             tv.tv_usec = 0;  
  306.             r = select(fd + 1,&fds,NULL,NULL,&tv);  
  307.             ret = get_main_time(&time , 1);  
  308.             //printf("AVI write time = %f\n",ret);  
  309.               
  310.             if(-1 == r)  
  311.             {  
  312.                  if(EINTR == errno)  
  313.                     continue;  
  314.                 perror("Fail to select");  
  315.                 exit(EXIT_FAILURE);  
  316.             }  
  317.             if(0 == r)  
  318.             {  
  319.                 fprintf(stderr,"select Timeout\n");  
  320.                 exit(-1);  
  321.             }  
  322.   
  323.             if(read_frame(fd))  
  324.             {  
  325.                 break;  
  326.             }  
  327.         }  
  328.     }  
  329.     return 0;  
  330. }  
  331.   
  332. void stop_capture(int fd)  
  333. {  
  334.     enum v4l2_buf_type type;  
  335.     type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  336.     if(-1 == ioctl(fd,VIDIOC_STREAMOFF,&type))  
  337.     {  
  338.         perror("Fail to ioctl 'VIDIOC_STREAMOFF'");  
  339.         exit(EXIT_FAILURE);  
  340.     }  
  341. }  
  342.   
  343. void close_camera_device(int fd)  
  344. {  
  345.     unsigned int i;  
  346.     for(i = 0;i < n_buffer; i++)  
  347.     {  
  348.         if(-1 == munmap(usr_buf[i].start,usr_buf[i].length))  
  349.         {  
  350.             exit(-1);  
  351.         }  
  352.     }  
  353.   
  354.     free(usr_buf);  
  355.   
  356.     if(-1 == close(fd))  
  357.     {  
  358.         perror("Fail to close fd");  
  359.         exit(EXIT_FAILURE);  
  360.     }  
  361. }  
  362.   
  363. void init_avi(void)  
  364. {  
  365.      charchar *filename = "avi_test.avi";  
  366.     out_fd = AVI_open_output_file(filename);  
  367.     if(out_fd!=NULL)  
  368.     {  
  369.         AVI_set_video(out_fd, 32024025"MJPG");  
  370.     }  
  371.     else  
  372.     {  
  373.         perror("Fail to open AVI\n");  
  374.         exit(EXIT_FAILURE);  
  375.     }  
  376. }  
  377.   
  378. void close_avi(void)  
  379. {  
  380.     AVI_close(out_fd);  
  381. }  
  382.   
  383.   
  384. void main(void)  
  385. {  
  386.     int fd;  
  387.     fd = open_camera();  
  388.     init_avi();  
  389.     init_camera(fd);  
  390.     start_capture(fd);  
  391.     mainloop(fd);  
  392.     stop_capture(fd);  
  393.     close_avi();  
  394.     close_camera_device(fd);  
  395. }  
编译运行结果:

[objc]  view plain  copy
 print ?
  1. root@ubuntu:/home/share/test/v4l2_MJPEG_AVI# make clean  
  2. rm -f *.o a.out test core *~ *.avi  
  3. root@ubuntu:/home/share/test/v4l2_MJPEG_AVI# make  
  4. gcc    -c -o main.o main.c  
  5. gcc    -c -o avilib.o avilib.c  
  6. gcc  -o test main.o  avilib.o   
  7. root@ubuntu:/home/share/test/v4l2_MJPEG_AVI# ./test   
  8.   
  9. camera driver name is : gspca_zc3xx  
  10. camera device name is : PC Camera  
  11. camera bus information: usb-0000:02:00.0-2.1  
  12.   
  13. support device 1.JPEG  
  14.   
  15. n_buffer = 6  
  16. root@ubuntu:/home/share/test/v4l2_MJPEG_AVI# ls  
  17. avilib.c  avilib.h  avilib.o  avi_test.avi  main.c  main.o  Makefile  test  
  18. root@ubuntu:/home/share/test/v4l2_MJPEG_AVI#  
生成的avi_est.avi 文件,在迅雷播放器上播放如下:

     

    这里需要注意,可能是因为我的USB驱动问题,读取JPEG需要的时间过长,导致录制的视频,播放的时候会出现快进的问题。另外,如果在设置v4l2 内存映射的时候,如果申请的buff 块太少也是会导致数据采集过慢的问题。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值