audioconvert: implement support for converting between interleaved and non-interleave...
authorGeorge Kiagiadakis <george.kiagiadakis@collabora.com>
Thu, 1 Feb 2018 16:08:51 +0000 (18:08 +0200)
committerGeorge Kiagiadakis <george.kiagiadakis@collabora.com>
Wed, 11 Jul 2018 13:26:13 +0000 (16:26 +0300)
https://bugzilla.gnome.org/show_bug.cgi?id=705986

gst/audioconvert/gstaudioconvert.c

index 2c0bc89..e93ddf4 100644 (file)
@@ -138,6 +138,8 @@ static gboolean gst_audio_convert_transform_meta (GstBaseTransform * trans,
     GstBuffer * outbuf, GstMeta * meta, GstBuffer * inbuf);
 static GstFlowReturn gst_audio_convert_submit_input_buffer (GstBaseTransform *
     base, gboolean is_discont, GstBuffer * input);
+static GstFlowReturn gst_audio_convert_prepare_output_buffer (GstBaseTransform *
+    base, GstBuffer * inbuf, GstBuffer ** outbuf);
 static void gst_audio_convert_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * pspec);
 static void gst_audio_convert_get_property (GObject * object, guint prop_id,
@@ -169,7 +171,7 @@ G_DEFINE_TYPE_WITH_CODE (GstAudioConvert, gst_audio_convert,
 
 #define STATIC_CAPS \
 GST_STATIC_CAPS (GST_AUDIO_CAPS_MAKE (GST_AUDIO_FORMATS_ALL) \
-    ", layout = (string) interleaved")
+    ", layout = (string) { interleaved, non-interleaved }")
 
 static GstStaticPadTemplate gst_audio_convert_src_template =
 GST_STATIC_PAD_TEMPLATE ("src",
@@ -243,6 +245,8 @@ gst_audio_convert_class_init (GstAudioConvertClass * klass)
       GST_DEBUG_FUNCPTR (gst_audio_convert_transform_meta);
   basetransform_class->submit_input_buffer =
       GST_DEBUG_FUNCPTR (gst_audio_convert_submit_input_buffer);
+  basetransform_class->prepare_output_buffer =
+      GST_DEBUG_FUNCPTR (gst_audio_convert_prepare_output_buffer);
 
   basetransform_class->passthrough_on_same_caps = TRUE;
   basetransform_class->transform_ip_on_passthrough = FALSE;
@@ -308,6 +312,14 @@ remove_format_from_structure (GstCapsFeatures * features,
 }
 
 static gboolean
+remove_layout_from_structure (GstCapsFeatures * features,
+    GstStructure * structure, gpointer user_data G_GNUC_UNUSED)
+{
+  gst_structure_remove_field (structure, "layout");
+  return TRUE;
+}
+
+static gboolean
 remove_channels_from_structure (GstCapsFeatures * features, GstStructure * s,
     gpointer user_data)
 {
@@ -352,6 +364,7 @@ gst_audio_convert_transform_caps (GstBaseTransform * btrans,
   tmp = gst_caps_copy (caps);
 
   gst_caps_map_in_place (tmp, remove_format_from_structure, NULL);
+  gst_caps_map_in_place (tmp, remove_layout_from_structure, NULL);
   gst_caps_map_in_place (tmp, remove_channels_from_structure, btrans);
 
   /* We can infer the required input / output channels based on the
@@ -792,47 +805,28 @@ gst_audio_convert_transform (GstBaseTransform * base, GstBuffer * inbuf,
 {
   GstFlowReturn ret;
   GstAudioConvert *this = GST_AUDIO_CONVERT (base);
-  GstMapInfo srcmap = { NULL, }, dstmap;
-  gint insize, outsize;
+  GstAudioBuffer srcabuf, dstabuf;
   gboolean inbuf_writable;
   GstAudioConverterFlags flags;
-  gsize samples;
-
-  /* get amount of samples to convert. */
-  samples = gst_buffer_get_size (inbuf) / this->in_info.bpf;
-
-  /* get in/output sizes, to see if the buffers we got are of correct
-   * sizes */
-  insize = samples * this->in_info.bpf;
-  outsize = samples * this->out_info.bpf;
 
-  if (insize == 0 || outsize == 0)
+  /* https://bugzilla.gnome.org/show_bug.cgi?id=396835 */
+  if (gst_buffer_get_size (inbuf) == 0)
     return GST_FLOW_OK;
 
-  gst_buffer_resize (outbuf, 0, outsize);
-
-  /* get src and dst data */
   if (inbuf != outbuf) {
     inbuf_writable = gst_buffer_is_writable (inbuf)
         && gst_buffer_n_memory (inbuf) == 1
         && gst_memory_is_writable (gst_buffer_peek_memory (inbuf, 0));
 
-    if (!gst_buffer_map (inbuf, &srcmap,
+    if (!gst_audio_buffer_map (&srcabuf, &this->in_info, inbuf,
             inbuf_writable ? GST_MAP_READWRITE : GST_MAP_READ))
       goto inmap_error;
   } else {
     inbuf_writable = TRUE;
   }
-  if (!gst_buffer_map (outbuf, &dstmap, GST_MAP_WRITE))
-    goto outmap_error;
 
-  /* check in and outsize */
-  if (inbuf != outbuf) {
-    if (srcmap.size < insize)
-      goto wrong_size;
-  }
-  if (dstmap.size < outsize)
-    goto wrong_size;
+  if (!gst_audio_buffer_map (&dstabuf, &this->out_info, outbuf, GST_MAP_WRITE))
+    goto outmap_error;
 
   /* and convert the samples */
   flags = 0;
@@ -840,36 +834,28 @@ gst_audio_convert_transform (GstBaseTransform * base, GstBuffer * inbuf,
     flags |= GST_AUDIO_CONVERTER_FLAG_IN_WRITABLE;
 
   if (!GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP)) {
-    gpointer in[1] = { srcmap.data };
-    gpointer out[1] = { dstmap.data };
-
     if (!gst_audio_converter_samples (this->convert, flags,
-            inbuf != outbuf ? in : out, samples, out, samples))
+            inbuf != outbuf ? srcabuf.planes : dstabuf.planes,
+            dstabuf.n_samples, dstabuf.planes, dstabuf.n_samples))
       goto convert_error;
   } else {
     /* Create silence buffer */
-    gst_audio_format_fill_silence (this->out_info.finfo, dstmap.data, outsize);
+    gint i;
+    for (i = 0; i < dstabuf.n_planes; i++) {
+      gst_audio_format_fill_silence (this->out_info.finfo, dstabuf.planes[i],
+          GST_AUDIO_BUFFER_PLANE_SIZE (&dstabuf));
+    }
   }
   ret = GST_FLOW_OK;
 
 done:
-  gst_buffer_unmap (outbuf, &dstmap);
+  gst_audio_buffer_unmap (&dstabuf);
   if (inbuf != outbuf)
-    gst_buffer_unmap (inbuf, &srcmap);
+    gst_audio_buffer_unmap (&srcabuf);
 
   return ret;
 
   /* ERRORS */
-wrong_size:
-  {
-    GST_ELEMENT_ERROR (this, STREAM, FORMAT,
-        (NULL),
-        ("input/output buffers are of wrong size in: %" G_GSIZE_FORMAT " < %d"
-            " or out: %" G_GSIZE_FORMAT " < %d",
-            srcmap.size, insize, dstmap.size, outsize));
-    ret = GST_FLOW_ERROR;
-    goto done;
-  }
 convert_error:
   {
     GST_ELEMENT_ERROR (this, STREAM, FORMAT,
@@ -888,7 +874,7 @@ outmap_error:
     GST_ELEMENT_ERROR (this, STREAM, FORMAT,
         (NULL), ("failed to map output buffer"));
     if (inbuf != outbuf)
-      gst_buffer_unmap (inbuf, &srcmap);
+      gst_audio_buffer_unmap (&srcabuf);
     return GST_FLOW_ERROR;
   }
 }
@@ -935,6 +921,43 @@ gst_audio_convert_submit_input_buffer (GstBaseTransform * base,
       is_discont, input);
 }
 
+static GstFlowReturn
+gst_audio_convert_prepare_output_buffer (GstBaseTransform * base,
+    GstBuffer * inbuf, GstBuffer ** outbuf)
+{
+  GstAudioConvert *this = GST_AUDIO_CONVERT (base);
+  GstAudioMeta *meta;
+  GstFlowReturn ret;
+
+  ret = GST_BASE_TRANSFORM_CLASS (parent_class)->prepare_output_buffer (base,
+      inbuf, outbuf);
+
+  if (ret != GST_FLOW_OK)
+    return ret;
+
+  meta = gst_buffer_get_audio_meta (inbuf);
+
+  if (inbuf != *outbuf) {
+    gsize samples = meta ?
+        meta->samples : (gst_buffer_get_size (inbuf) / this->in_info.bpf);
+
+    /* ensure that the output buffer is not bigger than what we need */
+    gst_buffer_resize (*outbuf, 0, samples * this->out_info.bpf);
+
+    /* add the audio meta on the output buffer if it's planar */
+    if (this->out_info.layout == GST_AUDIO_LAYOUT_NON_INTERLEAVED) {
+      gst_buffer_add_audio_meta (*outbuf, &this->out_info, samples, NULL);
+    }
+  } else {
+    /* if the input buffer came with a GstAudioMeta,
+     * update it to reflect the properties of the output format */
+    if (meta)
+      meta->info = this->out_info;
+  }
+
+  return ret;
+}
+
 static void
 gst_audio_convert_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * pspec)