16 #include "ad_internal.h"
17 #include "wine/windef.h"
20 #include <CoreServices/CoreServices.h>
23 static ad_info_t info
= {
27 "Florian Schneider, Arpad Gereoffy, Alex Beregszaszi, Donnie Smith",
28 "binary real audio codecs"
33 void *__builtin_new(unsigned long size
) {
37 // required for cook's uninit:
38 void __builtin_delete(void* ize
) {
42 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
46 static unsigned long (*raCloseCodec
)(void*);
47 static unsigned long (*raDecode
)(void*, char*,unsigned long,char*,unsigned int*,long);
48 static unsigned long (*raFlush
)(unsigned long,unsigned long,unsigned long);
49 static unsigned long (*raFreeDecoder
)(void*);
50 static void* (*raGetFlavorProperty
)(void*,unsigned long,unsigned long,int*);
51 //static unsigned long (*raGetNumberOfFlavors2)(void);
52 static unsigned long (*raInitDecoder
)(void*, void*);
53 static unsigned long (*raOpenCodec
)(void*);
54 static unsigned long (*raOpenCodec2
)(void*, void*);
55 static unsigned long (*raSetFlavor
)(void*,unsigned long);
56 static void (*raSetDLLAccessPath
)(char*);
57 static void (*raSetPwd
)(char*,char*);
59 static unsigned long WINAPI (*wraCloseCodec
)(void*);
60 static unsigned long WINAPI (*wraDecode
)(void*, char*,unsigned long,char*,unsigned int*,long);
61 static unsigned long WINAPI (*wraFlush
)(unsigned long,unsigned long,unsigned long);
62 static unsigned long WINAPI (*wraFreeDecoder
)(void*);
63 static void* WINAPI (*wraGetFlavorProperty
)(void*,unsigned long,unsigned long,int*);
64 static unsigned long WINAPI (*wraInitDecoder
)(void*, void*);
65 static unsigned long WINAPI (*wraOpenCodec
)(void*);
66 static unsigned long WINAPI (*wraOpenCodec2
)(void*, void*);
67 static unsigned long WINAPI (*wraSetFlavor
)(void*,unsigned long);
68 static void WINAPI (*wraSetDLLAccessPath
)(char*);
69 static void WINAPI (*wraSetPwd
)(char*,char*);
71 static int dll_type
= 0; /* 0 = unix dlopen, 1 = win32 dll */
74 static void *rv_handle
= NULL
;
90 Probably the linux .so-s were compiled with old GCC without setting
91 packing, so it adds 2 bytes padding after the quality field.
92 In windows it seems that there's no padding in it.
97 /* linux dlls doesn't need packing */
98 typedef struct /*__attribute__((__packed__))*/ {
103 /* 2bytes padding here, by gcc */
110 /* windows dlls need packed structs (no padding) */
111 typedef struct __attribute__((__packed__
)) {
124 static int load_syms_linux(char *path
)
128 mp_msg(MSGT_DECVIDEO
, MSGL_INFO
, "opening shared obj '%s'\n", path
);
129 handle
= dlopen(path
, RTLD_LAZY
);
132 mp_msg(MSGT_DECVIDEO
, MSGL_WARN
, "Error: %s\n", dlerror());
136 raCloseCodec
= dlsym(handle
, "RACloseCodec");
137 raDecode
= dlsym(handle
, "RADecode");
138 raFlush
= dlsym(handle
, "RAFlush");
139 raFreeDecoder
= dlsym(handle
, "RAFreeDecoder");
140 raGetFlavorProperty
= dlsym(handle
, "RAGetFlavorProperty");
141 raOpenCodec
= dlsym(handle
, "RAOpenCodec");
142 raOpenCodec2
= dlsym(handle
, "RAOpenCodec2");
143 raInitDecoder
= dlsym(handle
, "RAInitDecoder");
144 raSetFlavor
= dlsym(handle
, "RASetFlavor");
145 raSetDLLAccessPath
= dlsym(handle
, "SetDLLAccessPath");
146 raSetPwd
= dlsym(handle
, "RASetPwd"); // optional, used by SIPR
148 if (raCloseCodec
&& raDecode
&& /*raFlush && */raFreeDecoder
&&
149 raGetFlavorProperty
&& (raOpenCodec
||raOpenCodec2
) && raSetFlavor
&&
150 /*raSetDLLAccessPath &&*/ raInitDecoder
)
156 mp_msg(MSGT_DECAUDIO
,MSGL_WARN
,"Cannot resolve symbols - incompatible dll: %s\n",path
);
165 #include "../loader/ldt_keeper.h"
167 void* WINAPI
LoadLibraryA(char* name
);
168 void* WINAPI
GetProcAddress(void* handle
,char *func
);
169 int WINAPI
FreeLibrary(void *handle
);
171 static int load_syms_windows(char *path
)
175 mp_msg(MSGT_DECVIDEO
, MSGL_INFO
, "opening win32 dll '%s'\n", path
);
179 handle
= LoadLibraryA(path
);
182 mp_msg(MSGT_DECVIDEO
, MSGL_WARN
, "Error loading dll\n");
186 wraCloseCodec
= GetProcAddress(handle
, "RACloseCodec");
187 wraDecode
= GetProcAddress(handle
, "RADecode");
188 wraFlush
= GetProcAddress(handle
, "RAFlush");
189 wraFreeDecoder
= GetProcAddress(handle
, "RAFreeDecoder");
190 wraGetFlavorProperty
= GetProcAddress(handle
, "RAGetFlavorProperty");
191 wraOpenCodec
= GetProcAddress(handle
, "RAOpenCodec");
192 wraOpenCodec2
= GetProcAddress(handle
, "RAOpenCodec2");
193 wraInitDecoder
= GetProcAddress(handle
, "RAInitDecoder");
194 wraSetFlavor
= GetProcAddress(handle
, "RASetFlavor");
195 wraSetDLLAccessPath
= GetProcAddress(handle
, "SetDLLAccessPath");
196 wraSetPwd
= GetProcAddress(handle
, "RASetPwd"); // optional, used by SIPR
198 if (wraCloseCodec
&& wraDecode
&& /*wraFlush && */wraFreeDecoder
&&
199 wraGetFlavorProperty
&& (wraOpenCodec
|| wraOpenCodec2
) && wraSetFlavor
&&
200 /*wraSetDLLAccessPath &&*/ wraInitDecoder
)
207 mp_msg(MSGT_DECAUDIO
,MSGL_WARN
,"Cannot resolve symbols - incompatible dll: %s\n",path
);
217 Helper function to create a function pointer (from a null terminated (!)
218 pascal string) like GetProcAddress(). Some assembler is required due
219 to different calling conventions, for further details, see
220 http://developer.apple.com/ samplecode/CFM_MachO_CFM/listing1.html .
222 Caller is expected to DisposePtr(mfp).
223 N.B.: Code is used by vd_realaud.c as well.
225 void *load_one_sym_mac(char *symbolName
, CFragConnectionID
*connID
) {
228 CFragSymbolClass symbolClass
;
232 if (strlen(symbolName
) > 255)
234 mp_msg(MSGT_DECVIDEO
, MSGL_V
, "FindSymbol symbolname overflow\n");
238 snprintf(realname
, 255, "%c%s", strlen(symbolName
), symbolName
);
240 if ( (err
= FindSymbol( *connID
, realname
,
241 &symbolAddr
, &symbolClass
)) != noErr
) {
242 mp_msg(MSGT_DECVIDEO
,MSGL_V
,"FindSymbol( \"%s\" ) failed with error code %d.\n", symbolName
+ 1, err
);
246 if ( (mfp
= (UInt32
*)NewPtr( 6 * sizeof(UInt32
) )) == nil
)
249 mfp
[0] = 0x3D800000 | ((UInt32
)symbolAddr
>> 16);
250 mfp
[1] = 0x618C0000 | ((UInt32
)symbolAddr
& 0xFFFF);
255 MakeDataExecutable( mfp
, 6 * sizeof(UInt32
) );
260 static int load_syms_mac(char *path
)
268 CFragConnectionID
*connID
;
270 mp_msg(MSGT_DECVIDEO
, MSGL_INFO
, "opening mac shlb '%s'\n", path
);
272 if ( (connID
= (CFragConnectionID
*)NewPtr( sizeof( CFragConnectionID
))) == nil
) {
273 mp_msg(MSGT_DECVIDEO
,MSGL_WARN
,"NewPtr() failed.\n" );
277 if ( (status
= FSPathMakeRef( path
, &fsref
, NULL
)) != noErr
) {
278 mp_msg(MSGT_DECVIDEO
,MSGL_WARN
,"FSPathMakeRef() failed with error %d.\n", status
);
282 if ( (status
= FSGetCatalogInfo( &fsref
, kFSCatInfoNone
, NULL
, NULL
, &fsspec
, NULL
)) != noErr
) {
283 mp_msg(MSGT_DECVIDEO
,MSGL_WARN
,"FSGetCatalogInfo() failed with error %d.\n", status
);
287 if ( (err
= GetDiskFragment( &fsspec
, 0, kCFragGoesToEOF
, NULL
, kPrivateCFragCopy
, connID
, &mainAddr
, errMessage
)) != noErr
) {
289 p2cstrcpy( errMessage
, errMessage
);
290 mp_msg(MSGT_DECVIDEO
,MSGL_WARN
,"GetDiskFragment() failed with error %d: %s\n", err
, errMessage
);
294 raCloseCodec
= load_one_sym_mac( "RACloseCodec", connID
);
295 raDecode
= load_one_sym_mac("RADecode", connID
);
296 raFlush
= load_one_sym_mac("RAFlush", connID
);
297 raFreeDecoder
= load_one_sym_mac("RAFreeDecoder", connID
);
298 raGetFlavorProperty
= load_one_sym_mac("RAGetFlavorProperty", connID
);
299 raOpenCodec
= load_one_sym_mac("RAOpenCodec", connID
);
300 raOpenCodec2
= load_one_sym_mac("RAOpenCodec2", connID
);
301 raInitDecoder
= load_one_sym_mac("RAInitDecoder", connID
);
302 raSetFlavor
= load_one_sym_mac("RASetFlavor", connID
);
303 raSetDLLAccessPath
= load_one_sym_mac("SetDLLAccessPath", connID
);
304 raSetPwd
= load_one_sym_mac("RASetPwd", connID
); // optional, used by SIPR
306 if (raCloseCodec
&& raDecode
&& /*raFlush && */raFreeDecoder
&&
307 raGetFlavorProperty
&& (raOpenCodec
|| raOpenCodec2
) && raSetFlavor
&&
308 /*raSetDLLAccessPath &&*/ raInitDecoder
)
314 mp_msg(MSGT_DECAUDIO
,MSGL_WARN
,"Cannot resolve symbols - incompatible shlb: %s\n",path
);
315 (void)CloseConnection(connID
);
321 static int preinit(sh_audio_t
*sh
){
322 // let's check if the driver is available, return 0 if not.
323 // (you should do that if you use external lib(s) which is optional)
329 path
= malloc(strlen(REALCODEC_PATH
)+strlen(sh
->codec
->dll
)+2);
331 sprintf(path
, REALCODEC_PATH
"/%s", sh
->codec
->dll
);
333 /* first try to load linux dlls, if failed and we're supporting win32 dlls,
334 then try to load the windows ones */
337 if (strstr(sh
->codec
->dll
,".shlb") && !load_syms_mac(path
))
340 if (strstr(sh
->codec
->dll
,".dll") || !load_syms_linux(path
))
343 if (!load_syms_windows(sh
->codec
->dll
))
346 mp_msg(MSGT_DECVIDEO
, MSGL_ERR
, MSGTR_MissingDLLcodec
, sh
->codec
->dll
);
347 mp_msg(MSGT_DECVIDEO
, MSGL_HINT
, "Read the RealAudio section of the DOCS!\n");
353 if((raSetDLLAccessPath
&& dll_type
== 0) || (wraSetDLLAccessPath
&& dll_type
== 1)){
355 if(raSetDLLAccessPath
){
359 path
= realloc(path
, strlen(REALCODEC_PATH
) + 12);
360 sprintf(path
, "DT_Codecs=" REALCODEC_PATH
);
361 if(path
[strlen(path
)-1]!='/'){
362 path
[strlen(path
)+1]=0;
363 path
[strlen(path
)]='/';
365 path
[strlen(path
)+1]=0;
369 for (i
=0; i
< strlen(path
); i
++)
370 if (path
[i
] == '/') path
[i
] = '\\';
371 wraSetDLLAccessPath(path
);
375 raSetDLLAccessPath(path
);
381 result
=wraOpenCodec2(&sh
->context
,REALCODEC_PATH
"\\");
383 result
=wraOpenCodec(&sh
->context
);
387 result
=raOpenCodec2(&sh
->context
,REALCODEC_PATH
"/");
389 result
=raOpenCodec(&sh
->context
);
391 mp_msg(MSGT_DECAUDIO
,MSGL_WARN
,"Decoder open failed, error code: 0x%X\n",result
);
394 // printf("opencodec ok (result: %x)\n", result);
395 free(path
); /* after this it isn't used anymore */
397 sh
->samplerate
=sh
->wf
->nSamplesPerSec
;
398 sh
->samplesize
=sh
->wf
->wBitsPerSample
/8;
399 sh
->channels
=sh
->wf
->nChannels
;
402 ra_init_t init_data
={
403 sh
->wf
->nSamplesPerSec
,
404 sh
->wf
->wBitsPerSample
,
407 ((short*)(sh
->wf
+1))[0], // subpacket size
408 ((short*)(sh
->wf
+1))[3], // coded frame size
409 ((short*)(sh
->wf
+1))[4], // codec data length
410 ((char*)(sh
->wf
+1))+10 // extras
412 #if defined(USE_WIN32DLL) || defined(USE_MACSHLB)
413 wra_init_t winit_data
={
414 sh
->wf
->nSamplesPerSec
,
415 sh
->wf
->wBitsPerSample
,
418 ((short*)(sh
->wf
+1))[0], // subpacket size
419 ((short*)(sh
->wf
+1))[3], // coded frame size
420 ((short*)(sh
->wf
+1))[4], // codec data length
421 ((char*)(sh
->wf
+1))+10 // extras
425 result
=raInitDecoder(sh
->context
,&winit_data
);
429 result
=wraInitDecoder(sh
->context
,&winit_data
);
432 result
=raInitDecoder(sh
->context
,&init_data
);
435 mp_msg(MSGT_DECAUDIO
,MSGL_WARN
,"Decoder init failed, error code: 0x%X\n",result
);
438 // printf("initdecoder ok (result: %x)\n", result);
442 if((raSetPwd
&& dll_type
== 0) || (wraSetPwd
&& dll_type
== 1)){
449 wraSetPwd(sh
->context
,"Ardubancel Quazanga");
452 raSetPwd(sh
->context
,"Ardubancel Quazanga"); // set password... lol.
457 result
=wraSetFlavor(sh
->context
,((short*)(sh
->wf
+1))[2]);
460 result
=raSetFlavor(sh
->context
,((short*)(sh
->wf
+1))[2]);
462 mp_msg(MSGT_DECAUDIO
,MSGL_WARN
,"Decoder flavor setup failed, error code: 0x%X\n",result
);
468 prop
=wraGetFlavorProperty(sh
->context
,((short*)(sh
->wf
+1))[2],0,&len
);
471 prop
=raGetFlavorProperty(sh
->context
,((short*)(sh
->wf
+1))[2],0,&len
);
472 mp_msg(MSGT_DECAUDIO
,MSGL_INFO
,"Audio codec: [%d] %s\n",((short*)(sh
->wf
+1))[2],prop
);
476 prop
=wraGetFlavorProperty(sh
->context
,((short*)(sh
->wf
+1))[2],1,&len
);
479 prop
=raGetFlavorProperty(sh
->context
,((short*)(sh
->wf
+1))[2],1,&len
);
481 sh
->i_bps
=((*((int*)prop
))+4)/8;
482 mp_msg(MSGT_DECAUDIO
,MSGL_INFO
,"Audio bitrate: %5.3f kbit/s (%d bps) \n",(*((int*)prop
))*0.001f
,sh
->i_bps
);
484 sh
->i_bps
=12000; // dunno :((( [12000 seems to be OK for crash.rmvb too]
486 // prop=raGetFlavorProperty(sh->context,((short*)(sh->wf+1))[2],0x13,&len);
487 // mp_msg(MSGT_DECAUDIO,MSGL_INFO,"Samples/block?: %d \n",(*((int*)prop)));
489 sh
->audio_out_minsize
=128000; // no idea how to get... :(
490 sh
->audio_in_minsize
=((short*)(sh
->wf
+1))[1]*sh
->wf
->nBlockAlign
;
492 return 1; // return values: 1=OK 0=ERROR
495 static int init(sh_audio_t
*sh_audio
){
496 // initialize the decoder, set tables etc...
498 // you can store HANDLE or private struct pointer at sh->context
499 // you can access WAVEFORMATEX header at sh->wf
501 // set sample format/rate parameters if you didn't do it in preinit() yet.
503 return 1; // return values: 1=OK 0=ERROR
506 static void uninit(sh_audio_t
*sh
){
507 // uninit the decoder etc...
508 // again: you don't have to free() a_in_buffer here! it's done by the core.
512 if (wraFreeDecoder
) wraFreeDecoder(sh
->context
);
513 if (wraCloseCodec
) wraCloseCodec(sh
->context
);
517 if (raFreeDecoder
) raFreeDecoder(sh
->context
);
518 if (raCloseCodec
) raCloseCodec(sh
->context
);
522 (void)CloseConnection(rv_handle
);
523 DisposePtr((Ptr
)rv_handle
);
525 if (raCloseCodec
) DisposePtr((Ptr
)raCloseCodec
);
526 if (raDecode
) DisposePtr((Ptr
)raDecode
);
527 if (raFlush
) DisposePtr((Ptr
)raFlush
);
528 if (raFreeDecoder
) DisposePtr((Ptr
)raFreeDecoder
);
529 if (raGetFlavorProperty
) DisposePtr((Ptr
)raGetFlavorProperty
);
530 if (raOpenCodec
) DisposePtr((Ptr
)raOpenCodec
);
531 if (raOpenCodec2
) DisposePtr((Ptr
)raOpenCodec2
);
532 if (raInitDecoder
) DisposePtr((Ptr
)raInitDecoder
);
538 if (rv_handle
) FreeLibrary(rv_handle
);
541 // this dlclose() causes some memory corruption, and crashes soon (in caller):
542 // if (rv_handle) dlclose(rv_handle);
546 static unsigned char sipr_swaps
[38][2]={
547 {0,63},{1,22},{2,44},{3,90},{5,81},{7,31},{8,86},{9,58},{10,36},{12,68},
548 {13,39},{14,73},{15,53},{16,69},{17,57},{19,88},{20,34},{21,71},{24,46},
549 {25,94},{26,54},{28,75},{29,50},{32,70},{33,92},{35,74},{38,85},{40,56},
550 {42,87},{43,65},{45,59},{48,79},{49,93},{51,89},{55,95},{61,76},{67,83},
553 static int decode_audio(sh_audio_t
*sh
,unsigned char *buf
,int minlen
,int maxlen
){
556 int sps
=((short*)(sh
->wf
+1))[0];
557 int w
=sh
->wf
->nBlockAlign
; // 5
558 int h
=((short*)(sh
->wf
+1))[1];
559 int cfs
=((short*)(sh
->wf
+1))[3];
561 // printf("bs=%d sps=%d w=%d h=%d \n",sh->wf->nBlockAlign,sps,w,h);
564 if(sh
->a_in_buffer_len
<=0){
566 if (sh
->format
== mmioFOURCC('1','4','_','4')) {
567 demux_read_data(sh
->ds
, sh
->a_in_buffer
, sh
->wf
->nBlockAlign
);
568 sh
->a_in_buffer_size
=
569 sh
->a_in_buffer_len
=sh
->wf
->nBlockAlign
;
571 if (sh
->format
== mmioFOURCC('2','8','_','8')) {
573 for (j
= 0; j
< h
; j
++)
574 for (i
= 0; i
< h
/2; i
++)
575 demux_read_data(sh
->ds
, sh
->a_in_buffer
+i
*2*w
+j
*cfs
, cfs
);
576 sh
->a_in_buffer_size
=
577 sh
->a_in_buffer_len
=sh
->wf
->nBlockAlign
*h
;
582 int bs
=h
*w
*2/96; // nibbles per subpacket
583 unsigned char *p
=sh
->a_in_buffer
;
584 demux_read_data(sh
->ds
, p
, h
*w
);
586 int i
=bs
*sipr_swaps
[n
][0];
587 int o
=bs
*sipr_swaps
[n
][1];
588 // swap nibbles of block 'i' with 'o' TODO: optimize
590 int x
=(i
&1) ? (p
[(i
>>1)]>>4) : (p
[(i
>>1)]&15);
591 int y
=(o
&1) ? (p
[(o
>>1)]>>4) : (p
[(o
>>1)]&15);
592 if(o
&1) p
[(o
>>1)]=(p
[(o
>>1)]&0x0F)|(x
<<4);
593 else p
[(o
>>1)]=(p
[(o
>>1)]&0xF0)|x
;
594 if(i
&1) p
[(i
>>1)]=(p
[(i
>>1)]&0x0F)|(y
<<4);
595 else p
[(i
>>1)]=(p
[(i
>>1)]&0xF0)|y
;
599 sh
->a_in_buffer_size
=
600 sh
->a_in_buffer_len
=w
*h
;
607 demux_read_data(sh
->ds
, sh
->a_in_buffer
+sps
*(h
*x
+((h
+1)/2)*(y
&1)+(y
>>1)), sps
);
609 sh
->a_in_buffer_size
=
610 sh
->a_in_buffer_len
=w
*h
*sps
;
615 if(sh
->a_in_buffer_len
<=0){
617 demux_read_data(sh
->ds
, sh
->a_in_buffer
, sh
->wf
->nBlockAlign
);
618 sh
->a_in_buffer_size
=
619 sh
->a_in_buffer_len
=sh
->wf
->nBlockAlign
;
625 result
=wraDecode(sh
->context
, sh
->a_in_buffer
+sh
->a_in_buffer_size
-sh
->a_in_buffer_len
, sh
->wf
->nBlockAlign
,
629 result
=raDecode(sh
->context
, sh
->a_in_buffer
+sh
->a_in_buffer_size
-sh
->a_in_buffer_len
, sh
->wf
->nBlockAlign
,
631 sh
->a_in_buffer_len
-=sh
->wf
->nBlockAlign
;
633 // printf("radecode: %d bytes, res=0x%X \n",len,result);
635 return len
; // return value: number of _bytes_ written to output buffer,
636 // or -1 for EOF (or uncorrectable error)
639 static int control(sh_audio_t
*sh
,int cmd
,void* arg
, ...){
640 // various optional functions you MAY implement:
642 case ADCTRL_RESYNC_STREAM
:
643 // it is called once after seeking, to resync.
644 // Note: sh_audio->a_in_buffer_len=0; is done _before_ this call!
646 case ADCTRL_SKIP_FRAME
:
647 // it is called to skip (jump over) small amount (1/10 sec or 1 frame)
648 // of audio data - used to sync audio to video after seeking
649 // if you don't return CONTROL_TRUE, it will defaults to:
650 // ds_fill_buffer(sh_audio->ds); // skip 1 demux packet
653 return CONTROL_UNKNOWN
;