/* Element-Checklist-Version: 5 */
/* 2001/04/03 - Updated parseau to use caps nego
- * Zaheer Merali <zaheer@grid9.net
+ * Zaheer Abbas Merali <zaheerabbas at merali dot org>
*/
#ifdef HAVE_CONFIG_H
GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_SOMETIMES, /* FIXME: spider */
- GST_STATIC_CAPS (GST_AUDIO_INT_PAD_TEMPLATE_CAPS "; " /* 24-bit PCM is barely supported by gstreamer actually */
- GST_AUDIO_FLOAT_PAD_TEMPLATE_CAPS "; " /* 64-bit float is barely supported by gstreamer actually */
- "audio/x-alaw, " "rate = (int) [ 8000, 192000 ], "
- "channels = (int) [ 1, 2 ]" "; " "audio/x-mulaw, "
+ GST_STATIC_CAPS (GST_AUDIO_INT_PAD_TEMPLATE_CAPS "; "
+ /* we don't use GST_AUDIO_FLOAT_PAD_TEMPLATE_CAPS
+ because of min buffer-frames which is 1, not 0 */
+ "audio/x-raw-float, "
+ "rate = (int) [ 1, MAX ], "
+ "channels = (int) [ 1, MAX ], "
+ "endianness = (int) { LITTLE_ENDIAN , BIG_ENDIAN }, "
+ "width = (int) { 32, 64 }, "
+ "buffer-frames = (int) [ 0, MAX]" "; "
+ "audio/x-alaw, "
+ "rate = (int) [ 8000, 192000 ], "
+ "channels = (int) [ 1, 2 ]" "; "
+ "audio/x-mulaw, "
"rate = (int) [ 8000, 192000 ], " "channels = (int) [ 1, 2 ]" "; "
/* Nothing to decode those ADPCM streams for now */
"audio/x-adpcm, " "layout = (string) { g721, g722, g723_3, g723_5 }")
);
-/* AuParse signals and args */
-enum
-{
- /* FILL ME */
- LAST_SIGNAL
-};
-
enum
{
ARG_0
static void gst_auparse_base_init (gpointer g_class);
static void gst_auparse_class_init (GstAuParseClass * klass);
static void gst_auparse_init (GstAuParse * auparse);
+static void gst_auparse_dispose (GObject * object);
-static void gst_auparse_chain (GstPad * pad, GstData * _data);
+static GstFlowReturn gst_auparse_chain (GstPad * pad, GstBuffer * buf);
-static GstElementStateReturn gst_auparse_change_state (GstElement * element);
+static GstStateChangeReturn gst_auparse_change_state (GstElement * element,
+ GstStateChange transition);
static GstElementClass *parent_class = NULL;
+
/*static guint gst_auparse_signals[LAST_SIGNAL] = { 0 }; */
GType
static void
gst_auparse_class_init (GstAuParseClass * klass)
{
+ GObjectClass *gobject_class;
GstElementClass *gstelement_class;
+ gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
+ gobject_class->dispose = gst_auparse_dispose;
+
gstelement_class->change_state = gst_auparse_change_state;
}
gst_element_add_pad (GST_ELEMENT (auparse), auparse->sinkpad);
gst_pad_set_chain_function (auparse->sinkpad, gst_auparse_chain);
- auparse->srcpad = NULL;
-#if 0 /* FIXME: spider */
- gst_pad_new_from_template (gst_static_pad_template_get
+ auparse->srcpad = gst_pad_new_from_template (gst_static_pad_template_get
(&gst_auparse_src_template), "src");
+ gst_pad_use_fixed_caps (auparse->srcpad);
gst_element_add_pad (GST_ELEMENT (auparse), auparse->srcpad);
- gst_pad_use_explicit_caps (auparse->srcpad);
-#endif
auparse->offset = 0;
+ auparse->buffer_offset = 0;
+ auparse->adapter = gst_adapter_new ();
auparse->size = 0;
auparse->encoding = 0;
auparse->frequency = 0;
}
static void
-gst_auparse_chain (GstPad * pad, GstData * _data)
+gst_auparse_dispose (GObject * object)
+{
+ GstAuParse *au = GST_AUPARSE (object);
+
+ if (au->adapter != NULL) {
+ gst_object_unref (au->adapter);
+ au->adapter = NULL;
+ }
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static GstFlowReturn
+gst_auparse_chain (GstPad * pad, GstBuffer * buf)
{
- GstBuffer *buf = GST_BUFFER (_data);
+ GstFlowReturn ret;
GstAuParse *auparse;
- gchar *data;
+ guchar *data;
glong size;
GstCaps *tempcaps;
gint law = 0, depth = 0, ieee = 0;
gchar layout[7];
+ GstBuffer *subbuf;
+ GstEvent *event;
layout[0] = 0;
- g_return_if_fail (pad != NULL);
- g_return_if_fail (GST_IS_PAD (pad));
- g_return_if_fail (buf != NULL);
-
auparse = GST_AUPARSE (gst_pad_get_parent (pad));
GST_DEBUG ("gst_auparse_chain: got buffer in '%s'",
/* if we haven't seen any data yet... */
if (auparse->size == 0) {
- GstBuffer *newbuf;
guint32 *head = (guint32 *) data;
/* normal format is big endian (au is a Sparc format) */
head++;
} else {
- g_warning ("help, dunno what I'm looking at!\n");
+ GST_ELEMENT_ERROR (auparse, STREAM, WRONG_TYPE, (NULL), (NULL));
gst_buffer_unref (buf);
- return;
+ g_object_unref (auparse);
+ return GST_FLOW_ERROR;
}
GST_DEBUG
- ("offset %ld, size %ld, encoding %ld, frequency %ld, channels %ld",
+ ("offset %ld, size %ld, encoding %ld, frequency %ld, channels %ld\n",
auparse->offset, auparse->size, auparse->encoding, auparse->frequency,
auparse->channels);
default:
GST_ELEMENT_ERROR (auparse, STREAM, FORMAT, (NULL), (NULL));
gst_buffer_unref (buf);
- return;
+ g_object_unref (auparse);
+ return GST_FLOW_ERROR;
}
- auparse->srcpad =
- gst_pad_new_from_template (gst_static_pad_template_get
- (&gst_auparse_src_template), "src");
- gst_pad_use_explicit_caps (auparse->srcpad);
-
if (law) {
tempcaps =
gst_caps_new_simple ((law == 1) ? "audio/x-mulaw" : "audio/x-alaw",
- "rate", G_TYPE_INT, auparse->frequency, "channels", G_TYPE_INT,
- auparse->channels, NULL);
+ "rate", G_TYPE_INT, auparse->frequency,
+ "channels", G_TYPE_INT, auparse->channels, NULL);
+ auparse->sample_size = auparse->channels;
} else if (ieee) {
tempcaps = gst_caps_new_simple ("audio/x-raw-float",
- "width", G_TYPE_INT, depth,
+ "rate", G_TYPE_INT, auparse->frequency,
+ "channels", G_TYPE_INT, auparse->channels,
"endianness", G_TYPE_INT,
- auparse->le ? G_LITTLE_ENDIAN : G_BIG_ENDIAN, NULL);
+ auparse->le ? G_LITTLE_ENDIAN : G_BIG_ENDIAN,
+ "width", G_TYPE_INT, depth, NULL);
+ auparse->sample_size = auparse->channels * depth / 8;
} else if (layout[0]) {
tempcaps = gst_caps_new_simple ("audio/x-adpcm",
"layout", G_TYPE_STRING, layout, NULL);
+ auparse->sample_size = 0;
} else {
tempcaps = gst_caps_new_simple ("audio/x-raw-int",
+ "rate", G_TYPE_INT, auparse->frequency,
+ "channels", G_TYPE_INT, auparse->channels,
"endianness", G_TYPE_INT,
- auparse->le ? G_LITTLE_ENDIAN : G_BIG_ENDIAN, "rate", G_TYPE_INT,
- auparse->frequency, "channels", G_TYPE_INT, auparse->channels,
- "depth", G_TYPE_INT, depth, "width", G_TYPE_INT, depth, "signed",
- G_TYPE_BOOLEAN, TRUE, NULL);
+ auparse->le ? G_LITTLE_ENDIAN : G_BIG_ENDIAN, "depth", G_TYPE_INT,
+ depth, "width", G_TYPE_INT, depth, "signed", G_TYPE_BOOLEAN, TRUE,
+ NULL);
+ auparse->sample_size = auparse->channels * depth / 8;
}
- if (!gst_pad_set_explicit_caps (auparse->srcpad, tempcaps)) {
- gst_buffer_unref (buf);
- gst_object_unref (GST_OBJECT (auparse->srcpad));
- auparse->srcpad = NULL;
- return;
- }
+ gst_pad_set_active (auparse->srcpad, TRUE);
+ gst_pad_set_caps (auparse->srcpad, tempcaps);
- gst_element_add_pad (GST_ELEMENT (auparse), auparse->srcpad);
+ event = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_DEFAULT,
+ 0, GST_CLOCK_TIME_NONE, 0);
- newbuf = gst_buffer_new ();
- GST_BUFFER_DATA (newbuf) = (gpointer) malloc (size - (auparse->offset));
- memcpy (GST_BUFFER_DATA (newbuf), data + (auparse->offset),
- size - (auparse->offset));
- GST_BUFFER_SIZE (newbuf) = size - (auparse->offset);
+ gst_pad_push_event (auparse->srcpad, event);
+
+ subbuf = gst_buffer_create_sub (buf, auparse->offset,
+ size - auparse->offset);
gst_buffer_unref (buf);
- gst_pad_push (auparse->srcpad, GST_DATA (newbuf));
- return;
+ gst_adapter_push (auparse->adapter, subbuf);
+ } else {
+ gst_adapter_push (auparse->adapter, buf);
+ }
+
+ if (auparse->sample_size) {
+ /* Ensure we push a buffer that's a multiple of the frame size downstream */
+ int avail = gst_adapter_available (auparse->adapter);
+
+ avail -= avail % auparse->sample_size;
+
+ if (avail > 0) {
+ const guint8 *data = gst_adapter_peek (auparse->adapter, avail);
+ GstBuffer *newbuf;
+
+ if ((ret =
+ gst_pad_alloc_buffer_and_set_caps (auparse->srcpad,
+ auparse->buffer_offset, avail, GST_PAD_CAPS (auparse->srcpad),
+ &newbuf)) == GST_FLOW_OK) {
+
+ memcpy (GST_BUFFER_DATA (newbuf), data, avail);
+ gst_adapter_flush (auparse->adapter, avail);
+
+ auparse->buffer_offset += avail;
+
+ ret = gst_pad_push (auparse->srcpad, newbuf);
+ }
+ } else
+ ret = GST_FLOW_OK;
+ } else {
+ /* It's something non-trivial (such as ADPCM), we don't understand it, so
+ * just push downstream and assume this will know what to do with it */
+ ret = gst_pad_push (auparse->srcpad, buf);
}
- gst_pad_push (auparse->srcpad, GST_DATA (buf));
+ g_object_unref (auparse);
+
+ return ret;
}
-static GstElementStateReturn
-gst_auparse_change_state (GstElement * element)
+static GstStateChangeReturn
+gst_auparse_change_state (GstElement * element, GstStateChange transition)
{
GstAuParse *auparse = GST_AUPARSE (element);
+ GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
- switch (GST_STATE_TRANSITION (element)) {
- case GST_STATE_PAUSED_TO_READY:
- if (auparse->srcpad) {
- gst_element_remove_pad (element, auparse->srcpad);
- auparse->srcpad = NULL;
- }
- break;
+ if (parent_class->change_state)
+ ret = parent_class->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ gst_adapter_clear (auparse->adapter);
+ auparse->buffer_offset = 0;
+ auparse->offset = 0;
+ auparse->size = 0;
+ auparse->encoding = 0;
+ auparse->frequency = 0;
+ auparse->channels = 0;
default:
break;
}
- if (parent_class->change_state)
- return parent_class->change_state (element);
-
- return GST_STATE_SUCCESS;
+ return ret;
}
static gboolean
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"auparse",
- "parses au streams", plugin_init, VERSION, "GPL", GST_PACKAGE, GST_ORIGIN)
+ "parses au streams", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,
+ GST_PACKAGE_ORIGIN)