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