summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog24
-rw-r--r--gst/real/gstrealaudiodec.c393
-rw-r--r--gst/real/gstrealvideodec.c179
-rw-r--r--gst/real/gstrealvideodec.h25
4 files changed, 441 insertions, 180 deletions
diff --git a/ChangeLog b/ChangeLog
index 3a1aa7b3..bcd4b93a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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>
patch by: Sebastian Pölsterl
diff --git a/gst/real/gstrealaudiodec.c b/gst/real/gstrealaudiodec.c
index 9cb1f5df..bb07de9d 100644
--- a/gst/real/gstrealaudiodec.c
+++ b/gst/real/gstrealaudiodec.c
@@ -38,7 +38,9 @@ GST_ELEMENT_DETAILS ("RealAudio decoder",
static GstStaticPadTemplate snk_t =
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 =
GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
GST_STATIC_CAPS ("audio/x-raw-int, "
@@ -67,25 +69,31 @@ enum
typedef enum
{
- GST_REAL_AUDIO_DEC_VERSION_COOK = 8,
GST_REAL_AUDIO_DEC_VERSION_ATRK = 3,
GST_REAL_AUDIO_DEC_VERSION_14_4 = 4,
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;
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);
- guint16 (*RACloseCodec) (gpointer);
- guint16 (*RAFreeDecoder) (gpointer);
- guint16 (*RAInitDecoder) (gpointer, gpointer);
- guint16 (*RAOpenCodec2) (gpointer, const gchar *);
- guint16 (*RASetFlavor) (gpointer, guint16);
+ guint16 (*RACloseCodec) (gpointer);
+ guint16 (*RAFreeDecoder) (gpointer);
+ guint16 (*RAInitDecoder) (gpointer, gpointer);
+ guint16 (*RAOpenCodec2) (gpointer, const gchar *);
+ guint16 (*RASetFlavor) (gpointer, guint16);
void (*SetDLLAccessPath) (gchar *);
void (*RASetPwd) (gpointer, gchar *);
-} RealFunctions;
+} GstRADecLibrary;
typedef struct
{
@@ -108,16 +116,21 @@ struct _GstRealAudioDec
/* Caps */
guint width, height, leaf_size;
- /* Hooks */
- GModule *module;
- RealFunctions funcs;
-
- /* Used by the REAL library. */
- gpointer context;
+ GstRADecLibrary lib;
/* Properties */
- gchar *real_codecs_path, *racook_names, *raatrk_names, *ra14_4_names,
- *ra28_8_names, *rasipr_names;
+ gboolean checked_modules;
+ 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;
};
@@ -139,7 +152,7 @@ gst_real_audio_dec_chain (GstPad * pad, GstBuffer * in)
guint16 res = 0;
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;
timestamp = GST_BUFFER_TIMESTAMP (in);
@@ -151,7 +164,7 @@ gst_real_audio_dec_chain (GstPad * pad, GstBuffer * in)
if (flow != GST_FLOW_OK)
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);
if (res != 0)
@@ -184,47 +197,36 @@ not_negotiated:
}
}
+static void
+close_library (GstRealAudioDec * dec, GstRADecLibrary * lib)
+{
+ if (lib->context) {
+ 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
-gst_real_audio_dec_setcaps (GstPad * pad, GstCaps * caps)
+open_library (GstRealAudioDec * dec, gint version, GstRADecLibrary * lib)
{
- GstRealAudioDec *dec = GST_REAL_AUDIO_DEC (GST_PAD_PARENT (pad));
- GstStructure *s = gst_caps_get_structure (caps, 0);
+ gchar *path, *names;
+ gchar **split_names, **split_path;
+ gint i, j;
gpointer ra_close_codec, ra_decode, ra_free_decoder;
gpointer ra_open_codec2, ra_init_decoder, ra_set_flavor;
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;
-
- 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);
+ guint16 res = 0;
path = dec->real_codecs_path ? dec->real_codecs_path :
DEFAULT_REAL_CODECS_PATH;
@@ -249,6 +251,8 @@ gst_real_audio_dec_setcaps (GstPad * pad, GstCaps * caps)
goto unknown_version;
}
+ GST_LOG_OBJECT (dec, "splitting paths %s, names %s", path, names);
+
split_path = g_strsplit (path, ":", 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++) {
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);
- if (module)
+ if (lib->module)
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 */
g_strfreev (split_names);
- if (module == NULL)
+ if (lib->module == NULL)
goto could_not_open;
- if (!g_module_symbol (module, "RACloseCodec", &ra_close_codec) ||
- !g_module_symbol (module, "RADecode", &ra_decode) ||
- !g_module_symbol (module, "RAFreeDecoder", &ra_free_decoder) ||
- !g_module_symbol (module, "RAOpenCodec2", &ra_open_codec2) ||
- !g_module_symbol (module, "RAInitDecoder", &ra_init_decoder) ||
- !g_module_symbol (module, "RASetFlavor", &ra_set_flavor)) {
+ GST_LOG_OBJECT (dec, "finding symbols");
+
+ if (!g_module_symbol (lib->module, "RACloseCodec", &ra_close_codec) ||
+ !g_module_symbol (lib->module, "RADecode", &ra_decode) ||
+ !g_module_symbol (lib->module, "RAFreeDecoder", &ra_free_decoder) ||
+ !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;
}
- g_module_symbol (module, "RASetPwd", &ra_set_pwd);
- g_module_symbol (module, "SetDLLAccessPath", &set_dll_access_path);
+ g_module_symbol (lib->module, "RASetPwd", &ra_set_pwd);
+ g_module_symbol (lib->module, "SetDLLAccessPath", &set_dll_access_path);
- funcs.RACloseCodec = (guint16 (*)(gpointer)) ra_close_codec;
- funcs.RADecode =
+ lib->RACloseCodec = (guint16 (*)(gpointer)) ra_close_codec;
+ lib->RADecode =
(guint16 (*)(gpointer, guint8 *, guint32, guint8 *, guint32 *, guint32))
ra_decode;
- funcs.RAFreeDecoder = (guint16 (*)(gpointer)) ra_free_decoder;
- funcs.RAOpenCodec2 = (guint16 (*)(gpointer, const gchar *)) ra_open_codec2;
- funcs.RAInitDecoder = (guint16 (*)(gpointer, gpointer)) ra_init_decoder;
- funcs.RASetFlavor = (guint16 (*)(gpointer, guint16)) ra_set_flavor;
- funcs.RASetPwd = (void (*)(gpointer, gchar *)) ra_set_pwd;
- funcs.SetDLLAccessPath = (void (*)(gchar *)) set_dll_access_path;
+ lib->RAFreeDecoder = (guint16 (*)(gpointer)) ra_free_decoder;
+ lib->RAOpenCodec2 = (guint16 (*)(gpointer, const gchar *)) ra_open_codec2;
+ lib->RAInitDecoder = (guint16 (*)(gpointer, gpointer)) ra_init_decoder;
+ lib->RASetFlavor = (guint16 (*)(gpointer, guint16)) ra_set_flavor;
+ lib->RASetPwd = (void (*)(gpointer, gchar *)) ra_set_pwd;
+ lib->SetDLLAccessPath = (void (*)(gchar *)) set_dll_access_path;
- if (funcs.SetDLLAccessPath)
- funcs.SetDLLAccessPath (split_path[i]);
+ if (lib->SetDLLAccessPath)
+ lib->SetDLLAccessPath (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);
goto could_not_initialize;
}
@@ -306,6 +316,157 @@ codec_search_done:
/* now we are done with the split paths, so free them */
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.width = width;
data.channels = channels;
@@ -315,16 +476,16 @@ codec_search_done:
data.datalen = buf ? GST_BUFFER_SIZE (buf) : 0;
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");
goto could_not_initialize;
}
- if (funcs.RASetPwd) {
- funcs.RASetPwd (context, dec->pwd ? dec->pwd : DEFAULT_PWD);
+ if (dec->lib.RASetPwd) {
+ 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);
goto could_not_initialize;
}
@@ -343,15 +504,8 @@ codec_search_done:
dec->width = width;
dec->height = height;
dec->leaf_size = leaf_size;
- if (dec->context) {
- dec->funcs.RACloseCodec (dec->context);
- dec->funcs.RAFreeDecoder (dec->context);
- }
- dec->context = context;
- if (dec->module)
- g_module_close (dec->module);
- dec->module = module;
- dec->funcs = funcs;
+
+ GST_LOG_OBJECT (dec, "opened module");
return TRUE;
@@ -360,41 +514,21 @@ missing_keys:
GST_DEBUG_OBJECT (dec, "Could not find all necessary keys in structure.");
return FALSE;
}
-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_module_close (module);
- g_strfreev (split_path);
- GST_DEBUG_OBJECT (dec, "Could not load all symbols: %s", g_module_error ());
+ GST_DEBUG_OBJECT (dec, "Could not find decoder");
return FALSE;
}
could_not_initialize:
{
- if (context) {
- funcs.RACloseCodec (context);
- funcs.RAFreeDecoder (context);
- }
- g_module_close (module);
+ close_library (dec, &dec->lib);
GST_WARNING_OBJECT (dec, "Initialization of REAL driver failed (%i).", res);
return FALSE;
}
could_not_set_caps:
{
- if (context) {
- funcs.RACloseCodec (context);
- funcs.RAFreeDecoder (context);
- }
- g_module_close (module);
+ /* should normally not fail */
+ close_library (dec, &dec->lib);
GST_DEBUG_OBJECT (dec, "Could not convince peer to accept caps.");
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");
gst_pad_set_setcaps_function (dec->snk,
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_DEBUG_FUNCPTR (gst_real_audio_dec_chain));
gst_element_add_pad (GST_ELEMENT (dec), dec->snk);
@@ -430,10 +566,25 @@ gst_real_audio_dec_change_state (GstElement * element,
GstStateChange transition)
{
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);
+
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;
@@ -446,19 +597,7 @@ gst_real_audio_dec_finalize (GObject * object)
{
GstRealAudioDec *dec = GST_REAL_AUDIO_DEC (object);
- if (dec->context) {
- 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;
- }
+ close_library (dec, &dec->lib);
if (dec->real_codecs_path) {
g_free (dec->real_codecs_path);
diff --git a/gst/real/gstrealvideodec.c b/gst/real/gstrealvideodec.c
index 3c471f5d..27558426 100644
--- a/gst/real/gstrealvideodec.c
+++ b/gst/real/gstrealvideodec.c
@@ -65,8 +65,8 @@ GST_BOILERPLATE (GstRealVideoDec, gst_real_video_dec, GstElement,
GST_TYPE_ELEMENT);
static gboolean open_library (GstRealVideoDec * dec,
- GstRealVideoDecHooks * hooks, GstRealVideoDecVersion version);
-static void close_library (GstRealVideoDecHooks hooks);
+ GstRealVideoDecVersion version, GstRVDecLibrary * lib);
+static void close_library (GstRealVideoDec * dec, GstRVDecLibrary * lib);
typedef struct
{
@@ -103,7 +103,7 @@ gst_real_video_dec_chain (GstPad * pad, GstBuffer * in)
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;
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 */
data += frag_size;
- result = dec->hooks.transform (
+ result = dec->lib.Transform (
(gchar *) data,
- (gchar *) GST_BUFFER_DATA (out), &tin, &tout, dec->hooks.context);
+ (gchar *) GST_BUFFER_DATA (out), &tin, &tout, dec->lib.context);
if (result)
goto could_not_transform;
@@ -243,10 +243,51 @@ could_not_push:
}
}
-static gboolean
-gst_real_video_dec_activate_push (GstPad * pad, gboolean active)
+static GstCaps *
+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
@@ -259,7 +300,6 @@ gst_real_video_dec_setcaps (GstPad * pad, GstCaps * caps)
gchar data[36];
gboolean bres;
const GValue *v;
- GstRealVideoDecHooks hooks = { 0, 0, 0, 0, 0, 0 };
if (!gst_structure_get_int (s, "rmversion", &version) ||
!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);
- if (!open_library (dec, &hooks, version))
- return FALSE;
+ close_library (dec, &dec->lib);
+
+ if (!open_library (dec, version, &dec->lib))
+ goto open_failed;
/* Initialize REAL driver. */
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 + 20, format);
- res = hooks.init (&data, &hooks.context);
- if (res)
+ if ((res = dec->lib.Init (&data, &dec->lib.context)))
goto could_not_initialize;
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++)
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);
if (res)
@@ -344,8 +385,6 @@ gst_real_video_dec_setcaps (GstPad * pad, GstCaps * caps)
if (!bres)
goto could_not_set_caps;
- close_library (dec->hooks);
- dec->hooks = hooks;
dec->version = version;
dec->width = width;
dec->height = height;
@@ -361,34 +400,35 @@ missing_keys:
GST_ERROR_OBJECT (dec, "Could not find all necessary keys in structure.");
return FALSE;
}
-
+open_failed:
+ {
+ GST_ERROR_OBJECT (dec, "failed to open library");
+ return FALSE;
+ }
could_not_initialize:
{
- close_library (hooks);
GST_ERROR_OBJECT (dec, "Initialization of REAL driver failed (%i).", res);
+ close_library (dec, &dec->lib);
return FALSE;
}
-
could_not_allocate:
{
- close_library (hooks);
GST_ERROR_OBJECT (dec, "Could not allocate memory.");
+ close_library (dec, &dec->lib);
return FALSE;
}
-
could_not_send_message:
{
- close_library (hooks);
GST_ERROR_OBJECT (dec, "Failed to send custom message needed for "
"initialization (%i).", res);
+ close_library (dec, &dec->lib);
return FALSE;
}
-
could_not_set_caps:
{
- close_library (hooks);
GST_ERROR_OBJECT (dec, "Could not convince peer to accept dimensions "
"%i x %i.", dec->width, dec->height);
+ close_library (dec, &dec->lib);
return FALSE;
}
}
@@ -396,8 +436,8 @@ could_not_set_caps:
/* Attempts to open the correct library for the configured version */
static gboolean
-open_library (GstRealVideoDec * dec, GstRealVideoDecHooks * hooks,
- GstRealVideoDecVersion version)
+open_library (GstRealVideoDec * dec, GstRealVideoDecVersion version,
+ GstRVDecLibrary * lib)
{
gpointer rv_custom_msg, rv_free, rv_init, rv_transform;
GModule *module = NULL;
@@ -464,11 +504,11 @@ codec_search_done:
goto could_not_load;
}
- hooks->init = (GstRealVideoDecInitFunc) rv_init;
- hooks->free = (GstRealVideoDecFreeFunc) rv_free;
- hooks->transform = (GstRealVideoDecTransformFunc) rv_transform;
- hooks->custom_message = (GstRealVideoDecMessageFunc) rv_custom_msg;
- hooks->module = module;
+ lib->Init = rv_init;
+ lib->Free = rv_free;
+ lib->Transform = rv_transform;
+ lib->Message = rv_custom_msg;
+ lib->module = module;
dec->error_count = 0;
@@ -479,44 +519,93 @@ unknown_version:
GST_ERROR_OBJECT (dec, "Cannot handle version %i.", version);
return FALSE;
}
-
could_not_open:
{
GST_ERROR_OBJECT (dec, "Could not open library '%s' in '%s': %s", names,
path, g_module_error ());
return FALSE;
}
-
could_not_load:
{
- close_library (*hooks);
+ close_library (dec, lib);
GST_ERROR_OBJECT (dec, "Could not load all symbols: %s", g_module_error ());
return FALSE;
}
}
static void
-close_library (GstRealVideoDecHooks hooks)
+close_library (GstRealVideoDec * dec, GstRVDecLibrary * lib)
+{
+ if (lib->context) {
+ GST_LOG_OBJECT (dec, "closing library");
+ if (lib->Free)
+ lib->Free (lib->context);
+ }
+ 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)
{
- if (hooks.context && hooks.free)
- hooks.free (hooks.context);
+ GstStateChangeReturn ret;
+ GstRealVideoDec *dec = GST_REAL_VIDEO_DEC (element);
- if (hooks.module) {
- g_module_close (hooks.module);
- hooks.module = NULL;
+ 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
gst_real_video_dec_init (GstRealVideoDec * dec, GstRealVideoDecClass * klass)
{
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_DEBUG_FUNCPTR (gst_real_video_dec_setcaps));
gst_pad_set_chain_function (dec->snk,
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);
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);
- close_library (dec->hooks);
- memset (&dec->hooks, 0, sizeof (dec->hooks));
+ close_library (dec, &dec->lib);
if (dec->real_codecs_path) {
g_free (dec->real_codecs_path);
@@ -641,11 +729,14 @@ static void
gst_real_video_dec_class_init (GstRealVideoDecClass * 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->get_property = gst_real_video_dec_get_property;
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_param_spec_string ("real-codecs-path",
"Path where to search for RealPlayer codecs",
diff --git a/gst/real/gstrealvideodec.h b/gst/real/gstrealvideodec.h
index d3ac5391..e80b6f46 100644
--- a/gst/real/gstrealvideodec.h
+++ b/gst/real/gstrealvideodec.h
@@ -35,11 +35,6 @@ typedef struct _GstRealVideoDec GstRealVideoDec;
typedef struct _GstRealVideoDecClass GstRealVideoDecClass;
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
{
GST_REAL_VIDEO_DEC_VERSION_2 = 2,
@@ -50,13 +45,21 @@ enum _GstRealVideoDecVersion
typedef struct {
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;
GstRealVideoDecFreeFunc free;
GstRealVideoDecInitFunc init;
GstRealVideoDecTransformFunc transform;
+ */
- gpointer context;
-} GstRealVideoDecHooks;
+} GstRVDecLibrary;
struct _GstRealVideoDec
{
@@ -72,14 +75,18 @@ struct _GstRealVideoDec
gint error_count;
- /* Hooks */
- GstRealVideoDecHooks hooks;
+ /* Library functions */
+ GstRVDecLibrary lib;
/* Properties */
gchar *real_codecs_path;
+ gboolean checked_modules;
gchar *rv20_names;
+ gboolean valid_rv20;
gchar *rv30_names;
+ gboolean valid_rv30;
gchar *rv40_names;
+ gboolean valid_rv40;
gint max_errors;
};