From 5a6b121d5b41b28911c74b0773e109d121c81691 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sun, 27 Nov 2016 11:44:14 +0200 Subject: [PATCH] rawparse: Properly align raw audio/video output buffers 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 | 36 +++++++++++++++++++++++++ gst/rawparse/gstrawbaseparse.c | 47 +++++++++++++++++++++++++++++++++ gst/rawparse/gstrawbaseparse.h | 3 +++ gst/rawparse/gstrawvideoparse.c | 13 +++++++-- 4 files changed, 97 insertions(+), 2 deletions(-) diff --git a/gst/rawparse/gstrawaudioparse.c b/gst/rawparse/gstrawaudioparse.c index 98575ddb73..626604c02a 100644 --- a/gst/rawparse/gstrawaudioparse.c +++ b/gst/rawparse/gstrawaudioparse.c @@ -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, diff --git a/gst/rawparse/gstrawbaseparse.c b/gst/rawparse/gstrawbaseparse.c index c2ccee511c..99d64dad09 100644 --- a/gst/rawparse/gstrawbaseparse.c +++ b/gst/rawparse/gstrawbaseparse.c @@ -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), ¶ms); + + /* 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. diff --git a/gst/rawparse/gstrawbaseparse.h b/gst/rawparse/gstrawbaseparse.h index 519b409ed2..4af4408c23 100644 --- a/gst/rawparse/gstrawbaseparse.h +++ b/gst/rawparse/gstrawbaseparse.h @@ -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); }; diff --git a/gst/rawparse/gstrawvideoparse.c b/gst/rawparse/gstrawvideoparse.c index 2fb58c1383..38083699e7 100644 --- a/gst/rawparse/gstrawvideoparse.c +++ b/gst/rawparse/gstrawvideoparse.c @@ -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,