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