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