/* 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
#include <stdlib.h>
#include <string.h>
-#include <gstauparse.h>
+#include "gstauparse.h"
#include <gst/audio/audio.h>
/* elementfactory information */
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, " "rate = (int) [ 8000, 192000 ], " "channels = (int) [ 1, 2 ]" /*"; "
- "audio/x-adpcm, "
- "layout = (string) { g721, g722, g723_3, g723_5 }" */ )
- /* Nothing to decode those ADPCM streams for now */
+ 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,
- /* FILL ME */
+ ARG_0
+ /* FILL ME */
};
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, ieee = 0;
+ gint law = 0, depth = 0, ieee = 0;
+ gchar layout[7];
+ GstBuffer *subbuf;
+ GstEvent *event;
- g_return_if_fail (pad != NULL);
- g_return_if_fail (GST_IS_PAD (pad));
- g_return_if_fail (buf != NULL);
+ layout[0] = 0;
auparse = GST_AUPARSE (gst_pad_get_parent (pad));
/* 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) */
- if (GUINT32_FROM_BE (*head) == 0x2e736e64) { /* ".snd" */
+ if (GST_READ_UINT32_BE (head) == 0x2e736e64) { /* ".snd" */
head++;
auparse->le = 0;
- auparse->offset = GUINT32_FROM_BE (*head);
+ auparse->offset = GST_READ_UINT32_BE (head);
head++;
- auparse->size = GUINT32_FROM_BE (*head); /* Do not trust size, could be set to -1 : unknown */
+ /* Do not trust size, could be set to -1 : unknown */
+ auparse->size = GST_READ_UINT32_BE (head);
head++;
- auparse->encoding = GUINT32_FROM_BE (*head);
+ auparse->encoding = GST_READ_UINT32_BE (head);
head++;
- auparse->frequency = GUINT32_FROM_BE (*head);
+ auparse->frequency = GST_READ_UINT32_BE (head);
head++;
- auparse->channels = GUINT32_FROM_BE (*head);
+ auparse->channels = GST_READ_UINT32_BE (head);
head++;
/* and of course, someone had to invent a little endian
* version. Used by DEC systems. */
- } else if (GUINT32_FROM_LE (*head) == 0x0064732E) { /* other source say it is "dns." */
+ } else if (GST_READ_UINT32_LE (head) == 0x0064732E) { /* other source say it is "dns." */
head++;
auparse->le = 1;
- auparse->offset = GUINT32_FROM_LE (*head);
+ auparse->offset = GST_READ_UINT32_LE (head);
head++;
- auparse->size = GUINT32_FROM_LE (*head); /* Do not trust size, could be set to -1 : unknown */
+ /* Do not trust size, could be set to -1 : unknown */
+ auparse->size = GST_READ_UINT32_LE (head);
head++;
- auparse->encoding = GUINT32_FROM_LE (*head);
+ auparse->encoding = GST_READ_UINT32_LE (head);
head++;
- auparse->frequency = GUINT32_FROM_LE (*head);
+ auparse->frequency = GST_READ_UINT32_LE (head);
head++;
- auparse->channels = GUINT32_FROM_LE (*head);
+ auparse->channels = GST_READ_UINT32_LE (head);
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);
depth = 64;
break;
+ case 23: /* 4-bit CCITT G.721 ADPCM 32kbps -> modplug/libsndfile (compressed 8-bit mu-law) */
+ strcpy (layout, "g721");
+ break;
+ case 24: /* 8-bit CCITT G.722 ADPCM -> rtp */
+ strcpy (layout, "g722");
+ break;
+ case 25: /* 3-bit CCITT G.723.3 ADPCM 24kbps -> rtp/xine/modplug/libsndfile */
+ strcpy (layout, "g723_3");
+ break;
+ case 26: /* 5-bit CCITT G.723.5 ADPCM 40kbps -> rtp/xine/modplug/libsndfile */
+ strcpy (layout, "g723_5");
+ break;
+
case 8: /* Fragmented sample data */
case 9: /* AU_ENCODING_NESTED */
case 21: /* Music kit DSP commands */
case 22: /* Music kit DSP commands samples */
- case 23: /* 4-bit CCITT G.721 ADPCM 32kbps -> modplug/libsndfile (compressed 8-bit mu-law) */
- case 24: /* 8-bit CCITT G.722 ADPCM -> rtp */
- case 25: /* 3-bit CCITT G.723.3 ADPCM 24kbps -> rtp/xine/modplug/libsndfile */
- case 26: /* 5-bit CCITT G.723.5 ADPCM 40kbps -> rtp/xine/modplug/libsndfile */
-
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);
-/*
- } else if (layout) {
+ 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);
+
+ event = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_DEFAULT,
+ 0, GST_CLOCK_TIME_NONE, 0);
- gst_element_add_pad (GST_ELEMENT (auparse), auparse->srcpad);
+ gst_pad_push_event (auparse->srcpad, event);
- 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);
+ 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);
}
- gst_pad_push (auparse->srcpad, GST_DATA (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);
+ }
+
+ 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)