diff --git a/ChangeLog b/ChangeLog index aa62bf889d..93b9431147 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2007-01-06 Edward Hervey + + Patch by: Lutz Mueller + + * gst/real/Makefile.am: + * gst/real/gstreal.c: (plugin_init): + * gst/real/gstrealaudiodec.c: (gst_real_audio_dec_chain), + (gst_real_audio_dec_setcaps), (gst_real_audio_dec_init), + (gst_real_audio_dec_base_init), (gst_real_audio_dec_change_state), + (gst_real_audio_dec_finalize), (gst_real_audio_dec_set_property), + (gst_real_audio_dec_get_property), (gst_real_audio_dec_class_init): + * gst/real/gstrealaudiodec.h: + Added RealAudio wrapper elementfactory. + Modified structures so it can also work on x86_64 using the + adequate .so . + 2007-01-05 Tim-Philipp Müller * configure.ac: diff --git a/gst/real/Makefile.am b/gst/real/Makefile.am index 8096c579d4..63696591dd 100644 --- a/gst/real/Makefile.am +++ b/gst/real/Makefile.am @@ -1,9 +1,14 @@ plugin_LTLIBRARIES = libgstreal.la -libgstreal_la_SOURCES = gstrealvideodec.c gstreal.c +libgstreal_la_SOURCES = \ + gstrealvideodec.c \ + gstrealaudiodec.c \ + gstreal.c libgstreal_la_CFLAGS = $(GST_BASE_CFLAGS) $(GST_CFLAGS) libgstreal_la_LIBADD = $(GST_BASE_LIBS) libgstreal_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -noinst_HEADERS = gstrealvideodec.h \ No newline at end of file +noinst_HEADERS = \ + gstrealvideodec.h \ + gstrealaudiodec.h \ No newline at end of file diff --git a/gst/real/gstreal.c b/gst/real/gstreal.c index afb28d0e69..c2a9b23a0b 100644 --- a/gst/real/gstreal.c +++ b/gst/real/gstreal.c @@ -23,6 +23,7 @@ #endif #include "gstrealvideodec.h" +#include "gstrealaudiodec.h" static gboolean plugin_init (GstPlugin * p) @@ -30,6 +31,9 @@ plugin_init (GstPlugin * p) if (!gst_element_register (p, "realvideodec", GST_RANK_PRIMARY, GST_TYPE_REAL_VIDEO_DEC)) return FALSE; + if (!gst_element_register (p, "realaudiodec", GST_RANK_PRIMARY, + GST_TYPE_REAL_AUDIO_DEC)) + return FALSE; return TRUE; } diff --git a/gst/real/gstrealaudiodec.c b/gst/real/gstrealaudiodec.c new file mode 100644 index 0000000000..a7f37bae15 --- /dev/null +++ b/gst/real/gstrealaudiodec.c @@ -0,0 +1,509 @@ +/* GStreamer + * + * Copyright (C) 2006 Lutz Mueller + * 2006 Edward Hervey + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstrealaudiodec.h" + +#include +#include + +GST_DEBUG_CATEGORY_STATIC (real_audio_dec_debug); +#define GST_CAT_DEFAULT real_audio_dec_debug + +static GstElementDetails real_audio_dec_details = +GST_ELEMENT_DETAILS ("RealAudio decoder", + "Codec/Decoder", "Decoder for RealAudio streams", + "Lutz Mueller "); + +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 ")); +static GstStaticPadTemplate src_t = +GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, + GST_STATIC_CAPS ("audio/x-raw-int, " + "width = (int) [ 1, MAX ], " + "depth = (int) [ 1, MAX ], " + "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]")); + +#ifdef HAVE_CPU_I386 +#define DEFAULT_PATH "/usr/lib/win32/" +#endif +#ifdef HAVE_CPU_X86_64 +#define DEFAULT_PATH "/usr/lib/" +#endif + +#define DEFAULT_PATH_RACOOK DEFAULT_PATH "cook.so.6.0" +#define DEFAULT_PATH_RAATRK DEFAULT_PATH "atrk.so.6.0" +#define DEFAULT_PATH_RA14_4 DEFAULT_PATH "14_4.so.6.0" +#define DEFAULT_PATH_RA28_8 DEFAULT_PATH "28_8.so.6.0" +#define DEFAULT_PATH_RASIPR DEFAULT_PATH "sipr.so.6.0" +#define DEFAULT_PWD "Ardubancel Quazanga" + +enum +{ + PROP_0, + PROP_PATH_RACOOK, + PROP_PATH_RAATRK, + PROP_PATH_RA14_4, + PROP_PATH_RA28_8, + PROP_PATH_RASIPR, + PROP_PASSWORD +}; + +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 +} GstRealAudioDecVersion; + +typedef struct +{ + 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); + void (*SetDLLAccessPath) (gchar *); + void (*RASetPwd) (gpointer, gchar *); +} RealFunctions; + +typedef struct +{ + guint32 samplerate; + guint16 width; + guint16 channels; + guint16 quality; + guint32 leaf_size; + guint32 packet_size; + guint32 datalen; + gpointer data; +} RAInit; + +struct _GstRealAudioDec +{ + GstElement parent; + + GstPad *src, *snk; + + /* Caps */ + guint width, height, leaf_size; + + /* Hooks */ + gpointer handle; + RealFunctions funcs; + + /* Used by the REAL library. */ + gpointer context; + + /* Properties */ + gchar *path_racook, *path_raatrk, *path_ra14_4, *path_ra28_8, *path_rasipr; + gchar *pwd; +}; + +struct _GstRealAudioDecClass +{ + GstElementClass parent_class; +}; + +GST_BOILERPLATE (GstRealAudioDec, gst_real_audio_dec, GstElement, + GST_TYPE_ELEMENT); + +static GstFlowReturn +gst_real_audio_dec_chain (GstPad * pad, GstBuffer * in) +{ + GstRealAudioDec *dec = GST_REAL_AUDIO_DEC (GST_PAD_PARENT (pad)); + guint len; + GstBuffer *out = NULL; + guint16 res = 0; + GstFlowReturn ret = GST_FLOW_OK; + GstClockTime timestamp = GST_BUFFER_TIMESTAMP (in); + + if ((ret = gst_pad_alloc_buffer (dec->src, GST_BUFFER_OFFSET_NONE, + dec->width * dec->leaf_size * dec->height * 16, + GST_PAD_CAPS (dec->src), &out)) != GST_FLOW_OK) + return ret; + res = dec->funcs.RADecode (dec->context, GST_BUFFER_DATA (in), + GST_BUFFER_SIZE (in), GST_BUFFER_DATA (out), &len, -1); + if (res) + goto could_not_decode; + GST_BUFFER_SIZE (out) = len; + GST_BUFFER_TIMESTAMP (out) = timestamp; + return gst_pad_push (dec->src, out); + + /* Errors */ +could_not_decode: + gst_buffer_unref (out); + GST_ELEMENT_ERROR (dec, STREAM, DECODE, ("Could not decode buffer (%i).", + res), (NULL)); + return GST_FLOW_ERROR; +} + +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); + gchar *path; + gint version, flavor, channels, rate, leaf_size, packet_size, width, height; + guint16 res; + RAInit data; + gboolean bres; + const GValue *v; + GstBuffer *buf = NULL; + const gchar *name = gst_structure_get_name (s); + gpointer context = NULL, handle; + RealFunctions funcs; + + 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); + + switch (version) { + case GST_REAL_AUDIO_DEC_VERSION_COOK: + path = dec->path_racook ? dec->path_racook : DEFAULT_PATH_RACOOK; + break; + case GST_REAL_AUDIO_DEC_VERSION_ATRK: + path = dec->path_raatrk ? dec->path_raatrk : DEFAULT_PATH_RAATRK; + break; + case GST_REAL_AUDIO_DEC_VERSION_14_4: + path = dec->path_ra14_4 ? dec->path_ra14_4 : DEFAULT_PATH_RA14_4; + break; + case GST_REAL_AUDIO_DEC_VERSION_28_8: + path = dec->path_ra28_8 ? dec->path_ra28_8 : DEFAULT_PATH_RA28_8; + break; + case GST_REAL_AUDIO_DEC_VERSION_SIPR: + path = dec->path_rasipr ? dec->path_rasipr : DEFAULT_PATH_RASIPR; + break; + default: + goto unknown_version; + } + + handle = dlopen (path, RTLD_LAZY); + if (!handle) + goto could_not_open; + funcs.RACloseCodec = dlsym (handle, "RACloseCodec"); + funcs.RADecode = dlsym (handle, "RADecode"); + funcs.RAFreeDecoder = dlsym (handle, "RAFreeDecoder"); + funcs.RAOpenCodec2 = dlsym (handle, "RAOpenCodec2"); + funcs.RAInitDecoder = dlsym (handle, "RAInitDecoder"); + funcs.RASetFlavor = dlsym (handle, "RASetFlavor"); + funcs.SetDLLAccessPath = dlsym (handle, "SetDLLAccessPath"); + funcs.RASetPwd = dlsym (handle, "RASetPwd"); + if (!(funcs.RACloseCodec && funcs.RADecode && + funcs.RAFreeDecoder && funcs.RAOpenCodec2 && + funcs.RAInitDecoder && funcs.RASetFlavor)) + goto could_not_load; + + if (funcs.SetDLLAccessPath) + funcs.SetDLLAccessPath (DEFAULT_PATH); + + if ((res = funcs.RAOpenCodec2 (&context, NULL))) + goto could_not_initialize; + + data.samplerate = rate; + data.width = width; + data.channels = channels; + data.quality = 100; + data.leaf_size = leaf_size; + data.packet_size = packet_size; + data.datalen = buf ? GST_BUFFER_SIZE (buf) : 0; + data.data = buf ? GST_BUFFER_DATA (buf) : NULL; + + if ((res = funcs.RAInitDecoder (context, &data))) + goto could_not_initialize; + + if (funcs.RASetPwd) + funcs.RASetPwd (dec->context, dec->pwd ? dec->pwd : DEFAULT_PWD); + + res = funcs.RASetFlavor (context, flavor); + if (res) + goto could_not_initialize; + + caps = gst_caps_new_simple ("audio/x-raw-int", + "endianness", G_TYPE_INT, G_BYTE_ORDER, + "width", G_TYPE_INT, width, + "depth", G_TYPE_INT, height, + "rate", G_TYPE_INT, rate, + "channels", G_TYPE_INT, channels, "signed", G_TYPE_BOOLEAN, TRUE, NULL); + bres = gst_pad_set_caps (GST_PAD (dec->src), caps); + gst_caps_unref (caps); + if (!bres) + goto could_not_set_caps; + + 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->handle) + dlclose (dec->handle); + dec->handle = handle; + dec->funcs = funcs; + + return TRUE; + +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: + GST_DEBUG_OBJECT (dec, "Could not open library '%s'.", path); + return FALSE; +could_not_load: + dlclose (handle); + GST_DEBUG_OBJECT (dec, "Could not load all symbols."); + return FALSE; +could_not_initialize: + if (context) { + funcs.RACloseCodec (context); + funcs.RAFreeDecoder (context); + } + dlclose (handle); + GST_DEBUG_OBJECT (dec, "Initialization of REAL driver failed (%i).", res); + return FALSE; +could_not_set_caps: + if (context) { + funcs.RACloseCodec (context); + funcs.RAFreeDecoder (context); + } + dlclose (handle); + GST_DEBUG_OBJECT (dec, "Could not convince peer to accept caps."); + return FALSE; +} + +static void +gst_real_audio_dec_init (GstRealAudioDec * dec, GstRealAudioDecClass * klass) +{ + dec->snk = + gst_pad_new_from_template (gst_static_pad_template_get (&snk_t), "sink"); + gst_pad_set_setcaps_function (dec->snk, gst_real_audio_dec_setcaps); + gst_pad_set_chain_function (dec->snk, gst_real_audio_dec_chain); + gst_element_add_pad (GST_ELEMENT (dec), dec->snk); + dec->src = + gst_pad_new_from_template (gst_static_pad_template_get (&src_t), "src"); + gst_element_add_pad (GST_ELEMENT (dec), dec->src); +} + +static void +gst_real_audio_dec_base_init (gpointer g_class) +{ + GstElementClass *ec = GST_ELEMENT_CLASS (g_class); + + gst_element_class_add_pad_template (ec, gst_static_pad_template_get (&snk_t)); + gst_element_class_add_pad_template (ec, gst_static_pad_template_get (&src_t)); + gst_element_class_set_details (ec, &real_audio_dec_details); +} + +static GstStateChangeReturn +gst_real_audio_dec_change_state (GstElement * element, + GstStateChange transition) +{ + GstStateChangeReturn ret; + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + switch (transition) { + case GST_STATE_CHANGE_PAUSED_TO_READY: + break; + default: + break; + } + return ret; +} + +static void +gst_real_audio_dec_finalize (GObject * object) +{ + GstRealAudioDec *dec = GST_REAL_AUDIO_DEC (object); + + if (dec->context) { + dec->funcs.RACloseCodec (dec->context); + dec->funcs.RAFreeDecoder (dec->context); + dec->context = NULL; + } + if (dec->handle) { + dlclose (dec->handle); + dec->handle = NULL; + } + + if (dec->path_racook) { + g_free (dec->path_racook); + dec->path_racook = NULL; + } + if (dec->path_raatrk) { + g_free (dec->path_raatrk); + dec->path_raatrk = NULL; + } + if (dec->path_ra14_4) { + g_free (dec->path_ra14_4); + dec->path_ra14_4 = NULL; + } + if (dec->path_ra28_8) { + g_free (dec->path_ra28_8); + dec->path_ra28_8 = NULL; + } + if (dec->path_rasipr) { + g_free (dec->path_rasipr); + dec->path_rasipr = NULL; + } + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gst_real_audio_dec_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstRealAudioDec *dec = GST_REAL_AUDIO_DEC (object); + + switch (prop_id) { + case PROP_PATH_RACOOK: + if (dec->path_racook) + g_free (dec->path_racook); + dec->path_racook = g_value_dup_string (value); + break; + case PROP_PATH_RAATRK: + if (dec->path_raatrk) + g_free (dec->path_raatrk); + dec->path_raatrk = g_value_dup_string (value); + break; + case PROP_PATH_RA14_4: + if (dec->path_ra14_4) + g_free (dec->path_ra14_4); + dec->path_ra14_4 = g_value_dup_string (value); + break; + case PROP_PATH_RA28_8: + if (dec->path_ra28_8) + g_free (dec->path_ra28_8); + dec->path_ra28_8 = g_value_dup_string (value); + break; + case PROP_PATH_RASIPR: + if (dec->path_rasipr) + g_free (dec->path_rasipr); + dec->path_rasipr = g_value_dup_string (value); + break; + case PROP_PASSWORD: + if (dec->pwd) + g_free (dec->pwd); + dec->pwd = g_value_dup_string (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_real_audio_dec_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstRealAudioDec *dec = GST_REAL_AUDIO_DEC (object); + + switch (prop_id) { + case PROP_PATH_RACOOK: + g_value_set_string (value, dec->path_racook ? dec->path_racook : + DEFAULT_PATH_RACOOK); + break; + case PROP_PATH_RAATRK: + g_value_set_string (value, dec->path_raatrk ? dec->path_raatrk : + DEFAULT_PATH_RAATRK); + break; + case PROP_PATH_RA14_4: + g_value_set_string (value, dec->path_ra14_4 ? dec->path_ra14_4 : + DEFAULT_PATH_RA14_4); + break; + case PROP_PATH_RA28_8: + g_value_set_string (value, dec->path_ra28_8 ? dec->path_ra28_8 : + DEFAULT_PATH_RA28_8); + break; + case PROP_PATH_RASIPR: + g_value_set_string (value, dec->path_rasipr ? dec->path_rasipr : + DEFAULT_PATH_RASIPR); + break; + case PROP_PASSWORD: + g_value_set_string (value, dec->pwd ? dec->pwd : DEFAULT_PWD); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_real_audio_dec_class_init (GstRealAudioDecClass * klass) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->set_property = gst_real_audio_dec_set_property; + object_class->get_property = gst_real_audio_dec_get_property; + object_class->finalize = gst_real_audio_dec_finalize; + + element_class->change_state = gst_real_audio_dec_change_state; + + g_object_class_install_property (object_class, PROP_PATH_RACOOK, + g_param_spec_string ("path_racook", "Path to cook driver", + "Path to cook driver", DEFAULT_PATH_RACOOK, G_PARAM_READWRITE)); + g_object_class_install_property (object_class, PROP_PATH_RAATRK, + g_param_spec_string ("path_raatrk", "Path to atrk driver", + "Path to atrk driver", DEFAULT_PATH_RAATRK, G_PARAM_READWRITE)); + g_object_class_install_property (object_class, PROP_PATH_RA14_4, + g_param_spec_string ("path_ra14_4", "Path to 14_4 driver", + "Path to 14_4 driver", DEFAULT_PATH_RA14_4, G_PARAM_READWRITE)); + g_object_class_install_property (object_class, PROP_PATH_RA28_8, + g_param_spec_string ("path_ra28_8", "Path to 28_8 driver", + "Path to 28_8 driver", DEFAULT_PATH_RA28_8, G_PARAM_READWRITE)); + g_object_class_install_property (object_class, PROP_PATH_RASIPR, + g_param_spec_string ("path_rasipr", "Path to sipr driver", + "Path to sipr driver", DEFAULT_PATH_RASIPR, G_PARAM_READWRITE)); + g_object_class_install_property (object_class, PROP_PASSWORD, + g_param_spec_string ("password", "Password", + "Password", DEFAULT_PWD, G_PARAM_READWRITE)); + + GST_DEBUG_CATEGORY_INIT (real_audio_dec_debug, "realaudiodec", 0, + "RealAudio decoder"); +} diff --git a/gst/real/gstrealaudiodec.h b/gst/real/gstrealaudiodec.h new file mode 100644 index 0000000000..517b077fec --- /dev/null +++ b/gst/real/gstrealaudiodec.h @@ -0,0 +1,40 @@ +/* GStreamer + * + * Copyright (C) 2006 Lutz Mueller + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_REAL_AUDIO_DEC_H__ +#define __GST_REAL_AUDIO_DEC_H__ + +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_REAL_AUDIO_DEC (gst_real_audio_dec_get_type()) +#define GST_REAL_AUDIO_DEC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_REAL_AUDIO_DEC,GstRealAudioDec)) +#define GST_REAL_AUDIO_DEC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_REAL_AUDIO_DEC,GstRealAudioDecClass)) + +typedef struct _GstRealAudioDec GstRealAudioDec; +typedef struct _GstRealAudioDecClass GstRealAudioDecClass; + +GType gst_real_audio_dec_get_type (void) G_GNUC_CONST; + +G_END_DECLS + +#endif /* __GST_REAL_AUDIO_DEC_H__ */