gst/real/gstrealaudiodec.c: Add raversions we can support on the caps.

Original commit message from CVS:
* gst/real/gstrealaudiodec.c: (gst_real_audio_dec_chain),
(close_library), (open_library),
(gst_real_audio_dec_probe_modules), (gst_real_audio_dec_getcaps),
(gst_real_audio_dec_setcaps), (gst_real_audio_dec_init),
(gst_real_audio_dec_change_state), (gst_real_audio_dec_finalize):
Add raversions we can support on the caps.
Refactor the loading of the real codecs like realvideo so that we can
implement probing.
Probe all supported formats by trying to load the .so files, only report
the versions on the caps that we can actually load.
* gst/real/gstrealvideodec.c: (gst_real_video_dec_chain),
(gst_real_video_dec_getcaps), (gst_real_video_dec_setcaps),
(open_library), (close_library),
(gst_real_video_dec_probe_modules),
(gst_real_video_dec_change_state), (gst_real_video_dec_init),
(gst_real_video_dec_finalize), (gst_real_video_dec_class_init):
* gst/real/gstrealvideodec.h:
Change the loading of the library like the audio decoder.
Probe the supported formats by trying to load the .so files and only
report the versions on the caps that we can actually load.
This commit is contained in:
Wim Taymans 2008-06-13 18:03:16 +00:00
parent 7ce74ccd5d
commit 1a39f60d9f
4 changed files with 443 additions and 182 deletions

View file

@ -1,3 +1,27 @@
2008-06-13 Wim Taymans <wim.taymans@collabora.co.uk>
* gst/real/gstrealaudiodec.c: (gst_real_audio_dec_chain),
(close_library), (open_library),
(gst_real_audio_dec_probe_modules), (gst_real_audio_dec_getcaps),
(gst_real_audio_dec_setcaps), (gst_real_audio_dec_init),
(gst_real_audio_dec_change_state), (gst_real_audio_dec_finalize):
Add raversions we can support on the caps.
Refactor the loading of the real codecs like realvideo so that we can
implement probing.
Probe all supported formats by trying to load the .so files, only report
the versions on the caps that we can actually load.
* gst/real/gstrealvideodec.c: (gst_real_video_dec_chain),
(gst_real_video_dec_getcaps), (gst_real_video_dec_setcaps),
(open_library), (close_library),
(gst_real_video_dec_probe_modules),
(gst_real_video_dec_change_state), (gst_real_video_dec_init),
(gst_real_video_dec_finalize), (gst_real_video_dec_class_init):
* gst/real/gstrealvideodec.h:
Change the loading of the library like the audio decoder.
Probe the supported formats by trying to load the .so files and only
report the versions on the caps that we can actually load.
2008-06-13 Zaheer Abbas Merali <zaheerabbas at merali dot org> 2008-06-13 Zaheer Abbas Merali <zaheerabbas at merali dot org>
patch by: Sebastian Pölsterl patch by: Sebastian Pölsterl

View file

