]> git.sesse.net Git - vlc/blob - modules/codec/quicktime.c
* include/main.h
[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.2 2003/05/21 15:40:03 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 #ifdef SYS_DARWIN
356 /* on OS X QT is not threadsafe */
357     vlc_mutex_lock( &p_dec->p_fifo->p_vlc->quicktime_lock );
358 #endif
359
360     i_error = p_dec->SoundConverterOpen( &p_dec->InputFormatInfo,
361                                          &p_dec->OutputFormatInfo,
362                                          &p_dec->myConverter );
363 #ifdef SYS_DARWIN
364     vlc_mutex_unlock( &p_dec->p_fifo->p_vlc->quicktime_lock );
365 #endif
366
367     if( i_error )
368     {
369         msg_Dbg( p_dec->p_fifo, "error while SoundConverterOpen = %d", i_error );
370         goto exit_error;
371     }
372
373     if( p_wf->cbSize > 36 + 8 )
374     {
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 );
379     }
380
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 );
386
387     msg_Dbg( p_dec->p_fifo, "WantedBufferSize=%li InputBufferSize=%li OutputBufferSize=%li FramesToGet=%li",
388              WantedBufferSize, InputBufferSize, OutputBufferSize, p_dec->FramesToGet );
389
390     p_dec->InFrameSize  = (InputBufferSize + p_dec->FramesToGet - 1 ) / p_dec->FramesToGet;
391     p_dec->OutFrameSize = OutputBufferSize / p_dec->FramesToGet;
392
393     msg_Dbg( p_dec->p_fifo, "frame size %d -> %d", p_dec->InFrameSize, p_dec->OutFrameSize );
394
395     i_error = p_dec->SoundConverterBeginConversion( p_dec->myConverter );
396     if( i_error )
397     {
398         msg_Err( p_dec->p_fifo, "error while SoundConverterBeginConversion = %d", i_error );
399         goto exit_error;
400     }
401
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,
409                                        &p_dec->p_aout,
410                                        &p_dec->output_format );
411     if( !p_dec->p_aout_input )
412     {
413         msg_Err( p_dec->p_fifo, "cannot create aout" );
414         goto exit_error;
415     }
416
417     p_dec->i_buffer      = 0;
418     p_dec->i_buffer_size = 100*1000;
419     p_dec->p_buffer      = malloc( p_dec->i_buffer_size );
420
421     p_dec->pts = -1;
422
423     vlc_mutex_unlock( lockval.p_address );
424     return VLC_SUCCESS;
425
426 exit_error:
427 #ifndef SYS_DARWIN
428     Restore_LDT_Keeper( p_dec->ldt_fs );
429 #endif
430     vlc_mutex_unlock( lockval.p_address );
431     return VLC_EGENERIC;
432
433 }
434 static void DecodeThreadAudio   ( adec_thread_t *p_dec )
435 {
436     pes_packet_t    *p_pes;
437     vlc_value_t     lockval;
438     int             i_error;
439
440     var_Get( p_dec->p_fifo->p_libvlc, "qt_mutex", &lockval );
441
442     input_ExtractPES( p_dec->p_fifo, &p_pes );
443     if( !p_pes )
444     {
445         msg_Err( p_dec->p_fifo, "cannot get PES" );
446         p_dec->p_fifo->b_error = 1;
447         return;
448     }
449     /*if( p_dec->pts <= 0 )*/
450     {
451         p_dec->pts = p_pes->i_pts;
452     }
453
454     if( p_pes->i_pes_size > 0 && p_pes->i_pts > mdate() )
455     {
456
457         if( p_dec->i_buffer_size < p_dec->i_buffer + p_pes->i_pes_size )
458         {
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 );
462         }
463
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;
467
468         if( p_dec->i_buffer > p_dec->InFrameSize )
469         {
470             int i_frames = p_dec->i_buffer / p_dec->InFrameSize;
471             long i_out_frames, i_out_bytes;
472             /* enougth data */
473
474             vlc_mutex_lock( lockval.p_address );
475             i_error = p_dec->SoundConverterConvertBuffer( p_dec->myConverter,
476                                                           p_dec->p_buffer,
477                                                           i_frames,
478                                                           p_dec->buffer_out,
479                                                           &i_out_frames, &i_out_bytes );
480             vlc_mutex_unlock( lockval.p_address );
481
482             /*msg_Dbg( p_dec->p_fifo, "decoded %d frames -> %ld frames (error=%d)",
483                      i_frames, i_out_frames, i_error );
484
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 )
488             {
489                 memmove( &p_dec->p_buffer[0],
490                          &p_dec->p_buffer[i_frames * p_dec->InFrameSize],
491                          p_dec->i_buffer );
492             }
493
494             if( i_out_frames > 0 )
495             {
496                 aout_buffer_t   *p_aout_buffer;
497                 uint8_t         *p_buff = p_dec->buffer_out;
498
499                 /*msg_Dbg( p_dec->p_fifo, "pts=%lld date=%lld dateget=%lld",
500                          p_dec->pts, mdate(), aout_DateGet( &p_dec->date ) );*/
501
502                 if( p_dec->pts != 0 && p_dec->pts != aout_DateGet( &p_dec->date ) )
503                 {
504                     aout_DateSet( &p_dec->date, p_dec->pts );
505                 }
506                 else if( !aout_DateGet( &p_dec->date ) )
507                 {
508                     input_DeletePES( p_dec->p_fifo->p_packets_mgt, p_pes );
509                     return;
510                 }
511
512                 while( i_out_frames > 0 )
513                 {
514                     int i_frames;
515
516                     i_frames = __MIN( i_out_frames, 1000 );
517                     p_aout_buffer = aout_DecNewBuffer( p_dec->p_aout,
518                                                        p_dec->p_aout_input,
519                                                        i_frames );
520                     if( !p_aout_buffer )
521                     {
522                         msg_Err( p_dec->p_fifo, "cannot get aout buffer" );
523                         p_dec->p_fifo->b_error = 1;
524                         return;
525                     }
526                     p_aout_buffer->start_date = aout_DateGet( &p_dec->date );
527                     p_aout_buffer->end_date = aout_DateIncrement( &p_dec->date,
528                                                                   i_frames );
529
530                     memcpy( p_aout_buffer->p_buffer,
531                             p_buff,
532                             p_aout_buffer->i_nb_bytes );
533
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 );
538
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;
542                 }
543
544                 p_dec->pts = -1;
545             }
546         }
547     }
548
549     input_DeletePES( p_dec->p_fifo->p_packets_mgt, p_pes );
550 }
551 static void EndThreadAudio      ( adec_thread_t *p_dec )
552 {
553     vlc_value_t             lockval;
554     int i_error;
555     unsigned long ConvertedFrames=0;
556     unsigned long ConvertedBytes=0;
557
558     /* get lock, avoid segfault */
559     var_Get( p_dec->p_fifo->p_libvlc, "qt_mutex", &lockval );
560     vlc_mutex_lock( lockval.p_address );
561
562     i_error = p_dec->SoundConverterEndConversion( p_dec->myConverter, NULL, &ConvertedFrames, &ConvertedBytes );
563     msg_Dbg( p_dec->p_fifo, "SoundConverterEndConversion => %d", i_error );
564
565     i_error = p_dec->SoundConverterClose( p_dec->myConverter );
566     msg_Dbg( p_dec->p_fifo, "SoundConverterClose => %d", i_error );
567
568     /*FreeLibrary( p_dec->qtml );
569     msg_Dbg( p_dec->p_fifo, "FreeLibrary ok." ); */
570
571     vlc_mutex_unlock( lockval.p_address );
572
573     /*Restore_LDT_Keeper( p_dec->ldt_fs );
574     msg_Dbg( p_dec->p_fifo, "Restore_LDT_Keeper" ); */
575 #ifdef SYS_DARWIN
576     ExitMovies();
577 #endif
578     aout_DecDelete( p_dec->p_aout, p_dec->p_aout_input );
579 }
580
581 /* Video part will follow when the LOADER code arrives */
582
583