做qt摄像头程序的时候发现yuv转rgb然后显示 效果很不好 所以考虑转jpg后显示 但是使用libjpeg发现格式怎么设置都不对 之前在android上使用的函数拿过来都不能直接使用 所以还是研究硬编吧 这里使用的是广州斯道ICOOL210开发板 内核版本linux2.6.35
前面的一些流程我就不上代码了标准的v4l2流程 格式设置为V4L2_PIX_FMT_YUYV即yuv422格式 宽 640 高 480 主要是在获取到yuv数据后转成jpg然后保存 摄像头的程序网上有大把的例子 我这里比较乱我只放增加的函数了
首先把内核里的s3c-jpeg.h拷贝过来 这里是我的头文件
/* * v4l2.h * Author: hclydao */ #ifndef V4L2_H_ #define V4L2_H_ #include "s3c-jpeg.h" #define CLEAR(x) memset (&(x), 0, sizeof (x)) void errno_exit(const char* s); int xioctl(int fd, int request, void* argp); void deviceOpen(void); int select_input(int input); void deviceInit(void); void mmapInit(void); void captureStart(void); void mainLoop(void); unsigned char* frameRead(void); void imageProcess(const void* p); static void deviceUninit(void); static int jfd; unsigned char *ydata; static int name = 0; struct jpg_args mArgs; unsigned char *pInBuf; int jpeg_init(void); int test; int jpg_enc(const void *p,int len); #endif /* V4L2_H_ */</span>
我还是上代码吧 前面的这些流程完全都是标准的 网上的说明很详细 这里就不说明了
<span style="font-size:14px;">/* * v4l2.c * Author: hclydao */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include <getopt.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <malloc.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/time.h> #include <sys/mman.h> #include <sys/ioctl.h> #include <asm/types.h> #include <linux/videodev2.h> #include <jpeglib.h> #include <linux/fb.h> #include "v4l2.h" struct buffer { void * start; size_t length; }; int fd = -1; struct buffer * buffers = NULL; static unsigned int n_buffers = 0; // global settings static unsigned int width = 640; static unsigned int height = 480; static char* deviceName = "/dev/video0"; static char* jpgdev = "/dev/s3c-jpg"; static int fb_bpp; static int cam_fp = -1; static int fb_fp = -1; static char *fb_addr = NULL; void deviceOpen(void) { struct stat st; // stat file if (-1 == stat(deviceName, &st)) { fprintf(stderr, "Cannot identify '%s': %d, %s\n", deviceName, errno, strerror (errno)); exit(EXIT_FAILURE); } // check if its device if (!S_ISCHR (st.st_mode)) { fprintf(stderr, "%s is no device\n", deviceName); exit(EXIT_FAILURE); } // open device fd = open(deviceName, O_RDWR /* required */ | O_NONBLOCK, 0); // check if opening was successfull if (-1 == fd) { fprintf(stderr, "Cannot open '%s': %d, %s\n", deviceName, errno, strerror (errno)); exit(EXIT_FAILURE); } } int select_input(int input) { int ret; ret = xioctl(fd, VIDIOC_S_INPUT, &input); if (ret) { printf("xioctl VIDIOC_S_INPUT failed errno(%d)\n", errno); } return ret; } /** initialize device */ void deviceInit(void) { struct v4l2_capability cap; struct v4l2_format fmt; unsigned int min; if (-1 == xioctl(fd, VIDIOC_QUERYCAP, &cap)) { if (EINVAL == errno) { fprintf(stderr, "%s is no V4L2 device\n",deviceName); exit(EXIT_FAILURE); } else { errno_exit("VIDIOC_QUERYCAP"); } } if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { fprintf(stderr, "%s is no video capture device\n",deviceName); exit(EXIT_FAILURE); } if (!(cap.capabilities & V4L2_CAP_STREAMING)) { fprintf(stderr, "%s does not support streaming i/o\n",deviceName); exit(EXIT_FAILURE); } CLEAR (fmt); // v4l2_format fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.fmt.pix.width = width; fmt.fmt.pix.height = height; fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;//V4L2_PIX_FMT_RGB32; fmt.fmt.pix.field = V4L2_FIELD_NONE;//V4L2_FIELD_INTERLACED;//V4L2_FIELD_NONE; fmt.fmt.pix.priv = 1; if (-1 == xioctl(fd, VIDIOC_S_FMT, &fmt)) errno_exit("VIDIOC_S_FMT"); /* Note VIDIOC_S_FMT may change width and height. */ if (width != fmt.fmt.pix.width) { width = fmt.fmt.pix.width; fprintf(stderr,"Image width set to %i by device %s.\n",width,deviceName); } if (height != fmt.fmt.pix.height) { height = fmt.fmt.pix.height; fprintf(stderr,"Image height set to %i by device %s.\n",height,deviceName); } /* Buggy driver paranoia. */ min = fmt.fmt.pix.width * 2; if (fmt.fmt.pix.bytesperline < min) fmt.fmt.pix.bytesperline = min; min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height; if (fmt.fmt.pix.sizeimage < min) fmt.fmt.pix.sizeimage = min; mmapInit(); } void mmapInit(void) { struct v4l2_requestbuffers req; CLEAR (req); req.count = 4; req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_MMAP; if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) { if (EINVAL == errno) { fprintf(stderr, "%s does not support memory mapping\n", deviceName); exit(EXIT_FAILURE); } else { errno_exit("VIDIOC_REQBUFS"); } } if (req.count < 2) { fprintf(stderr, "Insufficient buffer memory on %s\n", deviceName); exit(EXIT_FAILURE); } buffers = calloc(req.count, sizeof(*buffers)); if (!buffers) { fprintf(stderr, "Out of memory\n"); exit(EXIT_FAILURE); } for (n_buffers = 0; n_buffers < req.count; ++n_buffers) { struct v4l2_buffer buf; CLEAR (buf); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = n_buffers; if (-1 == xioctl(fd, VIDIOC_QUERYBUF, &buf)) errno_exit("VIDIOC_QUERYBUF"); buffers[n_buffers].length = buf.length; buffers[n_buffers].start = mmap (NULL /* start anywhere */, buf.length, PROT_READ | PROT_WRITE /* required */, MAP_SHARED /* recommended */, fd, buf.m.offset); if (MAP_FAILED == buffers[n_buffers].start) errno_exit("mmap"); } } void captureStart(void) { unsigned int i; enum v4l2_buf_type type; for (i = 0; i < n_buffers; ++i) { struct v4l2_buffer buf; CLEAR (buf); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = i; if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) errno_exit("VIDIOC_QBUF"); } type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (-1 == xioctl(fd, VIDIOC_STREAMON, &type)) errno_exit("VIDIOC_STREAMON"); } void mainLoop(void) { unsigned int count; count = 1; while (count-- > 0) { for (;;) { fd_set fds; struct timeval tv; int r; FD_ZERO(&fds); FD_SET(fd, &fds); /* Timeout. */ tv.tv_sec = 2; tv.tv_usec = 0; r = select(fd + 1, &fds, NULL, NULL, &tv); if (-1 == r) { if (EINTR == errno) continue; errno_exit("select"); } if (0 == r) { fprintf (stderr, "select timeout\n"); exit(EXIT_FAILURE); } if (frameRead()) break; } } } unsigned char* frameRead(void) { struct v4l2_buffer buf; CLEAR (buf); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) { switch (errno) { case EAGAIN: return 0; case EIO: default: errno_exit("VIDIOC_DQBUF"); } } assert (buf.index < n_buffers); //imageProcess(buffers[buf.index].start); if(test > 44)//放弃前面的数据 jpg_enc(buffers[buf.index].start,buffers[buf.index].length); if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) errno_exit("VIDIOC_QBUF"); return (unsigned char*)buffers[buf.index].start; } void imageProcess(const void* p) { unsigned char* src = (unsigned char*)p; memcpy(&fb_addr[0],src,width*height*4); } void deviceUninit(void) { unsigned int i; for (i = 0; i < n_buffers; ++i) { if (-1 == munmap (buffers[i].start, buffers[i].length)) errno_exit("munmap"); } free(buffers); } void errno_exit(const char* s) { fprintf(stderr, "%s error %d, %s\n", s, errno, strerror (errno)); exit(EXIT_FAILURE); } int xioctl(int fd, int request, void* argp) { int r; do r = ioctl(fd, request, argp); while (-1 == r && EINTR == errno); return r; } int jpg_enc(const void *p,int len)//编码函数 { FILE *fp; char tmp[20]; int err; enum jpg_return_status ret = JPG_FAIL; unsigned char* src = (unsigned char*)p; memcpy(pInBuf, src, len); ret = (enum jpg_return_status)ioctl(jfd, IOCTL_JPG_ENCODE, &mArgs); if (ret != JPG_SUCCESS) { printf("++++++++IOCTL_JPG_ENCODE failed\n"); return -1; } mArgs.out_buf = (char *)ioctl(jfd, IOCTL_JPG_GET_STRBUF, mArgs.mapped_addr); sprintf(tmp, "%d.jpg", name++); fp = fopen(tmp,"wb"); if(fp < 0) { printf("+++++++++++=open file %s failed\n",tmp); return -1; } err = fwrite(mArgs.out_buf,sizeof(char),mArgs.enc_param->file_size,fp); if(err < 0) { printf("+++++++++++=write data failed\n"); return -1; } fclose(fp); return mArgs.enc_param->file_size; } int jpeg_init(void)//jpg初始化 { jfd = open(jpgdev,O_RDWR); if(jfd < 0) { printf("++++open jfd failed\n"); return -1; } mArgs.mapped_addr = mmap(0,640*480*4,PROT_READ | PROT_WRITE,MAP_SHARED, jfd, 0); if(mArgs.mapped_addr == MAP_FAILED) { printf("++++addr_base mmap failed\n"); return -1; } mArgs.enc_param = (struct jpg_enc_proc_param *)malloc(sizeof(struct jpg_enc_proc_param)); if(mArgs.enc_param == NULL) { printf("++++enc_param malloc failed\n"); return -1; } memset(mArgs.enc_param,0,sizeof(struct jpg_enc_proc_param)); mArgs.enc_param->sample_mode = JPG_422; mArgs.enc_param->enc_type = JPG_MAIN; mArgs.enc_param->in_format = JPG_MODESEL_YCBCR; mArgs.enc_param->quality = JPG_QUALITY_LEVEL_1; mArgs.enc_param->width = 640; mArgs.enc_param->height = 480; pInBuf = (unsigned char *)ioctl(jfd, IOCTL_JPG_GET_FRMBUF, mArgs.mapped_addr); if (pInBuf == NULL) { printf("+++++++=JPEG input buffer is NULL!!\n"); return -1; } }下面是主函数
/* * main.c * * Created on: Aug 4, 2011 * Author: gavin */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include <getopt.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <malloc.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/time.h> #include <sys/mman.h> #include <sys/ioctl.h> #include <asm/types.h> #include <linux/videodev2.h> #include <jpeglib.h> #include <linux/fb.h> #include "v4l2.h" int main() { jpeg_init(); deviceOpen(); select_input(0); deviceInit(); captureStart(); for(test=0;test<50;test++) { mainLoop(); } return 1; }不要前面的一些帧 前面的有可能会是全绿的 以下是效果图
测试完成开始修改qt工程
工程下载地址:http://download.csdn.net/detail/hclydao/8217081
============================================
作者:hclydao
http://blog.csdn.net/hclydao
版权没有,但是转载请保留此段声明
============================================