然后就是申请缓存空间、内存块映射等工作了,使用到的方法有malloc、ioctl、mmap等:
int V4l2_Grab()
{
unsigned int n_buffers;
buffers =(buffer*)malloc(req.count*sizeof (*buffers));
if (!buffers)
{
printf ("Out of memory
");
return 0;
}
for (n_buffers = 0; n_buffers < req.count; n_buffers++)
{
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = n_buffers;
//query buffers
if (ioctl (fd_video,VIDIOC_QUERYBUF, &buf) == -1)
{
printf("query buffer error
");
return(0);
}
buffers[n_buffers].length = buf.length;
buffers[n_buffers].start = mmap(NULL,buf.length,PROT_READ |PROT_WRITE, MAP_SHARED,
fd_video, buf.m.offset);
if (buffers[n_buffers].start == MAP_FAILED)
{
printf("buffer map error
");
return 0;
}
}
for (n_buffers = 0; n_buffers < req.count; n_buffers++)
{
buf.index = n_buffers;
ioctl(fd_video, VIDIOC_QBUF, &buf);
}
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ioctl (fd_video, VIDIOC_STREAMON, &type);
ioctl(fd_video, VIDIOC_DQBUF, &buf);
printf("grab yuyv OK
");
return 1;
}
再做YUYV42转RGB888的算法代码,以实现将摄像头采集到的数据显示到Frame上面:
int Yuyv_2_RGB888(buffer* input_buffers,unsigned char *output_buffer)
{
int i,j,r1,g1,b1,r2,g2,b2;
unsigned char y1,y2,u,v;
unsigned char *pointer;
pointer =(unsigned char*)input_buffers[0].start;
for(i=0;i
{
for(j=0;j
//每次取4个字节,也就是两个像素点,转换rgb,6个字节,还是两个像素点
{
y1 = *( pointer + (i*IMAGEWIDTH/2+j)*4);
u = *( pointer + (i*IMAGEWIDTH/2+j)*4 + 1);
y2 = *( pointer + (i*IMAGEWIDTH/2+j)*4 + 2);
v = *( pointer + (i*IMAGEWIDTH/2+j)*4 + 3);
r1 = y1 + 1.042*(v-128);
g1 = y1 - 0.34414*(u-128) - 0.71414*(v-128);
b1 = y1 + 1.772*(u-128);
r2 = y2 + 1.042*(v-128);
g2 = y2 - 0.34414*(u-128) - 0.71414*(v-128);
b2 = y2 + 1.772*(u-128);
if(r1>255)
r1 = 255;
else if(r1<0)
r1 = 0;
if(b1>255)
b1 = 255;
else if(b1<0)
b1 = 0;
if(g1>255)
g1 = 255;
else if(g1<0)
g1 = 0;
if(r2>255)
r2 = 255;
else if(r2<0)
r2 = 0;
if(b2>255)
b2 = 255;
else if(b2<0)
b2 = 0;
if(g2>255)
g2 = 255;
else if(g2<0)
g2 = 0;
*(output_buffer + (i*IMAGEWIDTH/2+j)*6 ) = (unsigned char)b1;
*(output_buffer + (i*IMAGEWIDTH/2+j)*6 + 1) = (unsigned char)g1;
*(output_buffer + (i*IMAGEWIDTH/2+j)*6 + 2) = (unsigned char)r1;
*(output_buffer + (i*IMAGEWIDTH/2+j)*6 + 3) = (unsigned char)b2;
*(output_buffer + (i*IMAGEWIDTH/2+j)*6 + 4) = (unsigned char)g2;
*(output_buffer + (i*IMAGEWIDTH/2+j)*6 + 5) = (unsigned char)r2;
}
}
printf("change to RGB OK
");
free(input_buffers);
}
做好了之后,有个unsigned char *类型的指针,这个指针指向的用户内存就是存放摄像头数据的缓存了,我们既可以直接输出到FrameBuffer上面:
int LCD_Show_Buffer(char *dev_name,int width,int height,unsigned char *frame_buffer)
{
int fd_lcd,i,j;
fd_lcd=open(dev_name,O_RDWR);
if(fd_lcd==-1)
{
printf("open LCD failed!
");
return -1;
}
for(i=0;i
{
for(j=0;j
if(i<=height&&j<=width)
{
lcd_buf[i*LCD_WIDTH+j]=
frame_buffer[(i*width+j)*3]|
frame_buffer[(i*width+j)*3+1]<<8|
frame_buffer[(i*width+j)*3+2]<<16;
}
else lcd_buf[i*LCD_WIDTH+j]=0;
}
write(fd_lcd,lcd_buf,LCD_WIDTH*LCD_HEIGHT*4);
close(fd_lcd);
}
也可以保存为JPG文件:
int Encode_Jpeg(char *lpbuf,int width,int height,char *output_filename)
{
struct jpeg_compress_struct cinfo ;
struct jpeg_error_mgr jerr ;
JSAMPROW row_pointer[1] ;
int row_stride ;
char *buf=NULL ;
int x ;
FILE *fptr_jpg = fopen (output_filename,"wb");//注意这里为什么用fopen而不用open
if(fptr_jpg==NULL)
{
printf("Encoder:open file failed!/n") ;
return 0;
}
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
jpeg_stdio_dest(&cinfo, fptr_jpg);
cinfo.image_width = width;
cinfo.image_height = height;
cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB;
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, 80,1);
jpeg_start_compress(&cinfo, 1);
row_stride = width * 3;
buf=(char*)malloc(row_stride);
row_pointer[0] =(unsigned char*)buf;
while (cinfo.next_scanline < height)
{
for (x=0;x
{
buf[x] = lpbuf[x];
buf[x+1] = lpbuf[x+1];
buf[x+2] = lpbuf[x+2];
}
jpeg_write_scanlines (&cinfo, row_pointer, 1);
lpbuf += row_stride;
}
jpeg_finish_compress(&cinfo);
fclose(fptr_jpg);
jpeg_destroy_compress(&cinfo);
free(buf);
printf("save "JPEG"OK
");
return 0 ;
}
int close_v4l2(void)
{
if(fd_video!=-1)
{
close(fd_video);
return 1;
}
return 0;
}
使用成本低廉像素极渣的UVC摄像头采集一下我简陋但舒服的小房间(PS:等我发工资了,我一定要买一个高清顺畅2000W像素柔光360度拍摄照亮你的美的UVC摄像头):
然后是使用JPG采集即拍照:
`