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

filehandler.cc

Go to the documentation of this file.
00001 /*
00002 * filehandler.cc -- saving DV data into different file formats
00003 * Copyright (C) 2000 Arne Schirmacher <arne@schirmacher.de>
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 
00021 #ifdef HAVE_CONFIG_H
00022 #include <config.h>
00023 #endif
00024 
00025 #include <string>
00026 #include <iostream>
00027 #include <sstream>
00028 #include <iomanip>
00029 
00030 using std::cerr;
00031 using std::endl;
00032 using std::ostringstream;
00033 using std::setw;
00034 using std::setfill;
00035 
00036 #include <signal.h>
00037 #include <unistd.h>
00038 #include <fcntl.h>
00039 #include <sys/stat.h>
00040 #include <assert.h>
00041 #include <time.h>
00042 #include <sys/time.h>
00043 
00044 #include "filehandler.h"
00045 #include "error.h"
00046 #include "riff.h"
00047 #include "avi.h"
00048 #include "frame.h"
00049 
00050 FileTracker *FileTracker::instance = NULL;
00051 
00052 FileTracker::FileTracker( ) : mode( CAPTURE_MOVIE_APPEND )
00053 {
00054     cerr << ">> Constructing File Capture tracker" << endl;
00055 }
00056 
00057 FileTracker::~FileTracker( )
00058 {
00059     cerr << ">> Destroying File Capture tracker" << endl;
00060 }
00061 
00062 FileTracker &FileTracker::GetInstance( )
00063 {
00064     if ( instance == NULL )
00065         instance = new FileTracker();
00066 
00067     return *instance;
00068 }
00069 
00070 void FileTracker::SetMode( FileCaptureMode mode )
00071 {
00072     this->mode = mode;
00073 }
00074 
00075 FileCaptureMode FileTracker::GetMode( )
00076 {
00077     return this->mode;
00078 }
00079 
00080 char *FileTracker::Get( int index )
00081 {
00082     return list[ index ];
00083 }
00084 
00085 void FileTracker::Add( const char *file )
00086 {
00087     if ( this->mode != CAPTURE_IGNORE )
00088     {
00089         cerr << ">>>> Registering " << file << " with the tracker" << endl;
00090         list.push_back( strdup( file ) );
00091     }
00092 }
00093 
00094 unsigned int FileTracker::Size( )
00095 {
00096     return list.size();
00097 }
00098 
00099 void FileTracker::Clear( )
00100 {
00101     while ( Size() > 0 )
00102     {
00103         free( list[ Size() - 1 ] );
00104         list.pop_back( );
00105     }
00106     this->mode = CAPTURE_MOVIE_APPEND;
00107 }
00108 
00109 FileHandler::FileHandler() : done( false ), autoSplit( false ), maxFrameCount( 999999 ),
00110         framesWritten( 0 ), filename( "" )
00111 {
00112     /* empty body */
00113 }
00114 
00115 
00116 FileHandler::~FileHandler()
00117 {
00118     /* empty body */
00119 }
00120 
00121 
00122 bool FileHandler::GetAutoSplit() const
00123 {
00124     return autoSplit;
00125 }
00126 
00127 
00128 bool FileHandler::GetTimeStamp() const
00129 {
00130     return timeStamp;
00131 }
00132 
00133 
00134 string FileHandler::GetBaseName() const
00135 {
00136     return base;
00137 }
00138 
00139 
00140 string FileHandler::GetExtension() const
00141 {
00142     return extension;
00143 }
00144 
00145 
00146 int FileHandler::GetMaxFrameCount() const
00147 {
00148     return maxFrameCount;
00149 }
00150 
00151 off_t FileHandler::GetMaxFileSize() const
00152 {
00153     return maxFileSize;
00154 }
00155 
00156 string FileHandler::GetFilename() const
00157 {
00158     return filename;
00159 }
00160 
00161 
00162 void FileHandler::SetAutoSplit( bool flag )
00163 {
00164     autoSplit = flag;
00165 }
00166 
00167 
00168 void FileHandler::SetTimeStamp( bool flag )
00169 {
00170     timeStamp = flag;
00171 }
00172 
00173 
00174 void FileHandler::SetBaseName( const string& s )
00175 {
00176     base = s;
00177 }
00178 
00179 
00180 void FileHandler::SetMaxFrameCount( int count )
00181 {
00182     assert( count >= 0 );
00183     maxFrameCount = count;
00184 }
00185 
00186 
00187 void FileHandler::SetEveryNthFrame( int every )
00188 {
00189     assert ( every > 0 );
00190 
00191     everyNthFrame = every;
00192 }
00193 
00194 
00195 void FileHandler::SetMaxFileSize( off_t size )
00196 {
00197     assert ( size >= 0 );
00198     maxFileSize = size;
00199 }
00200 
00201 
00202 void FileHandler::SetSampleFrame( const Frame& sample )
00203 {
00204     /* empty body */
00205 }
00206 
00207 
00208 bool FileHandler::Done()
00209 {
00210     return done;
00211 }
00212 
00213 
00214 bool FileHandler::WriteFrame( const Frame& frame )
00215 {
00216     static TimeCode prevTimeCode = { 0, 0, -1, 0 };
00217     TimeCode timeCode;
00218 
00219     /* If the user wants autosplit, start a new file if a
00220        new recording is detected. */
00221     frame.GetTimeCode( timeCode );
00222     int time_diff = timeCode.sec - prevTimeCode.sec;
00223     bool discontinuity = prevTimeCode.sec != -1 && ( time_diff > 1 || ( time_diff < 0 && time_diff > -59 ) );
00224     if ( FileIsOpen() && GetAutoSplit() == true && ( frame.IsNewRecording() || discontinuity ) )
00225     {
00226         Close();
00227     }
00228 
00229     if ( FileIsOpen() == false )
00230     {
00231 
00232         string filename;
00233         static int counter = 0;
00234 
00235         if ( GetTimeStamp() == true )
00236         {
00237             ostringstream sb, sb2;
00238             struct tm   date;
00239             string  recDate;
00240 
00241             if ( ! frame.GetRecordingDate( date ) )
00242             {
00243                 struct timeval tv;
00244                 struct timezone tz;
00245                 gettimeofday( &tv, &tz );
00246                 localtime_r( static_cast< const time_t * >( &tv.tv_sec ), &date );
00247             }
00248             sb << setfill( '0' )
00249             << setw( 4 ) << date.tm_year + 1900 << '.'
00250             << setw( 2 ) << date.tm_mon + 1 << '.'
00251             << setw( 2 ) << date.tm_mday << '_'
00252             << setw( 2 ) << date.tm_hour << '-'
00253             << setw( 2 ) << date.tm_min << '-'
00254             << setw( 2 ) << date.tm_sec;
00255             recDate = sb.str();
00256             sb2 << GetBaseName() << recDate << GetExtension();
00257             filename = sb2.str();
00258             cerr << ">>> Trying " << filename << endl;
00259         }
00260         else
00261         {
00262             struct stat stats;
00263             do
00264             {
00265                 ostringstream sb;
00266                 sb << GetBaseName() << setfill( '0' ) << setw( 3 ) << ++ counter << GetExtension();
00267                 filename = sb.str();
00268                 cerr << ">>> Trying " << filename << endl;
00269             }
00270             while ( stat( filename.c_str(), &stats ) == 0 );
00271         }
00272 
00273         SetSampleFrame( frame );
00274         if ( Create( filename ) == false )
00275         {
00276             cerr << ">>> Error creating file!" << endl;
00277             return false;
00278         }
00279         framesWritten = 0;
00280         framesToSkip = 0;
00281     }
00282 
00283     /* write frame */
00284 
00285     if ( framesToSkip == 0 )
00286     {
00287         if ( 0 > Write( frame ) )
00288         {
00289             cerr << ">>> Error writing frame!" << endl;
00290             return false;
00291         }
00292         framesToSkip = everyNthFrame;
00293         ++framesWritten;
00294     }
00295     framesToSkip--;
00296 
00297     /* If the frame count is exceeded, close the current file.
00298        If the autosplit flag is set, a new file will be created in the next iteration.
00299        If the flag is not set, we are done. */
00300 
00301     if ( ( GetMaxFrameCount() > 0 ) &&
00302             ( framesWritten >= GetMaxFrameCount() ) )
00303     {
00304         Close();
00305         done = !GetAutoSplit();
00306     }
00307 
00308     /* If the file size could be exceeded by another frame, close the current file.
00309        If the autosplit flag is set, a new file will be created on the next iteration.
00310        If the flag is not set, we are done. */
00311     /* not exact, but should be good enough to prevent going over. */
00312     if ( FileIsOpen() )
00313     {
00314         AudioInfo info;
00315         frame.GetAudioInfo( info );
00316         if ( ( GetFileSize() > 0 ) && ( GetMaxFileSize() > 0 ) &&
00317                 ( GetFileSize() + frame.GetFrameSize() + info.samples * 4 + 12 )
00318                 >= GetMaxFileSize() )
00319         {                     // 12 = sizeof chunk metadata
00320             Close();
00321             done = !GetAutoSplit();
00322         }
00323     }
00324     prevTimeCode.sec = timeCode.sec;
00325     return true;
00326 }
00327 
00328 
00329 RawHandler::RawHandler() : fd( -1 )
00330 {
00331     extension = ".dv";
00332 }
00333 
00334 
00335 RawHandler::~RawHandler()
00336 {
00337     Close();
00338 }
00339 
00340 
00341 bool RawHandler::FileIsOpen()
00342 {
00343     return fd != -1;
00344 }
00345 
00346 
00347 bool RawHandler::Create( const string& filename )
00348 {
00349     fd = open( filename.c_str(), O_CREAT | O_TRUNC | O_RDWR | O_NONBLOCK, 0644 );
00350     if ( fd != -1 )
00351     {
00352         FileTracker::GetInstance().Add( filename.c_str() );
00353         this->filename = filename;
00354     }
00355     return ( fd != -1 );
00356 }
00357 
00358 
00359 int RawHandler::Write( const Frame& frame )
00360 {
00361     int result = write( fd, frame.data, frame.GetFrameSize() );
00362     return result;
00363 }
00364 
00365 
00366 int RawHandler::Close()
00367 {
00368     if ( fd != -1 )
00369     {
00370         close( fd );
00371         fd = -1;
00372     }
00373     return 0;
00374 }
00375 
00376 
00377 off_t RawHandler::GetFileSize()
00378 {
00379     struct stat file_status;
00380     fstat( fd, &file_status );
00381     return file_status.st_size;
00382 }
00383 
00384 int RawHandler::GetTotalFrames()
00385 {
00386     return GetFileSize() / ( 480 * numBlocks );
00387 }
00388 
00389 
00390 bool RawHandler::Open( const char *s )
00391 {
00392     unsigned char data[ 4 ];
00393     assert( fd == -1 );
00394     fd = open( s, O_RDONLY | O_NONBLOCK );
00395     if ( fd < 0 )
00396         return false;
00397     if ( read( fd, data, 4 ) < 0 )
00398         return false;
00399     lseek( fd, 0, SEEK_SET );
00400     numBlocks = ( ( data[ 3 ] & 0x80 ) == 0 ) ? 250 : 300;
00401     filename = s;
00402     return true;
00403 
00404 }
00405 
00406 int RawHandler::GetFrame( Frame &frame, int frameNum )
00407 {
00408     assert( fd != -1 );
00409     int size = 480 * numBlocks;
00410     if ( frameNum < 0 )
00411         return -1;
00412     off_t offset = ( ( off_t ) frameNum * ( off_t ) size );
00413     fail_if( lseek( fd, offset, SEEK_SET ) == ( off_t ) - 1 );
00414     if ( read( fd, frame.data, size ) > 0 )
00415     {
00416         frame.ExtractHeader();
00417         return 0;
00418     }
00419     else
00420         return -1;
00421 }
00422 
00423 
00424 /***************************************************************************/
00425 
00426 #define AVI_AUDIO_BUFFER_SECS (2)
00427 
00428 AVIHandler::AVIHandler( int format ) : avi( NULL ), aviFormat( format ), isOpenDML( false ),
00429         fccHandler( make_fourcc( "dvsd" ) ), channels( 2 ), isFullyInitialized( false ),
00430         audioBuffer( NULL ), isInterleave1to1( true )
00431 {
00432     extension = ".avi";
00433     for ( int c = 0; c < 4; c++ )
00434         audioChannels[ c ] = NULL;
00435 }
00436 
00437 
00438 AVIHandler::~AVIHandler()
00439 {
00440     if ( audioBuffer != NULL )
00441     {
00442         delete[] audioBuffer;
00443         audioBuffer = NULL;
00444     }
00445     for ( int c = 0; c < 4; c++ )
00446     {
00447         if ( audioChannels[ c ] != NULL )
00448         {
00449             delete[] audioChannels[ c ];
00450             audioChannels[ c ] = NULL;
00451         }
00452     }
00453 
00454     delete avi;
00455 }
00456 
00457 void AVIHandler::SetSampleFrame( const Frame& sample )
00458 {
00459     Pack pack;
00460     sample.GetAudioInfo( audioInfo );
00461     sample.GetVideoInfo( videoInfo );
00462 
00463     sample.GetAAUXPack( 0x50, pack );
00464     dvinfo.dwDVAAuxSrc = *( DWORD* ) ( pack.data + 1 );
00465     sample.GetAAUXPack( 0x51, pack );
00466     dvinfo.dwDVAAuxCtl = *( DWORD* ) ( pack.data + 1 );
00467 
00468     sample.GetAAUXPack( 0x52, pack );
00469     dvinfo.dwDVAAuxSrc1 = *( DWORD* ) ( pack.data + 1 );
00470     sample.GetAAUXPack( 0x53, pack );
00471     dvinfo.dwDVAAuxCtl1 = *( DWORD* ) ( pack.data + 1 );
00472 
00473     sample.GetVAUXPack( 0x60, pack );
00474     dvinfo.dwDVVAuxSrc = *( DWORD* ) ( pack.data + 1 );
00475     sample.GetVAUXPack( 0x61, pack );
00476     dvinfo.dwDVVAuxCtl = *( DWORD* ) ( pack.data + 1 );
00477 
00478 #ifdef HAVE_LIBDV
00479     if ( sample.decoder->std == e_dv_std_smpte_314m )
00480         fccHandler = make_fourcc( "dv25" );
00481 #endif
00482 }
00483 
00484 
00485 bool AVIHandler::FileIsOpen()
00486 {
00487     return avi != NULL;
00488 }
00489 
00490 
00491 bool AVIHandler::Create( const string& filename )
00492 {
00493     assert( avi == NULL );
00494 
00495     switch ( aviFormat )
00496     {
00497 
00498     case AVI_DV1_FORMAT:
00499         fail_null( avi = new AVI1File );
00500         if ( avi->Create( filename.c_str() ) == false )
00501             return false;
00502         avi->Init( videoInfo.isPAL ? AVI_PAL : AVI_NTSC, audioInfo.frequency,
00503                    AVI_LARGE_INDEX );
00504         break;
00505 
00506     case AVI_DV2_FORMAT:
00507         fail_null( avi = new AVI2File );
00508         if ( avi->Create( filename.c_str() ) == false )
00509             return false;
00510         if ( GetOpenDML() )
00511             avi->Init( videoInfo.isPAL ? AVI_PAL : AVI_NTSC, audioInfo.frequency,
00512                        ( AVI_SMALL_INDEX | AVI_LARGE_INDEX ) );
00513         else
00514             avi->Init( videoInfo.isPAL ? AVI_PAL : AVI_NTSC, audioInfo.frequency,
00515                        ( AVI_SMALL_INDEX ) );
00516         break;
00517 
00518     default:
00519         assert( aviFormat == AVI_DV1_FORMAT || aviFormat == AVI_DV2_FORMAT );
00520     }
00521 
00522     avi->setDVINFO( dvinfo );
00523     avi->setFccHandler( make_fourcc( "iavs" ), fccHandler );
00524     avi->setFccHandler( make_fourcc( "vids" ), fccHandler );
00525     this->filename = filename;
00526     FileTracker::GetInstance().Add( filename.c_str() );
00527     return ( avi != NULL );
00528 }
00529 
00530 
00531 int AVIHandler::Write( const Frame& frame )
00532 {
00533     assert( avi != NULL );
00534     try
00535     {
00536         return avi->WriteFrame( frame ) ? 0 : -1;
00537     }
00538     catch (...)
00539     {
00540         return -1;
00541     }
00542 }
00543 
00544 
00545 int AVIHandler::Close()
00546 {
00547     if ( avi != NULL )
00548     {
00549         avi->WriteRIFF();
00550         delete avi;
00551         avi = NULL;
00552     }
00553     if ( audioBuffer != NULL )
00554     {
00555         delete audioBuffer;
00556         audioBuffer = NULL;
00557     }
00558     for ( int c = 0; c < 4; c++ )
00559     {
00560         if ( audioChannels[ c ] != NULL )
00561         {
00562             delete audioChannels[ c ];
00563             audioChannels[ c ] = NULL;
00564         }
00565     }
00566     isFullyInitialized = false;
00567     return 0;
00568 }
00569 
00570 off_t AVIHandler::GetFileSize()
00571 {
00572     return avi->GetFileSize();
00573 }
00574 
00575 int AVIHandler::GetTotalFrames()
00576 {
00577     return avi->GetTotalFrames();
00578 }
00579 
00580 
00581 bool AVIHandler::Open( const char *s )
00582 {
00583     assert( avi == NULL );
00584     fail_null( avi = new AVI1File );
00585     if ( avi->Open( s ) )
00586     {
00587         avi->ParseRIFF();
00588         if ( ! (
00589                     avi->verifyStreamFormat( make_fourcc( "dvsd" ) ) ||
00590                     avi->verifyStreamFormat( make_fourcc( "DVSD" ) ) ||
00591                     avi->verifyStreamFormat( make_fourcc( "dvcs" ) ) ||
00592                     avi->verifyStreamFormat( make_fourcc( "DVCS" ) ) ||
00593                     avi->verifyStreamFormat( make_fourcc( "dvcp" ) ) ||
00594                     avi->verifyStreamFormat( make_fourcc( "DVCP" ) ) ||
00595                     avi->verifyStreamFormat( make_fourcc( "CDVC" ) ) ||
00596                     avi->verifyStreamFormat( make_fourcc( "cdvc" ) ) ||
00597                     avi->verifyStreamFormat( make_fourcc( "DV25" ) ) ||
00598                     avi->verifyStreamFormat( make_fourcc( "dv25" ) ) ) )
00599             return false;
00600         avi->ReadIndex();
00601         if ( avi->verifyStream( make_fourcc( "auds" ) ) )
00602         {
00603             aviFormat = AVI_DV2_FORMAT;
00604             isInterleave1to1 = avi->isInterleave1to1();
00605         }
00606         else
00607         {
00608             aviFormat = AVI_DV1_FORMAT;
00609         }
00610         isOpenDML = avi->isOpenDML();
00611         filename = s;
00612         return true;
00613     }
00614     else
00615         return false;
00616 
00617 }
00618 
00619 int AVIHandler::GetFrame( Frame &frame, int frameNum )
00620 {
00621     int result = avi->GetDVFrame( frame, frameNum );
00622     if ( result == 0 )
00623     {
00624         /* get the audio from the audio stream, if available */
00625         if ( aviFormat == AVI_DV2_FORMAT )
00626         {
00627             WAVEFORMATEX wav;
00628             FOURCC fccWav = make_fourcc( "01wb" );
00629 
00630             if ( ! isFullyInitialized && 
00631                  avi->getStreamFormat( ( void* ) &wav, make_fourcc( "auds" ) ) )
00632             {
00633                 if ( channels > 0 && channels < 5 )
00634                 {
00635                     // Allocate interleaved audio buffer to accomodate large chunks
00636                     audioBuffer = new int16_t[ wav.nSamplesPerSec * channels * AVI_AUDIO_BUFFER_SECS ];
00637 
00638                     // Allocate non-interleaved audio buffers
00639                     for ( int c = 0; c < channels; c++ )
00640                         audioChannels[ c ] = new int16_t[ 2 * DV_AUDIO_MAX_SAMPLES ];
00641                     
00642                     // Get the audio parameters from AVI for subsequent calls to method
00643                     audioInfo.channels = wav.nChannels;
00644                     audioInfo.frequency = wav.nSamplesPerSec;
00645 
00646                     // Skip initialization on subsequent calls to method
00647                     isFullyInitialized = true;
00648                     cerr << ">>> using audio from separate AVI audio stream" << endl;
00649                 }
00650             }
00651 
00652             // Get the frame from AVI
00653             if ( isInterleave1to1 )
00654             {
00655                 int n = avi->getFrame( audioBuffer, frameNum, fccWav );
00656                 if ( n > 0 )
00657                 {
00658                     // Temporary pointer to audio scratch buffer
00659                     int16_t * s = audioBuffer;
00660     
00661                     // Determine samples in this frame
00662                     audioInfo.samples = n / audioInfo.channels / sizeof( int16_t );
00663                     if ( audioInfo.samples > DV_AUDIO_MAX_SAMPLES )
00664                         audioInfo.samples = DV_AUDIO_MAX_SAMPLES;
00665                     
00666                     // Convert interleaved audio into non-interleaved
00667                     for ( int n = 0; n < audioInfo.samples; ++n )
00668                         for ( int i = 0; i < audioInfo.channels; i++ )
00669                             audioChannels[ i ][ n ] = *s++;
00670                 }
00671             }
00672             else
00673             {
00674                 int16_t* s;
00675                 int availSamples = 0;
00676 
00677                 // Fetch correct audio chunk and get audio buffer offset
00678                 if ( ( s = SeekAudioFrame( frame, frameNum, availSamples ) ) )
00679                 {
00680                     if ( availSamples < audioInfo.samples )
00681                     {
00682                         // Not enough samples in audio buffer
00683                         int n;
00684 
00685                         // Convert interleaved samples remaining in the buffer
00686                         for ( n = 0; n < availSamples; ++n )
00687                             for ( int i = 0; i < audioInfo.channels; i++ )
00688                                 audioChannels[ i ][ n ] = *s++;
00689 
00690                         // Load the next audio chunk into buffer
00691                         if ( ( s = SeekAudioFrame( frame, frameNum + 1, availSamples ) ) )
00692                         {
00693                             // Convert interleaved audio into non-interleaved
00694                             for ( --n; n < audioInfo.samples; ++n )
00695                                 for ( int i = 0; i < audioInfo.channels; i++ )
00696                                     audioChannels[ i ][ n ] = *s++;
00697                         }
00698                         else if ( availSamples >= 0 )
00699                         {
00700                             // Just truncate number of samples in this frame
00701                             audioInfo.samples = availSamples;
00702                         }
00703                     }
00704                     else
00705                     {
00706                         // Convert interleaved audio into non-interleaved
00707                         for ( int n = 0; n < audioInfo.samples; ++n )
00708                             for ( int i = 0; i < audioInfo.channels; i++ )
00709                                 audioChannels[ i ][ n ] = *s++;
00710                     }   
00711                 }
00712                 // <0 signals an error in SeekAudioFrame
00713                 if ( availSamples < 0 )
00714                     return result;
00715             }
00716             // Write interleaved audio into frame
00717             frame.EncodeAudio( audioInfo, audioChannels );
00718         }
00719         // Parse important metadata in DV bitstream
00720         frame.ExtractHeader();
00721     }
00722     return result;
00723 }
00724 
00725 
00726 int16_t* AVIHandler::SeekAudioFrame( Frame& frame, int frameNum, int& availableSize )
00727 {
00728     // Not very optimized - needs to seek to PCM sample offset
00729     FOURCC fccWav = make_fourcc( "01wb" );
00730     frame.ExtractHeader();
00731     off_t offsetBytes = off_t( 0.5 + (float) frameNum / frame.GetFrameRate() * audioInfo.frequency );
00732     offsetBytes *= audioInfo.channels * sizeof(int16_t);
00733 
00734     // If cache miss
00735     if ( offsetBytes < audioOffset || offsetBytes >= ( audioOffset + audioBufferSize ) )
00736     {
00737         int i = 0;
00738         off_t dummy;
00739 
00740         // Find chunk corresponding to offset
00741         for ( audioOffset = 0; avi->GetFrameInfo( dummy, audioBufferSize, i, fccWav ) != -1; ++i )
00742         {
00743             if ( audioBufferSize <= 0 )
00744             {
00745                 availableSize = -1;
00746                 return 0;
00747             }
00748             if ( audioOffset + audioBufferSize > offsetBytes )
00749                 break;
00750             audioOffset += audioBufferSize;
00751         }
00752         // Read chunk if buffer is large enough to hold it
00753         if ( audioBufferSize > ( off_t( audioInfo.frequency ) * audioInfo.channels * sizeof(int16_t) * AVI_AUDIO_BUFFER_SECS ) ||
00754              !avi->getFrame( audioBuffer, i, fccWav ) )
00755         {
00756             return 0;
00757         }
00758     }
00759     // Return how many samples in buffer are available after seeking
00760     availableSize = ( audioBufferSize - int( offsetBytes - audioOffset ) ) >> 2;
00761     // Set number of samples to use in this frame
00762     audioInfo.samples = frame.CalculateNumberSamples( audioInfo.frequency, frameNum );
00763     // Return offset into audio buffer
00764     return audioBuffer + ( ( offsetBytes - audioOffset ) >> 1 );
00765 }
00766 
00767 
00768 void AVIHandler::SetOpenDML( bool flag )
00769 {
00770     isOpenDML = flag;
00771 }
00772 
00773 
00774 bool AVIHandler::GetOpenDML() const
00775 {
00776     return isOpenDML;
00777 }
00778 
00779 
00780 /***************************************************************************/
00781 
00782 #ifdef HAVE_LIBQUICKTIME
00783 
00784 QtHandler::QtHandler() : fd( NULL )
00785 {
00786     extension = ".mov";
00787     Init();
00788 }
00789 
00790 
00791 QtHandler::~QtHandler()
00792 {
00793     Close();
00794 }
00795 
00796 void QtHandler::Init()
00797 {
00798     if ( fd != NULL )
00799         Close();
00800 
00801     fd = NULL;
00802     samplingRate = 48000;
00803     samplesPerBuffer = 0;
00804     channels = 2;
00805     audioBuffer = NULL;
00806     audioChannelBuffer = NULL;
00807     isFullyInitialized = false;
00808 }
00809 
00810 
00811 bool QtHandler::FileIsOpen()
00812 {
00813     return fd != NULL;
00814 }
00815 
00816 
00817 bool QtHandler::Create( const string& filename )
00818 {
00819     Init();
00820 
00821     if ( open( filename.c_str(), O_CREAT | O_TRUNC | O_RDWR | O_NONBLOCK, 0644 ) != -1 )
00822     {
00823         fd = quicktime_open( const_cast<char*>( filename.c_str() ), 0, 1 );
00824         if ( fd != NULL )
00825             FileTracker::GetInstance().Add( filename.c_str() );
00826     }
00827     else
00828         return false;
00829     this->filename = filename;
00830     return true;
00831 }
00832 
00833 void QtHandler::AllocateAudioBuffers()
00834 {
00835     if ( channels > 0 && channels < 5 )
00836     {
00837         audioBufferSize = DV_AUDIO_MAX_SAMPLES * 2;
00838         audioBuffer = new int16_t[ audioBufferSize * channels ];
00839 
00840         audioChannelBuffer = new short int * [ channels ];
00841         for ( int c = 0; c < channels; c++ )
00842             audioChannelBuffer[ c ] = new short int[ audioBufferSize ];
00843         isFullyInitialized = true;
00844     }
00845 }
00846 
00847 inline void QtHandler::DeinterlaceStereo16( void* pInput, int iBytes,
00848         void* pLOutput, void* pROutput )
00849 {
00850     short int * piSampleInput = ( short int* ) pInput;
00851     short int* piSampleLOutput = ( short int* ) pLOutput;
00852     short int* piSampleROutput = ( short int* ) pROutput;
00853 
00854     while ( ( char* ) piSampleInput < ( ( char* ) pInput + iBytes ) )
00855     {
00856         *piSampleLOutput++ = *piSampleInput++;
00857         *piSampleROutput++ = *piSampleInput++;
00858     }
00859 }
00860 
00861 int QtHandler::Write( const Frame& frame )
00862 {
00863     if ( ! isFullyInitialized )
00864     {
00865         AudioInfo audio;
00866         const char* fourcc = frame.IsPAL() ? "dvcp" : QUICKTIME_DV;
00867 
00868         if ( frame.GetAudioInfo( audio ) )
00869         {
00870             channels = 2;
00871             samplingRate = audio.frequency;
00872             quicktime_set_audio( fd, channels, audio.frequency, 16, QUICKTIME_TWOS );
00873         }
00874         else
00875         {
00876             channels = 0;
00877         }
00878 
00879         quicktime_set_video( fd, 1, 720, frame.IsPAL() ? 576 : 480,
00880                              frame.GetFrameRate(), const_cast<char*>( fourcc ) );
00881         AllocateAudioBuffers();
00882     }
00883 
00884     int result = quicktime_write_frame( fd, const_cast<unsigned char*>( frame.data ),
00885                                         frame.GetFrameSize(), 0 );
00886 
00887     if ( channels > 0 )
00888     {
00889         AudioInfo audio;
00890         if ( frame.GetAudioInfo( audio ) && ( unsigned int ) audio.samples < audioBufferSize )
00891         {
00892             long bytesRead = frame.ExtractAudio( audioBuffer );
00893 
00894             if ( bytesRead )
00895             {
00896                 DeinterlaceStereo16( audioBuffer, bytesRead,
00897                                     audioChannelBuffer[ 0 ],
00898                                     audioChannelBuffer[ 1 ] );
00899             }
00900             else
00901             {
00902                 // XXX: desired sample rate is unkown if not initialized with frame
00903                 // carrying audio.
00904                 audio.samples = int( (float)samplingRate / frame.GetFrameRate() );
00905                 memset( audioChannelBuffer[0], 0, audio.samples * sizeof(int16_t) );
00906                 memset( audioChannelBuffer[1], 0, audio.samples * sizeof(int16_t) );
00907             }
00908             quicktime_encode_audio( fd, audioChannelBuffer, NULL, audio.samples );
00909         }
00910     }
00911     return result;
00912 }
00913 
00914 
00915 int QtHandler::Close()
00916 {
00917     if ( fd != NULL )
00918     {
00919         quicktime_close( fd );
00920         fd = NULL;
00921     }
00922     if ( audioBuffer != NULL )
00923     {
00924         delete[] audioBuffer;
00925         audioBuffer = NULL;
00926     }
00927     if ( audioChannelBuffer != NULL )
00928     {
00929         for ( int c = 0; c < channels; c++ )
00930             delete[] audioChannelBuffer[ c ];
00931         delete[] audioChannelBuffer;
00932         audioChannelBuffer = NULL;
00933     }
00934     return 0;
00935 }
00936 
00937 
00938 off_t QtHandler::GetFileSize()
00939 {
00940     struct stat file_status;
00941     stat( filename.c_str(), &file_status );
00942     return file_status.st_size;
00943 }
00944 
00945 
00946 int QtHandler::GetTotalFrames()
00947 {
00948     return ( int ) quicktime_video_length( fd, 0 );
00949 }
00950 
00951 
00952 bool QtHandler::Open( const char *s )
00953 {
00954     Init();
00955 
00956     fd = quicktime_open( ( char * ) s, 1, 0 );
00957     if ( fd == NULL )
00958     {
00959         fprintf( stderr, "Error opening: %s\n", s );
00960         return false;
00961     }
00962 
00963     if ( quicktime_has_video( fd ) <= 0 )
00964     {
00965         fprintf( stderr, "There must be at least one video track in the input file (%s).\n",
00966                  s );
00967         Close();
00968         return false;
00969     }
00970     const char* fourcc = quicktime_video_compressor( fd, 0 );
00971     if ( strncmp( fourcc, QUICKTIME_DV, 4 ) != 0 &&
00972          strncmp( fourcc, "dv25", 4 ) != 0 &&
00973          strncmp( fourcc, "dvsd", 4 ) != 0 &&
00974          strncmp( fourcc, "dvcp", 4 ) != 0 &&
00975          strncmp( fourcc, "AVdv", 4 ) != 0 )
00976     {
00977         fprintf( stderr, "Video in input file (%s) must be in DV format.\n", s );
00978         Close();
00979         return false;
00980     }
00981     if ( quicktime_has_audio( fd ) )
00982         channels = quicktime_track_channels( fd, 0 );
00983     filename = s;
00984     return true;
00985 }
00986 
00987 int QtHandler::GetFrame( Frame &frame, int frameNum )
00988 {
00989     assert( fd != NULL );
00990 
00991     quicktime_set_video_position( fd, frameNum, 0 );
00992     frame.bytesInFrame = quicktime_read_frame( fd, frame.data, 0 );
00993 
00994     if ( quicktime_has_audio( fd ) )
00995     {
00996         AudioInfo info;
00997         double samples;
00998 
00999         if ( ! isFullyInitialized )
01000         {
01001             cerr << ">>> using audio from separarate Quicktime audio track" << endl;
01002             AllocateAudioBuffers();
01003         }
01004 
01005         info.channels = channels;
01006         info.frequency = quicktime_sample_rate( fd, 0 );
01007         samples = info.frequency / quicktime_frame_rate( fd, 0 );
01008         info.samples = (int) samples;
01009         for ( int i = 0; i < channels; i++ )
01010         {
01011             quicktime_set_audio_position( fd, ( int64_t )( frameNum * samples ), 0 );
01012             quicktime_decode_audio( fd, audioChannelBuffer[ i ], NULL, (long) samples, i );
01013         }
01014         frame.EncodeAudio( info, audioChannelBuffer );
01015     }
01016     frame.ExtractHeader();
01017     return 0;
01018 }
01019 #endif

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