1 /*****************************************************************************
2 * quicktime.c: a quicktime decoder that uses the QT library/dll
3 *****************************************************************************
4 * Copyright (C) 2003 VideoLAN
5 * $Id: quicktime.c,v 1.3 2003/05/21 19:55:25 hartman Exp $
7 * Authors: Laurent Aimar <fenrir at via.ecp.fr>
8 * Derk-Jan Hartman <thedj at users.sf.net>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
31 #include <vlc/decoder.h>
32 #include <vlc/input.h>
34 #include <stdlib.h> /* malloc(), free() */
35 #include <string.h> /* strdup() */
39 #include <QuickTime/QuickTimeComponents.h>
40 #include <QuickTime/Movies.h>
41 #include <QuickTime/ImageCodec.h>
44 /*****************************************************************************
46 *****************************************************************************/
47 static int OpenDecoder ( vlc_object_t * );
49 static int RunDecoderAudio( decoder_fifo_t * );
51 /*****************************************************************************
53 *****************************************************************************/
56 set_description( _("QT binary library decoder") );
57 set_capability( "decoder", 10 );
58 set_callbacks( OpenDecoder, NULL );
61 var_Create( p_module->p_libvlc, "qt_mutex", VLC_VAR_MUTEX );
66 #define FCC( a, b , c, d ) \
67 ((uint32_t)( ((a)<<24)|((b)<<16)|((c)<<8)|(d)))
70 typedef struct OpaqueSoundConverter* SoundConverter;
71 typedef unsigned long UnsignedFixed;
73 typedef struct SoundComponentData {
78 UnsignedFixed sampleRate;
87 /* Input properties */
88 decoder_fifo_t *p_fifo;
94 OSErr (*InitializeQTML) ( long flags );
96 OSErr (*EnterMovies) ( void );
97 OSErr (*ExitMovies) ( void );
98 int (*SoundConverterOpen) ( const SoundComponentData *, const SoundComponentData *, SoundConverter* );
99 int (*SoundConverterClose) ( SoundConverter );
100 int (*SoundConverterSetInfo) ( SoundConverter , OSType ,void * );
101 int (*SoundConverterGetBufferSizes) ( SoundConverter, unsigned long,
102 unsigned long*, unsigned long*, unsigned long* );
103 int (*SoundConverterBeginConversion)( SoundConverter );
104 int (*SoundConverterEndConversion) ( SoundConverter, void *, unsigned long *, unsigned long *);
105 int (*SoundConverterConvertBuffer) ( SoundConverter, const void *, unsigned long, void *,
106 unsigned long *,unsigned long * );
107 SoundConverter myConverter;
108 SoundComponentData InputFormatInfo, OutputFormatInfo;
111 unsigned int InFrameSize;
112 unsigned int OutFrameSize;
114 /* Output properties */
115 aout_instance_t * p_aout; /* opaque */
116 aout_input_t * p_aout_input; /* opaque */
117 audio_sample_format_t output_format;
123 unsigned int i_buffer;
124 unsigned int i_buffer_size;
127 uint8_t buffer_out[1000000]; /* FIXME */
131 static int pi_channels_maps[6] =
135 AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,
136 AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER,
137 AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARLEFT,
138 AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
139 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARLEFT
143 static uint16_t GetWBE( uint8_t *p_buff )
145 return( (p_buff[0]<<8) + p_buff[1] );
148 static uint32_t GetDWBE( uint8_t *p_buff )
150 return( (p_buff[0] << 24) + ( p_buff[1] <<16 ) +
151 ( p_buff[2] <<8 ) + p_buff[3] );
155 static int GetPESData( uint8_t *p_buf, int i_max, pes_packet_t *p_pes )
160 data_packet_t *p_data;
163 p_data = p_pes->p_first;
164 while( p_data != NULL && i_count < i_max )
167 i_copy = __MIN( p_data->p_payload_end - p_data->p_payload_start,
173 p_data->p_payload_start,
177 p_data = p_data->p_next;
182 if( i_count < i_max )
184 memset( p_buf, 0, i_max - i_count );
189 /*****************************************************************************
190 * OpenDecoder: probe the decoder and return score
191 *****************************************************************************
192 * Tries to launch a decoder and return score so that the interface is able
194 *****************************************************************************/
195 static int OpenDecoder( vlc_object_t *p_this )
197 decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this;
199 switch( p_fifo->i_fourcc )
201 case VLC_FOURCC('Q','D','M','C'): /* QDesign */
202 case VLC_FOURCC('Q','D','M','2'): /* QDesign* 2 */
203 case VLC_FOURCC('Q','c','l','p'): /* Qualcomm Purevoice Codec */
204 case VLC_FOURCC('Q','C','L','P'): /* Qualcomm Purevoice Codec */
205 case VLC_FOURCC('M','A','C','3'): /* MACE3 audio decoder */
206 case VLC_FOURCC('M','A','C','6'): /* MACE6 audio decoder */
207 case VLC_FOURCC('f','l','3','2'): /* 32-bit Floating Point */
208 case VLC_FOURCC('f','l','6','4'): /* 64-bit Floating Point */
209 case VLC_FOURCC('i','n','2','4'): /* 24-bit Interger */
210 case VLC_FOURCC('i','n','3','2'): /* 32-bit Integer */
211 case VLC_FOURCC('m','p','4','a'): /* MPEG-4 Audio */
212 case VLC_FOURCC('d','v','c','a'): /* DV Audio */
213 case VLC_FOURCC('s','o','w','t'): /* 16-bit Little Endian */
214 case VLC_FOURCC('t','w','o','s'): /* 16-bit Big Endian */
215 case VLC_FOURCC('a','l','a','w'): /* ALaw 2:1 */
216 case VLC_FOURCC('u','l','a','w'): /* mu-Law 2:1 */
217 case VLC_FOURCC('r','a','w',' '): /* 8-bit offset binaries */
218 case 0x31: /* MS GSM */
219 case 0x32: /* MSN Audio */
220 case 0x0011: /* DVI IMA */
221 case 0x6D730002: /* Microsoft ADPCM-ACM */
222 case 0x6D730011: /* DVI Intel IMAADPCM-ACM */
224 p_fifo->pf_run = RunDecoderAudio;
231 /****************************************************************************
232 ****************************************************************************
236 ****************************************************************************
237 ****************************************************************************/
239 static int InitThreadAudio ( adec_thread_t * );
240 static void DecodeThreadAudio ( adec_thread_t * );
241 static void EndThreadAudio ( adec_thread_t * );
243 static int RunDecoderAudio( decoder_fifo_t *p_fifo )
245 adec_thread_t *p_dec;
248 p_dec = malloc( sizeof( adec_thread_t ) );
251 msg_Err( p_fifo, "out of memory" );
252 DecoderError( p_fifo );
255 p_dec->p_fifo = p_fifo;
257 if( InitThreadAudio( p_dec ) != 0 )
259 DecoderError( p_fifo );
263 while( !p_dec->p_fifo->b_die && !p_dec->p_fifo->b_error )
265 DecodeThreadAudio( p_dec );
269 if( ( b_error = p_dec->p_fifo->b_error ) )
271 DecoderError( p_dec->p_fifo );
274 EndThreadAudio( p_dec );
283 static int InitThreadAudio ( adec_thread_t *p_dec )
288 unsigned long WantedBufferSize;
289 unsigned long InputBufferSize = 0;
290 unsigned long OutputBufferSize = 0;
294 if( !( p_wf = (WAVEFORMATEX*)p_dec->p_fifo->p_waveformatex ) )
296 msg_Err( p_dec->p_fifo, "missing WAVEFORMATEX");
299 memcpy( fcc, &p_dec->p_fifo->i_fourcc, 4 );
301 /* get lock, avoid segfault */
302 var_Get( p_dec->p_fifo->p_libvlc, "qt_mutex", &lockval );
303 vlc_mutex_lock( lockval.p_address );
307 p_dec->ldt_fs = Setup_LDT_Keeper();
309 msg_Dbg( p_dec->p_fifo, "trying to load `qtmlClient.dll'" );
310 if( !( p_dec->qtml = LoadLibraryA("qtmlClient.dll") ) )
312 msg_Err( p_dec->p_fifo, "cannot load qtmlClient.dll");
316 msg_Dbg( p_dec->p_fifo, "qtmlClient.dll loaded" );
318 /* (void*) to shut up gcc */
319 p_dec->InitializeQTML = (void*)InitializeQTML;
321 p_dec->SoundConverterOpen = (void*)SoundConverterOpen;
322 p_dec->SoundConverterClose = (void*)SoundConverterClose;
323 p_dec->SoundConverterSetInfo = (void*)SoundConverterSetInfo;
324 p_dec->SoundConverterGetBufferSizes = (void*)SoundConverterGetBufferSizes;
325 p_dec->SoundConverterConvertBuffer = (void*)SoundConverterConvertBuffer;
326 p_dec->SoundConverterBeginConversion= (void*)SoundConverterBeginConversion;
327 p_dec->SoundConverterEndConversion = (void*)SoundConverterEndConversion;
330 if( !p_dec->InitializeQTML ||
331 !p_dec->SoundConverterOpen || !p_dec->SoundConverterClose ||
332 !p_dec->SoundConverterSetInfo || !p_dec->SoundConverterGetBufferSizes ||
333 !p_dec->SoundConverterConvertBuffer ||
334 !p_dec->SoundConverterBeginConversion || !p_dec->SoundConverterEndConversion )
336 msg_Err( p_dec->p_fifo, "error getting qtmlClient.dll symbols");
340 if( ( i_error = p_dec->InitializeQTML( 6 + 16 ) ) )
342 msg_Dbg( p_dec->p_fifo, "error while InitializeQTML = %d", i_error );
347 /* input format settings */
348 p_dec->InputFormatInfo.flags = 0;
349 p_dec->InputFormatInfo.sampleCount = 0;
350 p_dec->InputFormatInfo.buffer = NULL;
351 p_dec->InputFormatInfo.reserved = 0;
352 p_dec->InputFormatInfo.numChannels = p_wf->nChannels;
353 p_dec->InputFormatInfo.sampleSize = p_wf->wBitsPerSample;
354 p_dec->InputFormatInfo.sampleRate = p_wf->nSamplesPerSec;
355 p_dec->InputFormatInfo.format = FCC( fcc[0], fcc[1], fcc[2], fcc[3] );
357 /* output format settings */
358 p_dec->OutputFormatInfo.flags = 0;
359 p_dec->OutputFormatInfo.sampleCount = 0;
360 p_dec->OutputFormatInfo.buffer = NULL;
361 p_dec->OutputFormatInfo.reserved = 0;
362 p_dec->OutputFormatInfo.numChannels = p_wf->nChannels;
363 p_dec->OutputFormatInfo.sampleSize = 16;
364 p_dec->OutputFormatInfo.sampleRate = p_wf->nSamplesPerSec;
365 p_dec->OutputFormatInfo.format = FCC( 'N', 'O', 'N', 'E' );
368 /* on OS X QT is not threadsafe */
369 vlc_mutex_lock( &p_dec->p_fifo->p_vlc->quicktime_lock );
372 i_error = p_dec->SoundConverterOpen( &p_dec->InputFormatInfo,
373 &p_dec->OutputFormatInfo,
374 &p_dec->myConverter );
376 vlc_mutex_unlock( &p_dec->p_fifo->p_vlc->quicktime_lock );
381 msg_Dbg( p_dec->p_fifo, "error while SoundConverterOpen = %d", i_error );
385 if( p_wf->cbSize > 36 + 8 )
387 i_error = p_dec->SoundConverterSetInfo( p_dec->myConverter,
388 FCC( 'w', 'a', 'v', 'e' ),
389 ((uint8_t*)&p_wf[1]) + 36 + 8 );
390 msg_Dbg( p_dec->p_fifo, "error while SoundConverterSetInfo = %d", i_error );
393 WantedBufferSize = p_dec->OutputFormatInfo.numChannels * p_dec->OutputFormatInfo.sampleRate * 2;
394 p_dec->FramesToGet = 0;
395 i_error = p_dec->SoundConverterGetBufferSizes( p_dec->myConverter,
396 WantedBufferSize, &p_dec->FramesToGet,
397 &InputBufferSize, &OutputBufferSize );
399 msg_Dbg( p_dec->p_fifo, "WantedBufferSize=%li InputBufferSize=%li OutputBufferSize=%li FramesToGet=%li",
400 WantedBufferSize, InputBufferSize, OutputBufferSize, p_dec->FramesToGet );
402 p_dec->InFrameSize = (InputBufferSize + p_dec->FramesToGet - 1 ) / p_dec->FramesToGet;
403 p_dec->OutFrameSize = OutputBufferSize / p_dec->FramesToGet;
405 msg_Dbg( p_dec->p_fifo, "frame size %d -> %d", p_dec->InFrameSize, p_dec->OutFrameSize );
407 i_error = p_dec->SoundConverterBeginConversion( p_dec->myConverter );
410 msg_Err( p_dec->p_fifo, "error while SoundConverterBeginConversion = %d", i_error );
414 p_dec->output_format.i_format = AOUT_FMT_S16_NE;
415 p_dec->output_format.i_rate = p_wf->nSamplesPerSec;
416 p_dec->output_format.i_physical_channels =
417 p_dec->output_format.i_original_channels =
418 pi_channels_maps[p_wf->nChannels];
419 aout_DateInit( &p_dec->date, p_dec->output_format.i_rate );
420 p_dec->p_aout_input = aout_DecNew( p_dec->p_fifo,
422 &p_dec->output_format );
423 if( !p_dec->p_aout_input )
425 msg_Err( p_dec->p_fifo, "cannot create aout" );
430 p_dec->i_buffer_size = 100*1000;
431 p_dec->p_buffer = malloc( p_dec->i_buffer_size );
435 vlc_mutex_unlock( lockval.p_address );
440 Restore_LDT_Keeper( p_dec->ldt_fs );
442 vlc_mutex_unlock( lockval.p_address );
446 static void DecodeThreadAudio ( adec_thread_t *p_dec )
452 var_Get( p_dec->p_fifo->p_libvlc, "qt_mutex", &lockval );
454 input_ExtractPES( p_dec->p_fifo, &p_pes );
457 msg_Err( p_dec->p_fifo, "cannot get PES" );
458 p_dec->p_fifo->b_error = 1;
461 /*if( p_dec->pts <= 0 )*/
463 p_dec->pts = p_pes->i_pts;
466 if( p_pes->i_pes_size > 0 && p_pes->i_pts > mdate() )
469 if( p_dec->i_buffer_size < p_dec->i_buffer + p_pes->i_pes_size )
471 p_dec->i_buffer_size = p_dec->i_buffer + p_pes->i_pes_size + 1024;
472 p_dec->p_buffer = realloc( p_dec->p_buffer,
473 p_dec->i_buffer_size );
476 GetPESData( &p_dec->p_buffer[p_dec->i_buffer],
477 p_dec->i_buffer_size - p_dec->i_buffer, p_pes );
478 p_dec->i_buffer += p_pes->i_pes_size;
480 if( p_dec->i_buffer > p_dec->InFrameSize )
482 int i_frames = p_dec->i_buffer / p_dec->InFrameSize;
483 long i_out_frames, i_out_bytes;
486 vlc_mutex_lock( lockval.p_address );
487 i_error = p_dec->SoundConverterConvertBuffer( p_dec->myConverter,
491 &i_out_frames, &i_out_bytes );
492 vlc_mutex_unlock( lockval.p_address );
494 /*msg_Dbg( p_dec->p_fifo, "decoded %d frames -> %ld frames (error=%d)",
495 i_frames, i_out_frames, i_error );
497 msg_Dbg( p_dec->p_fifo, "decoded %ld frames = %ld bytes", i_out_frames, i_out_bytes );*/
498 p_dec->i_buffer -= i_frames * p_dec->InFrameSize;
499 if( p_dec->i_buffer > 0 )
501 memmove( &p_dec->p_buffer[0],
502 &p_dec->p_buffer[i_frames * p_dec->InFrameSize],
506 if( i_out_frames > 0 )
508 aout_buffer_t *p_aout_buffer;
509 uint8_t *p_buff = p_dec->buffer_out;
511 /*msg_Dbg( p_dec->p_fifo, "pts=%lld date=%lld dateget=%lld",
512 p_dec->pts, mdate(), aout_DateGet( &p_dec->date ) );*/
514 if( p_dec->pts != 0 && p_dec->pts != aout_DateGet( &p_dec->date ) )
516 aout_DateSet( &p_dec->date, p_dec->pts );
518 else if( !aout_DateGet( &p_dec->date ) )
520 input_DeletePES( p_dec->p_fifo->p_packets_mgt, p_pes );
524 while( i_out_frames > 0 )
528 i_frames = __MIN( i_out_frames, 1000 );
529 p_aout_buffer = aout_DecNewBuffer( p_dec->p_aout,
534 msg_Err( p_dec->p_fifo, "cannot get aout buffer" );
535 p_dec->p_fifo->b_error = 1;
538 p_aout_buffer->start_date = aout_DateGet( &p_dec->date );
539 p_aout_buffer->end_date = aout_DateIncrement( &p_dec->date,
542 memcpy( p_aout_buffer->p_buffer,
544 p_aout_buffer->i_nb_bytes );
546 /*msg_Dbg( p_dec->p_fifo, "==> start=%lld end=%lld date=%lld",
547 p_aout_buffer->start_date, p_aout_buffer->end_date, mdate() );*/
548 aout_DecPlay( p_dec->p_aout, p_dec->p_aout_input, p_aout_buffer );
549 /*msg_Dbg( p_dec->p_fifo, "s1=%d s2=%d", i_framesperchannels, p_aout_buffer->i_nb_samples );
551 msg_Dbg( p_dec->p_fifo, "i_nb_bytes=%d i_nb_samples*4=%d", p_aout_buffer->i_nb_bytes, p_aout_buffer->i_nb_samples * 4 );*/
552 p_buff += i_frames * 4;
553 i_out_frames -= i_frames;
561 input_DeletePES( p_dec->p_fifo->p_packets_mgt, p_pes );
563 static void EndThreadAudio ( adec_thread_t *p_dec )
567 unsigned long ConvertedFrames=0;
568 unsigned long ConvertedBytes=0;
570 /* get lock, avoid segfault */
571 var_Get( p_dec->p_fifo->p_libvlc, "qt_mutex", &lockval );
572 vlc_mutex_lock( lockval.p_address );
574 i_error = p_dec->SoundConverterEndConversion( p_dec->myConverter, NULL, &ConvertedFrames, &ConvertedBytes );
575 msg_Dbg( p_dec->p_fifo, "SoundConverterEndConversion => %d", i_error );
577 i_error = p_dec->SoundConverterClose( p_dec->myConverter );
578 msg_Dbg( p_dec->p_fifo, "SoundConverterClose => %d", i_error );
580 /*FreeLibrary( p_dec->qtml );
581 msg_Dbg( p_dec->p_fifo, "FreeLibrary ok." ); */
583 vlc_mutex_unlock( lockval.p_address );
585 /*Restore_LDT_Keeper( p_dec->ldt_fs );
586 msg_Dbg( p_dec->p_fifo, "Restore_LDT_Keeper" ); */
590 aout_DecDelete( p_dec->p_aout, p_dec->p_aout_input );
593 /* Video part will follow when the LOADER code arrives */