/** * Copyright (C) 2001 Billy Biggs . * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include "videoinput.h" struct videoinput_s { int foo; }; static int grab_fd; static int grab_size; static int numframes; static int have_mmap; static int width; static int height; /* Wouldn't it be nice if ... */ static int maxbufs = 16; static unsigned char *grab_data; static unsigned char *map; static struct video_mmap *grab_buf; static struct video_window grab_win; static struct video_audio audio; static int curframe = 0; static struct video_mbuf gb_buffers = { 2*0x151000, 0, {0,0x151000 }}; int videoinput_get_num_frames( videoinput_t *vidin ) { return numframes; } static int grab_next( void ) { int frame = curframe++ % numframes; if( ioctl( grab_fd, VIDIOCMCAPTURE, grab_buf + frame ) < 0 ) { perror( "VIDIOCMCAPTURE" ); } return frame; } static int grab_wait( void ) { int frame = curframe % numframes; if( ioctl( grab_fd, VIDIOCSYNC, grab_buf + frame ) < 0 ) { perror( "VIDIOCSYNC" ); } return frame; } unsigned char *videoinput_next_image( videoinput_t *vidin ) { int rc; for(;;) { if( have_mmap ) { return map + gb_buffers.offsets[ grab_wait() ]; } else { rc = read( grab_fd, grab_data, grab_size ); if( grab_size != rc ) { fprintf( stderr, "videoinput: grabber read error (rc=%d)\n", rc ); return NULL; } else { return grab_data; } } sleep( 1 ); } } void videoinput_free_last_frame( videoinput_t *vidin ) { grab_next(); } void videoinput_free_all_frames( videoinput_t *vidin ) { int i; for( i = 0; i < numframes; i++ ) grab_next(); } int videoinput_get_width( videoinput_t *vidin ) { return width; } int videoinput_get_height( videoinput_t *vidin ) { return height; } /** * Reasonable defaults: * * v4l_device : /dev/video0 * inputnum : 1 * max_buffers : 16 */ videoinput_t *videoinput_new( const char *v4l_device, int inputnum, int capwidth, int capheight, int palmode ) { videoinput_t *vidin = (videoinput_t *) malloc( sizeof( videoinput_t ) ); struct video_capability grab_cap; struct video_channel grab_chan; struct video_picture grab_pict; int i; if( !vidin ) return 0; width = capwidth; height = capheight; grab_fd = open( v4l_device, O_RDWR ); if( grab_fd < 0 ) { fprintf( stderr, "videoinput: Can't open %s: %s\n", v4l_device, strerror( errno ) ); free( vidin ); return 0; } if( ioctl( grab_fd, VIDIOCGCAP, &grab_cap ) < 0 ) { fprintf( stderr, "videoinput: No v4l device (%s).\n", v4l_device ); /* XXX */ return 0; } grab_chan.channel = inputnum; if( ioctl( grab_fd, VIDIOCGCHAN, &grab_chan ) < 0 ) { perror( "ioctl VIDIOCGCHAN" ); return 0; } grab_chan.channel = inputnum; grab_chan.norm = palmode ? VIDEO_MODE_PAL : VIDEO_MODE_NTSC; if( ioctl( grab_fd, VIDIOCSCHAN, &grab_chan ) < 0 ) { perror( "ioctl VIDIOCSCHAN" ); return 0; } if( ioctl( grab_fd, VIDIOCGMBUF, &gb_buffers ) < 0 ) { perror( "VIDIOCGMBUF" ); return 0; } if( ioctl( grab_fd, VIDIOCGAUDIO, &audio ) < 0 ) { perror( "VIDIOCGAUDIO" ); return 0; } audio.flags &= ~VIDEO_AUDIO_MUTE; if( ioctl( grab_fd, VIDIOCSAUDIO, &audio ) < 0 ) { perror( "VIDIOCGAUDIO" ); return 0; } if( ioctl( grab_fd, VIDIOCGPICT, &grab_pict ) < 0 ) { perror("ioctl VIDIOCGPICT"); return 0; } fprintf( stderr, "videoinput: brightness %d, hue %d, colour %d, contrast %d.\n", grab_pict.brightness, grab_pict.hue, grab_pict.colour, grab_pict.contrast ); /* grab_pict.brightness = 32000; grab_pict.colour = 32768; grab_pict.contrast = 23000; if( ioctl( grab_fd, VIDIOCSPICT, &grab_pict ) < 0 ) { perror( "ioctl VIDIOCSPICT" ); return 0; } */ //grab_pict.brightness = 32000; grab_pict.brightness = 32768; grab_pict.colour = 32768; grab_pict.contrast = 23155; //grab_pict.contrast = 32768; if( ioctl( grab_fd, VIDIOCSPICT, &grab_pict ) < 0 ) { perror( "ioctl VIDIOCSPICT" ); return 0; } numframes = gb_buffers.frames; if( maxbufs < numframes ) numframes = maxbufs; grab_buf = (struct video_mmap *) malloc( sizeof( struct video_mmap ) * numframes ); /* Try to setup mmap-based capture. */ for( i = 0; i < numframes; i++ ) { grab_buf[ i ].format = VIDEO_PALETTE_YUV422P; /* Y'CbCr 4:2:0 Planar */ grab_buf[ i ].frame = i; grab_buf[ i ].width = width; grab_buf[ i ].height = height; } map = (unsigned char *) mmap( 0, gb_buffers.size, PROT_READ|PROT_WRITE, MAP_SHARED, grab_fd, 0 ); if( (int) map != -1 ) { have_mmap = 1; //for( i = 0; i < numframes - 1; i++ ) { //grab_wait(); //} //for( i = 0; i < numframes - 2; i++ ) { //grab_next(); //} return vidin; } /* Fallback to read(). */ fprintf( stderr, "videoinput: No mmap support available, using read().\n" ); have_mmap = 0; /* grab_pict.depth = 12; grab_pict.palette = VIDEO_PALETTE_YUV420P; */ grab_pict.depth = 16; grab_pict.palette = VIDEO_PALETTE_YUV422P; if( ioctl( grab_fd, VIDIOCSPICT, &grab_pict ) < 0 ) { perror( "ioctl VIDIOCSPICT" ); return 0; } fprintf( stderr, "\n\nbright %d, hue %d, colour %d, contrast %d, whiteness %d\n\n", grab_pict.brightness, grab_pict.hue, grab_pict.colour, grab_pict.contrast, grab_pict.whiteness ); if( ioctl( grab_fd, VIDIOCGPICT, &grab_pict ) < 0 ) { perror("ioctl VIDIOCGPICT"); return 0; } memset( &grab_win, 0, sizeof( struct video_window ) ); grab_win.width = width; grab_win.height = height; if( ioctl( grab_fd, VIDIOCSWIN, &grab_win ) < 0 ) { perror( "ioctl VIDIOCSWIN" ); return 0; } if( ioctl( grab_fd, VIDIOCGWIN, &grab_win ) < 0 ) { perror( "ioctl VIDIOCGWIN" ); return 0; } grab_size = grab_win.width * grab_win.height * 3; grab_data = (unsigned char *) malloc( grab_size ); return vidin; } void videoinput_delete( videoinput_t *vidin ) { if( ioctl( grab_fd, VIDIOCGAUDIO, &audio ) < 0 ) { perror( "VIDIOCGAUDIO" ); return; } audio.flags |= VIDEO_AUDIO_MUTE; if( ioctl( grab_fd, VIDIOCSAUDIO, &audio ) < 0 ) { perror( "VIDIOCGAUDIO" ); return; } if( have_mmap ) { munmap( map, gb_buffers.size ); } close( grab_fd ); if( !have_mmap ) { free( grab_data ); } free( grab_buf ); free( vidin ); }