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.2 2003/05/21 15:40:03 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('i','m','a','4'): /* IMA ADPCM */
208 case 0x31: /* MS GSM */
209 case 0x32: /* MSN Audio */
210 case 0x0011: /* DVI IMA */
212 p_fifo->pf_run = RunDecoderAudio;
219 /****************************************************************************
220 ****************************************************************************
224 ****************************************************************************
225 ****************************************************************************/
227 static int InitThreadAudio ( adec_thread_t * );
228 static void DecodeThreadAudio ( adec_thread_t * );
229 static void EndThreadAudio ( adec_thread_t * );
231 static int RunDecoderAudio( decoder_fifo_t *p_fifo )
233 adec_thread_t *p_dec;
236 p_dec = malloc( sizeof( adec_thread_t ) );
239 msg_Err( p_fifo, "out of memory" );
240 DecoderError( p_fifo );
243 p_dec->p_fifo = p_fifo;
245 if( InitThreadAudio( p_dec ) != 0 )
247 DecoderError( p_fifo );
251 while( !p_dec->p_fifo->b_die && !p_dec->p_fifo->b_error )
253 DecodeThreadAudio( p_dec );
257 if( ( b_error = p_dec->p_fifo->b_error ) )
259 DecoderError( p_dec->p_fifo );
262 EndThreadAudio( p_dec );
271 static int InitThreadAudio ( adec_thread_t *p_dec )
276 unsigned long WantedBufferSize;
277 unsigned long InputBufferSize = 0;
278 unsigned long OutputBufferSize = 0;
282 if( !( p_wf = (WAVEFORMATEX*)p_dec->p_fifo->p_waveformatex ) )
284 msg_Err( p_dec->p_fifo, "missing WAVEFORMATEX");
287 memcpy( fcc, &p_dec->p_fifo->i_fourcc, 4 );
289 /* get lock, avoid segfault */
290 var_Get( p_dec->p_fifo->p_libvlc, "qt_mutex", &lockval );
291 vlc_mutex_lock( lockval.p_address );
295 p_dec->ldt_fs = Setup_LDT_Keeper();
297 msg_Dbg( p_dec->p_fifo, "trying to load `qtmlClient.dll'" );
298 if( !( p_dec->qtml = LoadLibraryA("qtmlClient.dll") ) )
300 msg_Err( p_dec->p_fifo, "cannot load qtmlClient.dll");
304 msg_Dbg( p_dec->p_fifo, "qtmlClient.dll loaded" );
306 /* (void*) to shut up gcc */
307 p_dec->InitializeQTML = (void*)InitializeQTML;
309 p_dec->SoundConverterOpen = (void*)SoundConverterOpen;
310 p_dec->SoundConverterClose = (void*)SoundConverterClose;
311 p_dec->SoundConverterSetInfo = (void*)SoundConverterSetInfo;
312 p_dec->SoundConverterGetBufferSizes = (void*)SoundConverterGetBufferSizes;
313 p_dec->SoundConverterConvertBuffer = (void*)SoundConverterConvertBuffer;
314 p_dec->SoundConverterBeginConversion= (void*)SoundConverterBeginConversion;
315 p_dec->SoundConverterEndConversion = (void*)SoundConverterEndConversion;
318 if( !p_dec->InitializeQTML ||
319 !p_dec->SoundConverterOpen || !p_dec->SoundConverterClose ||
320 !p_dec->SoundConverterSetInfo || !p_dec->SoundConverterGetBufferSizes ||
321 !p_dec->SoundConverterConvertBuffer ||
322 !p_dec->SoundConverterBeginConversion || !p_dec->SoundConverterEndConversion )
324 msg_Err( p_dec->p_fifo, "error getting qtmlClient.dll symbols");
328 if( ( i_error = p_dec->InitializeQTML( 6 + 16 ) ) )
330 msg_Dbg( p_dec->p_fifo, "error while InitializeQTML = %d", i_error );
335 /* input format settings */
336 p_dec->InputFormatInfo.flags = 0;
337 p_dec->InputFormatInfo.sampleCount = 0;
338 p_dec->InputFormatInfo.buffer = NULL;
339 p_dec->InputFormatInfo.reserved = 0;
340 p_dec->InputFormatInfo.numChannels = p_wf->nChannels;
341 p_dec->InputFormatInfo.sampleSize = p_wf->wBitsPerSample;
342 p_dec->InputFormatInfo.sampleRate = p_wf->nSamplesPerSec;
343 p_dec->InputFormatInfo.format = FCC( fcc[0], fcc[1], fcc[2], fcc[3] );
345 /* output format settings */
346 p_dec->OutputFormatInfo.flags = 0;
347 p_dec->OutputFormatInfo.sampleCount = 0;
348 p_dec->OutputFormatInfo.buffer = NULL;
349 p_dec->OutputFormatInfo.reserved = 0;
350 p_dec->OutputFormatInfo.numChannels = p_wf->nChannels;
351 p_dec->OutputFormatInfo.sampleSize = 16;
352 p_dec->OutputFormatInfo.sampleRate = p_wf->nSamplesPerSec;
353 p_dec->OutputFormatInfo.format = FCC( 'N', 'O', 'N', 'E' );
356 /* on OS X QT is not threadsafe */
357 vlc_mutex_lock( &p_dec->p_fifo->p_vlc->quicktime_lock );
360 i_error = p_dec->SoundConverterOpen( &p_dec->InputFormatInfo,
361 &p_dec->OutputFormatInfo,
362 &p_dec->myConverter );
364 vlc_mutex_unlock( &p_dec->p_fifo->p_vlc->quicktime_lock );
369 msg_Dbg( p_dec->p_fifo, "error while SoundConverterOpen = %d", i_error );
373 if( p_wf->cbSize > 36 + 8 )
375 i_error = p_dec->SoundConverterSetInfo( p_dec->myConverter,
376 FCC( 'w', 'a', 'v', 'e' ),
377 ((uint8_t*)&p_wf[1]) + 36 + 8 );
378 msg_Dbg( p_dec->p_fifo, "error while SoundConverterSetInfo = %d", i_error );
381 WantedBufferSize = p_dec->OutputFormatInfo.numChannels * p_dec->OutputFormatInfo.sampleRate * 2;
382 p_dec->FramesToGet = 0;
383 i_error = p_dec->SoundConverterGetBufferSizes( p_dec->myConverter,
384 WantedBufferSize, &p_dec->FramesToGet,
385 &InputBufferSize, &OutputBufferSize );
387 msg_Dbg( p_dec->p_fifo, "WantedBufferSize=%li InputBufferSize=%li OutputBufferSize=%li FramesToGet=%li",
388 WantedBufferSize, InputBufferSize, OutputBufferSize, p_dec->FramesToGet );
390 p_dec->InFrameSize = (InputBufferSize + p_dec->FramesToGet - 1 ) / p_dec->FramesToGet;
391 p_dec->OutFrameSize = OutputBufferSize / p_dec->FramesToGet;
393 msg_Dbg( p_dec->p_fifo, "frame size %d -> %d", p_dec->InFrameSize, p_dec->OutFrameSize );
395 i_error = p_dec->SoundConverterBeginConversion( p_dec->myConverter );
398 msg_Err( p_dec->p_fifo, "error while SoundConverterBeginConversion = %d", i_error );
402 p_dec->output_format.i_format = AOUT_FMT_S16_NE;
403 p_dec->output_format.i_rate = p_wf->nSamplesPerSec;
404 p_dec->output_format.i_physical_channels =
405 p_dec->output_format.i_original_channels =
406 pi_channels_maps[p_wf->nChannels];
407 aout_DateInit( &p_dec->date, p_dec->output_format.i_rate );
408 p_dec->p_aout_input = aout_DecNew( p_dec->p_fifo,
410 &p_dec->output_format );
411 if( !p_dec->p_aout_input )
413 msg_Err( p_dec->p_fifo, "cannot create aout" );
418 p_dec->i_buffer_size = 100*1000;
419 p_dec->p_buffer = malloc( p_dec->i_buffer_size );
423 vlc_mutex_unlock( lockval.p_address );
428 Restore_LDT_Keeper( p_dec->ldt_fs );
430 vlc_mutex_unlock( lockval.p_address );
434 static void DecodeThreadAudio ( adec_thread_t *p_dec )
440 var_Get( p_dec->p_fifo->p_libvlc, "qt_mutex", &lockval );
442 input_ExtractPES( p_dec->p_fifo, &p_pes );
445 msg_Err( p_dec->p_fifo, "cannot get PES" );
446 p_dec->p_fifo->b_error = 1;
449 /*if( p_dec->pts <= 0 )*/
451 p_dec->pts = p_pes->i_pts;
454 if( p_pes->i_pes_size > 0 && p_pes->i_pts > mdate() )
457 if( p_dec->i_buffer_size < p_dec->i_buffer + p_pes->i_pes_size )
459 p_dec->i_buffer_size = p_dec->i_buffer + p_pes->i_pes_size + 1024;
460 p_dec->p_buffer = realloc( p_dec->p_buffer,
461 p_dec->i_buffer_size );
464 GetPESData( &p_dec->p_buffer[p_dec->i_buffer],
465 p_dec->i_buffer_size - p_dec->i_buffer, p_pes );
466 p_dec->i_buffer += p_pes->i_pes_size;
468 if( p_dec->i_buffer > p_dec->InFrameSize )
470 int i_frames = p_dec->i_buffer / p_dec->InFrameSize;
471 long i_out_frames, i_out_bytes;
474 vlc_mutex_lock( lockval.p_address );
475 i_error = p_dec->SoundConverterConvertBuffer( p_dec->myConverter,
479 &i_out_frames, &i_out_bytes );
480 vlc_mutex_unlock( lockval.p_address );
482 /*msg_Dbg( p_dec->p_fifo, "decoded %d frames -> %ld frames (error=%d)",
483 i_frames, i_out_frames, i_error );
485 msg_Dbg( p_dec->p_fifo, "decoded %ld frames = %ld bytes", i_out_frames, i_out_bytes );*/
486 p_dec->i_buffer -= i_frames * p_dec->InFrameSize;
487 if( p_dec->i_buffer > 0 )
489 memmove( &p_dec->p_buffer[0],
490 &p_dec->p_buffer[i_frames * p_dec->InFrameSize],
494 if( i_out_frames > 0 )
496 aout_buffer_t *p_aout_buffer;
497 uint8_t *p_buff = p_dec->buffer_out;
499 /*msg_Dbg( p_dec->p_fifo, "pts=%lld date=%lld dateget=%lld",
500 p_dec->pts, mdate(), aout_DateGet( &p_dec->date ) );*/
502 if( p_dec->pts != 0 && p_dec->pts != aout_DateGet( &p_dec->date ) )
504 aout_DateSet( &p_dec->date, p_dec->pts );
506 else if( !aout_DateGet( &p_dec->date ) )
508 input_DeletePES( p_dec->p_fifo->p_packets_mgt, p_pes );
512 while( i_out_frames > 0 )
516 i_frames = __MIN( i_out_frames, 1000 );
517 p_aout_buffer = aout_DecNewBuffer( p_dec->p_aout,
522 msg_Err( p_dec->p_fifo, "cannot get aout buffer" );
523 p_dec->p_fifo->b_error = 1;
526 p_aout_buffer->start_date = aout_DateGet( &p_dec->date );
527 p_aout_buffer->end_date = aout_DateIncrement( &p_dec->date,
530 memcpy( p_aout_buffer->p_buffer,
532 p_aout_buffer->i_nb_bytes );
534 /*msg_Dbg( p_dec->p_fifo, "==> start=%lld end=%lld date=%lld",
535 p_aout_buffer->start_date, p_aout_buffer->end_date, mdate() );*/
536 aout_DecPlay( p_dec->p_aout, p_dec->p_aout_input, p_aout_buffer );
537 /*msg_Dbg( p_dec->p_fifo, "s1=%d s2=%d", i_framesperchannels, p_aout_buffer->i_nb_samples );
539 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 );*/
540 p_buff += i_frames * 4;
541 i_out_frames -= i_frames;
549 input_DeletePES( p_dec->p_fifo->p_packets_mgt, p_pes );
551 static void EndThreadAudio ( adec_thread_t *p_dec )
555 unsigned long ConvertedFrames=0;
556 unsigned long ConvertedBytes=0;
558 /* get lock, avoid segfault */
559 var_Get( p_dec->p_fifo->p_libvlc, "qt_mutex", &lockval );
560 vlc_mutex_lock( lockval.p_address );
562 i_error = p_dec->SoundConverterEndConversion( p_dec->myConverter, NULL, &ConvertedFrames, &ConvertedBytes );
563 msg_Dbg( p_dec->p_fifo, "SoundConverterEndConversion => %d", i_error );
565 i_error = p_dec->SoundConverterClose( p_dec->myConverter );
566 msg_Dbg( p_dec->p_fifo, "SoundConverterClose => %d", i_error );
568 /*FreeLibrary( p_dec->qtml );
569 msg_Dbg( p_dec->p_fifo, "FreeLibrary ok." ); */
571 vlc_mutex_unlock( lockval.p_address );
573 /*Restore_LDT_Keeper( p_dec->ldt_fs );
574 msg_Dbg( p_dec->p_fifo, "Restore_LDT_Keeper" ); */
578 aout_DecDelete( p_dec->p_aout, p_dec->p_aout_input );
581 /* Video part will follow when the LOADER code arrives */