summaryrefslogtreecommitdiffstats
path: root/gst/real/gstrealaudiodec.c
diff options
context:
space:
mode:
Diffstat (limited to 'gst/real/gstrealaudiodec.c')
-rw-r--r--gst/real/gstrealaudiodec.c393
1 files changed, 266 insertions, 127 deletions
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);