[MPlayer-dev-eng] [PATCH] Real Audio/Video DLL support for Mac OS X

Donnie Smith xc0bead2d8130df59 at f4n.org
Wed Jun 25 17:14:07 CEST 2003


As requsted by Alex Beregszaszi I'm sending in a "raw" patch to add
support for Real's shared libraries for Mac OS X. 

I decided upon the following (no one answered), numbering refering to
http://mplayerhq.hu/pipermail/mplayer-dev-eng/2003-June/019418.html:
1, Using USE_MACSHLB
2, Put load_one_sym_mac in ad_realaud.c and using it in vd_realvid.c
   as well.
3, Did some creative #if:ing.

I have not patched configure, codecs.conf or the documentation. I felt
a bit uneasy trying to update configure, so perhaps someone could add
a --enable/disable-macshlb switch that controls USE_MACSHLB. I wasn't
sure if updating codecs.conf was a good idea either since someone
might find it annoying (it would try to load Mac OS X codecs if the
Linux and Windows codecs failed to load); why isn't there a platform
directive for codecs.conf? I guess I could simply add a .shlb entry
after the .so and .dll entries, but it's not a perfect solution.
(On Mac OS X it would try to open the .so and .dll files first,
resulting in quite a lot of output).

Entries like the following should be added:
videocodec rv40mac
  info "Mac RealPlayer 9 RV40 decoder"
  status working
  fourcc RV40,rv40
  driver realvid
  dll "drv4.shlb"
  out I420

(However, if you want you can name your .shlb --> .so.6.0 and it will work
just fine, although the "Linux" part might be a bit misleading.)

I plan to update the documentation (in accordance with patches.txt),
but I'd like someone to clarify the correct changes of codecs.conf
first (should a platform directive be added?). I should mention one
important point though: The codecs reside in 
RealOne\ Player.app/Contents/MacOS/Library/Codecs, but you need to
copy RealOne\ Player.app/Contents/MacOS/Library/Codecs/pncrt.Shlb
into the Codecs directory (or somewhere else where CFM will find it).
When copying the .shlb:s, remember that they have a resource fork
(with an important cfrag-resource), so it's easiest to copy them with
the Finder or ditto -rsrcFork. If you fail to move the pncrt.Shlb to
the correct place, or fail to copy the resource fork you'll get an
error message like:

GetDiskFragment() failed with error -2804: 
<<Unknown disk fragment>><<Unknown disk fragment>><pncrt.Shlb><>

I've tried it with various .rm/.ra files and it appears to be working
(Ah My Goddess.rm, hehe). Sorry I didn't submit it a year ago ;)

------

I also have a general suggestion for ad_realaud/vd_realvid:

Currently (with the patch applied) there are three different ways to
load a Real library and the selection is controlled by HAVE_LIBDL,
USE_WIN32DLL and USE_MACSHLB. It's probably a good idea to change the
HAVE_LIBDL to USE_XXX (something suitable). Mac OS X doesn't support
libdl natively, but there is a "compatibility" library available, and
with HAVE_LIBDL and USE_MACSHLB defined on Mac OS X, the code will
break (although it's possible to #ifdef out of this problem).
Suggestion: extend the dll_type to always signal what type of library
that's used.  This way one could switch() (or whatever) in the cleanup
code to decide whether to dlclose() (libdl), FreeLibrary() (DLL) or
CloseConnection() (shlb). The current code assumes that
defined(HAVE_LIBDL) && defined(USE_MACSHLB) always is false.

I also spotted a (very) probably bug in ad_realaud.c (I left it alone
in the current patch though):

-------
#ifdef USE_WIN32DLL
    if (dll_type == 1)
    {
        if (rv_handle) FreeLibrary(rv_handle);
    } else
#endif
// this dlclose() causes some memory corruption, and crashes soon (in
// caller):
//    if (rv_handle) dlclose(rv_handle);
    rv_handle = NULL;
-------

It doesn't always set rv_handle = NULL with Win32 DLLs...

-------

I'll have a look at the cache2.c code tonight and see if I can spot
the potential Mac OS X incompatiblity. Also it appears as if -liconv
isn't added in the linking process (which results in an build error on
Mac OS X at least), I'll check that one out too.

Donnie Smith
-------------- next part --------------
--- MPlayer-20030625-orig/libmpcodecs/vd_realvid.c	2003-05-20 21:19:32.000000000 +0200
+++ MPlayer-20030625/libmpcodecs/vd_realvid.c	2003-06-25 14:05:24.000000000 +0200
@@ -13,6 +13,10 @@
 
 #include "vd_internal.h"
 
