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