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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 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 
FileTracker()57 FileTracker::FileTracker( ) : mode( CAPTURE_MOVIE_APPEND )
58 {
59 	cerr << ">> Constructing File Capture tracker" << endl;
60 }
61 
~FileTracker()62 FileTracker::~FileTracker( )
63 {
64 	cerr << ">> Destroying File Capture tracker" << endl;
65 }
66 
GetInstance()67 FileTracker &FileTracker::GetInstance( )
68 {
69 	if ( instance == NULL )
70 		instance = new FileTracker();
71 
72 	return *instance;
73 }
74 
SetMode(FileCaptureMode mode)75 void FileTracker::SetMode( FileCaptureMode mode )
76 {
77 	this->mode = mode;
78 }
79 
GetMode()80 FileCaptureMode FileTracker::GetMode( )
81 {
82 	return this->mode;
83 }
84 
Get(int index)85 char *FileTracker::Get( int index )
86 {
87 	return list[ index ];
88 }
89 
Add(const char * file)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 
Size()99 unsigned int FileTracker::Size( )
100 {
101 	return list.size();
102 }
103 
Clear()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 
FileHandler()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 
~FileHandler()125 FileHandler::~FileHandler()
126 {
127 	/* empty body */
128 }
129 
130 
GetAutoSplit() const131 bool FileHandler::GetAutoSplit() const
132 {
133 	return autoSplit;
134 }
135 
136 
GetTimeStamp() const137 bool FileHandler::GetTimeStamp() const
138 {
139 	return timeStamp;
140 }
141 
142 
GetBaseName() const143 string FileHandler::GetBaseName() const
144 {
145 	return base;
146 }
147 
148 
GetExtension() const149 string FileHandler::GetExtension() const
150 {
151 	return extension;
152 }
153 
154 
GetMaxFrameCount() const155 int FileHandler::GetMaxFrameCount() const
156 {
157 	return maxFrameCount;
158 }
159 
GetMaxFileSize() const160 off_t FileHandler::GetMaxFileSize() const
161 {
162 	return maxFileSize;
163 }
164 
GetFilename() const165 string FileHandler::GetFilename() const
166 {
167 	return filename;
168 }
169 
170 
SetAutoSplit(bool flag)171 void FileHandler::SetAutoSplit( bool flag )
172 {
173 	autoSplit = flag;
174 }
175 
176 
SetTimeStamp(bool flag)177 void FileHandler::SetTimeStamp( bool flag )
178 {
179 	timeStamp = flag;
180 }
181 
182 
SetBaseName(const string & s)183 void FileHandler::SetBaseName( const string& s )
184 {
185 	base = s;
186 }
187 
188 
SetMaxFrameCount(int count)189 void FileHandler::SetMaxFrameCount( int count )
190 {
191 	assert( count >= 0 );
192 	maxFrameCount = count;
193 }
194 
195 
SetEveryNthFrame(int every)196 void FileHandler::SetEveryNthFrame( int every )
197 {
198 	assert ( every > 0 );
199 
200 	everyNthFrame = every;
201 }
202 
203 
SetMaxFileSize(off_t size)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 
Done()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 
RawHandler()340 RawHandler::RawHandler() : fd( -1 )
341 {
342 	extension = ".dv";
343 	numBlocks = 0;
344 }
345 
346 
~RawHandler()347 RawHandler::~RawHandler()
348 {
349 	Close();
350 }
351 
352 
FileIsOpen()353 bool RawHandler::FileIsOpen()
354 {
355 	return fd != -1;
356 }
357 
358 
Create(const string & filename)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 
Close()379 int RawHandler::Close()
380 {
381 	if ( fd != -1 )
382 	{
383 		close( fd );
384 		fd = -1;
385 	}
386 	return 0;
387 }
388 
389 
GetFileSize()390 off_t RawHandler::GetFileSize()
391 {
392 	struct stat file_status;
393 	fstat( fd, &file_status );
394 	return file_status.st_size;
395 }
396 
GetTotalFrames()397 int RawHandler::GetTotalFrames()
398 {
399 	return GetFileSize() / ( 480 * numBlocks );
400 }
401 
402 
Open(const char * s)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 
GetFrame(uint8_t * data,int frameNum)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 
AVIHandler(int format)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 
~AVIHandler()449 AVIHandler::~AVIHandler()
450 {
451 	delete audioBuffer;
452 	audioBuffer = NULL;
453 
454 	for ( int c = 0; c < 4; c++ )
455 	{
456 		delete audioChannels[ c ];
457 		audioChannels[ c ] = NULL;
458 	}
459 
460 	delete avi;
461 }
462 
463 #if 0
464 void AVIHandler::SetSampleFrame( const Frame& sample )
465 {
466 	Pack pack;
467 	sample.GetAudioInfo( audioInfo );
468 	sample.GetVideoInfo( videoInfo );
469 
470 	sample.GetAAUXPack( 0x50, pack );
471 	dvinfo.dwDVAAuxSrc = *( DWORD* ) ( pack.data + 1 );
472 	sample.GetAAUXPack( 0x51, pack );
473 	dvinfo.dwDVAAuxCtl = *( DWORD* ) ( pack.data + 1 );
474 
475 	sample.GetAAUXPack( 0x52, pack );
476 	dvinfo.dwDVAAuxSrc1 = *( DWORD* ) ( pack.data + 1 );
477 	sample.GetAAUXPack( 0x53, pack );
478 	dvinfo.dwDVAAuxCtl1 = *( DWORD* ) ( pack.data + 1 );
479 
480 	sample.GetVAUXPack( 0x60, pack );
481 	dvinfo.dwDVVAuxSrc = *( DWORD* ) ( pack.data + 1 );
482 	sample.GetVAUXPack( 0x61, pack );
483 	dvinfo.dwDVVAuxCtl = *( DWORD* ) ( pack.data + 1 );
484 
485 #ifdef WITH_LIBDV
486 
487 	if ( sample.decoder->std == e_dv_std_smpte_314m )
488 		fccHandler = make_fourcc( "dv25" );
489 #endif
490 }
491 #endif
492 
FileIsOpen()493 bool AVIHandler::FileIsOpen()
494 {
495 	return avi != NULL;
496 }
497 
498 
Create(const string & filename)499 bool AVIHandler::Create( const string& filename )
500 {
501 	assert( avi == NULL );
502 
503 	switch ( aviFormat )
504 	{
505 
506 	case AVI_DV1_FORMAT:
507 		fail_null( avi = new AVI1File );
508 		if ( !avi || avi->Create( filename.c_str() ) == false )
509 			return false;
510 		//avi->Init( videoInfo.isPAL ? AVI_PAL : AVI_NTSC, audioInfo.frequency, AVI_LARGE_INDEX );
511 		break;
512 
513 	case AVI_DV2_FORMAT:
514 		fail_null( avi = new AVI2File );
515 		if ( !avi || avi->Create( filename.c_str() ) == false )
516 			return false;
517 		//if ( GetOpenDML() )
518 			//avi->Init( videoInfo.isPAL ? AVI_PAL : AVI_NTSC, audioInfo.frequency,
519 			           //( AVI_SMALL_INDEX | AVI_LARGE_INDEX ) );
520 		//else
521 			//avi->Init( videoInfo.isPAL ? AVI_PAL : AVI_NTSC, audioInfo.frequency,
522 			           //( AVI_SMALL_INDEX ) );
523 		break;
524 
525 	default:
526 		assert( aviFormat == AVI_DV1_FORMAT || aviFormat == AVI_DV2_FORMAT );
527 	}
528 
529 	avi->setDVINFO( dvinfo );
530 	avi->setFccHandler( make_fourcc( "iavs" ), fccHandler );
531 	avi->setFccHandler( make_fourcc( "vids" ), fccHandler );
532 	this->filename = filename;
533 	FileTracker::GetInstance().Add( filename.c_str() );
534 	return ( avi != NULL );
535 }
536 
537 #if 0
538 int AVIHandler::Write( const Frame& frame )
539 {
540 	assert( avi != NULL );
541 	try
542 	{
543 		return avi->WriteFrame( frame ) ? 0 : -1;
544 	}
545 	catch (...)
546 	{
547 		return -1;
548 	}
549 }
550 #endif
551 
Close()552 int AVIHandler::Close()
553 {
554 	if ( avi != NULL )
555 	{
556 		avi->WriteRIFF();
557 		delete avi;
558 		avi = NULL;
559 	}
560 	if ( audioBuffer != NULL )
561 	{
562 		delete audioBuffer;
563 		audioBuffer = NULL;
564 	}
565 	for ( int c = 0; c < 4; c++ )
566 	{
567 		if ( audioChannels[ c ] != NULL )
568 		{
569 			delete audioChannels[ c ];
570 			audioChannels[ c ] = NULL;
571 		}
572 	}
573 	isFullyInitialized = false;
574 	return 0;
575 }
576 
GetFileSize()577 off_t AVIHandler::GetFileSize()
578 {
579 	return avi->GetFileSize();
580 }
581 
GetTotalFrames()582 int AVIHandler::GetTotalFrames()
583 {
584 	return avi->GetTotalFrames();
585 }
586 
587 
Open(const char * s)588 bool AVIHandler::Open( const char *s )
589 {
590 	assert( avi == NULL );
591 	fail_null( avi = new AVI1File );
592 	if ( avi->Open( s ) )
593 	{
594 		avi->ParseRIFF();
595 		if ( ! (
596 		            avi->verifyStreamFormat( make_fourcc( "dvsd" ) ) ||
597 		            avi->verifyStreamFormat( make_fourcc( "DVSD" ) ) ||
598 		            avi->verifyStreamFormat( make_fourcc( "dvcs" ) ) ||
599 		            avi->verifyStreamFormat( make_fourcc( "DVCS" ) ) ||
600 		            avi->verifyStreamFormat( make_fourcc( "dvcp" ) ) ||
601 		            avi->verifyStreamFormat( make_fourcc( "DVCP" ) ) ||
602 		            avi->verifyStreamFormat( make_fourcc( "CDVC" ) ) ||
603 		            avi->verifyStreamFormat( make_fourcc( "cdvc" ) ) ||
604 		            avi->verifyStreamFormat( make_fourcc( "DV25" ) ) ||
605 		            avi->verifyStreamFormat( make_fourcc( "dv25" ) ) ) )
606 			return false;
607 		avi->ReadIndex();
608 		if ( avi->verifyStream( make_fourcc( "auds" ) ) )
609 			aviFormat = AVI_DV2_FORMAT;
610 		else
611 			aviFormat = AVI_DV1_FORMAT;
612 		isOpenDML = avi->isOpenDML();
613 		filename = s;
614 		return true;
615 	}
616 	else
617 		return false;
618 
619 }
620 
GetFrame(uint8_t * data,int frameNum)621 int AVIHandler::GetFrame( uint8_t *data, int frameNum )
622 {
623 	int result = avi->GetDVFrame( data, frameNum );
624 #if 0
625 	if ( result == 0 )
626 	{
627 		/* get the audio from the audio stream, if available */
628 		if ( aviFormat == AVI_DV2_FORMAT )
629 		{
630 			WAVEFORMATEX wav;
631 
632 			if ( ! isFullyInitialized &&
633 				 avi->getStreamFormat( ( void* ) &wav, make_fourcc( "auds" ) ) )
634 			{
635 				if ( channels > 0 && channels < 5 )
636 				{
637 					// Allocate interleaved audio buffer
638 					audioBuffer = new int16_t[ 2 * DV_AUDIO_MAX_SAMPLES * channels ];
639 
640 					// Allocate non-interleaved audio buffers
641 					for ( int c = 0; c < channels; c++ )
642 						audioChannels[ c ] = new int16_t[ 2 * DV_AUDIO_MAX_SAMPLES ];
643 
644 					// Get the audio parameters from AVI for subsequent calls to method
645 					audioInfo.channels = wav.nChannels;
646 					audioInfo.frequency = wav.nSamplesPerSec;
647 
648 					// Skip initialization on subsequent calls to method
649 					isFullyInitialized = true;
650 					cerr << ">>> using audio from separate AVI audio stream" << endl;
651 				}
652 			}
653 
654 			// Get the frame from AVI
655 			int n = avi->getFrame( audioBuffer, frameNum, make_fourcc( "01wb" ) );
656 			if ( n > 0 )
657 			{
658 				// Temporary pointer to audio scratch buffer
659 				int16_t * s = audioBuffer;
660 
661 				// Determine samples in this frame
662 				audioInfo.samples = n / audioInfo.channels / sizeof( int16_t );
663 
664 				// Convert interleaved audio into non-interleaved
665 				for ( int n = 0; n < audioInfo.samples; ++n )
666 					for ( int i = 0; i < audioInfo.channels; i++ )
667 						audioChannels[ i ][ n ] = *s++;
668 
669 				// Write interleaved audio into frame
670 				frame.EncodeAudio( audioInfo, audioChannels );
671 			}
672 		}
673 
674 		// Parse important metadata in DV bitstream
675 		frame.ExtractHeader();
676 	}
677 #endif
678 	return result;
679 }
680 
681 
SetOpenDML(bool flag)682 void AVIHandler::SetOpenDML( bool flag )
683 {
684 	isOpenDML = flag;
685 }
686 
687 
GetOpenDML() const688 bool AVIHandler::GetOpenDML() const
689 {
690 	return isOpenDML;
691 }
692 
693 
694 /***************************************************************************/
695 
696 #ifdef HAVE_LIBQUICKTIME
697 
698 #ifndef HAVE_LIBDV
699 #define DV_AUDIO_MAX_SAMPLES 1944
700 #endif
701 
702 // Missing fourcc's in libquicktime (allows compilation)
703 #ifndef QUICKTIME_DV_AVID
704 #define QUICKTIME_DV_AVID "AVdv"
705 #endif
706 
707 #ifndef QUICKTIME_DV_AVID_A
708 #define QUICKTIME_DV_AVID_A "dvcp"
709 #endif
710 
711 #ifndef QUICKTIME_DVCPRO
712 #define QUICKTIME_DVCPRO "dvpp"
713 #endif
714 
QtHandler()715 QtHandler::QtHandler() : fd( NULL )
716 {
717 	extension = ".mov";
718 	Init();
719 }
720 
721 
~QtHandler()722 QtHandler::~QtHandler()
723 {
724 	Close();
725 }
726 
Init()727 void QtHandler::Init()
728 {
729 	if ( fd != NULL )
730 		Close();
731 
732 	fd = NULL;
733 	samplingRate = 0;
734 	samplesPerBuffer = 0;
735 	channels = 2;
736 	audioBuffer = NULL;
737 	audioChannelBuffer = NULL;
738 	isFullyInitialized = false;
739 }
740 
741 
FileIsOpen()742 bool QtHandler::FileIsOpen()
743 {
744 	return fd != NULL;
745 }
746 
747 
Create(const string & filename)748 bool QtHandler::Create( const string& filename )
749 {
750 	Init();
751 
752 	if ( open( filename.c_str(), O_CREAT | O_TRUNC | O_RDWR | O_NONBLOCK, 0644 ) != -1 )
753 	{
754 		fd = quicktime_open( const_cast<char*>( filename.c_str() ), 0, 1 );
755 		if ( fd != NULL )
756 			FileTracker::GetInstance().Add( filename.c_str() );
757 	}
758 	else
759 		return false;
760 	this->filename = filename;
761 	return true;
762 }
763 
AllocateAudioBuffers()764 void QtHandler::AllocateAudioBuffers()
765 {
766 	if ( channels > 0 && channels < 5 )
767 	{
768 		audioBufferSize = DV_AUDIO_MAX_SAMPLES * 2;
769 		audioBuffer = new int16_t[ audioBufferSize * channels ];
770 
771 		audioChannelBuffer = new short int * [ channels ];
772 		for ( int c = 0; c < channels; c++ )
773 			audioChannelBuffer[ c ] = new short int[ audioBufferSize ];
774 		isFullyInitialized = true;
775 	}
776 }
777 
DeinterlaceStereo16(void * pInput,int iBytes,void * pLOutput,void * pROutput)778 inline void QtHandler::DeinterlaceStereo16( void* pInput, int iBytes,
779         void* pLOutput, void* pROutput )
780 {
781 	short int * piSampleInput = ( short int* ) pInput;
782 	short int* piSampleLOutput = ( short int* ) pLOutput;
783 	short int* piSampleROutput = ( short int* ) pROutput;
784 
785 	while ( ( char* ) piSampleInput < ( ( char* ) pInput + iBytes ) )
786 	{
787 		*piSampleLOutput++ = *piSampleInput++;
788 		*piSampleROutput++ = *piSampleInput++;
789 	}
790 }
791 
792 #if 0
793 int QtHandler::Write( const Frame& frame )
794 {
795 	if ( ! isFullyInitialized )
796 	{
797 		AudioInfo audio;
798 
799 		if ( frame.GetAudioInfo( audio ) )
800 		{
801 			channels = 2;
802 			quicktime_set_audio( fd, channels, audio.frequency, 16, QUICKTIME_TWOS );
803 		}
804 		else
805 		{
806 			channels = 0;
807 		}
808 
809 		quicktime_set_video( fd, 1, 720, frame.IsPAL() ? 576 : 480,
810 		                     frame.GetFrameRate(), QUICKTIME_DV );
811 		AllocateAudioBuffers();
812 	}
813 
814 	int result = quicktime_write_frame( fd, const_cast<unsigned char*>( frame.data ),
815 	                                    frame.GetFrameSize(), 0 );
816 
817 	if ( channels > 0 )
818 	{
819 		AudioInfo audio;
820 		if ( frame.GetAudioInfo( audio ) && ( unsigned int ) audio.samples < audioBufferSize )
821 		{
822 			long bytesRead = frame.ExtractAudio( audioBuffer );
823 
824 			DeinterlaceStereo16( audioBuffer, bytesRead,
825 			                     audioChannelBuffer[ 0 ],
826 			                     audioChannelBuffer[ 1 ] );
827 
828 			quicktime_encode_audio( fd, audioChannelBuffer, NULL, audio.samples );
829 		}
830 	}
831 	return result;
832 }
833 #endif
834 
Close()835 int QtHandler::Close()
836 {
837 	if ( fd != NULL )
838 	{
839 		quicktime_close( fd );
840 		fd = NULL;
841 	}
842 	if ( audioBuffer != NULL )
843 	{
844 		delete audioBuffer;
845 		audioBuffer = NULL;
846 	}
847 	if ( audioChannelBuffer != NULL )
848 	{
849 		for ( int c = 0; c < channels; c++ )
850 			delete audioChannelBuffer[ c ];
851 		delete audioChannelBuffer;
852 		audioChannelBuffer = NULL;
853 	}
854 	return 0;
855 }
856 
857 
GetFileSize()858 off_t QtHandler::GetFileSize()
859 {
860 	struct stat file_status;
861 	stat( filename.c_str(), &file_status );
862 	return file_status.st_size;
863 }
864 
865 
GetTotalFrames()866 int QtHandler::GetTotalFrames()
867 {
868 	return ( int ) quicktime_video_length( fd, 0 );
869 }
870 
871 
Open(const char * s)872 bool QtHandler::Open( const char *s )
873 {
874 	Init();
875 
876 	fd = quicktime_open( s, 1, 0 );
877 	if ( fd == NULL )
878 	{
879 		fprintf( stderr, "Error opening: %s\n", s );
880 		return false;
881 	}
882 
883 	if ( quicktime_has_video( fd ) <= 0 )
884 	{
885 		fprintf( stderr, "There must be at least one video track in the input file (%s).\n",
886 		         s );
887 		Close();
888 		return false;
889 	}
890 	char * fcc = quicktime_video_compressor( fd, 0 );
891 	if ( strncmp( fcc, QUICKTIME_DV, 4 ) != 0 &&
892 	     strncmp( fcc, QUICKTIME_DV_AVID, 4 ) != 0 &&
893 	     strncmp( fcc, QUICKTIME_DV_AVID_A, 4 ) != 0 &&
894 	     strncmp( fcc, QUICKTIME_DVCPRO, 4 ) != 0 )
895 	{
896 		Close();
897 		return false;
898 	}
899 	if ( quicktime_has_audio( fd ) )
900 		channels = quicktime_track_channels( fd, 0 );
901 	filename = s;
902 	return true;
903 }
904 
GetFrame(uint8_t * data,int frameNum)905 int QtHandler::GetFrame( uint8_t *data, int frameNum )
906 {
907 	assert( fd != NULL );
908 
909 	quicktime_set_video_position( fd, frameNum, 0 );
910 	quicktime_read_frame( fd, data, 0 );
911 
912 #ifdef HAVE_LIBDV
913 	if ( quicktime_has_audio( fd ) )
914 	{
915 		if ( ! isFullyInitialized )
916 			AllocateAudioBuffers();
917 
918 		// Fetch the frequency of the audio track and calc number of samples needed
919 		int frequency = quicktime_sample_rate( fd, 0 );
920 		float fps = ( data[ 3 ] & 0x80 ) ? 25.0f : 29.97f;
921 		int samples = mlt_sample_calculator( fps, frequency, frameNum );
922 		int64_t seek = mlt_sample_calculator_to_now( fps, frequency, frameNum );
923 
924 		// Obtain a dv encoder and initialise it with minimal info
925 		dv_encoder_t *encoder = dv_encoder_new( 0, 0, 0 );
926 		encoder->isPAL = ( data[ 3 ] & 0x80 );
927 		encoder->samples_this_frame = samples;
928 
929 		// Seek to the calculated position and decode
930 		quicktime_set_audio_position( fd, seek, 0 );
931 		lqt_decode_audio( fd, audioChannelBuffer, NULL, (long) samples );
932 
933 		// Encode the audio on the frame and done
934 		dv_encode_full_audio( encoder, audioChannelBuffer, channels, frequency, data );
935 		dv_encoder_free( encoder );
936 	}
937 #endif
938 
939 	return 0;
940 }
941 #endif
942