|
/*************************************
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);
}
这是我修改的天嵌的代码,但触摸屏却显示花屏不能显示图像,求高手指点啊! |
|