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