+#ifdef USE_MACSHLB
+#include <CoreServices/CoreServices.h>
+#endif
+
 static vd_info_t info = {
 	"RealVideo decoder",
 	"realvid",
@@ -176,6 +180,68 @@
 }
 #endif
 
+#ifdef USE_MACSHLB
+void *load_one_sym_mac(char *symbolName, CFragConnectionID *connID);
+static int load_syms_mac(char *path) {
+    void *handle;
+
+    Ptr mainAddr;
+    OSStatus status;
+    FSRef fsref;
+    FSSpec fsspec;
+    OSErr err;
+    Str255 errMessage;
+    CFragConnectionID *connID;
+    
+    mp_msg(MSGT_DECVIDEO,MSGL_INFO, "opening mac shlb '%s'\n", path);
+
+    if ( (connID = (CFragConnectionID *)NewPtr( sizeof( CFragConnectionID ))) == nil ) {
+        mp_msg(MSGT_DECVIDEO,MSGL_WARN,"NewPtr() failed.\n" );
+        return 0;
+    }
+
+    rv_handle = connID;
+
+    if ( (status = FSPathMakeRef( path, &fsref, NULL )) != noErr ) {
+        mp_msg(MSGT_DECVIDEO,MSGL_WARN,"FSPathMakeRef() failed with error %d.\n", status );
+        return 0;
+    }
+
+    if ( (status = FSGetCatalogInfo( &fsref, kFSCatInfoNone, NULL, NULL, &fsspec, NULL )) != noErr ) {
+        mp_msg(MSGT_DECVIDEO,MSGL_WARN,"FSGetCatalogInfo() failed with error %d.\n", status );
+        return 0;
+    }
+    
+    if ( (err = GetDiskFragment( &fsspec, 0, kCFragGoesToEOF, NULL, kPrivateCFragCopy, connID, &mainAddr, errMessage )) != noErr ) {
+
+        p2cstrcpy( errMessage, errMessage );
+        mp_msg(MSGT_DECVIDEO,MSGL_WARN,"GetDiskFragment() failed with error %d: %s\n", err, errMessage );
+        return 0;
+    }
+
+    rvyuv_custom_message = load_one_sym_mac("\x19RV20toYUV420CustomMessage", connID);
+    rvyuv_free = load_one_sym_mac("\x10RV20toYUV420Free", connID);
+    rvyuv_hive_message = load_one_sym_mac("\x17RV20toYUV420HiveMessage", connID);
+    rvyuv_init = load_one_sym_mac("\x10RV20toYUV420Init", connID);
+    rvyuv_transform = load_one_sym_mac("\x15RV20toYUV420Transform", connID);
+
+    if(rvyuv_custom_message &&
+       rvyuv_free &&
+       rvyuv_hive_message &&
+       rvyuv_init &&
+       rvyuv_transform)
+    {
+    rv_handle = connID;
+    return 1;
+    }
+
+    mp_msg(MSGT_DECVIDEO,MSGL_WARN,"Error resolving symbols! (version incompatibility?)\n");
+    (void)CloseConnection(connID);
+    return 0; // error
+}
+#endif
+
+
 /* we need exact positions */
 struct rv_init_t {
 	short unk1;
@@ -213,6 +279,9 @@
 #ifdef USE_WIN32DLL
 	    if (!load_syms_windows(path))
 #endif
+#ifdef USE_MACSHLB
+        if (!load_syms_mac(path))
+#endif
 	{
 		mp_msg(MSGT_DECVIDEO,MSGL_ERR,MSGTR_MissingDLLcodec,sh->codec->dll);
 		mp_msg(MSGT_DECVIDEO,MSGL_HINT,"Read the RealVideo section of the DOCS!\n");
@@ -270,6 +339,17 @@
 #ifdef HAVE_LIBDL
 	if(rv_handle) dlclose(rv_handle);
 #endif
+#ifdef USE_MACSHLB
+    if (rv_handle){
+      (void)CloseConnection(rv_handle);
+      DisposePtr((Ptr)rv_handle);
+    }
+    if (rvyuv_custom_message) DisposePtr((Ptr)rvyuv_custom_message);
+    if (rvyuv_free) DisposePtr((Ptr)rvyuv_free);
+    if (rvyuv_hive_message) DisposePtr((Ptr)rvyuv_hive_message);
+    if (rvyuv_init) DisposePtr((Ptr)rvyuv_init);
+    if (rvyuv_transform) DisposePtr((Ptr)rvyuv_transform);
+#endif
 	rv_handle=NULL;
 }
 
--- MPlayer-20030625-orig/libmpcodecs/ad_realaud.c	2003-05-20 21:19:32.000000000 +0200
+++ MPlayer-20030625/libmpcodecs/ad_realaud.c	2003-06-25 14:17:16.000000000 +0200
@@ -15,6 +15,10 @@
 
 #include "ad_internal.h"
 
+#ifdef USE_MACSHLB
+#include <CoreServices/CoreServices.h>
+#endif
+
 static ad_info_t info =  {
 	"RealAudio decoder",
 	"realaud",
@@ -205,6 +209,104 @@
 }
 #endif
 
+#ifdef USE_MACSHLB
+/*
+ Helper function to create a function pointer (from a null terminated
+ pascal string) like GetProcAddress(). Some assembler is required due
+ to different calling conventions, see http://developer.apple.com/samplecode/
+ Sample_Code/Runtime_Architecture/CFM_MachO_CFM/CFM_MachO_CFM.c.htm for
+ further details.
+
+ Caller is expected to DisposePtr(mfp).
+ Code is used by vd_realaud.c as well.
+*/
+void *load_one_sym_mac(char *symbolName, CFragConnectionID *connID) {
+    OSErr err;
+    Ptr symbolAddr;
+    CFragSymbolClass symbolClass;
+    UInt32  *mfp;
+
+    if ( (err = FindSymbol( *connID, symbolName, 
+                            &symbolAddr, &symbolClass )) != noErr ) {
+        mp_msg(MSGT_DECVIDEO,MSGL_V,"FindSymbol( \"%s\" ) failed with error code %d.\n", symbolName + 1, err );
+        return NULL;
+    }
+
+    if ( (mfp = (UInt32 *)NewPtr( 6 * sizeof(UInt32) )) == nil )
+        return NULL;
+
+    mfp[0] = 0x3D800000 | ((UInt32)symbolAddr >> 16);
+    mfp[1] = 0x618C0000 | ((UInt32)symbolAddr & 0xFFFF);
+    mfp[2] = 0x800C0000;
+    mfp[3] = 0x804C0004;
+    mfp[4] = 0x7C0903A6;
+    mfp[5] = 0x4E800420;
+    MakeDataExecutable( mfp, 6 * sizeof(UInt32) );
+
+    return( mfp );
+}
+
+static int load_syms_mac(char *path)
+{
+    Ptr mainAddr;
+    OSStatus status;
+    FSRef fsref;
+    FSSpec fsspec;
+    OSErr err;
+    Str255 errMessage;
+    CFragConnectionID *connID;
+    
+    mp_msg(MSGT_DECVIDEO, MSGL_INFO, "opening mac shlb '%s'\n", path);
+
+    if ( (connID = (CFragConnectionID *)NewPtr( sizeof( CFragConnectionID ))) == nil ) {
+        mp_msg(MSGT_DECVIDEO,MSGL_WARN,"NewPtr() failed.\n" );
+        return 0;
+    }
+
+    if ( (status = FSPathMakeRef( path, &fsref, NULL )) != noErr ) {
+        mp_msg(MSGT_DECVIDEO,MSGL_WARN,"FSPathMakeRef() failed with error %d.\n", status );
+        return 0;
+    }
+
+    if ( (status = FSGetCatalogInfo( &fsref, kFSCatInfoNone, NULL, NULL, &fsspec, NULL )) != noErr ) {
+        mp_msg(MSGT_DECVIDEO,MSGL_WARN,"FSGetCatalogInfo() failed with error %d.\n", status );
+        return 0;
+    }
+    
+    if ( (err = GetDiskFragment( &fsspec, 0, kCFragGoesToEOF, NULL, kPrivateCFragCopy, connID, &mainAddr, errMessage )) != noErr ) {
+
+        p2cstrcpy( errMessage, errMessage );
+        mp_msg(MSGT_DECVIDEO,MSGL_WARN,"GetDiskFragment() failed with error %d: %s\n", err, errMessage );
+        return 0;
+    }
+
+    raCloseCodec = load_one_sym_mac( "\xcRACloseCodec", connID);
+    raDecode = load_one_sym_mac("\x8RADecode", connID);
+    raFlush = load_one_sym_mac("\x7RAFlush", connID);
+    raFreeDecoder = load_one_sym_mac("\xdRAFreeDecoder", connID);
+    raGetFlavorProperty = load_one_sym_mac("\x13RAGetFlavorProperty", connID);
+    raOpenCodec = load_one_sym_mac("\xbRAOpenCodec", connID);
+    raOpenCodec2 = load_one_sym_mac("\xcRAOpenCodec2", connID);
+    raInitDecoder = load_one_sym_mac("\xdRAInitDecoder", connID);
+    raSetFlavor = load_one_sym_mac("\xbRASetFlavor", connID);
+    raSetDLLAccessPath = load_one_sym_mac("\x10SetDLLAccessPath", connID);
+    raSetPwd = load_one_sym_mac("\x8RASetPwd", connID); // optional, used by SIPR
+    
+    if (raCloseCodec && raDecode && /*raFlush && */raFreeDecoder &&
+    raGetFlavorProperty && (raOpenCodec || raOpenCodec2) && raSetFlavor &&
+    /*raSetDLLAccessPath &&*/ raInitDecoder)
+    {
+    rv_handle = connID;
+    return 1;
+    }
+    
+    mp_msg(MSGT_DECAUDIO,MSGL_WARN,"Cannot resolve symbols - incompatible shlb: %s\n",path);
+    (void)CloseConnection(connID);
+    return 0;
+}
+
+#endif
+
 static int preinit(sh_audio_t *sh){
   // let's check if the driver is available, return 0 if not.
   // (you should do that if you use external lib(s) which is optional)
@@ -225,6 +327,9 @@
 #ifdef USE_WIN32DLL
 	if (!load_sysm_windows(path))
 #endif
+#ifdef USE_MACSHLB
+    if (!load_syms_mac(path))
+#endif
     {
 	mp_msg(MSGT_DECVIDEO, MSGL_ERR, MSGTR_MissingDLLcodec, sh->codec->dll);
 	mp_msg(MSGT_DECVIDEO, MSGL_HINT, "Read the RealAudio section of the DOCS!\n");
@@ -292,7 +397,8 @@
 	((short*)(sh->wf+1))[4], // codec data length
 	((char*)(sh->wf+1))+10 // extras
     };
-#ifdef USE_WIN32DLL
+
+#if defined(USE_WIN32DLL) || defined(USE_MACSHLB)
     wra_init_t winit_data={
 	sh->wf->nSamplesPerSec,
 	sh->wf->wBitsPerSample,
@@ -303,11 +409,17 @@
 	((short*)(sh->wf+1))[4], // codec data length
 	((char*)(sh->wf+1))+10 // extras
     };
+#endif
+#ifdef USE_MACSHLB
+    result=raInitDecoder(sh->context,&winit_data);
+#else
+#ifdef USE_WIN32DLL
     if (dll_type == 1)
 	result=wraInitDecoder(sh->context,&winit_data);
     else
 #endif
     result=raInitDecoder(sh->context,&init_data);
+#endif
     if(result){
       mp_msg(MSGT_DECAUDIO,MSGL_WARN,"Decoder init failed, error code: 0x%X\n",result);
       return 0;
@@ -394,6 +506,20 @@
     if (raFreeDecoder) raFreeDecoder(sh->context);
     if (raCloseCodec) raCloseCodec(sh->context);
 
+#ifdef USE_MACSHLB
+    if (rv_handle){
+      (void)CloseConnection(rv_handle);
+      DisposePtr((Ptr)rv_handle);
+    }
+    if (raCloseCodec) DisposePtr((Ptr)raCloseCodec);
+    if (raDecode) DisposePtr((Ptr)raDecode);
+    if (raFlush) DisposePtr((Ptr)raFlush);
+    if (raFreeDecoder) DisposePtr((Ptr)raFreeDecoder);
+    if (raGetFlavorProperty) DisposePtr((Ptr)raGetFlavorProperty);
+    if (raOpenCodec) DisposePtr((Ptr)raOpenCodec);
+    if (raOpenCodec2) DisposePtr((Ptr)raOpenCodec2);
+    if (raInitDecoder) DisposePtr((Ptr)raInitDecoder);
+#endif
 #ifdef USE_WIN32DLL
     if (dll_type == 1)
     {


More information about the MPlayer-dev-eng mailing list