Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

v4l.cc

Go to the documentation of this file.
00001 /*
00002 * v4l.cc Video4Linux management
00003 * Copyright (C) 2001 Charles Yates <charles.yates@pandora.be>
00004 * Copyright (C) 2001-2007 Dan Dennedy <dan@dennedy.org>
00005 *
00006 * This program is free software; you can redistribute it and/or modify
00007 * it under the terms of the GNU General Public License as published by
00008 * the Free Software Foundation; either version 2 of the License, or
00009 * (at your option) any later version.
00010 *
00011 * This program is distributed in the hope that it will be useful,
00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 * GNU General Public License for more details.
00015 *
00016 * You should have received a copy of the GNU General Public License
00017 * along with this program; if not, write to the Free Software Foundation,
00018 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00019 */
00020 #ifdef HAVE_CONFIG_H
00021 #include <config.h>
00022 #endif
00023 
00024 #include <deque>
00025 #include <unistd.h>
00026 #include <string>
00027 #include <sstream>
00028 #include <iostream>
00029 #include <iomanip>
00030 
00031 using std::ostringstream;
00032 using std::setw;
00033 using std::setfill;
00034 
00035 #include <pthread.h>
00036 
00037 #include "v4l.h"
00038 #include "kino_av_pipe.h"
00039 #include "kino_common.h"
00040 #include "filehandler.h"
00041 
00042 extern "C"
00043 {
00044 #include "support.h"
00045 #include <sys/types.h>
00046 #include <sys/soundcard.h>
00047 #include <sys/time.h>
00048 #include <unistd.h>
00049 #include <fcntl.h>
00050 #include <sys/stat.h>
00051 #include <sys/ioctl.h>
00052 #include <sys/mman.h>
00053 
00054     pthread_t v4lthread;
00055 }
00056 
00057 static int ENCODE_YUV = 0;
00058 
00062 bool V4LDevice::request( int req, V4LStruct *v4l )
00063 {
00064     ENCODE_YUV = getenv( "KINO_V4L_FFMPEG" ) != NULL;
00065     return request( req, v4l->getStruct() );
00066 }
00067 
00071 bool V4LDevice::request( int req, void *addr )
00072 {
00073     return ioctl( getHandle(), req, addr ) != -1;
00074 }
00075 
00076 V4LCapability::V4LCapability( V4LDevice *device )
00077 {
00078     device->request( VIDIOCGCAP, this );
00079 }
00080 
00081 V4LCapability::~V4LCapability()
00082 {
00083     cout << "Closing Capability" << endl;
00084 }
00085 
00086 void *V4LCapability::getStruct()
00087 {
00088     return & capability;
00089 }
00090 
00091 char *V4LCapability::getName()
00092 {
00093     return capability.name;
00094 }
00095 
00096 int V4LCapability::getNumberOfChannels()
00097 {
00098     return capability.channels;
00099 }
00100 
00101 int V4LCapability::getNumberOfAudioDevices()
00102 {
00103     return capability.audios;
00104 }
00105 
00106 int V4LCapability::getMinWidth()
00107 {
00108     return capability.minwidth;
00109 }
00110 
00111 int V4LCapability::getMinHeight()
00112 {
00113     return capability.minheight;
00114 }
00115 
00116 int V4LCapability::getMaxWidth()
00117 {
00118     return capability.maxwidth;
00119 }
00120 
00121 int V4LCapability::getMaxHeight()
00122 {
00123     return capability.maxheight;
00124 }
00125 
00126 bool V4LCapability::canCapture()
00127 {
00128     return capability.type & VID_TYPE_CAPTURE;
00129 }
00130 
00131 bool V4LCapability::hasTuner()
00132 {
00133     return capability.type & VID_TYPE_TUNER;
00134 }
00135 
00136 bool V4LCapability::hasChromakey()
00137 {
00138     return capability.type & VID_TYPE_CHROMAKEY;
00139 }
00140 
00141 bool V4LCapability::hasClipping()
00142 {
00143     return capability.type & VID_TYPE_CLIPPING;
00144 }
00145 
00146 bool V4LCapability::hasOverwrite()
00147 {
00148     return capability.type & VID_TYPE_FRAMERAM;
00149 }
00150 
00151 bool V4LCapability::hasScaling()
00152 {
00153     return capability.type & VID_TYPE_SCALES;
00154 }
00155 
00156 bool V4LCapability::isMonochrome()
00157 {
00158     return capability.type & VID_TYPE_MONOCHROME;
00159 }
00160 
00161 bool V4LCapability::canSubCapture()
00162 {
00163     return capability.type & VID_TYPE_SUBCAPTURE;
00164 }
00165 
00166 void V4LCapability::report()
00167 {
00168     cout << ">>> Name     : " << this->getName() << endl;
00169     cout << ">>> Channels : " << this->getNumberOfChannels() << endl;
00170     cout << ">>> Audio    : " << this->getNumberOfAudioDevices() << endl;
00171     cout << ">>> Min Size : " << this->getMinWidth() << "," << this->getMinHeight() << endl;
00172     cout << ">>> Max Size : " << this->getMaxWidth() << "," << this->getMaxHeight() << endl;
00173     cout << ">>> Functions: " << endl;
00174     if ( this->canCapture() )
00175         cout << "     + Can capture to memory" << endl;
00176     if ( this->hasTuner() )
00177         cout << "     + Has a Tuner" << endl;
00178     if ( this->hasChromakey() )
00179         cout << "       with Chromakey" << endl;
00180     if ( this->hasClipping() )
00181         cout << "       with Clipping" << endl;
00182     if ( this->hasOverwrite() )
00183         cout << "       overwrites buffer memory" << endl;
00184     if ( this->hasScaling() )
00185         cout << "     + Has hardware support for image scaling" << endl;
00186     if ( this->isMonochrome() )
00187         cout << "     - Monochrome only" << endl;
00188     if ( this->canSubCapture() )
00189         cout << "     + Can capture part of the image" << endl;
00190 }
00191 
00192 V4LTuner::V4LTuner( V4LDevice *device, int index )
00193 {
00194     this->device = device;
00195     this->tuner.tuner = index;
00196     this->device->request( VIDIOCGTUNER, this );
00197 }
00198 
00199 void *V4LTuner::getStruct()
00200 {
00201     return & tuner;
00202 }
00203 
00204 void V4LTuner::report()
00205 {}
00206 
00207 int V4LTuner::getRangeLow()
00208 {
00209     return tuner.rangelow;
00210 }
00211 
00212 void V4LTuner::setRangeLow( int low )
00213 {
00214     tuner.rangelow = low;
00215 }
00216 
00217 int V4LTuner::getRangeHigh()
00218 {
00219     return tuner.rangehigh;
00220 }
00221 
00222 void V4LTuner::setRangeHigh( int high )
00223 {
00224     tuner.rangehigh = high;
00225 }
00226 
00227 int V4LTuner::getFlags()
00228 {
00229     return tuner.flags;
00230 }
00231 
00232 void V4LTuner::setFlags( int flags )
00233 {
00234     tuner.flags = flags;
00235 }
00236 
00237 int V4LTuner::getMode()
00238 {
00239     return tuner.mode;
00240 }
00241 
00242 void V4LTuner::setMode( int mode )
00243 {
00244     tuner.mode = mode;
00245 }
00246 
00247 int V4LTuner::getSignal()
00248 {
00249     return tuner.signal;
00250 }
00251 
00252 V4LChannel::V4LChannel( V4LDevice *device, int index )
00253 {
00254     memset( &channel, 0, sizeof( struct video_channel ) );
00255     this->device = device;
00256     this->channel.channel = index;
00257     device->request( VIDIOCGCHAN, this );
00258     device->request( VIDIOCSCHAN, this );
00259     for ( unsigned int i = 0; i < getNumberOfTuners(); i ++ )
00260     {
00261         V4LTuner *tuner = new V4LTuner( this->device, i );
00262         tuners.insert( tuners.end(), tuner );
00263     }
00264 }
00265 
00266 V4LChannel::~V4LChannel()
00267 {
00268     cout << "Channel destroyed" << endl;
00269 }
00270 
00271 void *V4LChannel::getStruct()
00272 {
00273     return & channel;
00274 }
00275 
00276 char *V4LChannel::getName()
00277 {
00278     return channel.name;
00279 }
00280 
00281 bool V4LChannel::setTuner( unsigned int index )
00282 {
00283     if ( index >= 0 && index < tuners.size() )
00284     {
00285         current = tuners[ index ];
00286         // FIXME: Hardcoded tuner settings
00287         current->setRangeLow( 0 );
00288         current->setRangeHigh( 0xffff );
00289         return device->request( VIDIOCSTUNER, current );
00290     }
00291     else
00292     {
00293         return false;
00294     }
00295 }
00296 
00297 unsigned int V4LChannel::getNumberOfTuners()
00298 {
00299     return channel.tuners;
00300 }
00301 
00302 V4LTuner *V4LChannel::getTuner( unsigned int index )
00303 {
00304     if ( index >= 0 && index < tuners.size() )
00305     {
00306         return tuners[ index ];
00307     }
00308     else
00309     {
00310         return NULL;
00311     }
00312 }
00313 
00314 int V4LChannel::getSignal()
00315 {
00316     device->request( VIDIOCGTUNER, current );
00317     return current->getSignal();
00318 }
00319 
00320 void V4LChannel::report()
00321 {
00322     cout << ">>>> Channel # " << channel.channel << endl;
00323     cout << ">>>> Name    : " << this->getName() << endl;
00324     cout << ">>>> Tuners  : " << this->getNumberOfTuners() << endl;
00325     cout << ">>>> Flags   : " << endl;
00326     if ( channel.flags & VIDEO_VC_TUNER )
00327         cout << "     Channel has tuners" << endl;
00328     if ( channel.flags & VIDEO_VC_AUDIO )
00329         cout << "     Channel has audio" << endl;
00330     cout << ">>>> Type    : " << endl;
00331     if ( channel.type & VIDEO_TYPE_TV )
00332         cout << "     TV" << endl;
00333     if ( channel.type & VIDEO_TYPE_CAMERA )
00334         cout << "     Camera" << endl;
00335 }
00336 
00340 V4L::V4L()
00341 {
00342     cout << "Opening V4L" << endl;
00343 }
00344 
00345 void V4L::setInfo( char *device, char *input, char *audio, int sample )
00346 {
00347     this->device = device;
00348     this->input = input;
00349     this->audio = audio;
00350     this->sample = sample;
00351 }
00352 
00353 bool V4L::openDevice()
00354 {
00355     bool ret = true;
00356 
00357     if ( !strcmp( this->input, "PAL" ) )
00358     {
00359         this->width = 720;
00360         this->height = 576;
00361         this->fps = 25;
00362         this->frameSample = this->sample / this->fps;
00363     }
00364     else if ( !strcmp( this->input, "NTSC" ) )
00365     {
00366         this->width = 720;
00367         this->height = 480;
00368         this->fps = 30;
00369         this->frameSample = this->sample / this->fps;
00370     }
00371 
00372     this->current = NULL;
00373     this->fd = open( device, O_RDWR );
00374     if ( fd != -1 )
00375     {
00376         this->capability = new V4LCapability( this );
00377         for ( int index = 0; index < capability->getNumberOfChannels(); index ++ )
00378         {
00379             V4LChannel *channel = new V4LChannel( this, index );
00380             channels.insert( channels.end(), channel );
00381         }
00382         setCaptureResolution( this->width, this->height );
00383     }
00384     else
00385     {
00386         perror( "Unable to open video device" );
00387         ret = false;
00388     }
00389     return ret;
00390 }
00391 
00395 V4L::~V4L()
00396 {
00397     cout << "Closing V4L" << endl;
00398     if ( fd != -1 )
00399     {
00400         close( fd );
00401         for ( unsigned int index = 0; index < channels.size(); index ++ )
00402             delete channels[ index ];
00403         delete this->capability;
00404     }
00405 }
00406 
00412 bool V4L::deviceAvailable()
00413 {
00414     return fd != -1;
00415 }
00416 
00422 int V4L::getHandle()
00423 {
00424     return fd;
00425 }
00426 
00433 bool V4L::setChannel( unsigned int channel )
00434 {
00435     if ( channel >= 0 && channel < channels.size() )
00436     {
00437         current = channels[ channel ];
00438         return this->request( VIDIOCSCHAN, current );
00439     }
00440     else
00441     {
00442         return false;
00443     }
00444 }
00445 
00451 unsigned int V4L::getNumberOfChannels()
00452 {
00453     return channels.size();
00454 }
00455 
00462 V4LChannel *V4L::getChannel( unsigned int channel )
00463 {
00464     if ( channel >= 0 && channel < channels.size() )
00465         return channels[ channel ];
00466     else
00467         return NULL;
00468 }
00469 
00476 bool V4L::setTuner( unsigned int tuner )
00477 {
00478     if ( current != NULL )
00479         return current->setTuner( tuner );
00480     else
00481         return false;
00482 }
00483 
00489 unsigned int V4L::getNumberOfTuners( )
00490 {
00491     if ( current != NULL )
00492         return current->getNumberOfTuners();
00493     else
00494         return 0;
00495 }
00496 
00503 V4LTuner *V4L::getTuner( unsigned int tuner )
00504 {
00505     if ( current != NULL )
00506         return current->getTuner( tuner );
00507     else
00508         return NULL;
00509 }
00510 
00517 bool V4L::setCaptureResolution( int width, int height )
00518 {
00519     if ( width > capability->getMaxWidth() ||
00520             width < capability->getMinWidth() )
00521         return false;
00522     if ( height > capability->getMaxHeight() ||
00523             height < capability->getMinHeight() )
00524         return false;
00525     if ( !capability->hasScaling() && (
00526                 width != capability->getMaxWidth() ||
00527                 height != capability->getMaxHeight() ) )
00528         return false;
00529     this->width = width;
00530     this->height = height;
00531     cout << "Capture resolution set to " << width << ", " << height << endl;
00532     return true;
00533 }
00534 
00540 int V4L::getWidth()
00541 {
00542     return width;
00543 }
00544 
00550 int V4L::getHeight()
00551 {
00552     return height;
00553 }
00554 
00558 void V4L::startAudio()
00559 {
00560     struct video_audio audio;
00561     ioctl( fd, VIDIOCGAUDIO, &audio );
00562     if ( audio.flags & VIDEO_AUDIO_MUTE )
00563         audio.flags ^= VIDEO_AUDIO_MUTE;
00564     cout << "Volume : " << audio.volume << endl;
00565     audio.volume = 65535;
00566     ioctl( fd, VIDIOCSAUDIO, &audio );
00567 }
00568 
00572 void V4L::stopAudio()
00573 {
00574     struct video_audio audio;
00575     ioctl( fd, VIDIOCGAUDIO, &audio );
00576     audio.flags |= VIDEO_AUDIO_MUTE;
00577     cout << "Volume : " << audio.volume << endl;
00578     audio.volume = 0;
00579     ioctl( fd, VIDIOCSAUDIO, &audio );
00580 }
00581 
00582 int V4L::mappedMemorySize( bool init )
00583 {
00584     static video_mbuf buf;
00585     if ( init == true )
00586     {
00587         init = 1;
00588         ioctl( fd, VIDIOCGMBUF, &buf );
00589         cout << ">>> Mapped Memory Size = " << buf.size << " frames are " << buf.frames << endl;
00590         frame_maps = buf.frames;
00591     }
00592     return buf.size;
00593 }
00594 
00601 bool V4L::initialiseCapture( int format )
00602 {
00603     size = width * height * 4;
00604 
00605     map = mmap( 0, mappedMemorySize( true ), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0 );
00606 
00607     if ( map != NULL )
00608     {
00609         for ( int i = 0; i < frame_maps; i ++ )
00610         {
00611             frame[ i ].frame = i;
00612             frame[ i ].width = getWidth();
00613             frame[ i ].height = getHeight();
00614             frame[ i ].format = format;
00615         }
00616         
00617         struct timeval tv;
00618         gettimeofday( &tv, NULL );
00619         starttime = tv.tv_sec * 1000000 + tv.tv_usec;
00620         frames = 0;
00621         frame_next = 0;
00622         
00623         int retry = 0;
00624         while ( ioctl( fd, VIDIOCMCAPTURE, &frame[ 0 ] ) == -1 && retry ++ < frame_maps + 1 ) ;
00625         
00626         return true;
00627     }
00628     else
00629     {
00630         return false;
00631     }
00632 }
00633 
00639 void *V4L::getNextFrame()
00640 {
00641     unsigned char * ret = NULL;
00642 
00643     int current = frame_next;
00644     frame_next = ( frame_next + 1 ) % frame_maps;
00645     
00646     if ( ioctl( fd, VIDIOCMCAPTURE, &frame[ frame_next ] ) == -1 )
00647         ; //cout << "Frame 1 Failed to initialise" << endl;
00648     if ( ioctl( fd, VIDIOCSYNC, &frame[ current ].frame ) == -1 )
00649         ; //cout << "Frame 0 Failed to sync" << endl;
00650     ret = ( unsigned char * ) map + current * ( mappedMemorySize( ) / frame_maps );
00651     
00652     frames ++;
00653 
00654     return ( void * ) ret;
00655 }
00656 
00660 void V4L::stopCapture()
00661 {
00662     if ( map != NULL )
00663     {
00664         struct timeval tv;
00665         gettimeofday( &tv, NULL );
00666         long long endtime = tv.tv_sec * 1000000 + tv.tv_usec;
00667         double fps = ( frames ) / ( ( ( double ) ( endtime - starttime ) ) / 1000000 );
00668         cout << "fps: " << fps << endl;
00669         munmap( map, mappedMemorySize() );
00670         map = NULL;
00671         int enable = 0;
00672         ioctl( getHandle(), VIDIOCCAPTURE, &enable );
00673     }
00674 }
00675 
00681 int V4L::getFrequency()
00682 {
00683     unsigned long current;
00684     ioctl( fd, VIDIOCGFREQ, &current );
00685     return ( int ) current;
00686 }
00687 
00694 bool V4L::setFrequency( int frequency )
00695 {
00696     unsigned long val = ( unsigned long ) frequency & 0xffff;
00697     return ioctl( fd, VIDIOCSFREQ, &val ) != -1;
00698 }
00699 
00703 int V4L::getSignal()
00704 {
00705     return current->getSignal();
00706 }
00707 
00711 void V4L::report()
00712 {
00713     capability->report();
00714 
00715     for ( unsigned int index = 0; index < channels.size(); index ++ )
00716     {
00717         channels[ index ] ->report();
00718     }
00719 }
00720 
00721 
00726 EncoderFrame::EncoderFrame()
00727 {
00728     image = new uint8_t[ 720 * 576 * 3 ];
00729 }
00730 
00731 EncoderFrame::~EncoderFrame()
00732 {
00733     delete[] image;
00734 }
00735 
00736 void EncoderFrame::setVideo( void *image, int width, int height )
00737 {
00738     if ( ENCODE_YUV )
00739         memcpy( this->image, ( unsigned char * ) image, width * height * 2 );
00740     else
00741         memcpy( this->image, ( unsigned char * ) image, ( width * height * 3 ) / 2 );
00742 
00743     this->width = width;
00744     this->height = height;
00745 }
00746 
00747 void EncoderFrame::setAudio( void *audio, int length )
00748 {
00749     memcpy( this->audio, audio, length );
00750     this->length = length;
00751 }
00752 
00757 deque < EncoderFrame * > DvEncoder::used;
00758 deque < EncoderFrame * > DvEncoder::available;
00759 
00760 DvEncoder::DvEncoder( char *filename, int width, int height ) : active( false ), audio( "/dev/dsp" )
00761 {
00762     this->width = width;
00763     this->height = height;
00764 
00765     this->filename = filename;
00766     for ( int i = 0; i < Preferences::getInstance().dvCaptureBuffers; ++i )
00767     {
00768         available.push_back( NULL );
00769     }
00770 
00771     pthread_mutex_init( &mutex, NULL );
00772     pthread_create( &thread, NULL, startThread, this );
00773 }
00774 
00775 DvEncoder::~DvEncoder( )
00776 {
00777     active = false;
00778     pthread_join( thread, NULL );
00779 
00780     for ( int i = available.size(); i > 0; --i )
00781     {
00782         EncoderFrame *frame = available[ 0 ];
00783         available.pop_front();
00784         delete frame;
00785     }
00786 
00787     for ( int i = used.size(); i > 0; --i )
00788     {
00789         EncoderFrame *frame = used[ 0 ];
00790         used.pop_front();
00791         delete frame;
00792     }
00793 }
00794 
00795 EncoderFrame *DvEncoder::getFrame()
00796 {
00797     EncoderFrame * frame = NULL;
00798 
00799     pthread_mutex_lock( &mutex );
00800     if ( available.size() > 0 )
00801     {
00802         frame = available[ 0 ];
00803         if ( frame == NULL )
00804             frame = new EncoderFrame;
00805 
00806         available.pop_front();
00807     }
00808     pthread_mutex_unlock( &mutex );
00809 
00810     return frame;
00811 }
00812 
00813 void DvEncoder::doneWithFrame( EncoderFrame *frame )
00814 {
00815     pthread_mutex_lock( &mutex );
00816     used.push_back( frame );
00817     pthread_mutex_unlock( &mutex );
00818 }
00819 
00820 void *DvEncoder::startThread( void *ptr )
00821 {
00822     DvEncoder * encoder = ( DvEncoder * ) ptr;
00823     cout << "starting encoder thread..." << endl;
00824     encoder->writeThread( );
00825     return NULL;
00826 }
00827 
00828 void DvEncoder::writeThread()
00829 {
00830     struct timespec tm =
00831         {
00832             0, 0
00833         };
00834     char command[ 10240 ];
00835     int counter = 0;
00836     struct stat stats;
00837     string thisfile;
00838 
00839     active = true;
00840 
00841     do
00842     {
00843         ostringstream sb;
00844         sb << filename << setfill( '0' ) << setw( 3 ) << ++ counter << ".dv";
00845         thisfile = sb.str();
00846         cout << ">>> Trying " << thisfile << endl;
00847     }
00848     while ( stat( thisfile.c_str(), &stats ) == 0 );
00849 
00850     KinoVideoPipe *encode = NULL;
00851 
00852     if ( ENCODE_YUV )
00853     {
00854         encode = KinoVideoFactory::CreateVideoPipe( PIPE_VIDEO_DV_YUV );
00855         sprintf( command, "ffmpeg -threads 2 -f yuv4mpegpipe -i pipe: -f audio_device -ac 2 -ar 48000 -i %s -y %s", audio, thisfile.c_str() );
00856 //      sprintf( command, "ffmpeg -f yuv4mpegpipe -i pipe: -f audio_device -ac 2 -ar 48000 -i %s -vcodec mpeg4 -qscale 1 -aspect 4:3 -acodec pcm_s16le -y %s.avi", audio, thisfile.c_str() );
00857     }
00858     else
00859     {
00860         encode = KinoVideoFactory::CreateVideoPipe( PIPE_VIDEO_DV_PGM );
00861         sprintf( command, "encodedv -a dsp -i pgm -p 2 -q 2 - %s > %s", audio, thisfile.c_str() );
00862     }
00863 
00864     encode->OpenVideoPipe( command, width, height );
00865 
00866     while ( active || used.size() > 0 )
00867     {
00868         if ( used.size() > 0 )
00869         {
00870             pthread_mutex_lock( &mutex );
00871             EncoderFrame *frame = used.front();
00872             used.pop_front();
00873             pthread_mutex_unlock( &mutex );
00874 
00875             if ( frame != NULL )
00876             {
00877                 if ( ENCODE_YUV )
00878                     encode->OutputVideoFrame( frame->image, width * height * 2 );
00879                 else
00880                     encode->OutputVideoFrame( frame->image, width * height * 3 / 2 );
00881 
00882                 pthread_mutex_lock( &mutex );
00883                 available.push_back( frame );
00884                 pthread_mutex_unlock( &mutex );
00885             }
00886         }
00887 
00888         nanosleep( &tm, NULL );
00889     }
00890 
00891     encode->CloseVideo();
00892 
00893     delete encode;
00894 
00895     FileTracker::GetInstance().Add( thisfile.c_str() );
00896 }
00897 
00902 extern "C"
00903 {
00904     static void *gdkv4l_thread( void * ptr )
00905     {
00906         GDKV4L * v4l = ( GDKV4L * ) ptr;
00907         v4l->active = true;
00908         if ( !v4l->capturing )
00909         {
00910             while ( v4l->active )
00911             {
00912                 v4l->draw();
00913                 struct timespec t =
00914                     {
00915                         0, 0
00916                     };
00917                 nanosleep( &t, NULL );
00918             }
00919         }
00920         else
00921         {
00922             char filename[ 1024 ];
00923             GtkEntry *fileEntry = GTK_ENTRY( lookup_widget( v4l->widget, "entry_v4l_file" ) );
00924             strcpy( filename, gtk_entry_get_text( fileEntry ) );
00925 
00926             DvEncoder *encoder = new DvEncoder( filename, v4l->getWidth(), v4l->getHeight() );
00927             encoder->audio = v4l->audio;
00928             while ( v4l->active )
00929             {
00930                 v4l->capture( encoder );
00931                 struct timespec t =
00932                     {
00933                         0, 0
00934                     };
00935                 nanosleep( &t, NULL );
00936             }
00937             delete encoder;
00938         }
00939         return NULL;
00940     }
00941 }
00942 
00943 GDKV4L::GDKV4L( GtkWidget *widget ) : V4L(), active( false ), capturing( false )
00944 {
00945     cout << "Starting GDKV4L" << endl;
00946     this->widget = widget;
00947     this->displayer = NULL;
00948 }
00949 
00950 GDKV4L::~GDKV4L()
00951 {
00952     cout << "Closing GDKV4L" << endl;
00953     stopCapturing();
00954     stopVideo();
00955 }
00956 
00957 void GDKV4L::startVideo()
00958 {
00959     cout << ">>> Starting video" << endl;
00960     if ( !active )
00961     {
00962         pthread_create( &v4lthread, NULL, gdkv4l_thread, this );
00963     }
00964 }
00965 
00966 void GDKV4L::startCapturing()
00967 {
00968     if ( !capturing )
00969     {
00970         stopVideo();
00971         capturing = true;
00972         startVideo();
00973     }
00974 }
00975 
00976 void GDKV4L::stopVideo()
00977 {
00978     cout << ">>> Stopping video" << endl;
00979     if ( active )
00980     {
00981         active = false;
00982         gdk_threads_leave();
00983         pthread_join( v4lthread, NULL );
00984         gdk_threads_enter();
00985         this->stopCapture();
00986     }
00987     if ( displayer != NULL )
00988     {
00989         delete displayer;
00990         displayer = NULL;
00991     }
00992 }
00993 
00994 void GDKV4L::stopCapturing()
00995 {
00996     if ( capturing )
00997     {
00998         stopVideo();
00999         capturing = false;
01000         startVideo();
01001     }
01002 }
01003 
01004 void GDKV4L::draw()
01005 {
01006 
01007     if ( displayer == NULL )
01008     {
01009         gdk_threads_enter();
01010         displayer = FindDisplayer::getDisplayer( widget, getWidth(), getHeight() );
01011 
01012         switch ( displayer->format() )
01013         {
01014         case DISPLAY_YUV:
01015             input = DISPLAY_YUV;
01016             initialiseCapture( VIDEO_PALETTE_YUV422 );
01017             break;
01018         case DISPLAY_RGB:
01019             input = DISPLAY_BGR;
01020             initialiseCapture( VIDEO_PALETTE_RGB24 );
01021             break;
01022         case DISPLAY_RGB16:
01023             input = DISPLAY_RGB16;
01024             initialiseCapture( VIDEO_PALETTE_RGB565 );
01025             break;
01026         default:
01027             break;
01028         }
01029         gdk_threads_leave();
01030     }
01031 
01032     void *f = getNextFrame();
01033 
01034     if ( f != NULL )
01035     {
01036         gdk_threads_enter();
01037         displayer->put( input, f, getWidth(), getHeight() );
01038         gdk_flush();
01039         gdk_threads_leave();
01040     }
01041 }
01042 
01043 void GDKV4L::capture( DvEncoder *encoder )
01044 {
01045 
01046     static int count = 0;
01047     void *f = NULL;
01048 
01049     if ( displayer == NULL )
01050     {
01051         gdk_threads_enter();
01052         displayer = FindDisplayer::getDisplayer( widget, getWidth(), getHeight() );
01053 
01054         if ( ENCODE_YUV )
01055         {
01056             input = DISPLAY_YUV;    // Fake - YUV422P isn't supported by Displayer
01057             initialiseCapture( VIDEO_PALETTE_YUV422P );
01058         }
01059         else
01060         {
01061             input = DISPLAY_RGB;    // Fake - YUV420P isn't supported by Displayer
01062             initialiseCapture( VIDEO_PALETTE_YUV420P );
01063         }
01064 
01065         // skip the first frame
01066         f = getNextFrame();
01067 
01068         gdk_threads_leave();
01069     }
01070 
01071 
01072     f = getNextFrame();
01073 
01074     if ( f != NULL )
01075     {
01076         EncoderFrame * frame = encoder->getFrame();
01077         if ( frame != NULL )
01078         {
01079             frame->setVideo( f, getWidth(), getHeight() );
01080             encoder->doneWithFrame( frame );
01081         }
01082         else
01083         {
01084             cout << "No frames available..." << endl;
01085         }
01086     }
01087 
01088     // TODO: Determine if playback is desirable during capture
01089 
01090     if ( f != NULL && displayer->format() == input && ( ++ count ) % 25 == 0 )
01091     {
01092         gdk_threads_enter();
01093         displayer->put( input, f, getWidth(), getHeight() );
01094         gdk_flush();
01095         gdk_threads_leave();
01096     }
01097 }
01098 

Generated on Sun Mar 11 22:11:47 2007 for Kino by  doxygen 1.4.2