]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - glsdk/gst-plugins-ugly0-10.git/blobdiff - ext/amrnb/amrnbdec.c
add test for amrnbenc, enable test infrastructure, and fix a leak
[glsdk/gst-plugins-ugly0-10.git] / ext / amrnb / amrnbdec.c
index dbb7e1d02d21e1316bd243978a56fa2aba7cd8f6..54d2009bff42161c23a35eb8eebf9b6367821513 100644 (file)
@@ -26,8 +26,7 @@
 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
     GST_PAD_SINK,
     GST_PAD_ALWAYS,
-    GST_STATIC_CAPS ("audio/x-amr-nb, "
-        "rate = (int) 8000, " "channels = (int) 1")
+    GST_STATIC_CAPS ("audio/AMR, " "rate = (int) 8000, " "channels = (int) 1")
     );
 
 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
@@ -42,16 +41,18 @@ static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
     );
 
 static const gint block_size[16] = { 12, 13, 15, 17, 19, 20, 26, 31, 5,
-  0, 0, 0, 0, 0, 0, 0
+  -1, -1, -1, -1, -1, -1, 0
 };
 
 static void gst_amrnbdec_base_init (GstAmrnbDecClass * klass);
 static void gst_amrnbdec_class_init (GstAmrnbDecClass * klass);
 static void gst_amrnbdec_init (GstAmrnbDec * amrnbdec);
 
+static gboolean gst_amrnbdec_event (GstPad * pad, GstEvent * event);
 static GstFlowReturn gst_amrnbdec_chain (GstPad * pad, GstBuffer * buffer);
 static gboolean gst_amrnbdec_setcaps (GstPad * pad, GstCaps * caps);
-static GstElementStateReturn gst_amrnbdec_state_change (GstElement * element);
+static GstStateChangeReturn gst_amrnbdec_state_change (GstElement * element,
+    GstStateChange transition);
 
 static GstElementClass *parent_class = NULL;
 
@@ -104,7 +105,7 @@ gst_amrnbdec_class_init (GstAmrnbDecClass * klass)
 {
   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
 
-  parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
+  parent_class = g_type_class_peek_parent (klass);
 
   element_class->change_state = gst_amrnbdec_state_change;
 }
@@ -117,6 +118,7 @@ gst_amrnbdec_init (GstAmrnbDec * amrnbdec)
       gst_pad_new_from_template (gst_static_pad_template_get (&sink_template),
       "sink");
   gst_pad_set_setcaps_function (amrnbdec->sinkpad, gst_amrnbdec_setcaps);
+  gst_pad_set_event_function (amrnbdec->sinkpad, gst_amrnbdec_event);
   gst_pad_set_chain_function (amrnbdec->sinkpad, gst_amrnbdec_chain);
   gst_element_add_pad (GST_ELEMENT (amrnbdec), amrnbdec->sinkpad);
 
@@ -131,9 +133,6 @@ gst_amrnbdec_init (GstAmrnbDec * amrnbdec)
 
   /* init rest */
   amrnbdec->handle = NULL;
-  amrnbdec->channels = 0;
-  amrnbdec->rate = 0;
-  amrnbdec->ts = 0;
 }
 
 static gboolean
@@ -143,7 +142,7 @@ gst_amrnbdec_setcaps (GstPad * pad, GstCaps * caps)
   GstAmrnbDec *amrnbdec;
   GstCaps *copy;
 
-  amrnbdec = GST_AMRNBDEC (GST_PAD_PARENT (pad));
+  amrnbdec = GST_AMRNBDEC (gst_pad_get_parent (pad));
 
   structure = gst_caps_get_structure (caps, 0);
 
@@ -159,25 +158,67 @@ gst_amrnbdec_setcaps (GstPad * pad, GstCaps * caps)
       "endianness", G_TYPE_INT, G_BYTE_ORDER,
       "rate", G_TYPE_INT, amrnbdec->rate, "signed", G_TYPE_BOOLEAN, TRUE, NULL);
 
+  amrnbdec->duration = gst_util_uint64_scale_int (GST_SECOND, 160,
+      amrnbdec->rate * amrnbdec->channels);
+
   gst_pad_set_caps (amrnbdec->srcpad, copy);
   gst_caps_unref (copy);
 
+  gst_object_unref (amrnbdec);
+
   return TRUE;
 }
 
