]> git.sesse.net Git - vlc/blob - modules/codec/quicktime.c
* ALL: added a quicktime module.
[vlc] / modules / codec / quicktime.c
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.1 2003/05/20 21:35:52 hartman Exp $
6  *
7  * Authors: Laurent Aimar <fenrir at via.ecp.fr>
8  *          Derk-Jan Hartman <thedj at users.sf.net>
9  *
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.
14  * 
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.
19  *
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  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <vlc/vlc.h>
29 #include <vlc/aout.h>
30 #include <vlc/vout.h>
31 #include <vlc/decoder.h>
32 #include <vlc/input.h>
33
34 #include <stdlib.h>                                      /* malloc(), free() */
35 #include <string.h>                                              /* strdup() */
36 #include "codecs.h"
37
38 #ifdef SYS_DARWIN
39 #include <QuickTime/QuickTimeComponents.h>
40 #include <QuickTime/Movies.h>
41 #include <QuickTime/ImageCodec.h>
42 #endif
43
44 /*****************************************************************************
45  * Local prototypes
46  *****************************************************************************/
47 static int  OpenDecoder    ( vlc_object_t * );
48
49 static int  RunDecoderAudio( decoder_fifo_t * );
50
51 /*****************************************************************************
52  * Module descriptor
53  *****************************************************************************/
54
55 vlc_module_begin();
56     set_description( _("QT binary library decoder") );
57     set_capability( "decoder", 10 );
58     set_callbacks( OpenDecoder, NULL );
59
60     /* create a mutex */
61     var_Create( p_module->p_libvlc, "qt_mutex", VLC_VAR_MUTEX );
62 vlc_module_end();
63
64
65
66 #define FCC( a, b , c, d ) \
67     ((uint32_t)( ((a)<<24)|((b)<<16)|((c)<<8)|(d)))
68
69 #ifdef LOADER
70 typedef struct OpaqueSoundConverter*    SoundConverter;
71 typedef unsigned long                   UnsignedFixed;
72 typedef uint8_t                          Byte;
73 typedef struct SoundComponentData {
74     long                            flags;
75     OSType                          format;
76     short                           numChannels;
77     short                           sampleSize;
78     UnsignedFixed                   sampleRate;
79     long                            sampleCount;
80     Byte *                          buffer;
81     long                            reserved;
82 } SoundComponentData;
83 #endif
84
85 typedef struct
86 {
87     /* Input properties */
88     decoder_fifo_t *p_fifo;
89
90     /* library */
91 #ifdef LOADER
92     HMODULE     qtml;
93     ldt_fs_t    *ldt_fs;
94     OSErr       (*InitializeQTML)               ( long flags );
95 #endif
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;
109
110     long            FramesToGet;
111     unsigned int    InFrameSize;
112     unsigned int    OutFrameSize;
113
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;
118
119     audio_date_t        date;
120     mtime_t             pts;
121
122     /* buffer */
123     unsigned int        i_buffer;
124     unsigned int        i_buffer_size;
125     uint8_t             *p_buffer;
126
127     uint8_t             buffer_out[1000000];    /* FIXME */
128 } adec_thread_t;
129
130
131 static int pi_channels_maps[6] =
132 {
133     0,
134     AOUT_CHAN_CENTER,
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
140 };
141
142
143 static uint16_t GetWBE( uint8_t *p_buff )
144 {
145     return( (p_buff[0]<<8) + p_buff[1] );
146 }
147
148 static uint32_t GetDWBE( uint8_t *p_buff )
149 {
150     return( (p_buff[0] << 24) + ( p_buff[1] <<16 ) +
151             ( p_buff[2] <<8 ) + p_buff[3] );
152 }
153
154
155 static int GetPESData( uint8_t *p_buf, int i_max, pes_packet_t *p_pes )
156 {
157     int i_copy;
158     int i_count;
159
160     data_packet_t   *p_data;
161
162     i_count = 0;
163     p_data = p_pes->p_first;
164     while( p_data != NULL && i_count < i_max )
165     {
166
167         i_copy = __MIN( p_data->p_payload_end - p_data->p_payload_start,
168                         i_max - i_count );
169
170         if( i_copy > 0 )
171         {
172             memcpy( p_buf,
173                     p_data->p_payload_start,
174                     i_copy );
175         }
176
177         p_data = p_data->p_next;
178         i_count += i_copy;
179         p_buf   += i_copy;
180     }
181
182     if( i_count < i_max )
183     {
184         memset( p_buf, 0, i_max - i_count );
185     }
186     return( i_count );
187 }
188
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
193  * to choose.
194  *****************************************************************************/
195 static int OpenDecoder( vlc_object_t *p_this )
196 {
197     decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this;
198
199     switch( p_fifo->i_fourcc )
200     {
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 */
211
212             p_fifo->pf_run = RunDecoderAudio;
213             return VLC_SUCCESS;
214         default:
215             return VLC_EGENERIC;
216     }
217 }
218
219 /****************************************************************************
220  ****************************************************************************
221  **
222  **     audio part
223  **
224  **************************************************************************** 
225  ****************************************************************************/
226
227 static int  InitThreadAudio     ( adec_thread_t * );
228 static void DecodeThreadAudio   ( adec_thread_t * );
229 static void EndThreadAudio      ( adec_thread_t * );
230
231 static int  RunDecoderAudio( decoder_fifo_t *p_fifo )
232 {
233     adec_thread_t *p_dec;
234     vlc_bool_t    b_error;
235
236     p_dec = malloc( sizeof( adec_thread_t ) );
237     if( !p_dec )
238     {
239         msg_Err( p_fifo, "out of memory" );
240         DecoderError( p_fifo );
241         return VLC_EGENERIC;
242     }
243     p_dec->p_fifo = p_fifo;
244
245     if( InitThreadAudio( p_dec ) != 0 )
246     {
247         DecoderError( p_fifo );
248         return VLC_EGENERIC;
249     }
250
251     while( !p_dec->p_fifo->b_die && !p_dec->p_fifo->b_error )
252     {
253         DecodeThreadAudio( p_dec );
254     }
255
256
257     if( ( b_error = p_dec->p_fifo->b_error ) )
258     {
259         DecoderError( p_dec->p_fifo );
260     }
261
262     EndThreadAudio( p_dec );
263     if( b_error )
264     {
265         return VLC_EGENERIC;
266     }
267
268     return VLC_SUCCESS;
269 }
270
271 static int  InitThreadAudio     ( adec_thread_t *p_dec )
272 {
273     vlc_value_t     lockval;
274     int             i_error;
275     char            fcc[4];
276     unsigned long   WantedBufferSize;
277     unsigned long   InputBufferSize = 0;
278     unsigned long   OutputBufferSize = 0;
279
280     WAVEFORMATEX    *p_wf;
281
282     if( !( p_wf = (WAVEFORMATEX*)p_dec->p_fifo->p_waveformatex ) )
283     {
284         msg_Err( p_dec->p_fifo, "missing WAVEFORMATEX");
285         return VLC_EGENERIC;
286     }
287     memcpy( fcc, &p_dec->p_fifo->i_fourcc, 4 );
288
289     /* get lock, avoid segfault */
290     var_Get( p_dec->p_fifo->p_libvlc, "qt_mutex", &lockval );
291     vlc_mutex_lock( lockval.p_address );
292 #ifdef SYS_DARWIN
293     EnterMovies();
294 #else
295     p_dec->ldt_fs = Setup_LDT_Keeper();
296
297     msg_Dbg( p_dec->p_fifo, "trying to load `qtmlClient.dll'" );
298     if( !( p_dec->qtml = LoadLibraryA("qtmlClient.dll") ) )
299     {
300         msg_Err( p_dec->p_fifo, "cannot load qtmlClient.dll");
301         goto exit_error;
302     }
303
304     msg_Dbg( p_dec->p_fifo, "qtmlClient.dll loaded" );
305
306     /* (void*) to shut up gcc */
307     p_dec->InitializeQTML           = (void*)InitializeQTML;
308 #endif
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;
316
317 #ifndef SYS_DARWIN
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 )
323     {
324         msg_Err( p_dec->p_fifo, "error getting qtmlClient.dll symbols");
325         goto exit_error;
326     }
327
328     if( ( i_error = p_dec->InitializeQTML( 6 + 16 ) ) )
329     {
330         msg_Dbg( p_dec->p_fifo, "error while InitializeQTML = %d", i_error );
331         goto exit_error;
332     }
333 #endif
334
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] );
344
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' );
354
355     i_error = p_dec->SoundConverterOpen( &p_dec->InputFormatInfo,
356                                          &p_dec->OutputFormatInfo,
357                                          &p_dec->myConverter );
358     if( i_error )
359     {
360         msg_Dbg( p_dec->p_fifo, "error while SoundConverterOpen = %d", i_error );
361         goto exit_error;
362     }
363
364     if( p_wf->cbSize > 36 + 8 )
365     {
366         i_error = p_dec->SoundConverterSetInfo( p_dec->myConverter,
367                                                 FCC( 'w', 'a', 'v', 'e' ),
368                                                 ((uint8_t*)&p_wf[1]) + 36 + 8 );
369         msg_Dbg( p_dec->p_fifo, "error while SoundConverterSetInfo = %d", i_error );
370     }
371
372     WantedBufferSize   = p_dec->OutputFormatInfo.numChannels * p_dec->OutputFormatInfo.sampleRate * 2;
373     p_dec->FramesToGet = 0;
374     i_error = p_dec->SoundConverterGetBufferSizes( p_dec->myConverter,
375                                                    WantedBufferSize, &p_dec->FramesToGet,
376                                                    &InputBufferSize, &OutputBufferSize );
377
378     msg_Dbg( p_dec->p_fifo, "WantedBufferSize=%li InputBufferSize=%li OutputBufferSize=%li FramesToGet=%li",
379              WantedBufferSize, InputBufferSize, OutputBufferSize, p_dec->FramesToGet );
380
381     p_dec->InFrameSize  = (InputBufferSize + p_dec->FramesToGet - 1 ) / p_dec->FramesToGet;
382     p_dec->OutFrameSize = OutputBufferSize / p_dec->FramesToGet;
383
384     msg_Dbg( p_dec->p_fifo, "frame size %d -> %d", p_dec->InFrameSize, p_dec->OutFrameSize );
385
386     i_error = p_dec->SoundConverterBeginConversion( p_dec->myConverter );
387     if( i_error )
388     {
389         msg_Err( p_dec->p_fifo, "error while SoundConverterBeginConversion = %d", i_error );
390         goto exit_error;
391     }
392
393     p_dec->output_format.i_format   = AOUT_FMT_S16_NE;
394     p_dec->output_format.i_rate     = p_wf->nSamplesPerSec;
395     p_dec->output_format.i_physical_channels =
396         p_dec->output_format.i_original_channels =
397             pi_channels_maps[p_wf->nChannels];
398     aout_DateInit( &p_dec->date, p_dec->output_format.i_rate );
399     p_dec->p_aout_input = aout_DecNew( p_dec->p_fifo,
400                                        &p_dec->p_aout,
401                                        &p_dec->output_format );
402     if( !p_dec->p_aout_input )
403     {
404         msg_Err( p_dec->p_fifo, "cannot create aout" );
405         goto exit_error;
406     }
407
408     p_dec->i_buffer      = 0;
409     p_dec->i_buffer_size = 100*1000;
410     p_dec->p_buffer      = malloc( p_dec->i_buffer_size );
411
412     p_dec->pts = -1;
413
414     vlc_mutex_unlock( lockval.p_address );
415     return VLC_SUCCESS;
416
417 exit_error:
418 #ifndef SYS_DARWIN
419     Restore_LDT_Keeper( p_dec->ldt_fs );
420 #endif
421     vlc_mutex_unlock( lockval.p_address );
422     return VLC_EGENERIC;
423
424 }
425 static void DecodeThreadAudio   ( adec_thread_t *p_dec )
426 {
427     pes_packet_t    *p_pes;
428     vlc_value_t     lockval;
429     int             i_error;
430
431     var_Get( p_dec->p_fifo->p_libvlc, "qt_mutex", &lockval );
432
433     input_ExtractPES( p_dec->p_fifo, &p_pes );
434     if( !p_pes )
435     {
436         msg_Err( p_dec->p_fifo, "cannot get PES" );
437         p_dec->p_fifo->b_error = 1;
438         return;
439     }
440     /*if( p_dec->pts <= 0 )*/
441     {
442         p_dec->pts = p_pes->i_pts;
443     }
444
445     if( p_pes->i_pes_size > 0 && p_pes->i_pts > mdate() )
446     {
447
448         if( p_dec->i_buffer_size < p_dec->i_buffer + p_pes->i_pes_size )
449         {
450             p_dec->i_buffer_size = p_dec->i_buffer + p_pes->i_pes_size + 1024;
451             p_dec->p_buffer = realloc( p_dec->p_buffer,
452                                        p_dec->i_buffer_size );
453         }
454
455         GetPESData( &p_dec->p_buffer[p_dec->i_buffer],
456                     p_dec->i_buffer_size - p_dec->i_buffer, p_pes );
457         p_dec->i_buffer += p_pes->i_pes_size;
458
459         if( p_dec->i_buffer > p_dec->InFrameSize )
460         {
461             int i_frames = p_dec->i_buffer / p_dec->InFrameSize;
462             long i_out_frames, i_out_bytes;
463             /* enougth data */
464
465             vlc_mutex_lock( lockval.p_address );
466             i_error = p_dec->SoundConverterConvertBuffer( p_dec->myConverter,
467                                                           p_dec->p_buffer,
468                                                           i_frames,
469                                                           p_dec->buffer_out,
470                                                           &i_out_frames, &i_out_bytes );
471             vlc_mutex_unlock( lockval.p_address );
472
473             /*msg_Dbg( p_dec->p_fifo, "decoded %d frames -> %ld frames (error=%d)",
474                      i_frames, i_out_frames, i_error );
475
476             msg_Dbg( p_dec->p_fifo, "decoded %ld frames = %ld bytes", i_out_frames, i_out_bytes );*/
477             p_dec->i_buffer -= i_frames * p_dec->InFrameSize;
478             if( p_dec->i_buffer > 0 )
479             {
480                 memmove( &p_dec->p_buffer[0],
481                          &p_dec->p_buffer[i_frames * p_dec->InFrameSize],
482                          p_dec->i_buffer );
483             }
484
485             if( i_out_frames > 0 )
486             {
487                 aout_buffer_t   *p_aout_buffer;
488                 uint8_t         *p_buff = p_dec->buffer_out;
489
490                 /*msg_Dbg( p_dec->p_fifo, "pts=%lld date=%lld dateget=%lld",
491                          p_dec->pts, mdate(), aout_DateGet( &p_dec->date ) );*/
492
493                 if( p_dec->pts != 0 && p_dec->pts != aout_DateGet( &p_dec->date ) )
494                 {
495                     aout_DateSet( &p_dec->date, p_dec->pts );
496                 }
497                 else if( !aout_DateGet( &p_dec->date ) )
498                 {
499                     input_DeletePES( p_dec->p_fifo->p_packets_mgt, p_pes );
500                     return;
501                 }
502
503                 while( i_out_frames > 0 )
504                 {
505                     int i_frames;
506
507                     i_frames = __MIN( i_out_frames, 1000 );
508                     p_aout_buffer = aout_DecNewBuffer( p_dec->p_aout,
509                                                        p_dec->p_aout_input,
510                                                        i_frames );
511                     if( !p_aout_buffer )
512                     {
513                         msg_Err( p_dec->p_fifo, "cannot get aout buffer" );
514                         p_dec->p_fifo->b_error = 1;
515                         return;
516                     }
517                     p_aout_buffer->start_date = aout_DateGet( &p_dec->date );
518                     p_aout_buffer->end_date = aout_DateIncrement( &p_dec->date,
519                                                                   i_frames );
520
521                     memcpy( p_aout_buffer->p_buffer,
522                             p_buff,
523                             p_aout_buffer->i_nb_bytes );
524
525                     /*msg_Dbg( p_dec->p_fifo, "==> start=%lld end=%lld date=%lld",
526                              p_aout_buffer->start_date, p_aout_buffer->end_date, mdate() );*/
527                     aout_DecPlay( p_dec->p_aout, p_dec->p_aout_input, p_aout_buffer );
528                     /*msg_Dbg( p_dec->p_fifo, "s1=%d s2=%d", i_framesperchannels, p_aout_buffer->i_nb_samples );
529
530                     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 );*/
531                     p_buff += i_frames * 4;
532                     i_out_frames -= i_frames;
533                 }
534
535                 p_dec->pts = -1;
536             }
537         }
538     }
539
540     input_DeletePES( p_dec->p_fifo->p_packets_mgt, p_pes );
541 }
542 static void EndThreadAudio      ( adec_thread_t *p_dec )
543 {
544     vlc_value_t             lockval;
545     int i_error;
546     unsigned long ConvertedFrames=0;
547     unsigned long ConvertedBytes=0;
548
549     /* get lock, avoid segfault */
550     var_Get( p_dec->p_fifo->p_libvlc, "qt_mutex", &lockval );
551     vlc_mutex_lock( lockval.p_address );
552
553     i_error = p_dec->SoundConverterEndConversion( p_dec->myConverter, NULL, &ConvertedFrames, &ConvertedBytes );
554     msg_Dbg( p_dec->p_fifo, "SoundConverterEndConversion => %d", i_error );
555
556     i_error = p_dec->SoundConverterClose( p_dec->myConverter );
557     msg_Dbg( p_dec->p_fifo, "SoundConverterClose => %d", i_error );
558
559     /*FreeLibrary( p_dec->qtml );
560     msg_Dbg( p_dec->p_fifo, "FreeLibrary ok." ); */
561
562     vlc_mutex_unlock( lockval.p_address );
563
564     /*Restore_LDT_Keeper( p_dec->ldt_fs );
565     msg_Dbg( p_dec->p_fifo, "Restore_LDT_Keeper" ); */
566 #ifdef SYS_DARWIN
567     ExitMovies();
568 #endif
569     aout_DecDelete( p_dec->p_aout, p_dec->p_aout_input );
570 }
571
572 /* Video part will follow when the LOADER code arrives */
573
574