@ -38,7 +38,9 @@ GST_ELEMENT_DETAILS ("RealAudio decoder",
static GstStaticPadTemplate snk_t = static GstStaticPadTemplate snk_t =
GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
GST_STATIC_CAPS ("audio/x-pn-realaudio; " "audio/x-sipro ")); GST_STATIC_CAPS ("audio/x-pn-realaudio, "
"raversion = { 3, 4, 5, 6, 8 }; " "audio/x-sipro "));
static GstStaticPadTemplate src_t = static GstStaticPadTemplate src_t =
GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
GST_STATIC_CAPS ("audio/x-raw-int, " GST_STATIC_CAPS ("audio/x-raw-int, "
@ -67,25 +69,31 @@ enum
typedef enum typedef enum
{ {
GST_REAL_AUDIO_DEC_VERSION_COOK = 8,
GST_REAL_AUDIO_DEC_VERSION_ATRK = 3, GST_REAL_AUDIO_DEC_VERSION_ATRK = 3,
GST_REAL_AUDIO_DEC_VERSION_14_4 = 4, GST_REAL_AUDIO_DEC_VERSION_14_4 = 4,
GST_REAL_AUDIO_DEC_VERSION_28_8 = 5, GST_REAL_AUDIO_DEC_VERSION_28_8 = 5,
GST_REAL_AUDIO_DEC_VERSION_SIPR = 6 GST_REAL_AUDIO_DEC_VERSION_SIPR = 6,
GST_REAL_AUDIO_DEC_VERSION_COOK = 8
} GstRealAudioDecVersion; } GstRealAudioDecVersion;
typedef struct typedef struct
{ {
guint16 (*RADecode) (gpointer, guint8 *, guint32, guint8 *, guint32 *, /* Hooks */
GModule *module;
/* Used by the REAL library. */
gpointer context;
guint16 (*RADecode) (gpointer, guint8 *, guint32, guint8 *, guint32 *,
guint32); guint32);
guint16 (*RACloseCodec) (gpointer); guint16 (*RACloseCodec) (gpointer);
guint16 (*RAFreeDecoder) (gpointer); guint16 (*RAFreeDecoder) (gpointer);
guint16 (*RAInitDecoder) (gpointer, gpointer); guint16 (*RAInitDecoder) (gpointer, gpointer);
guint16 (*RAOpenCodec2) (gpointer, const gchar *); guint16 (*RAOpenCodec2) (gpointer, const gchar *);
guint16 (*RASetFlavor) (gpointer, guint16); guint16 (*RASetFlavor) (gpointer, guint16);
void (*SetDLLAccessPath) (gchar *); void (*SetDLLAccessPath) (gchar *);
void (*RASetPwd) (gpointer, gchar *); void (*RASetPwd) (gpointer, gchar *);
} RealFunctions; } GstRADecLibrary;
typedef struct typedef struct
{ {
@ -108,16 +116,21 @@ struct _GstRealAudioDec
/* Caps */ /* Caps */
guint width, height, leaf_size; guint width, height, leaf_size;
/* Hooks */ GstRADecLibrary lib;
GModule *module;
RealFunctions funcs;
/* Used by the REAL library. */
gpointer context;
/* Properties */ /* Properties */
gchar *real_codecs_path, *racook_names, *raatrk_names, *ra14_4_names, gboolean checked_modules;
*ra28_8_names, *rasipr_names; gchar *real_codecs_path;
gchar *raatrk_names;
gboolean valid_atrk;
gchar *ra14_4_names;
gboolean valid_ra14_4;
gchar *ra28_8_names;
gboolean valid_ra28_8;
gchar *rasipr_names;
gboolean valid_sipr;
gchar *racook_names;
gboolean valid_cook;
gchar *pwd; gchar *pwd;
}; };
@ -139,7 +152,7 @@ gst_real_audio_dec_chain (GstPad * pad, GstBuffer * in)
guint16 res = 0; guint16 res = 0;
guint len; guint len;
if (G_UNLIKELY (dec->funcs.RADecode == NULL || dec->module == NULL)) if (G_UNLIKELY (dec->lib.RADecode == NULL || dec->lib.module == NULL))
goto not_negotiated; goto not_negotiated;
timestamp = GST_BUFFER_TIMESTAMP (in); timestamp = GST_BUFFER_TIMESTAMP (in);
@ -151,7 +164,7 @@ gst_real_audio_dec_chain (GstPad * pad, GstBuffer * in)
if (flow != GST_FLOW_OK) if (flow != GST_FLOW_OK)
goto done; goto done;
res = dec->funcs.RADecode (dec->context, GST_BUFFER_DATA (in), res = dec->lib.RADecode (dec->lib.context, GST_BUFFER_DATA (in),
GST_BUFFER_SIZE (in), GST_BUFFER_DATA (out), &len, -1); GST_BUFFER_SIZE (in), GST_BUFFER_DATA (out), &len, -1);
if (res != 0) if (res != 0)
@ -184,47 +197,36 @@ not_negotiated:
} }
} }
static gboolean static void
gst_real_audio_dec_setcaps (GstPad * pad, GstCaps * caps) close_library (GstRealAudioDec * dec, GstRADecLibrary * lib)
{ {
GstRealAudioDec *dec = GST_REAL_AUDIO_DEC (GST_PAD_PARENT (pad)); if (lib->context) {
GstStructure *s = gst_caps_get_structure (caps, 0); GST_LOG_OBJECT (dec, "closing library");
if (lib->RACloseCodec)
lib->RACloseCodec (lib->context);
/* lib->RAFreeDecoder (lib->context); */
lib->context = NULL;
lib->module = NULL;
lib->RACloseCodec = NULL;
}
if (lib->module) {
GST_LOG_OBJECT (dec, "closing library module");
g_module_close (lib->module);
lib->module = NULL;
}
}
static gboolean
open_library (GstRealAudioDec * dec, gint version, GstRADecLibrary * lib)
{
gchar *path, *names;
gchar **split_names, **split_path;
gint i, j;
gpointer ra_close_codec, ra_decode, ra_free_decoder; gpointer ra_close_codec, ra_decode, ra_free_decoder;
gpointer ra_open_codec2, ra_init_decoder, ra_set_flavor; gpointer ra_open_codec2, ra_init_decoder, ra_set_flavor;
gpointer set_dll_access_path = NULL, ra_set_pwd = NULL; gpointer set_dll_access_path = NULL, ra_set_pwd = NULL;
gchar *path, *names;
gchar **split_names, **split_path;
gint version, flavor, channels, rate, leaf_size, packet_size, width, height;
guint16 res = 0;
RAInit data;
gboolean bres;
const GValue *v;
GstBuffer *buf = NULL;
const gchar *name = gst_structure_get_name (s);
GModule *module = NULL;
gpointer context = NULL;
RealFunctions funcs = { NULL, };
int i, j;
gchar *tmppath = NULL; gchar *tmppath = NULL;
guint16 res = 0;
if (!strcmp (name, "audio/x-sipro"))
version = GST_REAL_AUDIO_DEC_VERSION_SIPR;
else {
if (!gst_structure_get_int (s, "raversion", &version))
goto missing_keys;
}
if (!gst_structure_get_int (s, "flavor", &flavor) ||
!gst_structure_get_int (s, "channels", &channels) ||
!gst_structure_get_int (s, "width", &width) ||
!gst_structure_get_int (s, "rate", &rate) ||
!gst_structure_get_int (s, "height", &height) ||
!gst_structure_get_int (s, "leaf_size", &leaf_size) ||
!gst_structure_get_int (s, "packet_size", &packet_size))
goto missing_keys;
if ((v = gst_structure_get_value (s, "codec_data")))
buf = g_value_peek_pointer (v);
path = dec->real_codecs_path ? dec->real_codecs_path : path = dec->real_codecs_path ? dec->real_codecs_path :
DEFAULT_REAL_CODECS_PATH; DEFAULT_REAL_CODECS_PATH;
@ -249,6 +251,8 @@ gst_real_audio_dec_setcaps (GstPad * pad, GstCaps * caps)
goto unknown_version; goto unknown_version;
} }
GST_LOG_OBJECT (dec, "splitting paths %s, names %s", path, names);
split_path = g_strsplit (path, ":", 0); split_path = g_strsplit (path, ":", 0);
split_names = g_strsplit (names, ":", 0); split_names = g_strsplit (names, ":", 0);
@ -256,10 +260,14 @@ gst_real_audio_dec_setcaps (GstPad * pad, GstCaps * caps)
for (j = 0; split_names[j]; j++) { for (j = 0; split_names[j]; j++) {
gchar *codec = g_strconcat (split_path[i], "/", split_names[j], NULL); gchar *codec = g_strconcat (split_path[i], "/", split_names[j], NULL);
module = g_module_open (codec, G_MODULE_BIND_LAZY); GST_LOG_OBJECT (dec, "opening module %s", codec);
lib->module = g_module_open (codec, G_MODULE_BIND_LAZY);
g_free (codec); g_free (codec);
if (module) if (lib->module)
goto codec_search_done; goto codec_search_done;
GST_LOG_OBJECT (dec, "failure, try next one...");
} }
} }
@ -267,37 +275,39 @@ codec_search_done:
/* we keep the path for a while to set the dll access path */ /* we keep the path for a while to set the dll access path */
g_strfreev (split_names); g_strfreev (split_names);
if (module == NULL) if (lib->module == NULL)
goto could_not_open; goto could_not_open;
if (!g_module_symbol (module, "RACloseCodec", &ra_close_codec) || GST_LOG_OBJECT (dec, "finding symbols");
!g_module_symbol (module, "RADecode", &ra_decode) ||
!g_module_symbol (module, "RAFreeDecoder", &ra_free_decoder) || if (!g_module_symbol (lib->module, "RACloseCodec", &ra_close_codec) ||
!g_module_symbol (module, "RAOpenCodec2", &ra_open_codec2) || !g_module_symbol (lib->module, "RADecode", &ra_decode) ||
!g_module_symbol (module, "RAInitDecoder", &ra_init_decoder) || !g_module_symbol (lib->module, "RAFreeDecoder", &ra_free_decoder) ||
!g_module_symbol (module, "RASetFlavor", &ra_set_flavor)) { !g_module_symbol (lib->module, "RAOpenCodec2", &ra_open_codec2) ||
!g_module_symbol (lib->module, "RAInitDecoder", &ra_init_decoder) ||
!g_module_symbol (lib->module, "RASetFlavor", &ra_set_flavor)) {
goto could_not_load; goto could_not_load;
} }
g_module_symbol (module, "RASetPwd", &ra_set_pwd); g_module_symbol (lib->module, "RASetPwd", &ra_set_pwd);
g_module_symbol (module, "SetDLLAccessPath", &set_dll_access_path); g_module_symbol (lib->module, "SetDLLAccessPath", &set_dll_access_path);
funcs.RACloseCodec = (guint16 (*)(gpointer)) ra_close_codec; lib->RACloseCodec = (guint16 (*)(gpointer)) ra_close_codec;
funcs.RADecode = lib->RADecode =
(guint16 (*)(gpointer, guint8 *, guint32, guint8 *, guint32 *, guint32)) (guint16 (*)(gpointer, guint8 *, guint32, guint8 *, guint32 *, guint32))
ra_decode; ra_decode;
funcs.RAFreeDecoder = (guint16 (*)(gpointer)) ra_free_decoder; lib->RAFreeDecoder = (guint16 (*)(gpointer)) ra_free_decoder;
funcs.RAOpenCodec2 = (guint16 (*)(gpointer, const gchar *)) ra_open_codec2; lib->RAOpenCodec2 = (guint16 (*)(gpointer, const gchar *)) ra_open_codec2;
funcs.RAInitDecoder = (guint16 (*)(gpointer, gpointer)) ra_init_decoder; lib->RAInitDecoder = (guint16 (*)(gpointer, gpointer)) ra_init_decoder;
funcs.RASetFlavor = (guint16 (*)(gpointer, guint16)) ra_set_flavor; lib->RASetFlavor = (guint16 (*)(gpointer, guint16)) ra_set_flavor;
funcs.RASetPwd = (void (*)(gpointer, gchar *)) ra_set_pwd; lib->RASetPwd = (void (*)(gpointer, gchar *)) ra_set_pwd;
funcs.SetDLLAccessPath = (void (*)(gchar *)) set_dll_access_path; lib->SetDLLAccessPath = (void (*)(gchar *)) set_dll_access_path;
if (funcs.SetDLLAccessPath) if (lib->SetDLLAccessPath)
funcs.SetDLLAccessPath (split_path[i]); lib->SetDLLAccessPath (split_path[i]);
tmppath = g_strdup_printf ("%s/", split_path[i]); tmppath = g_strdup_printf ("%s/", split_path[i]);
if ((res = funcs.RAOpenCodec2 (&context, tmppath))) { if ((res = lib->RAOpenCodec2 (&lib->context, tmppath))) {
g_free (tmppath); g_free (tmppath);
goto could_not_initialize; goto could_not_initialize;
} }
@ -306,6 +316,157 @@ codec_search_done:
/* now we are done with the split paths, so free them */ /* now we are done with the split paths, so free them */
g_strfreev (split_path); g_strfreev (split_path);
return TRUE;
/* ERRORS */
unknown_version:
{
GST_DEBUG_OBJECT (dec, "Cannot handle version %i.", version);
return FALSE;
}
could_not_open:
{
g_strfreev (split_path);
GST_DEBUG_OBJECT (dec, "Could not find library '%s' in '%s'", names, path);
return FALSE;
}
could_not_load:
{
g_strfreev (split_path);
close_library (dec, lib);
GST_DEBUG_OBJECT (dec, "Could not load all symbols: %s", g_module_error ());
return FALSE;
}
could_not_initialize:
{
close_library (dec, lib);
GST_WARNING_OBJECT (dec, "Initialization of REAL driver failed (%i).", res);
return FALSE;
}
}
static void
gst_real_audio_dec_probe_modules (GstRealAudioDec * dec)
{
GstRADecLibrary dummy = { NULL };
if ((dec->valid_atrk =
open_library (dec, GST_REAL_AUDIO_DEC_VERSION_ATRK, &dummy)))
close_library (dec, &dummy);
if ((dec->valid_ra14_4 =
open_library (dec, GST_REAL_AUDIO_DEC_VERSION_14_4, &dummy)))
close_library (dec, &dummy);
if ((dec->valid_ra28_8 =
open_library (dec, GST_REAL_AUDIO_DEC_VERSION_28_8, &dummy)))
close_library (dec, &dummy);
if ((dec->valid_sipr =
open_library (dec, GST_REAL_AUDIO_DEC_VERSION_SIPR, &dummy)))
close_library (dec, &dummy);
if ((dec->valid_cook =
open_library (dec, GST_REAL_AUDIO_DEC_VERSION_COOK, &dummy)))
close_library (dec, &dummy);
}
static GstCaps *
gst_real_audio_dec_getcaps (GstPad * pad)
{
GstRealAudioDec *dec = GST_REAL_AUDIO_DEC (GST_PAD_PARENT (pad));
GstCaps *res;
if (dec->checked_modules) {
GValue versions = { 0 };
GValue version = { 0 };
GST_LOG_OBJECT (dec, "constructing caps");
res = gst_caps_new_empty ();
g_value_init (&versions, GST_TYPE_LIST);
g_value_init (&version, G_TYPE_INT);
if (dec->valid_atrk) {
g_value_set_int (&version, GST_REAL_AUDIO_DEC_VERSION_ATRK);
gst_value_list_append_value (&versions, &version);
}
if (dec->valid_ra14_4) {
g_value_set_int (&version, GST_REAL_AUDIO_DEC_VERSION_14_4);
gst_value_list_append_value (&versions, &version);
}
if (dec->valid_ra28_8) {
g_value_set_int (&version, GST_REAL_AUDIO_DEC_VERSION_28_8);
gst_value_list_append_value (&versions, &version);
}
if (dec->valid_sipr) {
g_value_set_int (&version, GST_REAL_AUDIO_DEC_VERSION_SIPR);
gst_value_list_append_value (&versions, &version);
}
if (dec->valid_cook) {
g_value_set_int (&version, GST_REAL_AUDIO_DEC_VERSION_COOK);
gst_value_list_append_value (&versions, &version);
}
if (gst_value_list_get_size (&versions) > 0) {
res = gst_caps_new_simple ("audio/x-pn-realaudio", NULL);
gst_structure_set_value (gst_caps_get_structure (res, 0),
"raversion", &versions);
} else {
res = gst_caps_new_empty ();
}
if (dec->valid_sipr) {
gst_caps_append (res, gst_caps_new_simple ("audio/x-sipro", NULL));
}
g_value_unset (&versions);
g_value_unset (&version);
} else {
GST_LOG_OBJECT (dec, "returning padtemplate caps");
res = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
}
GST_LOG_OBJECT (dec, "returning caps %" GST_PTR_FORMAT, res);
return res;
}
static gboolean
gst_real_audio_dec_setcaps (GstPad * pad, GstCaps * caps)
{
GstRealAudioDec *dec = GST_REAL_AUDIO_DEC (GST_PAD_PARENT (pad));
GstStructure *s = gst_caps_get_structure (caps, 0);
gint version, flavor, channels, rate, leaf_size, packet_size, width, height;
guint16 res = 0;
RAInit data;
gboolean bres;
const GValue *v;
GstBuffer *buf = NULL;
const gchar *name = gst_structure_get_name (s);
if (!strcmp (name, "audio/x-sipro")) {
version = GST_REAL_AUDIO_DEC_VERSION_SIPR;
} else {
if (!gst_structure_get_int (s, "raversion", &version))
goto missing_keys;
}
if (!gst_structure_get_int (s, "flavor", &flavor) ||
!gst_structure_get_int (s, "channels", &channels) ||
!gst_structure_get_int (s, "width", &width) ||
!gst_structure_get_int (s, "rate", &rate) ||
!gst_structure_get_int (s, "height", &height) ||
!gst_structure_get_int (s, "leaf_size", &leaf_size) ||
!gst_structure_get_int (s, "packet_size", &packet_size))
goto missing_keys;
if ((v = gst_structure_get_value (s, "codec_data")))
buf = g_value_peek_pointer (v);
GST_LOG_OBJECT (dec, "opening code for version %d", version);
/* first close existing decoder */
close_library (dec, &dec->lib);
if (!open_library (dec, version, &dec->lib))
goto could_not_open;
/* we have the module, no initialize with the caps data */
data.samplerate = rate; data.samplerate = rate;
data.width = width; data.width = width;
data.channels = channels; data.channels = channels;
@ -315,16 +476,16 @@ codec_search_done:
data.datalen = buf ? GST_BUFFER_SIZE (buf) : 0; data.datalen = buf ? GST_BUFFER_SIZE (buf) : 0;
data.data = buf ? GST_BUFFER_DATA (buf) : NULL; data.data = buf ? GST_BUFFER_DATA (buf) : NULL;
if ((res = funcs.RAInitDecoder (context, &data))) { if ((res = dec->lib.RAInitDecoder (dec->lib.context, &data))) {
GST_WARNING_OBJECT (dec, "RAInitDecoder() failed"); GST_WARNING_OBJECT (dec, "RAInitDecoder() failed");
goto could_not_initialize; goto could_not_initialize;
} }
if (funcs.RASetPwd) { if (dec->lib.RASetPwd) {
funcs.RASetPwd (context, dec->pwd ? dec->pwd : DEFAULT_PWD); dec->lib.RASetPwd (dec->lib.context, dec->pwd ? dec->pwd : DEFAULT_PWD);
} }
if ((res = funcs.RASetFlavor (context, flavor))) { if ((res = dec->lib.RASetFlavor (dec->lib.context, flavor))) {
GST_WARNING_OBJECT (dec, "RASetFlavor(%d) failed", flavor); GST_WARNING_OBJECT (dec, "RASetFlavor(%d) failed", flavor);
goto could_not_initialize; goto could_not_initialize;
} }
@ -343,15 +504,8 @@ codec_search_done:
dec->width = width; dec->width = width;
dec->height = height; dec->height = height;
dec->leaf_size = leaf_size; dec->leaf_size = leaf_size;
if (dec->context) {
dec->funcs.RACloseCodec (dec->context); GST_LOG_OBJECT (dec, "opened module");
dec->funcs.RAFreeDecoder (dec->context);
}
dec->context = context;
if (dec->module)
g_module_close (dec->module);
dec->module = module;
dec->funcs = funcs;
return TRUE; return TRUE;
@ -360,41 +514,21 @@ missing_keys:
GST_DEBUG_OBJECT (dec, "Could not find all necessary keys in structure."); GST_DEBUG_OBJECT (dec, "Could not find all necessary keys in structure.");
return FALSE; return FALSE;
} }
unknown_version:
{
GST_DEBUG_OBJECT (dec, "Cannot handle version %i.", version);
return FALSE;
}
could_not_open: could_not_open:
{ {
g_strfreev (split_path); GST_DEBUG_OBJECT (dec, "Could not find decoder");
GST_DEBUG_OBJECT (dec, "Could not find library '%s' in '%s'", names, path);
return FALSE;
}
could_not_load:
{
g_module_close (module);
g_strfreev (split_path);
GST_DEBUG_OBJECT (dec, "Could not load all symbols: %s", g_module_error ());
return FALSE; return FALSE;
} }
could_not_initialize: could_not_initialize:
{ {
if (context) { close_library (dec, &dec->lib);
funcs.RACloseCodec (context);
funcs.RAFreeDecoder (context);
}
g_module_close (module);
GST_WARNING_OBJECT (dec, "Initialization of REAL driver failed (%i).", res); GST_WARNING_OBJECT (dec, "Initialization of REAL driver failed (%i).", res);
return FALSE; return FALSE;
} }
could_not_set_caps: could_not_set_caps:
{ {
if (context) { /* should normally not fail */
funcs.RACloseCodec (context); close_library (dec, &dec->lib);
funcs.RAFreeDecoder (context);
}
g_module_close (module);
GST_DEBUG_OBJECT (dec, "Could not convince peer to accept caps."); GST_DEBUG_OBJECT (dec, "Could not convince peer to accept caps.");
return FALSE; return FALSE;
} }
@ -406,6 +540,8 @@ gst_real_audio_dec_init (GstRealAudioDec * dec, GstRealAudioDecClass * klass)
dec->snk = gst_pad_new_from_static_template (&snk_t, "sink"); dec->snk = gst_pad_new_from_static_template (&snk_t, "sink");
gst_pad_set_setcaps_function (dec->snk, gst_pad_set_setcaps_function (dec->snk,
GST_DEBUG_FUNCPTR (gst_real_audio_dec_setcaps)); GST_DEBUG_FUNCPTR (gst_real_audio_dec_setcaps));
gst_pad_set_getcaps_function (dec->snk,
GST_DEBUG_FUNCPTR (gst_real_audio_dec_getcaps));
gst_pad_set_chain_function (dec->snk, gst_pad_set_chain_function (dec->snk,
GST_DEBUG_FUNCPTR (gst_real_audio_dec_chain)); GST_DEBUG_FUNCPTR (gst_real_audio_dec_chain));
gst_element_add_pad (GST_ELEMENT (dec), dec->snk); gst_element_add_pad (GST_ELEMENT (dec), dec->snk);
@ -430,10 +566,25 @@ gst_real_audio_dec_change_state (GstElement * element,
GstStateChange transition) GstStateChange transition)
{ {
GstStateChangeReturn ret; GstStateChangeReturn ret;
GstRealAudioDec *dec = GST_REAL_AUDIO_DEC (element);
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
gst_real_audio_dec_probe_modules (dec);
dec->checked_modules = TRUE;
break;
default:
break;
}
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
switch (transition) { switch (transition) {
case GST_STATE_CHANGE_PAUSED_TO_READY: case GST_STATE_CHANGE_PAUSED_TO_READY:
close_library (dec, &dec->lib);
break;
case GST_STATE_CHANGE_READY_TO_NULL:
dec->checked_modules = FALSE;
break; break;
default: default:
break; break;
@ -446,19 +597,7 @@ gst_real_audio_dec_finalize (GObject * object)
{ {
GstRealAudioDec *dec = GST_REAL_AUDIO_DEC (object); GstRealAudioDec *dec = GST_REAL_AUDIO_DEC (object);
if (dec->context) { close_library (dec, &dec->lib);
dec->funcs.RACloseCodec (dec->context);
/* Calling RAFreeDecoder seems to randomly cause SEGFAULTs.
* All other implementation (xine, mplayer) have also got this function call
* commented. So until we know more, we comment it too. */
/* dec->funcs.RAFreeDecoder (dec->context); */
dec->context = NULL;
}
if (dec->module) {
g_module_close (dec->module);
dec->module = NULL;
}
if (dec->real_codecs_path) { if (dec->real_codecs_path) {
g_free (dec->real_codecs_path); g_free (dec->real_codecs_path);

View file

@ -65,8 +65,8 @@ GST_BOILERPLATE (GstRealVideoDec, gst_real_video_dec, GstElement,
GST_TYPE_ELEMENT); GST_TYPE_ELEMENT);
static gboolean open_library (GstRealVideoDec * dec, static gboolean open_library (GstRealVideoDec * dec,
GstRealVideoDecHooks * hooks, GstRealVideoDecVersion version); GstRealVideoDecVersion version, GstRVDecLibrary * lib);
static void close_library (GstRealVideoDecHooks hooks); static void close_library (GstRealVideoDec * dec, GstRVDecLibrary * lib);
typedef struct typedef struct
{ {
@ -103,7 +103,7 @@ gst_real_video_dec_chain (GstPad * pad, GstBuffer * in)
dec = GST_REAL_VIDEO_DEC (GST_PAD_PARENT (pad)); dec = GST_REAL_VIDEO_DEC (GST_PAD_PARENT (pad));
if (G_UNLIKELY (dec->hooks.transform == NULL || dec->hooks.module == NULL)) if (G_UNLIKELY (dec->lib.Transform == NULL || dec->lib.module == NULL))
goto not_negotiated; goto not_negotiated;
data = GST_BUFFER_DATA (in); data = GST_BUFFER_DATA (in);
@ -162,9 +162,9 @@ gst_real_video_dec_chain (GstPad * pad, GstBuffer * in)
/* jump over the frag table to the fragments */ /* jump over the frag table to the fragments */
data += frag_size; data += frag_size;
result = dec->hooks.transform ( result = dec->lib.Transform (
(gchar *) data, (gchar *) data,
(gchar *) GST_BUFFER_DATA (out), &tin, &tout, dec->hooks.context); (gchar *) GST_BUFFER_DATA (out), &tin, &tout, dec->lib.context);
if (result) if (result)
goto could_not_transform; goto could_not_transform;
@ -243,10 +243,51 @@ could_not_push:
} }
} }
static gboolean static GstCaps *
gst_real_video_dec_activate_push (GstPad * pad, gboolean active) gst_real_video_dec_getcaps (GstPad * pad)
{ {
return TRUE; GstRealVideoDec *dec = GST_REAL_VIDEO_DEC (GST_PAD_PARENT (pad));
GstCaps *res;
if (dec->checked_modules) {
GValue versions = { 0 };
GValue version = { 0 };
GST_LOG_OBJECT (dec, "constructing caps");
res = gst_caps_new_empty ();
g_value_init (&versions, GST_TYPE_LIST);
g_value_init (&version, G_TYPE_INT);
if (dec->valid_rv20) {
g_value_set_int (&version, GST_REAL_VIDEO_DEC_VERSION_2);
gst_value_list_append_value (&versions, &version);
}
if (dec->valid_rv30) {
g_value_set_int (&version, GST_REAL_VIDEO_DEC_VERSION_3);
gst_value_list_append_value (&versions, &version);
}
if (dec->valid_rv40) {
g_value_set_int (&version, GST_REAL_VIDEO_DEC_VERSION_4);
gst_value_list_append_value (&versions, &version);
}
if (gst_value_list_get_size (&versions) > 0) {
res = gst_caps_new_simple ("video/x-pn-realvideo", NULL);
gst_structure_set_value (gst_caps_get_structure (res, 0),
"rmversion", &versions);
} else {
res = gst_caps_new_empty ();
}
g_value_unset (&versions);
g_value_unset (&version);
} else {
GST_LOG_OBJECT (dec, "returning padtemplate caps");
res = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
}
GST_LOG_OBJECT (dec, "returning caps %" GST_PTR_FORMAT, res);
return res;
} }
static gboolean static gboolean
@ -259,7 +300,6 @@ gst_real_video_dec_setcaps (GstPad * pad, GstCaps * caps)
gchar data[36]; gchar data[36];
gboolean bres; gboolean bres;
const GValue *v; const GValue *v;
GstRealVideoDecHooks hooks = { 0, 0, 0, 0, 0, 0 };
if (!gst_structure_get_int (s, "rmversion", &version) || if (!gst_structure_get_int (s, "rmversion", &version) ||
!gst_structure_get_int (s, "width", (gint *) & width) || !gst_structure_get_int (s, "width", (gint *) & width) ||
@ -272,8 +312,10 @@ gst_real_video_dec_setcaps (GstPad * pad, GstCaps * caps)
GST_LOG_OBJECT (dec, "Setting version to %d", version); GST_LOG_OBJECT (dec, "Setting version to %d", version);
if (!open_library (dec, &hooks, version)) close_library (dec, &dec->lib);
return FALSE;
if (!open_library (dec, version, &dec->lib))
goto open_failed;
/* Initialize REAL driver. */ /* Initialize REAL driver. */
GST_WRITE_UINT16_LE (data + 0, 11); GST_WRITE_UINT16_LE (data + 0, 11);
@ -285,8 +327,7 @@ gst_real_video_dec_setcaps (GstPad * pad, GstCaps * caps)
GST_WRITE_UINT32_LE (data + 16, 1); GST_WRITE_UINT32_LE (data + 16, 1);
GST_WRITE_UINT32_LE (data + 20, format); GST_WRITE_UINT32_LE (data + 20, format);
res = hooks.init (&data, &hooks.context); if ((res = dec->lib.Init (&data, &dec->lib.context)))
if (res)
goto could_not_initialize; goto could_not_initialize;
if ((v = gst_structure_get_value (s, "codec_data"))) { if ((v = gst_structure_get_value (s, "codec_data"))) {
@ -328,7 +369,7 @@ gst_real_video_dec_setcaps (GstPad * pad, GstCaps * caps)
for (i = 0; i < bufsize; i++) for (i = 0; i < bufsize; i++)
msgdata[i + 2] = 4 * (guint32) bufdata[i]; msgdata[i + 2] = 4 * (guint32) bufdata[i];
res = hooks.custom_message (&msg, hooks.context); res = dec->lib.Message (&msg, dec->lib.context);
g_free (msgdata); g_free (msgdata);
if (res) if (res)
@ -344,8 +385,6 @@ gst_real_video_dec_setcaps (GstPad * pad, GstCaps * caps)
if (!bres) if (!bres)
goto could_not_set_caps; goto could_not_set_caps;
close_library (dec->hooks);
dec->hooks = hooks;
dec->version = version; dec->version = version;
dec->width = width; dec->width = width;
dec->height = height; dec->height = height;
@ -361,34 +400,35 @@ missing_keys:
GST_ERROR_OBJECT (dec, "Could not find all necessary keys in structure."); GST_ERROR_OBJECT (dec, "Could not find all necessary keys in structure.");
return FALSE; return FALSE;
} }
open_failed:
{
GST_ERROR_OBJECT (dec, "failed to open library");
return FALSE;
}
could_not_initialize: could_not_initialize:
{ {
close_library (hooks);
GST_ERROR_OBJECT (dec, "Initialization of REAL driver failed (%i).", res); GST_ERROR_OBJECT (dec, "Initialization of REAL driver failed (%i).", res);
close_library (dec, &dec->lib);
return FALSE; return FALSE;
} }
could_not_allocate: could_not_allocate:
{ {
close_library (hooks);
GST_ERROR_OBJECT (dec, "Could not allocate memory."); GST_ERROR_OBJECT (dec, "Could not allocate memory.");
close_library (dec, &dec->lib);
return FALSE; return FALSE;
} }
could_not_send_message: could_not_send_message:
{ {
close_library (hooks);
GST_ERROR_OBJECT (dec, "Failed to send custom message needed for " GST_ERROR_OBJECT (dec, "Failed to send custom message needed for "
"initialization (%i).", res); "initialization (%i).", res);
close_library (dec, &dec->lib);
return FALSE; return FALSE;
} }
could_not_set_caps: could_not_set_caps:
{ {
close_library (hooks);
GST_ERROR_OBJECT (dec, "Could not convince peer to accept dimensions " GST_ERROR_OBJECT (dec, "Could not convince peer to accept dimensions "
"%i x %i.", dec->width, dec->height); "%i x %i.", dec->width, dec->height);
close_library (dec, &dec->lib);
return FALSE; return FALSE;
} }
} }
@ -396,8 +436,8 @@ could_not_set_caps:
/* Attempts to open the correct library for the configured version */ /* Attempts to open the correct library for the configured version */
static gboolean static gboolean
open_library (GstRealVideoDec * dec, GstRealVideoDecHooks * hooks, open_library (GstRealVideoDec * dec, GstRealVideoDecVersion version,
GstRealVideoDecVersion version) GstRVDecLibrary * lib)
{ {
gpointer rv_custom_msg, rv_free, rv_init, rv_transform; gpointer rv_custom_msg, rv_free, rv_init, rv_transform;
GModule *module = NULL; GModule *module = NULL;
@ -464,11 +504,11 @@ codec_search_done:
goto could_not_load; goto could_not_load;
} }
hooks->init = (GstRealVideoDecInitFunc) rv_init; lib->Init = rv_init;
hooks->free = (GstRealVideoDecFreeFunc) rv_free; lib->Free = rv_free;
hooks->transform = (GstRealVideoDecTransformFunc) rv_transform; lib->Transform = rv_transform;
hooks->custom_message = (GstRealVideoDecMessageFunc) rv_custom_msg; lib->Message = rv_custom_msg;
hooks->module = module; lib->module = module;
dec->error_count = 0; dec->error_count = 0;
@ -479,44 +519,93 @@ unknown_version:
GST_ERROR_OBJECT (dec, "Cannot handle version %i.", version); GST_ERROR_OBJECT (dec, "Cannot handle version %i.", version);
return FALSE; return FALSE;
} }
could_not_open: could_not_open:
{ {
GST_ERROR_OBJECT (dec, "Could not open library '%s' in '%s': %s", names, GST_ERROR_OBJECT (dec, "Could not open library '%s' in '%s': %s", names,
path, g_module_error ()); path, g_module_error ());
return FALSE; return FALSE;
} }
could_not_load: could_not_load:
{ {
close_library (*hooks); close_library (dec, lib);
GST_ERROR_OBJECT (dec, "Could not load all symbols: %s", g_module_error ()); GST_ERROR_OBJECT (dec, "Could not load all symbols: %s", g_module_error ());
return FALSE; return FALSE;
} }
} }
static void static void
close_library (GstRealVideoDecHooks hooks) close_library (GstRealVideoDec * dec, GstRVDecLibrary * lib)
{ {
if (hooks.context && hooks.free) if (lib->context) {
hooks.free (hooks.context); GST_LOG_OBJECT (dec, "closing library");
if (lib->Free)
if (hooks.module) { lib->Free (lib->context);
g_module_close (hooks.module);
hooks.module = NULL;
} }
if (lib->module) {
GST_LOG_OBJECT (dec, "closing library module");
g_module_close (lib->module);
lib->module = NULL;
}
memset (lib, 0, sizeof (*lib));
}
static void
gst_real_video_dec_probe_modules (GstRealVideoDec * dec)
{
GstRVDecLibrary dummy = { NULL };
if ((dec->valid_rv20 =
open_library (dec, GST_REAL_VIDEO_DEC_VERSION_2, &dummy)))
close_library (dec, &dummy);
if ((dec->valid_rv30 =
open_library (dec, GST_REAL_VIDEO_DEC_VERSION_3, &dummy)))
close_library (dec, &dummy);
if ((dec->valid_rv40 =
open_library (dec, GST_REAL_VIDEO_DEC_VERSION_4, &dummy)))
close_library (dec, &dummy);
}
static GstStateChangeReturn
gst_real_video_dec_change_state (GstElement * element,
GstStateChange transition)
{
GstStateChangeReturn ret;
GstRealVideoDec *dec = GST_REAL_VIDEO_DEC (element);
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
gst_real_video_dec_probe_modules (dec);
dec->checked_modules = TRUE;
break;
default:
break;
}
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
switch (transition) {
case GST_STATE_CHANGE_PAUSED_TO_READY:
close_library (dec, &dec->lib);
break;
case GST_STATE_CHANGE_READY_TO_NULL:
dec->checked_modules = FALSE;
break;
default:
break;
}
return ret;
} }
static void static void
gst_real_video_dec_init (GstRealVideoDec * dec, GstRealVideoDecClass * klass) gst_real_video_dec_init (GstRealVideoDec * dec, GstRealVideoDecClass * klass)
{ {
dec->snk = gst_pad_new_from_static_template (&snk_t, "sink"); dec->snk = gst_pad_new_from_static_template (&snk_t, "sink");
gst_pad_set_getcaps_function (dec->snk,
GST_DEBUG_FUNCPTR (gst_real_video_dec_getcaps));
gst_pad_set_setcaps_function (dec->snk, gst_pad_set_setcaps_function (dec->snk,
GST_DEBUG_FUNCPTR (gst_real_video_dec_setcaps)); GST_DEBUG_FUNCPTR (gst_real_video_dec_setcaps));
gst_pad_set_chain_function (dec->snk, gst_pad_set_chain_function (dec->snk,
GST_DEBUG_FUNCPTR (gst_real_video_dec_chain)); GST_DEBUG_FUNCPTR (gst_real_video_dec_chain));
gst_pad_set_activatepush_function (dec->snk,
GST_DEBUG_FUNCPTR (gst_real_video_dec_activate_push));
gst_element_add_pad (GST_ELEMENT (dec), dec->snk); gst_element_add_pad (GST_ELEMENT (dec), dec->snk);
dec->src = gst_pad_new_from_static_template (&src_t, "src"); dec->src = gst_pad_new_from_static_template (&src_t, "src");
@ -542,8 +631,7 @@ gst_real_video_dec_finalize (GObject * object)
{ {
GstRealVideoDec *dec = GST_REAL_VIDEO_DEC (object); GstRealVideoDec *dec = GST_REAL_VIDEO_DEC (object);
close_library (dec->hooks); close_library (dec, &dec->lib);
memset (&dec->hooks, 0, sizeof (dec->hooks));
if (dec->real_codecs_path) { if (dec->real_codecs_path) {
g_free (dec->real_codecs_path); g_free (dec->real_codecs_path);
@ -641,11 +729,14 @@ static void
gst_real_video_dec_class_init (GstRealVideoDecClass * klass) gst_real_video_dec_class_init (GstRealVideoDecClass * klass)
{ {
GObjectClass *object_class = G_OBJECT_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass);
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
object_class->set_property = gst_real_video_dec_set_property; object_class->set_property = gst_real_video_dec_set_property;
object_class->get_property = gst_real_video_dec_get_property; object_class->get_property = gst_real_video_dec_get_property;
object_class->finalize = gst_real_video_dec_finalize; object_class->finalize = gst_real_video_dec_finalize;
element_class->change_state = gst_real_video_dec_change_state;
g_object_class_install_property (object_class, PROP_REAL_CODECS_PATH, g_object_class_install_property (object_class, PROP_REAL_CODECS_PATH,
g_param_spec_string ("real-codecs-path", g_param_spec_string ("real-codecs-path",
"Path where to search for RealPlayer codecs", "Path where to search for RealPlayer codecs",

View file

@ -35,11 +35,6 @@ typedef struct _GstRealVideoDec GstRealVideoDec;
typedef struct _GstRealVideoDecClass GstRealVideoDecClass; typedef struct _GstRealVideoDecClass GstRealVideoDecClass;
typedef enum _GstRealVideoDecVersion GstRealVideoDecVersion; typedef enum _GstRealVideoDecVersion GstRealVideoDecVersion;
typedef guint32 (*GstRealVideoDecMessageFunc) (gpointer, gpointer);
typedef guint32 (*GstRealVideoDecFreeFunc) (gpointer);
typedef guint32 (*GstRealVideoDecInitFunc) (gpointer, gpointer);
typedef guint32 (*GstRealVideoDecTransformFunc) (gchar *, gchar *, gpointer, gpointer, gpointer);
enum _GstRealVideoDecVersion enum _GstRealVideoDecVersion
{ {
GST_REAL_VIDEO_DEC_VERSION_2 = 2, GST_REAL_VIDEO_DEC_VERSION_2 = 2,
@ -50,13 +45,21 @@ enum _GstRealVideoDecVersion
typedef struct { typedef struct {
GModule *module; GModule *module;
gpointer context;
guint32 (*Init) (gpointer, gpointer);
guint32 (*Free) (gpointer);
guint32 (*Transform) (gchar *, gchar *, gpointer, gpointer, gpointer);
guint32 (*Message) (gpointer, gpointer);
/*
GstRealVideoDecMessageFunc custom_message; GstRealVideoDecMessageFunc custom_message;
GstRealVideoDecFreeFunc free; GstRealVideoDecFreeFunc free;
GstRealVideoDecInitFunc init; GstRealVideoDecInitFunc init;
GstRealVideoDecTransformFunc transform; GstRealVideoDecTransformFunc transform;
*/
gpointer context; } GstRVDecLibrary;
} GstRealVideoDecHooks;
struct _GstRealVideoDec struct _GstRealVideoDec
{ {
@ -72,14 +75,18 @@ struct _GstRealVideoDec
gint error_count; gint error_count;
/* Hooks */ /* Library functions */
GstRealVideoDecHooks hooks; GstRVDecLibrary lib;
/* Properties */ /* Properties */
gchar *real_codecs_path; gchar *real_codecs_path;
gboolean checked_modules;
gchar *rv20_names; gchar *rv20_names;
gboolean valid_rv20;
gchar *rv30_names; gchar *rv30_names;
gboolean valid_rv30;
gchar *rv40_names; gchar *rv40_names;
gboolean valid_rv40;
gint max_errors; gint max_errors;
}; };