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
This commit is contained in:
Sebastian Dröge 2016-11-27 11:44:14 +02:00
parent de99cf0de1
commit 5a6b121d5b
4 changed files with 97 additions and 2 deletions

View 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,

View 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.

View 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);
};

View 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,