在很多USB摄像头中,质量好点的可以输出很多种数据格式,也有一些只能设置MJPEG模式输出JPEG格式数据,比如我从师弟那顺过来的这颗,哈哈便宜没好货。JPEG数据如果是作为本地存储是没有什么问题的,它在摄像头中已经经过了一次压缩。但是,如果你是需要做视频流,直接使用JPEG格式数据,那么传输的码流就会很大,不利于传输。所以现在基本上所有的视频都是有经过压缩处理的。常见的压缩是H264格式,而H264是需要数据以YUV420格式输入的。对于在硬件平台有限的一些嵌入式设备中,一些大的数据格式装换的库是无法移植到那些平台上去的。比较小的一些JPEG格式装换的库,比如libjpeg和tinyjpegdecoder库,他们好像都是将JPEG数据转换为RGB格式数据,更加可恶的是tinyjpegdecoder库只能在奔腾的处理器上编译通过,因为他底层全部使用的是奔腾的汇编指令。在这里提供另外的一种比较简单的格式装换。
root@ubuntu:/home/share/v4l2MJPEG2YUV422# ll total 80 drwxr-xr-x 3 root root 4096 Dec 20 17:17 ./ drwxrwxrwx 13 root root 4096 Dec 20 15:57 ../ -rwxr--r-- 1 ysj002 ysj002 4012 Nov 17 2015 color.c* -rwxr--r-- 1 ysj002 ysj002 2902 Nov 17 2015 color.h* -rwxr--r-- 1 ysj002 ysj002 5652 Nov 17 2015 huffman.h* -rw-r--r-- 1 root root 8729 Dec 17 13:23 main.c -rw-r--r-- 1 root root 309 Dec 16 19:50 Makefile drwxr-xr-x 2 root root 4096 Dec 17 13:18 out/ -rwxr--r-- 1 ysj002 ysj002 28788 Jul 18 18:22 utils.c* -rwxr--r-- 1 ysj002 ysj002 2435 Dec 15 19:12 utils.h*
上面是我的整个测试测试程序,color和 utils 是用网上找的,具体出处我也没有找着,只是在网上有不少的这个程序。我们只需要调utils.h 中的jpeg_decode 这一个接口就可以了。
下面的是我的测试程序main.c
/*============================================================================= # FileName: main.c # Desc: MJPEG encoder to YUV422P # Author: Licaibiao # Version: # LastChange: 2016-12-16 # History: =============================================================================*/ #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <sys/ioctl.h> #include <stdlib.h> #include <linux/types.h> #include <linux/videodev2.h> #include <malloc.h> #include <math.h> #include <string.h> #include <sys/mman.h> #include <errno.h> #include <assert.h> #include <sys/time.h> #include "utils.h" #define WIDTH 640 #define HIGHT 480 #define FILE_VIDEO "/dev/video0" #define JPG "./out/image%d" typedef struct{ void *start; int length; }BUFTYPE; BUFTYPE *usr_buf; static unsigned int n_buffer = 0; struct timeval time; unsigned char* mjpeg_buff; unsigned char* yuyv_buff; unsigned char* yuv_buff; float get_main_time(struct timeval* start , int update) { float dt; struct timeval now; gettimeofday(&now, NULL); dt = (float)(now.tv_sec - start->tv_sec); dt += (float)(now.tv_usec - start->tv_usec) * 1e-6; if (update > 0) { start->tv_sec = now.tv_sec; start->tv_usec = now.tv_usec; } return dt; } int init_mmap(int fd) { /*to request frame cache, contain requested counts*/ struct v4l2_requestbuffers reqbufs; memset(&reqbufs, 0, sizeof(reqbufs)); reqbufs.count = 4; reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; reqbufs.memory = V4L2_MEMORY_MMAP; if(-1 == ioctl(fd,VIDIOC_REQBUFS,&reqbufs)) { perror("Fail to ioctl 'VIDIOC_REQBUFS'"); exit(EXIT_FAILURE); } n_buffer = reqbufs.count; printf("n_buffer = %d\n", n_buffer); usr_buf = calloc(reqbufs.count, sizeof(BUFTYPE)); if(usr_buf == NULL) { printf("Out of memory\n"); exit(-1); } /*map kernel cache to user process*/ for(n_buffer = 0; n_buffer < reqbufs.count; ++n_buffer) { //stand for a frame struct v4l2_buffer buf; memset(&buf, 0, sizeof(buf)); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = n_buffer; /*check the information of the kernel cache requested*/ if(-1 == ioctl(fd,VIDIOC_QUERYBUF,&buf)) { perror("Fail to ioctl : VIDIOC_QUERYBUF"); exit(EXIT_FAILURE); } usr_buf[n_buffer].length = buf.length; usr_buf[n_buffer].start = (char *)mmap(NULL,buf.length,PROT_READ | PROT_WRITE,MAP_PRIVATE, fd,buf.m.offset); if(MAP_FAILED == usr_buf[n_buffer].start) { perror("Fail to mmap"); exit(EXIT_FAILURE); } } } int open_camera(void) { int fd; /*open video device with block */ fd = open(FILE_VIDEO, O_RDONLY); if(fd < 0) { fprintf(stderr, "%s open err \n", FILE_VIDEO); exit(EXIT_FAILURE); }; return fd; } void init_mjpeg_encode(void) { mjpeg_buff = (unsigned char*)malloc(WIDTH * HIGHT * 2); if(mjpeg_buff == NULL) { perror("mjpeg_encode malloc err\n"); }; yuyv_buff = (unsigned char*)malloc(WIDTH * HIGHT * 2); if(yuyv_buff == NULL) { perror("mjpeg_encode malloc err\n"); }; yuv_buff = (unsigned char*)malloc(WIDTH * HIGHT * 2); if(yuyv_buff == NULL) { perror("mjpeg_encode malloc err\n"); }; memset(yuv_buff, 0, WIDTH * HIGHT * 2); } void release_mjpeg(void) { free(mjpeg_buff); free(yuyv_buff); free(yuv_buff); } int init_camera(int fd) { struct v4l2_capability cap; /* decive fuction, such as video input */ struct v4l2_format tv_fmt; /* frame format */ struct v4l2_fmtdesc fmtdesc;/* detail control value */ struct v4l2_control ctrl; int ret; /*show all the support format*/ memset(&fmtdesc, 0, sizeof(fmtdesc)); fmtdesc.index = 0 ; /* the number to check */ fmtdesc.type=V4L2_BUF_TYPE_VIDEO_CAPTURE; /* check video decive driver capability */ if(ret=ioctl(fd, VIDIOC_QUERYCAP, &cap)<0) { fprintf(stderr, "fail to ioctl VIDEO_QUERYCAP \n"); exit(EXIT_FAILURE); } /*judge wherher or not to be a video-get device*/ if(!(cap.capabilities & V4L2_BUF_TYPE_VIDEO_CAPTURE)) { fprintf(stderr, "The Current device is not a video capture device \n"); exit(EXIT_FAILURE); } /*judge whether or not to supply the form of video stream*/ if(!(cap.capabilities & V4L2_CAP_STREAMING)) { printf("The Current device does not support streaming i/o\n"); exit(EXIT_FAILURE); } printf("\ncamera driver name is : %s\n",cap.driver); printf("camera device name is : %s\n",cap.card); printf("camera bus information: %s\n",cap.bus_info); /*display the format device support*/ while(ioctl(fd,VIDIOC_ENUM_FMT,&fmtdesc)!=-1) { printf("\nsupport device %d.%s\n\n",fmtdesc.index+1,fmtdesc.description); fmtdesc.index++; } /*set the form of camera capture data*/ tv_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; /*v4l2_buf_typea,camera must use V4L2_BUF_TYPE_VIDEO_CAPTURE*/ tv_fmt.fmt.pix.width = 680; tv_fmt.fmt.pix.height = 480; tv_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG; /*V4L2_PIX_FMT_YYUV*/ tv_fmt.fmt.pix.field = V4L2_FIELD_NONE; /*V4L2_FIELD_NONE V4L2_FIELD_INTERLACED */ if (ioctl(fd, VIDIOC_S_FMT, &tv_fmt)< 0) { fprintf(stderr,"VIDIOC_S_FMT set err\n"); exit(-1); close(fd); } init_mmap(fd); } int start_capture(int fd) { unsigned int i; enum v4l2_buf_type type; /*place the kernel cache to a queue*/ for(i = 0; i < n_buffer; i++) { struct v4l2_buffer buf; memset(&buf, 0, sizeof(buf)); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = i; if(-1 == ioctl(fd, VIDIOC_QBUF, &buf)) { perror("Fail to ioctl 'VIDIOC_QBUF'"); exit(EXIT_FAILURE); } } type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if(-1 == ioctl(fd, VIDIOC_STREAMON, &type)) { printf("i=%d.\n", i); perror("VIDIOC_STREAMON"); close(fd); exit(EXIT_FAILURE); } return 0; } int process_image(void *addr, int length) { FILE *fp; static int num = 0; char image_name[20]; sprintf(image_name, JPG, num++); if((fp = fopen(image_name, "w")) == NULL) { perror("Fail to fopen"); exit(EXIT_FAILURE); } fwrite(addr, WIDTH*HIGHT*2 , 1, fp); usleep(500); fclose(fp); return 0; } int read_frame(int fd) { struct v4l2_buffer buf; unsigned int i; int k = WIDTH; int j = HIGHT; memset(&buf, 0, sizeof(struct v4l2_buffer)); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; if(-1 == ioctl(fd, VIDIOC_DQBUF,&buf)) { perror("Fail to ioctl 'VIDIOC_DQBUF'"); exit(EXIT_FAILURE); } assert(buf.index < n_buffer); memcpy(mjpeg_buff,usr_buf[buf.index].start,usr_buf[buf.index].length); jpeg_decode(&yuyv_buff, mjpeg_buff, &k, &j); process_image(yuyv_buff, WIDTH * HIGHT*2); if(-1 == ioctl(fd, VIDIOC_QBUF,&buf)) { perror("Fail to ioctl 'VIDIOC_QBUF'"); exit(EXIT_FAILURE); } return 1; } int mainloop(int fd) { int count = 20; while(count-- > 0) { for(;;) { fd_set fds; struct timeval tv; int r; FD_ZERO(&fds); FD_SET(fd,&fds); /*Timeout*/ tv.tv_sec = 0; tv.tv_usec = ; r = select(fd + 1,&fds,NULL,NULL,&tv); if(-1 == r) { if(EINTR == errno) continue; perror("Fail to select"); exit(EXIT_FAILURE); } if(0 == r) { fprintf(stderr,"select Timeout\n"); exit(-1); } if(read_frame(fd)) { break; } } } return 0; } void stop_capture(int fd) { enum v4l2_buf_type type; type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if(-1 == ioctl(fd,VIDIOC_STREAMOFF,&type)) { perror("Fail to ioctl 'VIDIOC_STREAMOFF'"); exit(EXIT_FAILURE); } } void close_camera_device(int fd) { unsigned int i; for(i = 0;i < n_buffer; i++) { if(-1 == munmap(usr_buf[i].start,usr_buf[i].length)) { exit(-1); } } free(usr_buf); if(-1 == close(fd)) { perror("Fail to close fd"); exit(EXIT_FAILURE); } } void main(void) { int fd; float ret = 0; fd = open_camera(); init_mjpeg_encode(); init_camera(fd); start_capture(fd); ret = get_main_time(&time , 1); mainloop(fd); ret = get_main_time(&time , 1); printf("encode spend time = %f\n",ret); stop_capture(fd); release_mjpeg(); close_camera_device(fd); }
编译执行:
root@ubuntu:/home/share/v4l2MJPEG2YUV422# make clean rm -f *.o a.out test core *~ *.avi ./out/* root@ubuntu:/home/share/v4l2MJPEG2YUV422# make gcc -c -o main.o main.c gcc -c -o color.o color.c gcc -c -o utils.o utils.c gcc -o test main.o color.o utils.o root@ubuntu:/home/share/v4l2MJPEG2YUV422# ./test camera driver name is : gspca_zc3xx camera device name is : PC Camera camera bus information: usb-0000:02:00.0-2.1 support device 1.JPEG n_buffer = 4 encode spend time = 1. root@ubuntu:/home/share/v4l2MJPEG2YUV422# ls ./out/ image0 image10 image12 image14 image16 image18 image2 image4 image6 image8 image1 image11 image13 image15 image17 image19 image3 image5 image7 image9 root@ubuntu:/home/share/v4l2MJPEG2YUV422# root@ubuntu:/home/share/v4l2MJPEG2YUV422#
可以看到已经采集了20张图片,该图片已经由JPEG装换为YUYV格式数据,它属于YUV422格式。使用pYUV 工具查看图片的时候,需要按下面的参数配置:
转换后的图片如下:
上面图片颜色偏绿,这个应该是我摄像头的问题,摄像头刚开始启动的几秒时间颜色都偏绿,后面就恢复正常。
完整的工程代码可以在这里下载:JPEG数据格式转YUV数据格式
今天的文章 JPEG数据转YUV数据应用实例分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/bian-cheng-ji-chu/102380.html