Support chapter seeking with ordered chapters
[mplayer.git] / libmpcodecs / ad_realaud.c
blob8135e21e4140d62af5af428d4e81d50171aa4960
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <unistd.h>
6 #include "config.h"
8 //#include <stddef.h>
9 #ifdef HAVE_LIBDL
10 #include <dlfcn.h>
11 #endif
12 #include "help_mp.h"
14 #include "ad_internal.h"
15 #include "loader/wine/windef.h"
17 static const ad_info_t info = {
18 "RealAudio decoder",
19 "realaud",
20 "Alex Beregszaszi",
21 "Florian Schneider, Arpad Gereoffy, Alex Beregszaszi, Donnie Smith",
22 "binary real audio codecs"
25 LIBAD_EXTERN(realaud)
27 void *__builtin_new(unsigned long size) {
28 return malloc(size);
31 // required for cook's uninit:
32 void __builtin_delete(void* ize) {
33 free(ize);
36 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
37 void *__ctype_b=NULL;
38 #endif
40 static unsigned long (*raCloseCodec)(void*);
41 static unsigned long (*raDecode)(void*, char*,unsigned long,char*,unsigned int*,long);
42 static unsigned long (*raFreeDecoder)(void*);
43 //static unsigned long (*raGetNumberOfFlavors2)(void);
44 static unsigned long (*raInitDecoder)(void*, void*);
45 static unsigned long (*raOpenCodec)(void*);
46 static unsigned long (*raOpenCodec2)(void*, void*);
47 static unsigned long (*raSetFlavor)(void*,unsigned long);
48 static void (*raSetDLLAccessPath)(char*);
49 static void (*raSetPwd)(char*,char*);
50 #ifdef CONFIG_WIN32DLL
51 static unsigned long WINAPI (*wraCloseCodec)(void*);
52 static unsigned long WINAPI (*wraDecode)(void*, char*,unsigned long,char*,unsigned int*,long);
53 static unsigned long WINAPI (*wraFreeDecoder)(void*);
54 static unsigned long WINAPI (*wraInitDecoder)(void*, void*);
55 static unsigned long WINAPI (*wraOpenCodec)(void*);
56 static unsigned long WINAPI (*wraOpenCodec2)(void*, void*);
57 static unsigned long WINAPI (*wraSetFlavor)(void*,unsigned long);
58 static void WINAPI (*wraSetDLLAccessPath)(char*);
59 static void WINAPI (*wraSetPwd)(char*,char*);
61 static int dll_type = 0; /* 0 = unix dlopen, 1 = win32 dll */
62 #endif
64 static void *rv_handle = NULL;
66 #if 0
67 typedef struct {
68 int samplerate;
69 short bits;
70 short channels;
71 int unk1;
72 int unk2;
73 int packetsize;
74 int unk3;
75 void* unk4;
76 } ra_init_t ;
77 #else
80 Probably the linux .so-s were compiled with old GCC without setting
81 packing, so it adds 2 bytes padding after the quality field.
82 In windows it seems that there's no padding in it.
84 -- alex
87 /* linux dlls doesn't need packing */
88 typedef struct /*__attribute__((__packed__))*/ {
89 int samplerate;
90 short bits;
91 short channels;
92 short quality;
93 /* 2bytes padding here, by gcc */
94 int bits_per_frame;
95 int packetsize;
96 int extradata_len;
97 void* extradata;
98 } ra_init_t;
100 /* windows dlls need packed structs (no padding) */
101 typedef struct __attribute__((__packed__)) {
102 int samplerate;
103 short bits;
104 short channels;
105 short quality;
106 int bits_per_frame;
107 int packetsize;
108 int extradata_len;
109 void* extradata;
110 } wra_init_t;
111 #endif
113 #ifdef HAVE_LIBDL
114 static int load_syms_linux(char *path)
116 void *handle;
118 mp_msg(MSGT_DECVIDEO, MSGL_V, "opening shared obj '%s'\n", path);
119 handle = dlopen(path, RTLD_LAZY);
120 if (!handle)
122 mp_msg(MSGT_DECVIDEO, MSGL_WARN, "Error: %s\n", dlerror());
123 return 0;
126 raCloseCodec = dlsym(handle, "RACloseCodec");
127 raDecode = dlsym(handle, "RADecode");
128 raFreeDecoder = dlsym(handle, "RAFreeDecoder");
129 raOpenCodec = dlsym(handle, "RAOpenCodec");
130 raOpenCodec2 = dlsym(handle, "RAOpenCodec2");
131 raInitDecoder = dlsym(handle, "RAInitDecoder");
132 raSetFlavor = dlsym(handle, "RASetFlavor");
133 raSetDLLAccessPath = dlsym(handle, "SetDLLAccessPath");
134 raSetPwd = dlsym(handle, "RASetPwd"); // optional, used by SIPR
136 if (raCloseCodec && raDecode && raFreeDecoder &&
137 (raOpenCodec||raOpenCodec2) && raSetFlavor &&
138 /*raSetDLLAccessPath &&*/ raInitDecoder)
140 rv_handle = handle;
141 return 1;
144 mp_msg(MSGT_DECAUDIO,MSGL_WARN,"Cannot resolve symbols - incompatible dll: %s\n",path);
145 dlclose(handle);
146 return 0;
148 #endif
150 #ifdef CONFIG_WIN32DLL
152 #ifdef WIN32_LOADER
153 #include "loader/ldt_keeper.h"
154 #endif
155 void* WINAPI LoadLibraryA(char* name);
156 void* WINAPI GetProcAddress(void* handle,char *func);
157 int WINAPI FreeLibrary(void *handle);
159 static int load_syms_windows(char *path)
161 void *handle;
163 mp_msg(MSGT_DECVIDEO, MSGL_V, "opening win32 dll '%s'\n", path);
164 #ifdef WIN32_LOADER
165 Setup_LDT_Keeper();
166 #endif
167 handle = LoadLibraryA(path);
168 if (!handle)
170 mp_msg(MSGT_DECVIDEO, MSGL_WARN, "Error loading dll\n");
171 return 0;
174 wraCloseCodec = GetProcAddress(handle, "RACloseCodec");
175 wraDecode = GetProcAddress(handle, "RADecode");
176 wraFreeDecoder = GetProcAddress(handle, "RAFreeDecoder");
177 wraOpenCodec = GetProcAddress(handle, "RAOpenCodec");
178 wraOpenCodec2 = GetProcAddress(handle, "RAOpenCodec2");
179 wraInitDecoder = GetProcAddress(handle, "RAInitDecoder");
180 wraSetFlavor = GetProcAddress(handle, "RASetFlavor");
181 wraSetDLLAccessPath = GetProcAddress(handle, "SetDLLAccessPath");
182 wraSetPwd = GetProcAddress(handle, "RASetPwd"); // optional, used by SIPR
184 if (wraCloseCodec && wraDecode && wraFreeDecoder &&
185 (wraOpenCodec || wraOpenCodec2) && wraSetFlavor &&
186 /*wraSetDLLAccessPath &&*/ wraInitDecoder)
188 rv_handle = handle;
189 dll_type = 1;
190 return 1;
193 mp_msg(MSGT_DECAUDIO,MSGL_WARN,"Cannot resolve symbols - incompatible dll: %s\n",path);
194 FreeLibrary(handle);
195 return 0;
198 #endif
201 static int preinit(sh_audio_t *sh){
202 // let's check if the driver is available, return 0 if not.
203 // (you should do that if you use external lib(s) which is optional)
204 unsigned int result;
205 char *path;
207 path = malloc(strlen(REALCODEC_PATH)+strlen(sh->codec->dll)+2);
208 if (!path) return 0;
209 sprintf(path, REALCODEC_PATH "/%s", sh->codec->dll);
211 /* first try to load linux dlls, if failed and we're supporting win32 dlls,
212 then try to load the windows ones */
214 #ifdef HAVE_LIBDL
215 if (strstr(sh->codec->dll,".dll") || !load_syms_linux(path))
216 #endif
217 #ifdef CONFIG_WIN32DLL
218 if (!load_syms_windows(sh->codec->dll))
219 #endif
221 mp_msg(MSGT_DECVIDEO, MSGL_ERR, MSGTR_MissingDLLcodec, sh->codec->dll);
222 mp_msg(MSGT_DECVIDEO, MSGL_HINT, "Read the RealAudio section of the DOCS!\n");
223 free(path);
224 return 0;
227 #ifdef CONFIG_WIN32DLL
228 if((raSetDLLAccessPath && dll_type == 0) || (wraSetDLLAccessPath && dll_type == 1)){
229 #else
230 if(raSetDLLAccessPath){
231 #endif
232 // used by 'SIPR'
233 path = realloc(path, strlen(REALCODEC_PATH) + 13);
234 sprintf(path, "DT_Codecs=" REALCODEC_PATH);
235 if(path[strlen(path)-1]!='/'){
236 path[strlen(path)+1]=0;
237 path[strlen(path)]='/';
239 path[strlen(path)+1]=0;
240 #ifdef CONFIG_WIN32DLL
241 if (dll_type == 1)
243 int i;
244 for (i=0; i < strlen(path); i++)
245 if (path[i] == '/') path[i] = '\\';
246 wraSetDLLAccessPath(path);
248 else
249 #endif
250 raSetDLLAccessPath(path);
253 #ifdef CONFIG_WIN32DLL
254 if (dll_type == 1){
255 if(wraOpenCodec2)
256 result=wraOpenCodec2(&sh->context,REALCODEC_PATH "\\");
257 else
258 result=wraOpenCodec(&sh->context);
259 } else
260 #endif
261 if(raOpenCodec2)
262 result=raOpenCodec2(&sh->context,REALCODEC_PATH "/");
263 else
264 result=raOpenCodec(&sh->context);
265 if(result){
266 mp_msg(MSGT_DECAUDIO,MSGL_WARN,"Decoder open failed, error code: 0x%X\n",result);
267 return 0;
269 // printf("opencodec ok (result: %x)\n", result);
270 free(path); /* after this it isn't used anymore */
272 sh->samplerate=sh->wf->nSamplesPerSec;
273 sh->samplesize=sh->wf->wBitsPerSample/8;
274 sh->channels=sh->wf->nChannels;
277 ra_init_t init_data={
278 sh->wf->nSamplesPerSec,
279 sh->wf->wBitsPerSample,
280 sh->wf->nChannels,
281 100, // quality
282 sh->wf->nBlockAlign, // subpacket size
283 sh->wf->nBlockAlign, // coded frame size
284 sh->wf->cbSize, // codec data length
285 (char*)(sh->wf+1) // extras
287 #ifdef CONFIG_WIN32DLL
288 wra_init_t winit_data={
289 sh->wf->nSamplesPerSec,
290 sh->wf->wBitsPerSample,
291 sh->wf->nChannels,
292 100, // quality
293 sh->wf->nBlockAlign, // subpacket size
294 sh->wf->nBlockAlign, // coded frame size
295 sh->wf->cbSize, // codec data length
296 (char*)(sh->wf+1) // extras
298 #endif
299 #ifdef CONFIG_WIN32DLL
300 if (dll_type == 1)
301 result=wraInitDecoder(sh->context,&winit_data);
302 else
303 #endif
304 result=raInitDecoder(sh->context,&init_data);
306 if(result){
307 mp_msg(MSGT_DECAUDIO,MSGL_WARN,"Decoder init failed, error code: 0x%X\n",result);
308 return 0;
310 // printf("initdecoder ok (result: %x)\n", result);
313 #ifdef CONFIG_WIN32DLL
314 if((raSetPwd && dll_type == 0) || (wraSetPwd && dll_type == 1)){
315 #else
316 if(raSetPwd){
317 #endif
318 // used by 'SIPR'
319 #ifdef CONFIG_WIN32DLL
320 if (dll_type == 1)
321 wraSetPwd(sh->context,"Ardubancel Quazanga");
322 else
323 #endif
324 raSetPwd(sh->context,"Ardubancel Quazanga"); // set password... lol.
327 if (sh->format == mmioFOURCC('s','i','p','r')) {
328 short flavor;
330 if (sh->wf->nAvgBytesPerSec > 1531)
331 flavor = 3;
332 else if (sh->wf->nAvgBytesPerSec > 937)
333 flavor = 1;
334 else if (sh->wf->nAvgBytesPerSec > 719)
335 flavor = 0;
336 else
337 flavor = 2;
338 mp_msg(MSGT_DECAUDIO,MSGL_V,"Got sipr flavor %d from bitrate %d\n",flavor, sh->wf->nAvgBytesPerSec);
340 #ifdef CONFIG_WIN32DLL
341 if (dll_type == 1)
342 result=wraSetFlavor(sh->context,flavor);
343 else
344 #endif
345 result=raSetFlavor(sh->context,flavor);
346 if(result){
347 mp_msg(MSGT_DECAUDIO,MSGL_WARN,"Decoder flavor setup failed, error code: 0x%X\n",result);
348 return 0;
350 } // sipr flavor
352 sh->i_bps=sh->wf->nAvgBytesPerSec;
354 sh->audio_out_minsize=128000; // no idea how to get... :(
355 sh->audio_in_minsize = sh->wf->nBlockAlign;
357 return 1; // return values: 1=OK 0=ERROR
360 static int init(sh_audio_t *sh_audio){
361 // initialize the decoder, set tables etc...
363 // you can store HANDLE or private struct pointer at sh->context
364 // you can access WAVEFORMATEX header at sh->wf
366 // set sample format/rate parameters if you didn't do it in preinit() yet.
368 return 1; // return values: 1=OK 0=ERROR
371 static void uninit(sh_audio_t *sh){
372 // uninit the decoder etc...
373 // again: you don't have to free() a_in_buffer here! it's done by the core.
374 #ifdef CONFIG_WIN32DLL
375 if (dll_type == 1)
377 if (wraFreeDecoder) wraFreeDecoder(sh->context);
378 if (wraCloseCodec) wraCloseCodec(sh->context);
380 #endif
382 if (raFreeDecoder) raFreeDecoder(sh->context);
383 if (raCloseCodec) raCloseCodec(sh->context);
386 #ifdef CONFIG_WIN32DLL
387 if (dll_type == 1)
389 if (rv_handle) FreeLibrary(rv_handle);
390 } else
391 #endif
392 // this dlclose() causes some memory corruption, and crashes soon (in caller):
393 // if (rv_handle) dlclose(rv_handle);
394 rv_handle = NULL;
397 static int decode_audio(sh_audio_t *sh,unsigned char *buf,int minlen,int maxlen){
398 int result;
399 int len=-1;
401 if(sh->a_in_buffer_len<=0){
402 // fill the buffer!
403 if (sh->ds->eof)
404 return 0;
405 demux_read_data(sh->ds, sh->a_in_buffer, sh->wf->nBlockAlign);
406 sh->a_in_buffer_size=
407 sh->a_in_buffer_len=sh->wf->nBlockAlign;
410 #ifdef CONFIG_WIN32DLL
411 if (dll_type == 1)
412 result=wraDecode(sh->context, sh->a_in_buffer+sh->a_in_buffer_size-sh->a_in_buffer_len, sh->wf->nBlockAlign,
413 buf, &len, -1);
414 else
415 #endif
416 result=raDecode(sh->context, sh->a_in_buffer+sh->a_in_buffer_size-sh->a_in_buffer_len, sh->wf->nBlockAlign,
417 buf, &len, -1);
418 sh->a_in_buffer_len-=sh->wf->nBlockAlign;
420 // printf("radecode: %d bytes, res=0x%X \n",len,result);
422 return len; // return value: number of _bytes_ written to output buffer,
423 // or -1 for EOF (or uncorrectable error)
426 static int control(sh_audio_t *sh,int cmd,void* arg, ...){
427 // various optional functions you MAY implement:
428 switch(cmd){
429 case ADCTRL_RESYNC_STREAM:
430 // it is called once after seeking, to resync.
431 // Note: sh_audio->a_in_buffer_len=0; is done _before_ this call!
432 return CONTROL_TRUE;
433 case ADCTRL_SKIP_FRAME:
434 // it is called to skip (jump over) small amount (1/10 sec or 1 frame)
435 // of audio data - used to sync audio to video after seeking
436 // if you don't return CONTROL_TRUE, it will defaults to:
437 // ds_fill_buffer(sh_audio->ds); // skip 1 demux packet
438 return CONTROL_TRUE;
440 return CONTROL_UNKNOWN;