Update for alloc_buffer changes.
[platform/upstream/gst-plugins-good.git] / gst / auparse / gstauparse.c
index b07129d..d39c239 100644 (file)
@@ -19,7 +19,7 @@
 /* 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
@@ -49,22 +49,24 @@ static GstStaticPadTemplate gst_auparse_src_template =
     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
@@ -74,13 +76,16 @@ enum
 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
@@ -124,12 +129,16 @@ gst_auparse_base_init (gpointer g_class)
 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;
 }
 
@@ -142,15 +151,14 @@ gst_auparse_init (GstAuParse * auparse)
   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;
@@ -158,22 +166,32 @@ gst_auparse_init (GstAuParse * auparse)
 }
 
 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'",
@@ -184,7 +202,6 @@ gst_auparse_chain (GstPad * pad, GstData * _data)
 
   /* 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) */
@@ -221,13 +238,14 @@ gst_auparse_chain (GstPad * pad, GstData * _data)
       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);
 
@@ -309,80 +327,115 @@ Samples :
       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
@@ -399,4 +452,5 @@ plugin_init (GstPlugin * plugin)
 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)