#include <stdio.h> #include <stdlib.h> #include <unistd.h>
#include <linux/videodev.h> #include <sys/ioctl.h>
#include <fcntl.h> #include <linux/fb.h> #include <sys/mman.h> #include <linux/delay.h> #include <time.h>
#define ERR_FRAME_BUFFER 1 #define ERR_VIDEO_OPEN 2 #define ERR_VIDEO_GCAP 3 #define ERR_VIDEO_GPIC 4 #define ERR_VIDEO_SPIC 5 #define ERR_SYNC 6 #define ERR_FRAME_USING 7 #define ERR_GET_FRAME 8
typedef struct _fb_v4l { int fbfd ; struct fb_var_screeninfo vinfo; struct fb_fix_screeninfo finfo; char *fbp; int fd; struct video_capability capability; struct video_buffer buffer; struct video_window window; struct video_channel channel[8]; struct video_picture picture; struct video_tuner tuner; struct video_audio audio[8]; struct video_mmap mmap; struct video_mbuf mbuf; unsigned char *map; int frame_current; int frame_using[VIDEO_MAX_FRAME]; }fb_v41;
struct file_header { unsigned short bfType; // Picture tpye, must set to 19778
int bfSize; // The file size in bytes
int bfRev; // Reserved
int bfOffBits; // the offset from the beginning of the file to the bitmap data.
}__attribute__ ((packed));
struct info_header { int biSize; // info_header's size in bytes
int biWidth; // width in pixels
int biHeight;//height in pixels
short biPlanes; //the number of planes of the target device
short biBitCount; //the number of bits per pixel
int biCompression;//the type of compression
int biSizeImage; //
int biXPelsPerMeter;//usually set to zero
int biYPelsPerMeter;//usually set to zero
int biClrUsed;//the number of colors used in the bitmap
int biClrImportant; }__attribute__ ((packed));
struct bmp_file { struct file_header header; struct info_header info; unsigned char bits[640*480*3]; }__attribute__ ((packed));
#define V4L_FILE "/dev/video0"
int get_grab_frame(fb_v41 *vd, int frame) { if (vd->frame_using[frame]) { fprintf(stderr, "get_grab_frame: frame %d is already used.\n", frame); return ERR_FRAME_USING; }
vd->mmap.frame = frame; if (ioctl(vd->fd, VIDIOCMCAPTURE, &(vd->mmap)) < 0) { perror("v4l_grab_frame"); return ERR_GET_FRAME; } vd->frame_using[frame] = 1; vd->frame_current = frame; return 0; }
int get_first_frame(fb_v41 *vd) { int ret; vd->frame_current = 0; ret = get_grab_frame( vd, 0 ); if ( ret<0 ) return ret;
if (ioctl(vd->fd, VIDIOCSYNC, &(vd->frame_current)) < 0) { perror("v4l_grab_sync"); return ERR_SYNC; } vd->frame_using[vd->frame_current] = 0 ; return (0); }
int get_next_frame(fb_v41 *vd) { int ret;
vd->frame_current ^= 1; ret = get_grab_frame( vd,vd->frame_current); if( ret < 0 ) return ret; if (ioctl(vd->fd, VIDIOCSYNC, &(vd->frame_current)) < 0) { perror("v4l_grab_sync"); return ERR_SYNC; } vd->frame_using[vd->frame_current] = 0 ; return 0; }
unsigned char *get_frame_address(fb_v41 *vd) { return (vd->map + vd->mbuf.offsets[vd->frame_current]); }
int open_video( char *fileptr,fb_v41 *vd ,int dep,int pal,int width,int height) { if ((vd->fd = open(fileptr, O_RDWR)) < 0) { perror("v4l_open:"); return ERR_VIDEO_OPEN; }
if (ioctl(vd->fd, VIDIOCGCAP, &(vd->capability)) < 0) { perror("v4l_get_capability:"); return ERR_VIDEO_GCAP; } if (ioctl(vd->fd, VIDIOCGPICT, &(vd->picture)) < 0) { perror("v4l_get_picture"); return ERR_VIDEO_GPIC; }
vd->picture.palette = pal; vd->picture.depth = dep;
vd->mmap.format = pal; if (ioctl(vd->fd, VIDIOCSPICT, &(vd->picture)) < 0) { perror("v4l_set_palette"); return ERR_VIDEO_SPIC; } vd->mmap.width = width; vd->mmap.height = height; vd->mmap.format = vd->picture.palette; vd->frame_current = 0; vd->frame_using[0] = 0; vd->frame_using[1] = 0; if (ioctl(vd->fd, VIDIOCGMBUF, &(vd->mbuf)) < 0) { perror("v4l_get_mbuf"); return -1; }
vd->map = mmap(0, vd->mbuf.size, PROT_READ|PROT_WRITE, MAP_SHARED, vd->fd, 0); if ( vd->map < 0) { perror("v4l_mmap_init:mmap"); return -1; }
printf("The video device was opened successfully.\n"); return 0; }
static void cvt_420p_to_rgb(int width, int height, const unsigned char *src, unsigned char *dst) { int r, g, b; int rdif, gdif, bdif, y; int yy, uu, vv; int xoff, yoff; int numpix = width*height; unsigned char *pout = dst + width*height*3;
for(yoff=0; yoff<height; yoff++) { for(xoff=0; xoff<width; xoff++) { yy = *(src+yoff*640+xoff); uu = *(src+(yoff/2)*320+xoff/2+numpix); vv = *(src+(yoff/2)*320+xoff/2+numpix+numpix/4);
uu -= 128; vv -= 128;
r = yy + vv + ((vv*103)>>8); g = yy - ((uu*88)>>8) - ((vv*183)>>8); b = yy + uu + ((uu*198)>>8);
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;}
*pout = (unsigned char)b; pout--; *pout = (unsigned char)r; pout--; *pout = (unsigned char)g; pout--; } } }
int main( void ) { fb_v41 vd; int ret,i; int k=0; unsigned char *imageptr; struct bmp_file myfile; int fd;
printf("sizeof short is %d\n", sizeof(short));
myfile.header.bfType = 19778; myfile.header.bfSize = sizeof(struct bmp_file); myfile.header.bfRev = 0; myfile.header.bfOffBits = 54;
myfile.info.biSize = 0x28; myfile.info.biWidth = 640; myfile.info.biHeight = 480; myfile.info.biPlanes = 1; myfile.info.biBitCount = 24; myfile.info.biCompression = 0; myfile.info.biSizeImage = 0; myfile.info.biClrUsed = 256*256*256; myfile.info.biClrImportant = 0; myfile.info.biXPelsPerMeter = 2048; myfile.info.biYPelsPerMeter = 2048;
fd = open("./first.bmp", O_RDWR); if(fd < 0) { printf("open file error!\n"); return 0; } ret = open_video( V4L_FILE, &vd, 24, VIDEO_PALETTE_YUV420P, 640, 480); if( ret ) { printf("Open video failed!\n"); goto err; } printf(vd.capability.name); printf(", Type:%d\n",vd.capability.type); printf("Maxwidth:%d,Maxheight:%d\n",vd.capability.maxwidth ,vd.capability.maxheight); printf("Minwidth:%d,Minheight:%d\n",vd.capability.minwidth,vd.capability.minheight); printf("Channels:%d,Audios:%d\n",vd.capability.channels,vd.capability.audios); for(i=0;i<10;i++) { imageptr = (unsigned char *)get_frame_address(&vd );
if(get_next_frame( &vd ) !=0 ) { goto err; }
printf("i = %d\n", i); }
cvt_420p_to_rgb(640, 480, imageptr, myfile.bits);
write(fd, &myfile, sizeof(struct bmp_file)); err: if(vd.fbfd) close(vd.fbfd); if(vd.fd) close(vd.fd);
exit(0);
return 0; }
|