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