avidemux: Ensure that raw video have properly aligned buffers
authorSebastian Dröge <sebastian@centricular.com>
Sun, 20 Nov 2016 11:14:08 +0000 (13:14 +0200)
committerSebastian Dröge <sebastian@centricular.com>
Sun, 20 Nov 2016 11:14:08 +0000 (13:14 +0200)
That is, aligned to 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/avi/gstavidemux.c
gst/avi/gstavidemux.h

index 1fe3176..5daeef0 100644 (file)
@@ -1936,6 +1936,7 @@ gst_avi_demux_check_caps (GstAviDemux * avi, GstAviStream * stream,
   s = gst_caps_get_structure (caps, 0);
   if (gst_structure_has_name (s, "video/x-raw")) {
     stream->is_raw = TRUE;
+    stream->alignment = 32;
     if (!gst_structure_has_field (s, "pixel-aspect-ratio"))
       gst_structure_set (s, "pixel-aspect-ratio", GST_TYPE_FRACTION,
           1, 1, NULL);
@@ -5137,6 +5138,44 @@ gst_avi_demux_find_next (GstAviDemux * avi, gfloat rate)
   return stream_num;
 }
 
+static GstBuffer *
+gst_avi_demux_align_buffer (GstAviDemux * demux,
+    GstBuffer * buffer, gsize alignment)
+{
+  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 (demux,
+        "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_avi_demux_loop_data (GstAviDemux * avi)
 {
@@ -5256,6 +5295,8 @@ gst_avi_demux_loop_data (GstAviDemux * avi)
         gst_buffer_get_size (buf), GST_TIME_ARGS (timestamp),
         GST_TIME_ARGS (duration), out_offset, out_offset_end);
 
+    if (stream->alignment > 1)
+      buf = gst_avi_demux_align_buffer (avi, buf, stream->alignment);
     ret = gst_pad_push (stream->pad, buf);
 
     /* mark as processed, we increment the frame and byte counters then
@@ -5545,6 +5586,9 @@ gst_avi_demux_stream_data (GstAviDemux * avi)
           } else {
             GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
           }
+
+          if (stream->alignment > 1)
+            buf = gst_avi_demux_align_buffer (avi, buf, stream->alignment);
           res = gst_pad_push (stream->pad, buf);
           buf = NULL;
 
index 813ec60..22e46a2 100644 (file)
@@ -120,6 +120,7 @@ typedef struct {
 
   gint           index_id;
   gboolean is_raw;
+  gsize alignment;
 } GstAviStream;
 
 typedef enum {