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