diff options
Diffstat (limited to 'gst')
-rw-r--r-- | gst/real/gstrealaudiodec.c | 393 | ||||
-rw-r--r-- | gst/real/gstrealvideodec.c | 179 | ||||
-rw-r--r-- | gst/real/gstrealvideodec.h | 25 |
3 files changed, 417 insertions, 180 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); 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; }; |