+static gboolean
+gst_amrnbdec_event (GstPad * pad, GstEvent * event)
+{
+  GstAmrnbDec *amrnbdec;
+  gboolean ret = TRUE;
+
+  amrnbdec = GST_AMRNBDEC (gst_pad_get_parent (pad));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_FLUSH_START:
+      ret = gst_pad_push_event (amrnbdec->srcpad, event);
+      break;
+    case GST_EVENT_FLUSH_STOP:
+      ret = gst_pad_push_event (amrnbdec->srcpad, event);
+      gst_adapter_clear (amrnbdec->adapter);
+      amrnbdec->ts = -1;
+      break;
+    case GST_EVENT_EOS:
+      gst_adapter_clear (amrnbdec->adapter);
+      ret = gst_pad_push_event (amrnbdec->srcpad, event);
+      break;
+    default:
+      ret = gst_pad_push_event (amrnbdec->srcpad, event);
+      break;
+  }
+  gst_object_unref (amrnbdec);
+
+  return ret;
+}
+
 static GstFlowReturn
 gst_amrnbdec_chain (GstPad * pad, GstBuffer * buffer)
 {
   GstAmrnbDec *amrnbdec;
   GstFlowReturn ret;
 
-  amrnbdec = GST_AMRNBDEC (GST_PAD_PARENT (pad));
-
-  GST_STREAM_LOCK (pad);
+  amrnbdec = GST_AMRNBDEC (gst_pad_get_parent (pad));
 
   if (amrnbdec->rate == 0 || amrnbdec->channels == 0)
     goto not_negotiated;
 
+  /* discontinuity, don't combine samples before and after the
+   * DISCONT */
+  if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) {
+    gst_adapter_clear (amrnbdec->adapter);
+    amrnbdec->ts = -1;
+  }
+
+  /* take latest timestamp, FIXME timestamp is the one of the
+   * first buffer in the adapter. */
   if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer))
     amrnbdec->ts = GST_BUFFER_TIMESTAMP (buffer);
 
@@ -200,63 +241,67 @@ gst_amrnbdec_chain (GstPad * pad, GstBuffer * buffer)
 
     if (gst_adapter_available (amrnbdec->adapter) < block)
       break;
-    data = (guint8 *) gst_adapter_peek (amrnbdec->adapter, block);
+    /* the library seems to write into the source data, hence
+     * the copy. */
+    data = gst_adapter_take (amrnbdec->adapter, block);
 
     /* get output */
     out = gst_buffer_new_and_alloc (160 * 2);
-    GST_BUFFER_DURATION (out) = GST_SECOND * 160 /
-        (amrnbdec->rate * amrnbdec->channels);
+    GST_BUFFER_DURATION (out) = amrnbdec->duration;
     GST_BUFFER_TIMESTAMP (out) = amrnbdec->ts;
-    amrnbdec->ts += GST_BUFFER_DURATION (out);
-    gst_buffer_set_caps (out, GST_RPAD_CAPS (amrnbdec->srcpad));
+    if (amrnbdec->ts != -1)
+      amrnbdec->ts += amrnbdec->duration;
+    gst_buffer_set_caps (out, GST_PAD_CAPS (amrnbdec->srcpad));
 
     /* decode */
     Decoder_Interface_Decode (amrnbdec->handle, data,
         (short *) GST_BUFFER_DATA (out), 0);
-
-    gst_adapter_flush (amrnbdec->adapter, block);
+    g_free (data);
 
     /* play */
     ret = gst_pad_push (amrnbdec->srcpad, out);
   }
-  GST_STREAM_UNLOCK (pad);
+  gst_object_unref (amrnbdec);
 
   return ret;
 
+  /* ERRORS */
 not_negotiated:
   {
-    GST_STREAM_UNLOCK (pad);
+    GST_ELEMENT_ERROR (amrnbdec, STREAM, TYPE_NOT_FOUND, (NULL),
+        ("Decoder is not initialized"));
+    gst_object_unref (amrnbdec);
     return GST_FLOW_NOT_NEGOTIATED;
   }
 }
 
-static GstElementStateReturn
-gst_amrnbdec_state_change (GstElement * element)
+static GstStateChangeReturn
+gst_amrnbdec_state_change (GstElement * element, GstStateChange transition)
 {
   GstAmrnbDec *amrnbdec;
-  GstElementStateReturn ret;
-  gint transition;
+  GstStateChangeReturn ret;
 
   amrnbdec = GST_AMRNBDEC (element);
-  transition = GST_STATE_TRANSITION (element);
 
   switch (transition) {
-    case GST_STATE_NULL_TO_READY:
+    case GST_STATE_CHANGE_NULL_TO_READY:
       if (!(amrnbdec->handle = Decoder_Interface_init ()))
-        return GST_STATE_FAILURE;
+        goto init_failed;
       break;
-    case GST_STATE_READY_TO_PAUSED:
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
       gst_adapter_clear (amrnbdec->adapter);
-      amrnbdec->ts = 0;
+      amrnbdec->rate = 0;
+      amrnbdec->channels = 0;
+      amrnbdec->ts = -1;
       break;
     default:
       break;
   }
 
-  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element);
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
 
   switch (transition) {
-    case GST_STATE_READY_TO_NULL:
+    case GST_STATE_CHANGE_READY_TO_NULL:
       Decoder_Interface_exit (amrnbdec->handle);
       break;
     default:
@@ -264,4 +309,12 @@ gst_amrnbdec_state_change (GstElement * element)
   }
 
   return ret;
+
+  /* ERRORS */
+init_failed:
+  {
+    GST_ELEMENT_ERROR (amrnbdec, LIBRARY, INIT, (NULL),
+        ("Failed to open AMR Decoder"));
+    return GST_STATE_CHANGE_FAILURE;
+  }
 }