|  | 
| /************************************* 
 NAME:usb_camera.c
 COPYRIGHT:www.embedsky.net
 
 *************************************/
 
 #include <errno.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <sys/ioctl.h>
 #include <unistd.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <asm/types.h>
 #include <linux/videodev2.h>
 #include <sys/mman.h>
 #include <string.h>
 #include <malloc.h>
 #include <linux/fb.h>
 #include <jpeglib.h>
 #include <jerror.h>
 
 typedef struct VideoBuffer
 {
 unsigned char *start;
 size_t offset;
 size_t length;
 } VideoBuffer;
 
 struct fb_dev
 {
 //for frame buffer
 int fb;
 void *fb_mem;        //frame buffer mmap
 int fb_width, fb_height, fb_line_len, fb_size;
 int fb_bpp;
 } fbdev;
 
 //得到framebuffer的长、宽和位宽,成功则返回0,失败返回-1
 int fb_stat(int fd)
 {
 struct fb_fix_screeninfo fb_finfo;
 struct fb_var_screeninfo fb_vinfo;
 
 if (ioctl(fd, FBIOGET_FSCREENINFO, &fb_finfo))
 {
 perror(__func__);
 return (-1);
 }
 
 if (ioctl(fd, FBIOGET_VSCREENINFO, &fb_vinfo))
 {
 perror(__func__);
 return (-1);
 }
 
 fbdev.fb_width = fb_vinfo.xres;
 fbdev.fb_height = fb_vinfo.yres;
 fbdev.fb_bpp = fb_vinfo.bits_per_pixel;
 fbdev.fb_line_len = fb_finfo.line_length;
 fbdev.fb_size = fb_finfo.smem_len;
 
 return (0);
 }
 
 int convert_yuv_to_rgb_pixel(int y, int u, int v)
 {
 unsigned int pixel32 = 0;
 unsigned char *pixel = (unsigned char *) &pixel32;
 int r, g, b;
 r = y + (1.370705 * (v - 128));
 g = y - (0.698001 * (v - 128)) - (0.337633 * (u - 128));
 b = y + (1.732446 * (u - 128));
 if (r > 255)
 r = 255;
 if (g > 255)
 g = 255;
 if (b > 255)
 b = 255;
 if (r < 0)
 r = 0;
 if (g < 0)
 g = 0;
 if (b < 0)
 b = 0;
 pixel[0] = r * 220 / 256;
 pixel[1] = g * 220 / 256;
 pixel[2] = b * 220 / 256;
 return pixel32;
 }
 int YUYVToRGB(unsigned char *yuv, unsigned char *rgb, unsigned int width,
 unsigned int height)
 {
 unsigned int in, out = 0;
 unsigned int pixel_16;
 unsigned char pixel_24[3];
 unsigned int pixel32;
 int y0, u, y1, v;
 for (in = 0; in < width * height * 2; in += 4)
 {
 pixel_16 = yuv[in + 3] << 24 | yuv[in + 2] << 16 | yuv[in + 1] << 8
 | yuv[in + 0];
 y0 = (pixel_16 & 0x000000ff);
 u = (pixel_16 & 0x0000ff00) >> 8;
 y1 = (pixel_16 & 0x00ff0000) >> 16;
 v = (pixel_16 & 0xff000000) >> 24;
 pixel32 = convert_yuv_to_rgb_pixel(y0, u, v);
 pixel_24[0] = ((pixel32 & 0x000000ff)>>3)&0x1f;      //r
 pixel_24[1] = (((pixel32 & 0x0000ff00) >> 8)>>2)&0x1f;  //g
 pixel_24[2] = (((pixel32 & 0x00ff0000) >> 16)>>3)&0x1f;  //b
 rgb[out++] = pixel_24[0];
 rgb[out++] = pixel_24[1];
 rgb[out++] = pixel_24[2];
 pixel32 = convert_yuv_to_rgb_pixel(y1, u, v);
 pixel_24[0] = ((pixel32 & 0x000000ff)>>3)&0xif;      //r
 pixel_24[1] = (((pixel32 & 0x0000ff00) >> 8)>>2)&0x1f;  //g
 pixel_24[2] = (((pixel32 & 0x00ff0000) >> 16)>>3)&0x1f;  //b
 rgb[out++] = pixel_24[0];
 rgb[out++] = pixel_24[1];
 rgb[out++] = pixel_24[2];
 }
 return 0;
 }
 
 
 
 int main(int argc, char** argv)
 {
 int numBufs;
 printf("USB Camera Test\n");
 
 int fd = open("/dev/video0", O_RDWR, 0);                        //打开摄像头设备,使用阻塞方式打开
 if (fd<0)
 {
 printf("open error\n");
 return  -1;
 }
 
 struct v4l2_format fmt;                                                //设置获取视频的格式
 memset( &fmt, 0, sizeof(fmt));
 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;                                //视频数据流类型,永远都是V4L2_BUF_TYPE_VIDEO_CAPTURE
 fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;                        //视频源的格式为JPEG或YUN4:2:2或RGB
 fmt.fmt.pix.width = 320;                                        //设置视频宽度
 fmt.fmt.pix.height = 240;                                        //设置视频高度
 if (ioctl(fd, VIDIOC_S_FMT, &fmt) < 0)                                //使配置生效
 {
 printf("set format failed\n");
 return -1;
 }
 
 struct v4l2_requestbuffers req;                                        //申请帧缓冲
 memset(&req, 0, sizeof (req));
 req.count = 1;                                                        //缓存数量,即可保存的图片数量
 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;                                //数据流类型,永远都是V4L2_BUF_TYPE_VIDEO_CAPTURE
 req.memory = V4L2_MEMORY_MMAP;                                        //存储类型:V4L2_MEMORY_MMAP或V4L2_MEMORY_USERPTR
 if (ioctl(fd, VIDIOC_REQBUFS, &req) == -1)                        //使配置生效
 {
 perror("request buffer error \n");
 return -1;
 }
 
 VideoBuffer *buffers = calloc(req.count, sizeof(VideoBuffer));        //将VIDIOC_REQBUFS获取内存转为物理空间
 //        printf("sizeof(VideoBuffer) is %d\n", sizeof(VideoBuffer));
 struct v4l2_buffer buf;
 for (numBufs = 0; numBufs < req.count; numBufs++)
 {
 memset( &buf, 0, sizeof(buf));
 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;                        //数据流类型,永远都是V4L2_BUF_TYPE_VIDEO_CAPTURE
 buf.memory = V4L2_MEMORY_MMAP;                                //存储类型:V4L2_MEMORY_MMAP(内存映射)或V4L2_MEMORY_USERPTR(用户指针)
 buf.index = numBufs;
 if (ioctl(fd, VIDIOC_QUERYBUF, &buf) < 0)                //使配置生效
 {
 printf("VIDIOC_QUERYBUF error\n");
 return -1;
 }
 //                printf("buf len is %d\n", sizeof(buf));
 buffers[numBufs].length = buf.length;
 buffers[numBufs].offset = (size_t) buf.m.offset;
 buffers[numBufs].start = mmap(NULL, buf.length, PROT_READ | PROT_WRITE,
 MAP_SHARED, fd, buf.m.offset);                        //使用mmap函数将申请的缓存地址转换应用程序的绝对地址
 
 if (buffers[numBufs].start == MAP_FAILED)
 {
 perror("buffers error\n");
 return -1;
 }
 if (ioctl(fd, VIDIOC_QBUF, &buf) < 0)                        //放入缓存队列
 {
 printf("VIDIOC_QBUF error\n");
 return -1;
 }
 
 }
 
 enum v4l2_buf_type type;                                        //开始视频显示
 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;                                //数据流类型,永远都是V4L2_BUF_TYPE_VIDEO_CAPTURE
 if (ioctl(fd, VIDIOC_STREAMON, &type) < 0)
 {
 printf("VIDIOC_STREAMON error\n");
 return -1;
 }
 
 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;                                //数据流类型,永远都是V4L2_BUF_TYPE_VIDEO_CAPTURE
 if (ioctl(fd, VIDIOC_G_FMT, &fmt) < 0)                                //读取视频源格式
 {
 printf("get format failed\n");
 return -1;
 }
 else
 {
 printf("Picture:Width = %d   Height = %d\n", fmt.fmt.pix.width, fmt.fmt.pix.height);
 //                printf("Image size = %d\n", fmt.fmt.pix.sizeimage);
 //                printf("pixelformat = %d\n", fmt.fmt.pix.pixelformat);
 }
 
 FILE * fd_y_file = 0;
 int a=0;
 int k = 0;
 
 //设置显卡设备framebuffer
 unsigned char *buffer;
 
 int fb;
 char *fb_device;
 unsigned int x;
 unsigned int y;
 
 if ((fb = open("/dev/fb0", O_RDWR)) < 0)                        //打开显卡设备
 {
 perror(__func__);
 return (-1);
 }
 
 //获取framebuffer的状态
 fb_stat(fb);                                                        //获取显卡驱动中的长、宽和显示位宽
 printf("frame buffer: %dx%d,  %dbpp, 0x%xbyte= %d\n",
 fbdev.fb_width, fbdev.fb_height, fbdev.fb_bpp, fbdev.fb_size, fbdev.fb_size);
 
 //映射framebuffer的地址
 fbdev.fb_mem = mmap (NULL, fbdev.fb_size, PROT_READ|PROT_WRITE,MAP_SHARED,fb,0);
 //映射显存地址
 fbdev.fb = fb;
 
 //预览采集到的图像
 while (1)
 {
 for (numBufs = 0; numBufs < req.count; numBufs++)
 {
 char s[15];
 sprintf(s, "%d.jpg", a);
 if ((fd_y_file = fopen(s, "wb")) < 0)
 {
 printf("Unable to create y frame recording file\n");
 return -1;
 }
 
 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;                //取得原始采集数据
 buf.memory = V4L2_MEMORY_MMAP;                        //存储类型:V4L2_MEMORY_MMAP(内存映射)或V4L2_MEMORY_USERPTR(用户指针)
 if (ioctl(fd, VIDIOC_DQBUF, &buf) < 0)
 {
 perror("VIDIOC_DQBUF failed.\n");
 return -1;
 }
 //buffer = (unsigned char *) malloc(320*240*3);
 unsigned char *ptcur = buffers[numBufs].start;                //开始霍夫曼解码
 YUYVToRGB(ptcur, fbdev.fb_mem, 320, 240);
 
 //获取下一帧视频数据
 if (ioctl(fd, VIDIOC_QBUF, &buf) < 0)
 {
 printf("VIDIOC_QBUF error\n");
 return -1;
 }
 }
 }
 fb_munmap(fbdev.fb_mem, fbdev.fb_size);                                        //释放framebuffer映射
 close(fb);                                                                //关闭Framebuffer设备
 
 close(fd);
 }
 这是我修改的天嵌的代码,但触摸屏却显示花屏不能显示图像,求高手指点啊!
 | 
 |