]> git.sesse.net Git - vlc/blob - modules/codec/quicktime.c
* vlc.ebuild: This ebuild should work if we release a test2.
[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.3 2003/05/21 19:55:25 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('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 */
223
224             p_fifo->pf_run = RunDecoderAudio;
225             return VLC_SUCCESS;
226         default:
227             return VLC_EGENERIC;
228     }
229 }
230
231 /****************************************************************************
232  ****************************************************************************
233  **
234  **     audio part
235  **
236  **************************************************************************** 
237  ****************************************************************************/
238
239 static int  InitThreadAudio     ( adec_thread_t * );
240 static void DecodeThreadAudio   ( adec_thread_t * );
241 static void EndThreadAudio      ( adec_thread_t * );
242
243 static int  RunDecoderAudio( decoder_fifo_t *p_fifo )
244 {
245     adec_thread_t *p_dec;
246     vlc_bool_t    b_error;
247
248     p_dec = malloc( sizeof( adec_thread_t ) );
249     if( !p_dec )
250     {
251         msg_Err( p_fifo, "out of memory" );
252         DecoderError( p_fifo );
253         return VLC_EGENERIC;
254     }
255     p_dec->p_fifo = p_fifo;
256
257     if( InitThreadAudio( p_dec ) != 0 )
258     {
259         DecoderError( p_fifo );
260         return VLC_EGENERIC;
261     }
262
263     while( !p_dec->p_fifo->b_die && !p_dec->p_fifo->b_error )
264     {
265         DecodeThreadAudio( p_dec );
266     }
267
268
269     if( ( b_error = p_dec->p_fifo->b_error ) )
270     {
271         DecoderError( p_dec->p_fifo );
272     }
273
274     EndThreadAudio( p_dec );
275     if( b_error )
276     {
277         return VLC_EGENERIC;
278     }
279
280     return VLC_SUCCESS;
281 }
282
283 static int  InitThreadAudio     ( adec_thread_t *p_dec )
284 {
285     vlc_value_t     lockval;
286     int             i_error;
287     char            fcc[4];
288     unsigned long   WantedBufferSize;
289     unsigned long   InputBufferSize = 0;
290     unsigned long   OutputBufferSize = 0;
291
292     WAVEFORMATEX    *p_wf;
293
294     if( !( p_wf = (WAVEFORMATEX*)p_dec->p_fifo->p_waveformatex ) )
295     {
296         msg_Err( p_dec->p_fifo, "missing WAVEFORMATEX");
297         return VLC_EGENERIC;
298     }
299     memcpy( fcc, &p_dec->p_fifo->i_fourcc, 4 );
300
301     /* get lock, avoid segfault */
302     var_Get( p_dec->p_fifo->p_libvlc, "qt_mutex", &lockval );
303     vlc_mutex_lock( lockval.p_address );
304 #ifdef SYS_DARWIN
305     EnterMovies();
306 #else
307     p_dec->ldt_fs = Setup_LDT_Keeper();
308
309     msg_Dbg( p_dec->p_fifo, "trying to load `qtmlClient.dll'" );
310     if( !( p_dec->qtml = LoadLibraryA("qtmlClient.dll") ) )
311     {
312         msg_Err( p_dec->p_fifo, "cannot load qtmlClient.dll");
313         goto exit_error;
314     }
315
316     msg_Dbg( p_dec->p_fifo, "qtmlClient.dll loaded" );
317
318     /* (void*) to shut up gcc */
319     p_dec->InitializeQTML           = (void*)InitializeQTML;
320 #endif
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;
328
329 #ifndef SYS_DARWIN
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 )
335     {
336         msg_Err( p_dec->p_fifo, "error getting qtmlClient.dll symbols");
337         goto exit_error;
338     }
339
340     if( ( i_error = p_dec->InitializeQTML( 6 + 16 ) ) )
341     {
342         msg_Dbg( p_dec->p_fifo, "error while InitializeQTML = %d", i_error );
343         goto exit_error;
344     }
345 #endif
346
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] );
356
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' );
366
367 #ifdef SYS_DARWIN
368 /* on OS X QT is not threadsafe */
369     vlc_mutex_lock( &p_dec->p_fifo->p_vlc->quicktime_lock );
370 #endif
371
372     i_error = p_dec->SoundConverterOpen( &p_dec->InputFormatInfo,
373                                          &p_dec->OutputFormatInfo,
374                                          &p_dec->myConverter );
375 #ifdef SYS_DARWIN
376     vlc_mutex_unlock( &p_dec->p_fifo->p_vlc->quicktime_lock );
377 #endif
378
379     if( i_error )
380     {
381         msg_Dbg( p_dec->p_fifo, "error while SoundConverterOpen = %d", i_error );
382         goto exit_error;
383     }
384
385     if( p_wf->cbSize > 36 + 8 )
386     {
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 );
391     }
392
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 );
398
399     msg_Dbg( p_dec->p_fifo, "WantedBufferSize=%li InputBufferSize=%li OutputBufferSize=%li FramesToGet=%li",
400              WantedBufferSize, InputBufferSize, OutputBufferSize, p_dec->FramesToGet );
401
402     p_dec->InFrameSize  = (InputBufferSize + p_dec->FramesToGet - 1 ) / p_dec->FramesToGet;
403     p_dec->OutFrameSize = OutputBufferSize / p_dec->FramesToGet;
404
405     msg_Dbg( p_dec->p_fifo, "frame size %d -> %d", p_dec->InFrameSize, p_dec->OutFrameSize );
406
407     i_error = p_dec->SoundConverterBeginConversion( p_dec->myConverter );
408     if( i_error )
409     {
410         msg_Err( p_dec->p_fifo, "error while SoundConverterBeginConversion = %d", i_error );
411         goto exit_error;
412     }
413
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,
421                                        &p_dec->p_aout,
422                                        &p_dec->output_format );
423     if( !p_dec->p_aout_input )
424     {
425         msg_Err( p_dec->p_fifo, "cannot create aout" );
426         goto exit_error;
427     }
428
429     p_dec->i_buffer      = 0;
430     p_dec->i_buffer_size = 100*1000;
431     p_dec->p_buffer      = malloc( p_dec->i_buffer_size );
432
433     p_dec->pts = -1;
434
435     vlc_mutex_unlock( lockval.p_address );
436     return VLC_SUCCESS;
437
438 exit_error:
439 #ifndef SYS_DARWIN
440     Restore_LDT_Keeper( p_dec->ldt_fs );
441 #endif
442     vlc_mutex_unlock( lockval.p_address );
443     return VLC_EGENERIC;
444
445 }
446 static void DecodeThreadAudio   ( adec_thread_t *p_dec )
447 {
448     pes_packet_t    *p_pes;
449     vlc_value_t     lockval;
450     int             i_error;
451
452     var_Get( p_dec->p_fifo->p_libvlc, "qt_mutex", &lockval );
453
454     input_ExtractPES( p_dec->p_fifo, &p_pes );
455     if( !p_pes )
456     {
457         msg_Err( p_dec->p_fifo, "cannot get PES" );
458         p_dec->p_fifo->b_error = 1;
459         return;
460     }
461     /*if( p_dec->pts <= 0 )*/
462     {
463         p_dec->pts = p_pes->i_pts;
464     }
465
466     if( p_pes->i_pes_size > 0 && p_pes->i_pts > mdate() )
467     {
468
469         if( p_dec->i_buffer_size < p_dec->i_buffer + p_pes->i_pes_size )
470         {
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 );
474         }
475
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;
479
480         if( p_dec->i_buffer > p_dec->InFrameSize )
481         {
482             int i_frames = p_dec->i_buffer / p_dec->InFrameSize;
483             long i_out_frames, i_out_bytes;
484             /* enougth data */
485
486             vlc_mutex_lock( lockval.p_address );
487             i_error = p_dec->SoundConverterConvertBuffer( p_dec->myConverter,
488                                                           p_dec->p_buffer,
489                                                           i_frames,
490                                                           p_dec->buffer_out,
491                                                           &i_out_frames, &i_out_bytes );
492             vlc_mutex_unlock( lockval.p_address );
493
494             /*msg_Dbg( p_dec->p_fifo, "decoded %d frames -> %ld frames (error=%d)",
495                      i_frames, i_out_frames, i_error );
496
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 )
500             {
501                 memmove( &p_dec->p_buffer[0],
502                          &p_dec->p_buffer[i_frames * p_dec->InFrameSize],
503                          p_dec->i_buffer );
504             }
505
506             if( i_out_frames > 0 )
507             {
508                 aout_buffer_t   *p_aout_buffer;
509                 uint8_t         *p_buff = p_dec->buffer_out;
510
511                 /*msg_Dbg( p_dec->p_fifo, "pts=%lld date=%lld dateget=%lld",
512                          p_dec->pts, mdate(), aout_DateGet( &p_dec->date ) );*/
513
514                 if( p_dec->pts != 0 && p_dec->pts != aout_DateGet( &p_dec->date ) )
515                 {
516                     aout_DateSet( &p_dec->date, p_dec->pts );
517                 }
518                 else if( !aout_DateGet( &p_dec->date ) )
519                 {
520                     input_DeletePES( p_dec->p_fifo->p_packets_mgt, p_pes );
521                     return;
522                 }
523
524                 while( i_out_frames > 0 )
525                 {
526                     int i_frames;
527
528                     i_frames = __MIN( i_out_frames, 1000 );
529                     p_aout_buffer = aout_DecNewBuffer( p_dec->p_aout,
530                                                        p_dec->p_aout_input,
531                                                        i_frames );
532                     if( !p_aout_buffer )
533                     {
534                         msg_Err( p_dec->p_fifo, "cannot get aout buffer" );
535                         p_dec->p_fifo->b_error = 1;
536                         return;
537                     }
538                     p_aout_buffer->start_date = aout_DateGet( &p_dec->date );
539                     p_aout_buffer->end_date = aout_DateIncrement( &p_dec->date,
540                                                                   i_frames );
541
542                     memcpy( p_aout_buffer->p_buffer,
543                             p_buff,
544                             p_aout_buffer->i_nb_bytes );
545
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 );
550
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;
554                 }
555
556                 p_dec->pts = -1;
557             }
558         }
559     }
560
561     input_DeletePES( p_dec->p_fifo->p_packets_mgt, p_pes );
562 }
563 static void EndThreadAudio      ( adec_thread_t *p_dec )
564 {
565     vlc_value_t             lockval;
566     int i_error;
567     unsigned long ConvertedFrames=0;
568     unsigned long ConvertedBytes=0;
569
570     /* get lock, avoid segfault */
571     var_Get( p_dec->p_fifo->p_libvlc, "qt_mutex", &lockval );
572     vlc_mutex_lock( lockval.p_address );
573
574     i_error = p_dec->SoundConverterEndConversion( p_dec->myConverter, NULL, &ConvertedFrames, &ConvertedBytes );
575     msg_Dbg( p_dec->p_fifo, "SoundConverterEndConversion => %d", i_error );
576
577     i_error = p_dec->SoundConverterClose( p_dec->myConverter );
578     msg_Dbg( p_dec->p_fifo, "SoundConverterClose => %d", i_error );
579
580     /*FreeLibrary( p_dec->qtml );
581     msg_Dbg( p_dec->p_fifo, "FreeLibrary ok." ); */
582
583     vlc_mutex_unlock( lockval.p_address );
584
585     /*Restore_LDT_Keeper( p_dec->ldt_fs );
586     msg_Dbg( p_dec->p_fifo, "Restore_LDT_Keeper" ); */
587 #ifdef SYS_DARWIN
588     ExitMovies();
589 #endif
590     aout_DecDelete( p_dec->p_aout, p_dec->p_aout_input );
591 }
592
593 /* Video part will follow when the LOADER code arrives */
594
595