rawparse: Properly align raw audio/video output buffers
authorSebastian Dröge <sebastian@centricular.com>
Sun, 27 Nov 2016 09:44:14 +0000 (11:44 +0200)
committerSebastian Dröge <sebastian@centricular.com>
Sun, 27 Nov 2016 09:45:33 +0000 (11:45 +0200)
That is, aligned to the basic type for audio and to 32 bytes for video.
Fixes crashes if the raw buffers are passed to SIMD processing functions.

https://bugzilla.gnome.org/show_bug.cgi?id=774428

gst/rawparse/gstrawaudioparse.c
gst/rawparse/gstrawbaseparse.c
gst/rawparse/gstrawbaseparse.h
gst/rawparse/gstrawvideoparse.c

index 98575dd..626604c 100644 (file)
@@ -161,6 +161,8 @@ static gboolean gst_raw_audio_parse_is_unit_format_supported (GstRawBaseParse *
 static void gst_raw_audio_parse_get_units_per_second (GstRawBaseParse *
     raw_base_parse, GstFormat format, GstRawBaseParseConfig config,
     gsize * units_per_sec_n, gsize * units_per_sec_d);
+static gint gst_raw_audio_parse_get_alignment (GstRawBaseParse * raw_base_parse,
+    GstRawBaseParseConfig config);
 
 static gboolean gst_raw_audio_parse_is_using_sink_caps (GstRawAudioParse *
     raw_audio_parse);
@@ -228,6 +230,8 @@ gst_raw_audio_parse_class_init (GstRawAudioParseClass * klass)
       GST_DEBUG_FUNCPTR (gst_raw_audio_parse_is_unit_format_supported);
   rawbaseparse_class->get_units_per_second =
       GST_DEBUG_FUNCPTR (gst_raw_audio_parse_get_units_per_second);
+  rawbaseparse_class->get_alignment =
+      GST_DEBUG_FUNCPTR (gst_raw_audio_parse_get_alignment);
 
   g_object_class_install_property (object_class,
       PROP_FORMAT,
@@ -669,6 +673,38 @@ gst_raw_audio_parse_is_config_ready (GstRawBaseParse * raw_base_parse,
   return gst_raw_audio_parse_get_config_ptr (raw_audio_parse, config)->ready;
 }
 
+static guint
+round_up_pow2 (guint n)
+{
+  n = n - 1;
+  n = n | (n >> 1);
+  n = n | (n >> 2);
+  n = n | (n >> 4);
+  n = n | (n >> 8);
+  n = n | (n >> 16);
+  return n + 1;
+}
+
+static gint
+gst_raw_audio_parse_get_alignment (GstRawBaseParse * raw_base_parse,
+    GstRawBaseParseConfig config)
+{
+  GstRawAudioParse *raw_audio_parse = GST_RAW_AUDIO_PARSE (raw_base_parse);
+  GstRawAudioParseConfig *config_ptr =
+      gst_raw_audio_parse_get_config_ptr (raw_audio_parse, config);
+  gint width;
+
+  if (config_ptr->format != GST_RAW_AUDIO_PARSE_FORMAT_PCM)
+    return 1;
+
+  width =
+      GST_AUDIO_FORMAT_INFO_WIDTH (gst_audio_format_get_info
+      (config_ptr->pcm_format)) / 8;
+  width = GST_ROUND_UP_8 (width);
+  width = round_up_pow2 (width);
+
+  return width;
+}
 
 static gboolean
 gst_raw_audio_parse_process (GstRawBaseParse * raw_base_parse,
index c2ccee5..99d64da 100644 (file)
@@ -430,6 +430,43 @@ done:
   return ret;
 }
 
+static GstBuffer *
+gst_raw_base_parse_align_buffer (GstRawBaseParse * raw_base_parse,
+    gsize alignment, GstBuffer * buffer)
+{
+  GstMapInfo map;
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+
+  if (map.size < sizeof (guintptr)) {
+    gst_buffer_unmap (buffer, &map);
+    return buffer;
+  }
+
+  if (((guintptr) map.data) & (alignment - 1)) {
+    GstBuffer *new_buffer;
+    GstAllocationParams params = { 0, alignment - 1, 0, 0, };
+
+    new_buffer = gst_buffer_new_allocate (NULL,
+        gst_buffer_get_size (buffer), &params);
+
+    /* Copy data "by hand", so ensure alignment is kept: */
+    gst_buffer_fill (new_buffer, 0, map.data, map.size);
+
+    gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
+    GST_DEBUG_OBJECT (raw_base_parse,
+        "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
+        alignment);
+
+    gst_buffer_unmap (buffer, &map);
+    gst_buffer_unref (buffer);
+
+    return new_buffer;
+  }
+
+  gst_buffer_unmap (buffer, &map);
+  return buffer;
+}
 
 static GstFlowReturn
 gst_raw_base_parse_handle_frame (GstBaseParse * parse,
@@ -442,6 +479,7 @@ gst_raw_base_parse_handle_frame (GstBaseParse * parse,
   guint64 buffer_duration;
   GstFlowReturn flow_ret = GST_FLOW_OK;
   GstEvent *new_caps_event = NULL;
+  gint alignment;
   GstRawBaseParse *raw_base_parse = GST_RAW_BASE_PARSE (parse);
   GstRawBaseParseClass *klass = GST_RAW_BASE_PARSE_GET_CLASS (parse);
 
@@ -567,6 +605,15 @@ gst_raw_base_parse_handle_frame (GstBaseParse * parse,
     frame->out_buffer = NULL;
   }
 
+  if (klass->get_alignment
+      && (alignment =
+          klass->get_alignment (raw_base_parse,
+              GST_RAW_BASE_PARSE_CONFIG_CURRENT)) != 1) {
+    frame->out_buffer =
+        gst_raw_base_parse_align_buffer (raw_base_parse, alignment,
+        gst_buffer_ref (frame->buffer));
+  }
+
   /* Set the duration of the output buffer, or if none exists, of
    * the input buffer. Do this after the process() call, since in
    * case out_buffer is set, the subclass has created a new buffer.
index 519b409..4af4408 100644 (file)
@@ -193,6 +193,9 @@ struct _GstRawBaseParseClass
 
   gint                  (*get_overhead_size)         (GstRawBaseParse * raw_base_parse,
                                                       GstRawBaseParseConfig config);
+
+  gint                  (*get_alignment)             (GstRawBaseParse * raw_base_parse,
+                                                      GstRawBaseParseConfig config);
 };
 
 
index 2fb58c1..3808369 100644 (file)
@@ -182,11 +182,12 @@ static GstRawVideoParseConfig
     * gst_raw_video_parse_get_config_ptr (GstRawVideoParse * raw_video_parse,
     GstRawBaseParseConfig config);
 
+static gint gst_raw_video_parse_get_alignment (GstRawBaseParse * raw_base_parse,
+    GstRawBaseParseConfig config);
+
 static void gst_raw_video_parse_init_config (GstRawVideoParseConfig * config);
 static void gst_raw_video_parse_update_info (GstRawVideoParseConfig * config);
 
-
-
 static void
 gst_raw_video_parse_class_init (GstRawVideoParseClass * klass)
 {
@@ -236,6 +237,8 @@ gst_raw_video_parse_class_init (GstRawVideoParseClass * klass)
       GST_DEBUG_FUNCPTR (gst_raw_video_parse_get_units_per_second);
   rawbaseparse_class->get_overhead_size =
       GST_DEBUG_FUNCPTR (gst_raw_video_parse_get_overhead_size);
+  rawbaseparse_class->get_alignment =
+      GST_DEBUG_FUNCPTR (gst_raw_video_parse_get_alignment);
 
   g_object_class_install_property (object_class,
       PROP_WIDTH,
@@ -929,6 +932,12 @@ gst_raw_video_parse_is_config_ready (GstRawBaseParse * raw_base_parse,
   return gst_raw_video_parse_get_config_ptr (raw_video_parse, config)->ready;
 }
 
+static gint
+gst_raw_video_parse_get_alignment (GstRawBaseParse * raw_base_parse,
+    GstRawBaseParseConfig config)
+{
+  return 32;
+}
 
 static gboolean
 gst_raw_video_parse_process (GstRawBaseParse * raw_base_parse,