]> git.sesse.net Git - vlc/blob - modules/codec/realaudio.c
* modules/codec/realaudio.c: subpackets re-ordering is now done in the demuxer.
[vlc] / modules / codec / realaudio.c
1 /*****************************************************************************
2  * realaudio.c: a realaudio decoder that uses the realaudio library/dll
3  *****************************************************************************
4  * Copyright (C) 2005 the VideoLAN team
5  * $Id$
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
20  *****************************************************************************/
21
22 /*****************************************************************************
23  * Preamble
24  *****************************************************************************/
25 #include <vlc/vlc.h>
26 #include <vlc/aout.h>
27 #include <vlc/vout.h>
28 #include <vlc/decoder.h>
29
30 #ifdef LOADER
31 /* Need the w32dll loader from mplayer */
32 #   include <wine/winerror.h>
33 #   include <ldt_keeper.h>
34 #   include <wine/windef.h>
35
36 void *WINAPI LoadLibraryA( char *name );
37 void *WINAPI GetProcAddress( void *handle, char *func );
38 int WINAPI FreeLibrary( void *handle );
39 #endif
40
41 #ifndef WINAPI
42 #   define WINAPI
43 #endif
44
45 #if defined(HAVE_DL_DLOPEN)
46 #   if defined(HAVE_DLFCN_H) /* Linux, BSD, Hurd */
47 #       include <dlfcn.h>
48 #   endif
49 #   if defined(HAVE_SYS_DL_H)
50 #       include <sys/dl.h>
51 #   endif
52 #endif
53
54 /*****************************************************************************
55  * Module descriptor
56  *****************************************************************************/
57 static int  Open ( vlc_object_t * );
58 static void Close( vlc_object_t * );
59
60 vlc_module_begin();
61     set_description( _("RealAudio library decoder") );
62     set_capability( "decoder", 10 );
63     set_category( CAT_INPUT );
64     set_subcategory( SUBCAT_INPUT_VCODEC );
65     set_callbacks( Open, Close );
66 vlc_module_end();
67
68 /*****************************************************************************
69  * Local prototypes
70  *****************************************************************************/
71 static int  OpenDll( decoder_t * );
72 static int  OpenNativeDll( decoder_t *, char *, char * );
73 static int  OpenWin32Dll( decoder_t *, char *, char * );
74 static void CloseDll( decoder_t * );
75
76 static aout_buffer_t *Decode( decoder_t *, block_t ** );
77
78 struct decoder_sys_t
79 {
80     audio_date_t end_date;
81
82     /* Output buffer */
83     char *p_out;
84     unsigned int i_out;
85
86     /* Codec params */
87     void *context;
88     int i_codec_flavor;
89
90     void *dll;
91     unsigned long (*raCloseCodec)(void*);
92     unsigned long (*raDecode)(void*, char*, unsigned long, char*,
93                               unsigned int*, long);
94     unsigned long (*raFlush)(unsigned long, unsigned long, unsigned long);
95     unsigned long (*raFreeDecoder)(void*);
96     void*         (*raGetFlavorProperty)(void*, unsigned long,
97                                          unsigned long, int*);
98     unsigned long (*raInitDecoder)(void*, void*);
99     unsigned long (*raOpenCodec)(void*);
100     unsigned long (*raOpenCodec2)(void*, void*);
101     unsigned long (*raSetFlavor)(void*, unsigned long);
102     void          (*raSetDLLAccessPath)(char*);
103     void          (*raSetPwd)(char*, char*);
104
105 #if defined(LOADER)
106     ldt_fs_t *ldt_fs;
107 #endif
108
109     void *win32_dll;
110     unsigned long WINAPI (*wraCloseCodec)(void*);
111     unsigned long WINAPI (*wraDecode)(void*, char*, unsigned long, char*,
112                                       unsigned int*, long);
113     unsigned long WINAPI (*wraFlush)(unsigned long, unsigned long,
114                                      unsigned long);
115     unsigned long WINAPI (*wraFreeDecoder)(void*);
116     void*         WINAPI (*wraGetFlavorProperty)(void*, unsigned long,
117                                                  unsigned long, int*);
118     unsigned long WINAPI (*wraInitDecoder)(void*, void*);
119     unsigned long WINAPI (*wraOpenCodec)(void*);
120     unsigned long WINAPI (*wraOpenCodec2)(void*, void*);
121     unsigned long WINAPI (*wraSetFlavor)(void*, unsigned long);
122     void          WINAPI (*wraSetDLLAccessPath)(char*);
123     void          WINAPI (*wraSetPwd)(char*, char*);
124 };
125
126 /* linux dlls doesn't need packing */
127 typedef struct /*__attribute__((__packed__))*/ {
128     int samplerate;
129     short bits;
130     short channels;
131     short quality;
132     /* 2bytes padding here, by gcc */
133     int bits_per_frame;
134     int packetsize;
135     int extradata_len;
136     void* extradata;
137 } ra_init_t;
138
139 /* windows dlls need packed structs (no padding) */
140 typedef struct __attribute__((__packed__)) {
141     int samplerate;
142     short bits;
143     short channels;
144     short quality;
145     int bits_per_frame;
146     int packetsize;
147     int extradata_len;
148     void* extradata;
149 } wra_init_t;
150
151 void *__builtin_new(unsigned long size) {return malloc(size);}
152 void __builtin_delete(void *p) {free(p);}
153
154 static int pi_channels_maps[7] =
155 {
156     0,
157     AOUT_CHAN_CENTER,
158     AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,
159     AOUT_CHAN_CENTER | AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,
160     AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT
161      | AOUT_CHAN_REARRIGHT,
162     AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
163      | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT,
164     AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
165      | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE
166 };
167
168 /*****************************************************************************
169  * Open: probe the decoder and return score
170  *****************************************************************************
171  * Tries to launch a decoder and return score so that the interface is able
172  * to choose.
173  *****************************************************************************/
174 static int Open( vlc_object_t *p_this )
175 {
176     decoder_t *p_dec = (decoder_t*)p_this;
177     decoder_sys_t *p_sys = p_dec->p_sys;
178
179     switch( p_dec->fmt_in.i_codec )
180     {
181     case VLC_FOURCC('c','o','o','k'):
182         break;
183
184     default:
185         return VLC_EGENERIC;
186     }
187
188     p_dec->p_sys = p_sys = malloc( sizeof( decoder_sys_t ) );
189     memset( p_sys, 0, sizeof(decoder_sys_t) );
190
191     p_sys->i_codec_flavor = -1;
192     if( p_dec->fmt_in.i_codec == VLC_FOURCC('s','i','p','r') )
193     {
194         if( p_dec->fmt_in.audio.i_bitspersample > 1531 )
195             p_sys->i_codec_flavor = 3;
196         else if( p_dec->fmt_in.audio.i_bitspersample > 937 )
197             p_sys->i_codec_flavor = 1;
198         else if( p_dec->fmt_in.audio.i_bitspersample > 719 )
199             p_sys->i_codec_flavor = 0;
200         else
201             p_sys->i_codec_flavor = 2;
202     }
203
204     if( OpenDll( p_dec ) != VLC_SUCCESS )
205     {
206         free( p_sys );
207         return VLC_EGENERIC;
208     }
209
210 #ifdef LOADER
211     if( p_sys->win32_dll ) Close( p_this );
212 #endif
213
214     es_format_Init( &p_dec->fmt_out, AUDIO_ES, AOUT_FMT_S16_NE );
215     p_dec->fmt_out.audio.i_rate = p_dec->fmt_in.audio.i_rate;
216     p_dec->fmt_out.audio.i_channels = p_dec->fmt_in.audio.i_channels;
217     p_dec->fmt_out.audio.i_bitspersample =
218         p_dec->fmt_in.audio.i_bitspersample;
219     p_dec->fmt_out.audio.i_physical_channels =
220     p_dec->fmt_out.audio.i_original_channels =
221         pi_channels_maps[p_dec->fmt_out.audio.i_channels];
222
223     aout_DateInit( &p_sys->end_date, p_dec->fmt_out.audio.i_rate );
224     aout_DateSet( &p_sys->end_date, 0 );
225
226     p_dec->pf_decode_audio = Decode;
227
228     p_sys->p_out = malloc( 4096 * 10 );
229     p_sys->i_out = 0;
230
231     return VLC_SUCCESS;
232 }
233
234 /*****************************************************************************
235  * Close:
236  *****************************************************************************/
237 static void Close( vlc_object_t *p_this )
238 {
239     decoder_t *p_dec = (decoder_t*)p_this;
240
241     CloseDll( p_dec );
242     if( p_dec->p_sys->p_out ) free( p_dec->p_sys->p_out );
243     free( p_dec->p_sys );
244 }
245
246 /*****************************************************************************
247  * OpenDll:
248  *****************************************************************************/
249 static int OpenDll( decoder_t *p_dec )
250 {
251     char *psz_dll;
252     int i, i_result;
253
254     char *ppsz_path[] =
255     {
256       ".",
257 #ifndef WIN32
258       "/usr/local/RealPlayer8/Codecs",
259       "/usr/RealPlayer8/Codecs",
260       "/usr/lib/RealPlayer8/Codecs",
261       "/opt/RealPlayer8/Codecs",
262       "/usr/lib/RealPlayer9/users/Real/Codecs",
263       "/usr/lib64/RealPlayer8/Codecs",
264       "/usr/lib64/RealPlayer9/users/Real/Codecs",
265       "/usr/lib/win32",
266 #endif
267       NULL,
268       NULL,
269       NULL
270     };
271
272 #ifdef WIN32
273     char psz_win32_real_codecs[MAX_PATH + 1];
274     char psz_win32_helix_codecs[MAX_PATH + 1];
275 #endif
276
277     for( i = 0; ppsz_path[i]; i++ )
278     {
279         asprintf( &psz_dll, "%s/%4.4s.so.6.0", ppsz_path[i],
280                   (char *)&p_dec->fmt_in.i_codec );
281         i_result = OpenNativeDll( p_dec, ppsz_path[i], psz_dll );
282         free( psz_dll );
283         if( i_result == VLC_SUCCESS ) return VLC_SUCCESS;
284     }
285
286 #ifdef WIN32
287     {
288         HKEY h_key;
289         DWORD i_type, i_data = MAX_PATH + 1, i_index = 1;
290         char *p_data;
291
292         p_data = psz_win32_real_codecs;
293         if( RegOpenKeyEx( HKEY_CLASSES_ROOT,
294                           _T("Software\\RealNetworks\\Preferences\\DT_Codecs"),
295                           0, KEY_READ, &h_key ) == ERROR_SUCCESS )
296         {
297              if( RegQueryValueEx( h_key, _T(""), 0, &i_type,
298                                   (LPBYTE)p_data, &i_data ) == ERROR_SUCCESS &&
299                  i_type == REG_SZ )
300              {
301                  int i_len = strlen( p_data );
302                  if( i_len && p_data[i_len-1] == '\\' ) p_data[i_len-1] = 0;
303                  ppsz_path[i_index++] = p_data;
304                  msg_Err( p_dec, "Real: %s", p_data );
305              }
306              RegCloseKey( h_key );
307         }
308
309         p_data = psz_win32_helix_codecs;
310         if( RegOpenKeyEx( HKEY_CLASSES_ROOT,
311                           _T("Helix\\HelixSDK\\10.0\\Preferences\\DT_Codecs"),
312                           0, KEY_READ, &h_key ) == ERROR_SUCCESS )
313         {
314              if( RegQueryValueEx( h_key, _T(""), 0, &i_type,
315                                   (LPBYTE)p_data, &i_data ) == ERROR_SUCCESS &&
316                  i_type == REG_SZ )
317              {
318                  int i_len = strlen( p_data );
319                  if( i_len && p_data[i_len-1] == '\\' ) p_data[i_len-1] = 0;
320                  ppsz_path[i_index++] = p_data;
321                  msg_Err( p_dec, "Real: %s", p_data );
322              }
323              RegCloseKey( h_key );
324         }
325     }
326 #endif
327
328     for( i = 0; ppsz_path[i]; i++ )
329     {
330         /* New format */
331         asprintf( &psz_dll, "%s\\%4.4s.dll", ppsz_path[i],
332                   (char *)&p_dec->fmt_in.i_codec );
333         i_result = OpenWin32Dll( p_dec, ppsz_path[i], psz_dll );
334         free( psz_dll );
335         if( i_result == VLC_SUCCESS ) return VLC_SUCCESS;
336
337         /* Old format */
338         asprintf( &psz_dll, "%s\\%4.4s3260.dll", ppsz_path[i],
339                   (char *)&p_dec->fmt_in.i_codec );
340         i_result = OpenWin32Dll( p_dec, ppsz_path[i], psz_dll );
341         free( psz_dll );
342         if( i_result == VLC_SUCCESS ) return VLC_SUCCESS;
343     }
344
345     return VLC_EGENERIC;
346 }
347
348 static int OpenNativeDll( decoder_t *p_dec, char *psz_path, char *psz_dll )
349 {
350 #if defined(HAVE_DL_DLOPEN)
351     decoder_sys_t *p_sys = p_dec->p_sys;
352     void *handle = 0, *context = 0;
353     unsigned int i_result;
354     void *p_prop;
355     int i_prop;
356
357     ra_init_t init_data =
358     {
359         p_dec->fmt_in.audio.i_rate,
360         p_dec->fmt_in.audio.i_bitspersample,
361         p_dec->fmt_in.audio.i_channels,
362         100, /* quality */
363         p_dec->fmt_in.audio.i_blockalign, /* subpacket size */
364         p_dec->fmt_in.audio.i_blockalign, /* coded frame size */
365         p_dec->fmt_in.i_extra, p_dec->fmt_in.p_extra
366     };
367
368     msg_Dbg( p_dec, "opening library '%s'", psz_dll );
369     if( !(handle = dlopen( psz_dll, RTLD_LAZY )) )
370     {
371         msg_Dbg( p_dec, "couldn't load library '%s' (%s)",
372                  psz_dll, dlerror() );
373         return VLC_EGENERIC;
374     }
375
376     p_sys->raCloseCodec = dlsym( handle, "RACloseCodec" );
377     p_sys->raDecode = dlsym( handle, "RADecode" );
378     p_sys->raFlush = dlsym( handle, "RAFlush" );
379     p_sys->raFreeDecoder = dlsym( handle, "RAFreeDecoder" );
380     p_sys->raGetFlavorProperty = dlsym( handle, "RAGetFlavorProperty" );
381     p_sys->raOpenCodec = dlsym( handle, "RAOpenCodec" );
382     p_sys->raOpenCodec2 = dlsym( handle, "RAOpenCodec2" );
383     p_sys->raInitDecoder = dlsym( handle, "RAInitDecoder" );
384     p_sys->raSetFlavor = dlsym( handle, "RASetFlavor" );
385     p_sys->raSetDLLAccessPath = dlsym( handle, "SetDLLAccessPath" );
386     p_sys->raSetPwd = dlsym( handle, "RASetPwd" ); // optional, used by SIPR
387
388     if( !(p_sys->raOpenCodec || p_sys->raOpenCodec2) ||
389         !p_sys->raCloseCodec || !p_sys->raInitDecoder ||
390         !p_sys->raDecode || !p_sys->raFreeDecoder ||
391         !p_sys->raGetFlavorProperty || !p_sys->raSetFlavor
392         /* || !p_sys->raFlush || !p_sys->raSetDLLAccessPath */ )
393     {
394         goto error_native;
395     }
396
397     if( p_sys->raOpenCodec2 )
398         i_result = p_sys->raOpenCodec2( &context, psz_path );
399     else
400         i_result = p_sys->raOpenCodec( &context );
401
402     if( i_result )
403     {
404         msg_Err( p_dec, "decoder open failed, error code: 0x%x", i_result );
405         goto error_native;
406     }
407
408     i_result = p_sys->raInitDecoder( context, &init_data );
409     if( i_result )
410     {
411         msg_Err( p_dec, "decoder init failed, error code: 0x%x", i_result );
412         goto error_native;
413     }
414
415     if( p_sys->i_codec_flavor >= 0 )
416     {
417         i_result = p_sys->raSetFlavor( context, p_sys->i_codec_flavor );
418         if( i_result )
419         {
420             msg_Err( p_dec, "decoder flavor setup failed, error code: 0x%x",
421                      i_result );
422             goto error_native;
423         }
424
425         p_prop = p_sys->raGetFlavorProperty( context, p_sys->i_codec_flavor,
426                                              0, &i_prop );
427         msg_Dbg( p_dec, "audio codec: [%d] %s",
428                  p_sys->i_codec_flavor, (char *)p_prop );
429
430         p_prop = p_sys->raGetFlavorProperty( context, p_sys->i_codec_flavor,
431                                              1, &i_prop );
432         if( p_prop )
433         {
434             int i_bps = ((*((int*)p_prop))+4)/8;
435             msg_Dbg( p_dec, "audio bitrate: %5.3f kbit/s (%d bps)",
436                      (*((int*)p_prop))*0.001f, i_bps );
437         }
438     }
439
440     p_sys->context = context;
441     p_sys->dll = handle;
442     return VLC_SUCCESS;
443
444  error_native:
445     if( context ) p_sys->raFreeDecoder( context );
446     if( context ) p_sys->raCloseCodec( context );
447     dlclose( handle );
448 #endif
449
450     return VLC_EGENERIC;
451 }
452
453 static int OpenWin32Dll( decoder_t *p_dec, char *psz_path, char *psz_dll )
454 {
455 #if defined(LOADER) || defined(WIN32)
456     decoder_sys_t *p_sys = p_dec->p_sys;
457     void *handle = 0, *context = 0;
458     unsigned int i_result;
459     void *p_prop;
460     int i_prop;
461
462     wra_init_t init_data =
463     {
464         p_dec->fmt_in.audio.i_rate,
465         p_dec->fmt_in.audio.i_bitspersample,
466         p_dec->fmt_in.audio.i_channels,
467         100, /* quality */
468         p_dec->fmt_in.audio.i_blockalign, /* subpacket size */
469         p_dec->fmt_in.audio.i_blockalign, /* coded frame size */
470         p_dec->fmt_in.i_extra, p_dec->fmt_in.p_extra
471     };
472
473     msg_Dbg( p_dec, "opening win32 dll '%s'", psz_dll );
474
475 #ifdef LOADER
476     Setup_LDT_Keeper();
477 #endif
478
479     if( !(handle = LoadLibraryA( psz_dll )) )
480     {
481         msg_Dbg( p_dec, "couldn't load dll '%s'", psz_dll );
482         return VLC_EGENERIC;
483     }
484
485     p_sys->wraCloseCodec = GetProcAddress( handle, "RACloseCodec" );
486     p_sys->wraDecode = GetProcAddress( handle, "RADecode" );
487     p_sys->wraFlush = GetProcAddress( handle, "RAFlush" );
488     p_sys->wraFreeDecoder = GetProcAddress( handle, "RAFreeDecoder" );
489     p_sys->wraGetFlavorProperty =
490         GetProcAddress( handle, "RAGetFlavorProperty" );
491     p_sys->wraOpenCodec = GetProcAddress( handle, "RAOpenCodec" );
492     p_sys->wraOpenCodec2 = GetProcAddress( handle, "RAOpenCodec2" );
493     p_sys->wraInitDecoder = GetProcAddress( handle, "RAInitDecoder" );
494     p_sys->wraSetFlavor = GetProcAddress( handle, "RASetFlavor" );
495     p_sys->wraSetDLLAccessPath = GetProcAddress( handle, "SetDLLAccessPath" );
496     p_sys->wraSetPwd =
497         GetProcAddress( handle, "RASetPwd" ); // optional, used by SIPR
498
499     if( !(p_sys->wraOpenCodec || p_sys->wraOpenCodec2) ||
500         !p_sys->wraCloseCodec || !p_sys->wraInitDecoder ||
501         !p_sys->wraDecode || !p_sys->wraFreeDecoder ||
502         !p_sys->wraGetFlavorProperty || !p_sys->wraSetFlavor
503         /* || !p_sys->wraFlush || !p_sys->wraSetDLLAccessPath */ )
504     {
505         FreeLibrary( handle );
506         return VLC_EGENERIC;
507     }
508
509     if( p_sys->wraOpenCodec2 )
510         i_result = p_sys->wraOpenCodec2( &context, psz_path );
511     else
512         i_result = p_sys->wraOpenCodec( &context );
513
514     if( i_result )
515     {
516         msg_Err( p_dec, "decoder open failed, error code: 0x%x", i_result );
517         goto error_win32;
518     }
519
520     i_result = p_sys->wraInitDecoder( context, &init_data );
521     if( i_result )
522     {
523         msg_Err( p_dec, "decoder init failed, error code: 0x%x", i_result );
524         goto error_win32;
525     }
526
527     if( p_sys->i_codec_flavor >= 0 )
528     {
529         i_result = p_sys->wraSetFlavor( context, p_sys->i_codec_flavor );
530         if( i_result )
531         {
532             msg_Err( p_dec, "decoder flavor setup failed, error code: 0x%x",
533                      i_result );
534             goto error_win32;
535         }
536
537         p_prop = p_sys->wraGetFlavorProperty( context, p_sys->i_codec_flavor,
538                                               0, &i_prop );
539         msg_Dbg( p_dec, "audio codec: [%d] %s",
540                  p_sys->i_codec_flavor, (char *)p_prop );
541
542         p_prop = p_sys->wraGetFlavorProperty( context, p_sys->i_codec_flavor,
543                                               1, &i_prop );
544         if( p_prop )
545         {
546             int i_bps = ((*((int*)p_prop))+4)/8;
547             msg_Dbg( p_dec, "audio bitrate: %5.3f kbit/s (%d bps)",
548                      (*((int*)p_prop))*0.001f, i_bps );
549         }
550     }
551
552     p_sys->context = context;
553     p_sys->win32_dll = handle;
554     return VLC_SUCCESS;
555
556  error_win32:
557     if( context ) p_sys->wraFreeDecoder( context );
558     if( context ) p_sys->wraCloseCodec( context );
559     FreeLibrary( handle );
560 #endif
561
562     return VLC_EGENERIC;
563 }
564
565 /*****************************************************************************
566  * CloseDll:
567  *****************************************************************************/
568 static void CloseDll( decoder_t *p_dec )
569 {
570     decoder_sys_t *p_sys = p_dec->p_sys;
571
572     if( p_sys->context && p_sys->dll )
573     {
574         p_sys->raFreeDecoder( p_sys->context );
575         p_sys->raCloseCodec( p_sys->context );
576     }
577
578     if( p_sys->context && p_sys->win32_dll )
579     {
580         p_sys->wraFreeDecoder( p_sys->context );
581         p_sys->wraCloseCodec( p_sys->context );
582     }
583
584 #if defined(HAVE_DL_DLOPEN)
585     if( p_sys->dll ) dlclose( p_sys->dll );
586 #endif
587
588 #if defined(LOADER) || defined(WIN32)
589     if( p_sys->win32_dll ) FreeLibrary( p_sys->win32_dll );
590
591 #if 0 //def LOADER /* Segfaults */
592     Restore_LDT_Keeper( p_sys->ldt_fs );
593     msg_Dbg( p_dec, "Restore_LDT_Keeper" );
594 #endif
595 #endif
596
597     p_sys->dll = 0;
598     p_sys->win32_dll = 0;
599     p_sys->context = 0;
600 }
601
602 /*****************************************************************************
603  * DecodeAudio:
604  *****************************************************************************/
605 static aout_buffer_t *Decode( decoder_t *p_dec, block_t **pp_block )
606 {
607     decoder_sys_t *p_sys = p_dec->p_sys;
608     aout_buffer_t *p_aout_buffer = 0;
609     unsigned int i_result;
610     int i_samples;
611     block_t *p_block;
612
613 #ifdef LOADER
614     if( !p_sys->win32_dll && !p_sys->dll )
615     {
616         /* We must do open and close in the same thread (unless we do
617          * Setup_LDT_Keeper in the main thread before all others */
618         if( OpenDll( p_dec ) != VLC_SUCCESS )
619         {
620             /* Fatal */
621             p_dec->b_error = VLC_TRUE;
622             return NULL;
623         }
624     }
625 #endif
626
627     if( pp_block == NULL || *pp_block == NULL ) return NULL;
628     p_block = *pp_block;
629
630     if( p_sys->dll )
631         i_result = p_sys->raDecode( p_sys->context, (char *)p_block->p_buffer,
632                                     (unsigned long)p_block->i_buffer,
633                                     p_sys->p_out, &p_sys->i_out, -1 );
634     else
635         i_result = p_sys->wraDecode( p_sys->context, (char *)p_block->p_buffer,
636                                      (unsigned long)p_block->i_buffer,
637                                      p_sys->p_out, &p_sys->i_out, -1 );
638
639 #if 0
640     msg_Err( p_dec, "decoded: %i samples (%i)",
641              p_sys->i_out * 8 / p_dec->fmt_out.audio.i_bitspersample /
642              p_dec->fmt_out.audio.i_channels, i_result );
643 #endif
644
645     /* Date management */
646     if( p_block->i_pts > 0 &&
647         p_block->i_pts != aout_DateGet( &p_sys->end_date ) )
648     {
649         aout_DateSet( &p_sys->end_date, p_block->i_pts );
650     }
651
652     if( !aout_DateGet( &p_sys->end_date ) )
653     {
654         /* We've just started the stream, wait for the first PTS. */
655         if( p_block ) block_Release( p_block );
656         return NULL;
657     }
658
659     i_samples = p_sys->i_out * 8 /
660         p_dec->fmt_out.audio.i_bitspersample /p_dec->fmt_out.audio.i_channels;
661
662     p_aout_buffer =
663         p_dec->pf_aout_buffer_new( p_dec, i_samples );
664     if( p_aout_buffer )
665     {
666         memcpy( p_aout_buffer->p_buffer, p_sys->p_out, p_sys->i_out );
667
668         /* Date management */
669         p_aout_buffer->start_date = aout_DateGet( &p_sys->end_date );
670         p_aout_buffer->end_date =
671             aout_DateIncrement( &p_sys->end_date, i_samples );
672     }
673
674     block_Release( p_block );
675     *pp_block = 0;
676     return p_aout_buffer;
677 }