]> git.sesse.net Git - mlt/blob - src/modules/kino/filehandler.cc
Initial version
[mlt] / src / modules / kino / filehandler.cc
1 /*
2 * filehandler.cc -- saving DV data into different file formats
3 * Copyright (C) 2000 Arne Schirmacher <arne@schirmacher.de>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software Foundation,
17 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20 #include "config.h"
21
22 #include <string>
23 #include <iostream>
24 #include <sstream>
25 #include <iomanip>
26
27 using std::cerr;
28 using std::endl;
29 using std::ostringstream;
30 using std::setw;
31 using std::setfill;
32
33 #include <signal.h>
34 #include <unistd.h>
35 #include <fcntl.h>
36 #include <sys/stat.h>
37 #include <assert.h>
38 #include <time.h>
39 #include <sys/time.h>
40
41 #include "filehandler.h"
42 #include "error.h"
43 #include "riff.h"
44 #include "avi.h"
45
46 FileTracker *FileTracker::instance = NULL;
47
48 FileTracker::FileTracker( ) : mode( CAPTURE_MOVIE_APPEND )
49 {
50         cerr << ">> Constructing File Capture tracker" << endl;
51 }
52
53 FileTracker::~FileTracker( )
54 {
55         cerr << ">> Destroying File Capture tracker" << endl;
56 }
57
58 FileTracker &FileTracker::GetInstance( )
59 {
60         if ( instance == NULL )
61                 instance = new FileTracker();
62
63         return *instance;
64 }
65
66 void FileTracker::SetMode( FileCaptureMode mode )
67 {
68         this->mode = mode;
69 }
70
71 FileCaptureMode FileTracker::GetMode( )
72 {
73         return this->mode;
74 }
75
76 char *FileTracker::Get( int index )
77 {
78         return list[ index ];
79 }
80
81 void FileTracker::Add( const char *file )
82 {
83         if ( this->mode != CAPTURE_IGNORE )
84         {
85                 cerr << ">>>> Registering " << file << " with the tracker" << endl;
86                 list.push_back( strdup( file ) );
87         }
88 }
89
90 unsigned int FileTracker::Size( )
91 {
92         return list.size();
93 }
94
95 void FileTracker::Clear( )
96 {
97         while ( Size() > 0 )
98         {
99                 free( list[ Size() - 1 ] );
100                 list.pop_back( );
101         }
102         this->mode = CAPTURE_MOVIE_APPEND;
103 }
104
105 FileHandler::FileHandler() : done( false ), autoSplit( false ), maxFrameCount( 999999 ),
106                 framesWritten( 0 ), filename( "" )
107 {
108         /* empty body */
109 }
110
111
112 FileHandler::~FileHandler()
113 {
114         /* empty body */
115 }
116
117
118 bool FileHandler::GetAutoSplit() const
119 {
120         return autoSplit;
121 }
122
123
124 bool FileHandler::GetTimeStamp() const
125 {
126         return timeStamp;
127 }
128
129
130 string FileHandler::GetBaseName() const
131 {
132         return base;
133 }
134
135
136 string FileHandler::GetExtension() const
137 {
138         return extension;
139 }
140
141
142 int FileHandler::GetMaxFrameCount() const
143 {
144         return maxFrameCount;
145 }
146
147 off_t FileHandler::GetMaxFileSize() const
148 {
149         return maxFileSize;
150 }
151
152 string FileHandler::GetFilename() const
153 {
154         return filename;
155 }
156
157
158 void FileHandler::SetAutoSplit( bool flag )
159 {
160         autoSplit = flag;
161 }
162
163
164 void FileHandler::SetTimeStamp( bool flag )
165 {
166         timeStamp = flag;
167 }
168
169
170 void FileHandler::SetBaseName( const string& s )
171 {
172         base = s;
173 }
174
175
176 void FileHandler::SetMaxFrameCount( int count )
177 {
178         assert( count >= 0 );
179         maxFrameCount = count;
180 }
181
182
183 void FileHandler::SetEveryNthFrame( int every )
184 {
185         assert ( every > 0 );
186
187         everyNthFrame = every;
188 }
189
190
191 void FileHandler::SetMaxFileSize( off_t size )
192 {
193         assert ( size >= 0 );
194         maxFileSize = size;
195 }
196
197
198 #if 0
199 void FileHandler::SetSampleFrame( const Frame& sample )
200 {
201         /* empty body */
202 }
203 #endif
204
205 bool FileHandler::Done()
206 {
207         return done;
208 }
209
210 #if 0
211 bool FileHandler::WriteFrame( const Frame& frame )
212 {
213         static TimeCode prevTimeCode;
214         TimeCode timeCode;
215
216         /* If the user wants autosplit, start a new file if a
217            new recording is detected. */
218         prevTimeCode.sec = -1;
219         frame.GetTimeCode( timeCode );
220         int time_diff = timeCode.sec - prevTimeCode.sec;
221         bool discontinuity = prevTimeCode.sec != -1 && ( time_diff > 1 || ( time_diff < 0 && time_diff > -59 ) );
222         if ( FileIsOpen() && GetAutoSplit() == true && ( frame.IsNewRecording() || discontinuity ) )
223         {
224                 Close();
225         }
226
227         if ( FileIsOpen() == false )
228         {
229
230                 string filename;
231                 static int counter = 0;
232
233                 if ( GetTimeStamp() == true )
234                 {
235                         ostringstream sb, sb2;
236                         struct tm       date;
237                         string  recDate;
238
239                         if ( ! frame.GetRecordingDate( date ) )
240                         {
241                                 struct timeval tv;
242                                 struct timezone tz;
243                                 gettimeofday( &tv, &tz );
244                                 localtime_r( static_cast< const time_t * >( &tv.tv_sec ), &date );
245                         }
246                         sb << setfill( '0' )
247                         << setw( 4 ) << date.tm_year + 1900 << '.'
248                         << setw( 2 ) << date.tm_mon + 1 << '.'
249                         << setw( 2 ) << date.tm_mday << '_'
250                         << setw( 2 ) << date.tm_hour << '-'
251                         << setw( 2 ) << date.tm_min << '-'
252                         << setw( 2 ) << date.tm_sec;
253                         recDate = sb.str();
254                         sb2 << GetBaseName() << recDate << GetExtension();
255                         filename = sb2.str();
256                         cerr << ">>> Trying " << filename << endl;
257                 }
258                 else
259                 {
260                         struct stat stats;
261                         do
262                         {
263                                 ostringstream sb;
264                                 sb << GetBaseName() << setfill( '0' ) << setw( 3 ) << ++ counter << GetExtension();
265                                 filename = sb.str();
266                                 cerr << ">>> Trying " << filename << endl;
267                         }
268                         while ( stat( filename.c_str(), &stats ) == 0 );
269                 }
270
271                 SetSampleFrame( frame );
272                 if ( Create( filename ) == false )
273                 {
274                         cerr << ">>> Error creating file!" << endl;
275                         return false;
276                 }
277                 framesWritten = 0;
278                 framesToSkip = 0;
279         }
280
281         /* write frame */
282
283         if ( framesToSkip == 0 )
284         {
285                 if ( 0 > Write( frame ) )
286                 {
287                         cerr << ">>> Error writing frame!" << endl;
288                         return false;
289                 }
290                 framesToSkip = everyNthFrame;
291                 ++framesWritten;
292         }
293         framesToSkip--;
294
295         /* If the frame count is exceeded, close the current file.
296            If the autosplit flag is set, a new file will be created in the next iteration.
297            If the flag is not set, we are done. */
298
299         if ( ( GetMaxFrameCount() > 0 ) &&
300                 ( framesWritten >= GetMaxFrameCount() ) )
301         {
302                 Close();
303                 done = !GetAutoSplit();
304         }
305
306         /* If the file size could be exceeded by another frame, close the current file.
307            If the autosplit flag is set, a new file will be created on the next iteration.
308            If the flag is not set, we are done. */
309         /* not exact, but should be good enough to prevent going over. */
310         if ( FileIsOpen() )
311         {
312                 AudioInfo info;
313                 frame.GetAudioInfo( info );
314                 if ( ( GetFileSize() > 0 ) && ( GetMaxFileSize() > 0 ) &&
315                         ( GetFileSize() + frame.GetFrameSize() + info.samples * 4 + 12 )
316                         >= GetMaxFileSize() )
317                 {                     // 12 = sizeof chunk metadata
318                         Close();
319                         done = !GetAutoSplit();
320                 }
321         }
322     prevTimeCode.sec = timeCode.sec;
323         return true;
324 }
325 #endif
326
327 RawHandler::RawHandler() : fd( -1 )
328 {
329         extension = ".dv";
330 }
331
332
333 RawHandler::~RawHandler()
334 {
335         Close();
336 }
337
338
339 bool RawHandler::FileIsOpen()
340 {
341         return fd != -1;
342 }
343
344
345 bool RawHandler::Create( const string& filename )
346 {
347         fd = open( filename.c_str(), O_CREAT | O_TRUNC | O_RDWR | O_NONBLOCK, 0644 );
348         if ( fd != -1 )
349         {
350                 FileTracker::GetInstance().Add( filename.c_str() );
351                 this->filename = filename;
352         }
353         return ( fd != -1 );
354 }
355
356
357 #if 0
358 int RawHandler::Write( const Frame& frame )
359 {
360         int result = write( fd, frame.data, frame.GetFrameSize() );
361         return result;
362 }
363 #endif
364
365 int RawHandler::Close()
366 {
367         if ( fd != -1 )
368         {
369                 close( fd );
370                 fd = -1;
371         }
372         return 0;
373 }
374
375
376 off_t RawHandler::GetFileSize()
377 {
378         struct stat file_status;
379         fstat( fd, &file_status );
380         return file_status.st_size;
381 }
382
383 int RawHandler::GetTotalFrames()
384 {
385         return GetFileSize() / ( 480 * numBlocks );
386 }
387
388
389 bool RawHandler::Open( const char *s )
390 {
391         unsigned char data[ 4 ];
392         assert( fd == -1 );
393         fd = open( s, O_RDONLY | O_NONBLOCK );
394         if ( fd < 0 )
395                 return false;
396         if ( read( fd, data, 4 ) < 0 )
397                 return false;
398         lseek( fd, 0, SEEK_SET );
399         numBlocks = ( ( data[ 3 ] & 0x80 ) == 0 ) ? 250 : 300;
400         filename = s;
401         return true;
402
403 }
404
405 int RawHandler::GetFrame( uint8_t *data, int frameNum )
406 {
407         assert( fd != -1 );
408         int size = 480 * numBlocks;
409         if ( frameNum < 0 )
410                 return -1;
411         off_t offset = ( ( off_t ) frameNum * ( off_t ) size );
412         fail_if( lseek( fd, offset, SEEK_SET ) == ( off_t ) - 1 );
413         if ( read( fd, data, size ) > 0 )
414                 return 0;
415         else
416                 return -1;
417 }
418
419
420 /***************************************************************************/
421
422
423 AVIHandler::AVIHandler( int format ) : avi( NULL ), aviFormat( format ), isOpenDML( false ),
424                 fccHandler( make_fourcc( "dvsd" ) ), channels( 2 ), isFullyInitialized( false ),
425                 audioBuffer( NULL )
426 {
427         extension = ".avi";
428         for ( int c = 0; c < 4; c++ )
429                 audioChannels[ c ] = NULL;
430 }
431
432
433 AVIHandler::~AVIHandler()
434 {
435         if ( audioBuffer != NULL )
436         {
437                 delete audioBuffer;
438                 audioBuffer = NULL;
439         }
440         for ( int c = 0; c < 4; c++ )
441         {
442                 if ( audioChannels[ c ] != NULL )
443                 {
444                         delete audioChannels[ c ];
445                         audioChannels[ c ] = NULL;
446                 }
447         }
448
449         delete avi;
450 }
451
452 #if 0
453 void AVIHandler::SetSampleFrame( const Frame& sample )
454 {
455         Pack pack;
456         sample.GetAudioInfo( audioInfo );
457         sample.GetVideoInfo( videoInfo );
458
459         sample.GetAAUXPack( 0x50, pack );
460         dvinfo.dwDVAAuxSrc = *( DWORD* ) ( pack.data + 1 );
461         sample.GetAAUXPack( 0x51, pack );
462         dvinfo.dwDVAAuxCtl = *( DWORD* ) ( pack.data + 1 );
463
464         sample.GetAAUXPack( 0x52, pack );
465         dvinfo.dwDVAAuxSrc1 = *( DWORD* ) ( pack.data + 1 );
466         sample.GetAAUXPack( 0x53, pack );
467         dvinfo.dwDVAAuxCtl1 = *( DWORD* ) ( pack.data + 1 );
468
469         sample.GetVAUXPack( 0x60, pack );
470         dvinfo.dwDVVAuxSrc = *( DWORD* ) ( pack.data + 1 );
471         sample.GetVAUXPack( 0x61, pack );
472         dvinfo.dwDVVAuxCtl = *( DWORD* ) ( pack.data + 1 );
473
474 #ifdef WITH_LIBDV
475
476         if ( sample.decoder->std == e_dv_std_smpte_314m )
477                 fccHandler = make_fourcc( "dv25" );
478 #endif
479 }
480 #endif
481
482 bool AVIHandler::FileIsOpen()
483 {
484         return avi != NULL;
485 }
486
487
488 bool AVIHandler::Create( const string& filename )
489 {
490         assert( avi == NULL );
491
492         switch ( aviFormat )
493         {
494
495         case AVI_DV1_FORMAT:
496                 fail_null( avi = new AVI1File );
497                 if ( avi->Create( filename.c_str() ) == false )
498                         return false;
499                 //avi->Init( videoInfo.isPAL ? AVI_PAL : AVI_NTSC, audioInfo.frequency, AVI_LARGE_INDEX );
500                 break;
501
502         case AVI_DV2_FORMAT:
503                 fail_null( avi = new AVI2File );
504                 if ( avi->Create( filename.c_str() ) == false )
505                         return false;
506                 //if ( GetOpenDML() )
507                         //avi->Init( videoInfo.isPAL ? AVI_PAL : AVI_NTSC, audioInfo.frequency,
508                                    //( AVI_SMALL_INDEX | AVI_LARGE_INDEX ) );
509                 //else
510                         //avi->Init( videoInfo.isPAL ? AVI_PAL : AVI_NTSC, audioInfo.frequency,
511                                    //( AVI_SMALL_INDEX ) );
512                 break;
513
514         default:
515                 assert( aviFormat == AVI_DV1_FORMAT || aviFormat == AVI_DV2_FORMAT );
516         }
517
518         avi->setDVINFO( dvinfo );
519         avi->setFccHandler( make_fourcc( "iavs" ), fccHandler );
520         avi->setFccHandler( make_fourcc( "vids" ), fccHandler );
521         this->filename = filename;
522         FileTracker::GetInstance().Add( filename.c_str() );
523         return ( avi != NULL );
524 }
525
526 #if 0
527 int AVIHandler::Write( const Frame& frame )
528 {
529         assert( avi != NULL );
530         try
531         {
532                 return avi->WriteFrame( frame ) ? 0 : -1;
533         }
534         catch (...)
535         {
536                 return -1;
537         }
538 }
539 #endif
540
541 int AVIHandler::Close()
542 {
543         if ( avi != NULL )
544         {
545                 avi->WriteRIFF();
546                 delete avi;
547                 avi = NULL;
548         }
549         if ( audioBuffer != NULL )
550         {
551                 delete audioBuffer;
552                 audioBuffer = NULL;
553         }
554         for ( int c = 0; c < 4; c++ )
555         {
556                 if ( audioChannels[ c ] != NULL )
557                 {
558                         delete audioChannels[ c ];
559                         audioChannels[ c ] = NULL;
560                 }
561         }
562         isFullyInitialized = false;
563         return 0;
564 }
565
566 off_t AVIHandler::GetFileSize()
567 {
568         return avi->GetFileSize();
569 }
570
571 int AVIHandler::GetTotalFrames()
572 {
573         return avi->GetTotalFrames();
574 }
575
576
577 bool AVIHandler::Open( const char *s )
578 {
579         assert( avi == NULL );
580         fail_null( avi = new AVI1File );
581         if ( avi->Open( s ) )
582         {
583                 avi->ParseRIFF();
584                 if ( ! (
585                             avi->verifyStreamFormat( make_fourcc( "dvsd" ) ) ||
586                             avi->verifyStreamFormat( make_fourcc( "DVSD" ) ) ||
587                             avi->verifyStreamFormat( make_fourcc( "dvcs" ) ) ||
588                             avi->verifyStreamFormat( make_fourcc( "DVCS" ) ) ||
589                             avi->verifyStreamFormat( make_fourcc( "dvcp" ) ) ||
590                             avi->verifyStreamFormat( make_fourcc( "DVCP" ) ) ||
591                             avi->verifyStreamFormat( make_fourcc( "CDVC" ) ) ||
592                             avi->verifyStreamFormat( make_fourcc( "cdvc" ) ) ||
593                             avi->verifyStreamFormat( make_fourcc( "DV25" ) ) ||
594                             avi->verifyStreamFormat( make_fourcc( "dv25" ) ) ) )
595                         return false;
596                 avi->ReadIndex();
597                 if ( avi->verifyStream( make_fourcc( "auds" ) ) )
598                         aviFormat = AVI_DV2_FORMAT;
599                 else
600                         aviFormat = AVI_DV1_FORMAT;
601                 isOpenDML = avi->isOpenDML();
602                 filename = s;
603                 return true;
604         }
605         else
606                 return false;
607
608 }
609
610 int AVIHandler::GetFrame( uint8_t *data, int frameNum )
611 {
612         int result = avi->GetDVFrame( data, frameNum );
613 #if 0
614         if ( result == 0 )
615         {
616                 /* get the audio from the audio stream, if available */
617                 if ( aviFormat == AVI_DV2_FORMAT )
618                 {
619                         WAVEFORMATEX wav;
620
621                         if ( ! isFullyInitialized && 
622                                  avi->getStreamFormat( ( void* ) &wav, make_fourcc( "auds" ) ) )
623                         {
624                                 if ( channels > 0 && channels < 5 )
625                                 {
626                                         // Allocate interleaved audio buffer
627                                         audioBuffer = new int16_t[ 2 * DV_AUDIO_MAX_SAMPLES * channels ];
628
629                                         // Allocate non-interleaved audio buffers
630                                         for ( int c = 0; c < channels; c++ )
631                                                 audioChannels[ c ] = new int16_t[ 2 * DV_AUDIO_MAX_SAMPLES ];
632                                         
633                                         // Get the audio parameters from AVI for subsequent calls to method
634                                         audioInfo.channels = wav.nChannels;
635                                         audioInfo.frequency = wav.nSamplesPerSec;
636
637                                         // Skip initialization on subsequent calls to method
638                                         isFullyInitialized = true;
639                                         cerr << ">>> using audio from separate AVI audio stream" << endl;
640                                 }
641                         }
642
643                         // Get the frame from AVI
644                         int n = avi->getFrame( audioBuffer, frameNum, make_fourcc( "01wb" ) );
645                         if ( n > 0 )
646                         {
647                                 // Temporary pointer to audio scratch buffer
648                                 int16_t * s = audioBuffer;
649
650                                 // Determine samples in this frame
651                                 audioInfo.samples = n / audioInfo.channels / sizeof( int16_t );
652                                 
653                                 // Convert interleaved audio into non-interleaved
654                                 for ( int n = 0; n < audioInfo.samples; ++n )
655                                         for ( int i = 0; i < audioInfo.channels; i++ )
656                                                 audioChannels[ i ][ n ] = *s++;
657
658                                 // Write interleaved audio into frame
659                                 frame.EncodeAudio( audioInfo, audioChannels );
660                         }
661                 }
662
663                 // Parse important metadata in DV bitstream
664                 frame.ExtractHeader();
665         }
666 #endif
667         return result;
668 }
669
670
671 void AVIHandler::SetOpenDML( bool flag )
672 {
673         isOpenDML = flag;
674 }
675
676
677 bool AVIHandler::GetOpenDML() const
678 {
679         return isOpenDML;
680 }
681
682
683 /***************************************************************************/
684
685 #ifdef HAVE_LIBQUICKTIME
686
687 #ifndef HAVE_LIBDV
688 #define DV_AUDIO_MAX_SAMPLES 1944
689 #endif
690
691 QtHandler::QtHandler() : fd( NULL )
692 {
693         extension = ".mov";
694         Init();
695 }
696
697
698 QtHandler::~QtHandler()
699 {
700         Close();
701 }
702
703 void QtHandler::Init()
704 {
705         if ( fd != NULL )
706                 Close();
707
708         fd = NULL;
709         samplingRate = 0;
710         samplesPerBuffer = 0;
711         channels = 2;
712         audioBuffer = NULL;
713         audioChannelBuffer = NULL;
714         isFullyInitialized = false;
715 }
716
717
718 bool QtHandler::FileIsOpen()
719 {
720         return fd != NULL;
721 }
722
723
724 bool QtHandler::Create( const string& filename )
725 {
726         Init();
727
728         if ( open( filename.c_str(), O_CREAT | O_TRUNC | O_RDWR | O_NONBLOCK, 0644 ) != -1 )
729         {
730                 fd = quicktime_open( const_cast<char*>( filename.c_str() ), 0, 1 );
731                 if ( fd != NULL )
732                         FileTracker::GetInstance().Add( filename.c_str() );
733         }
734         else
735                 return false;
736         this->filename = filename;
737         return true;
738 }
739
740 void QtHandler::AllocateAudioBuffers()
741 {
742         if ( channels > 0 && channels < 5 )
743         {
744                 audioBufferSize = DV_AUDIO_MAX_SAMPLES * 2;
745                 audioBuffer = new int16_t[ audioBufferSize * channels ];
746
747                 audioChannelBuffer = new short int * [ channels ];
748                 for ( int c = 0; c < channels; c++ )
749                         audioChannelBuffer[ c ] = new short int[ audioBufferSize ];
750                 isFullyInitialized = true;
751         }
752 }
753
754 inline void QtHandler::DeinterlaceStereo16( void* pInput, int iBytes,
755         void* pLOutput, void* pROutput )
756 {
757         short int * piSampleInput = ( short int* ) pInput;
758         short int* piSampleLOutput = ( short int* ) pLOutput;
759         short int* piSampleROutput = ( short int* ) pROutput;
760
761         while ( ( char* ) piSampleInput < ( ( char* ) pInput + iBytes ) )
762         {
763                 *piSampleLOutput++ = *piSampleInput++;
764                 *piSampleROutput++ = *piSampleInput++;
765         }
766 }
767
768 #if 0
769 int QtHandler::Write( const Frame& frame )
770 {
771         if ( ! isFullyInitialized )
772         {
773                 AudioInfo audio;
774
775                 if ( frame.GetAudioInfo( audio ) )
776                 {
777                         channels = 2;
778                         quicktime_set_audio( fd, channels, audio.frequency, 16, QUICKTIME_TWOS );
779                 }
780                 else
781                 {
782                         channels = 0;
783                 }
784
785                 quicktime_set_video( fd, 1, 720, frame.IsPAL() ? 576 : 480,
786                                      frame.GetFrameRate(), QUICKTIME_DV );
787                 AllocateAudioBuffers();
788         }
789
790         int result = quicktime_write_frame( fd, const_cast<unsigned char*>( frame.data ),
791                                             frame.GetFrameSize(), 0 );
792
793         if ( channels > 0 )
794         {
795                 AudioInfo audio;
796                 if ( frame.GetAudioInfo( audio ) && ( unsigned int ) audio.samples < audioBufferSize )
797                 {
798                         long bytesRead = frame.ExtractAudio( audioBuffer );
799
800                         DeinterlaceStereo16( audioBuffer, bytesRead,
801                                              audioChannelBuffer[ 0 ],
802                                              audioChannelBuffer[ 1 ] );
803
804                         quicktime_encode_audio( fd, audioChannelBuffer, NULL, audio.samples );
805                 }
806         }
807         return result;
808 }
809 #endif
810
811 int QtHandler::Close()
812 {
813         if ( fd != NULL )
814         {
815                 quicktime_close( fd );
816                 fd = NULL;
817         }
818         if ( audioBuffer != NULL )
819         {
820                 delete audioBuffer;
821                 audioBuffer = NULL;
822         }
823         if ( audioChannelBuffer != NULL )
824         {
825                 for ( int c = 0; c < channels; c++ )
826                         delete audioChannelBuffer[ c ];
827                 delete audioChannelBuffer;
828                 audioChannelBuffer = NULL;
829         }
830         return 0;
831 }
832
833
834 off_t QtHandler::GetFileSize()
835 {
836         struct stat file_status;
837         fstat( fileno( fd->stream ), &file_status );
838         return file_status.st_size;
839 }
840
841
842 int QtHandler::GetTotalFrames()
843 {
844         return ( int ) quicktime_video_length( fd, 0 );
845 }
846
847
848 bool QtHandler::Open( const char *s )
849 {
850         Init();
851
852         fd = quicktime_open( ( char * ) s, 1, 0 );
853         if ( fd == NULL )
854         {
855                 fprintf( stderr, "Error opening: %s\n", s );
856                 return false;
857         }
858
859         if ( quicktime_has_video( fd ) <= 0 )
860         {
861                 fprintf( stderr, "There must be at least one video track in the input file (%s).\n",
862                          s );
863                 Close();
864                 return false;
865         }
866         if ( strncmp( quicktime_video_compressor( fd, 0 ), QUICKTIME_DV, 4 ) != 0 )
867         {
868                 fprintf( stderr, "Video in input file (%s) must be in DV format.\n", s );
869                 Close();
870                 return false;
871         }
872         if ( quicktime_has_audio( fd ) )
873                 channels = quicktime_track_channels( fd, 0 );
874         filename = s;
875         return true;
876 }
877
878 int QtHandler::GetFrame( uint8_t *data, int frameNum )
879 {
880         assert( fd != NULL );
881
882         quicktime_set_video_position( fd, frameNum, 0 );
883         quicktime_read_frame( fd, data, 0 );
884
885 #if 0
886         if ( quicktime_has_audio( fd ) )
887         {
888                 AudioInfo info;
889                 double samples;
890
891                 if ( ! isFullyInitialized )
892                 {
893                         cerr << ">>> using audio from separarate Quicktime audio track" << endl;
894                         AllocateAudioBuffers();
895                 }
896
897                 info.channels = channels;
898                 info.frequency = quicktime_sample_rate( fd, 0 );
899                 samples = info.frequency / quicktime_frame_rate( fd, 0 );
900                 info.samples = (int) samples;
901                 for ( int i = 0; i < channels; i++ )
902                 {
903                         quicktime_set_audio_position( fd, ( int64_t )( frameNum * samples ), 0 );
904                         quicktime_decode_audio( fd, audioChannelBuffer[ i ], NULL, (long) samples, i );
905                 }
906                 frame.EncodeAudio( info, audioChannelBuffer );
907         }
908         frame.ExtractHeader();
909 #endif
910
911         return 0;
912 }
913 #endif