qtdemux: Ensure that raw audio and video have properly aligned 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-20 13:08:27 +02:00
parent 7fb278d7d2
commit bb35f15d44

View File

@ -298,6 +298,8 @@ struct _QtDemuxStream
GstAllocator *allocator; GstAllocator *allocator;
GstAllocationParams params; GstAllocationParams params;
gsize alignment;
/* when a discontinuity is pending */ /* when a discontinuity is pending */
gboolean discont; gboolean discont;
@ -1848,6 +1850,7 @@ _create_stream (void)
stream->n_samples_moof = 0; stream->n_samples_moof = 0;
stream->duration_moof = 0; stream->duration_moof = 0;
stream->duration_last_moof = 0; stream->duration_last_moof = 0;
stream->alignment = 1;
g_queue_init (&stream->protection_scheme_event_queue); g_queue_init (&stream->protection_scheme_event_queue);
return stream; return stream;
} }
@ -5127,6 +5130,44 @@ clipped:
} }
} }
static GstBuffer *
gst_qtdemux_align_buffer (GstQTDemux * 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;
}
/* the input buffer metadata must be writable, /* the input buffer metadata must be writable,
* but time/duration etc not yet set and need not be preserved */ * but time/duration etc not yet set and need not be preserved */
static GstBuffer * static GstBuffer *
@ -5248,6 +5289,8 @@ gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT); GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
} }
if (stream->alignment > 1)
buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
gst_pad_push (stream->pad, buffer); gst_pad_push (stream->pad, buffer);
stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers); stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
@ -5351,6 +5394,9 @@ gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
} }
} }
if (stream->alignment > 1)
buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
ret = gst_pad_push (stream->pad, buf); ret = gst_pad_push (stream->pad, buf);
if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) { if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
@ -13137,6 +13183,7 @@ qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
caps = gst_caps_new_empty_simple ("video/x-raw"); caps = gst_caps_new_empty_simple ("video/x-raw");
gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL); gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
_codec ("Windows Raw RGB"); _codec ("Windows Raw RGB");
stream->alignment = 32;
break; break;
case FOURCC_raw_: case FOURCC_raw_:
{ {
@ -13500,11 +13547,24 @@ qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
/* enable clipping for raw video streams */ /* enable clipping for raw video streams */
stream->need_clip = TRUE; stream->need_clip = TRUE;
stream->alignment = 32;
} }
return caps; return caps;
} }
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 GstCaps * static GstCaps *
qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream, qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
guint32 fourcc, const guint8 * data, int len, gchar ** codec_name) guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
@ -13547,6 +13607,8 @@ qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
caps = gst_caps_new_simple ("audio/x-raw", caps = gst_caps_new_simple ("audio/x-raw",
"format", G_TYPE_STRING, gst_audio_format_to_string (format), "format", G_TYPE_STRING, gst_audio_format_to_string (format),
"layout", G_TYPE_STRING, "interleaved", NULL); "layout", G_TYPE_STRING, "interleaved", NULL);
stream->alignment = GST_ROUND_UP_8 (depth);
stream->alignment = round_up_pow2 (stream->alignment);
break; break;
} }
case GST_MAKE_FOURCC ('f', 'l', '6', '4'): case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
@ -13554,12 +13616,14 @@ qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
caps = gst_caps_new_simple ("audio/x-raw", caps = gst_caps_new_simple ("audio/x-raw",
"format", G_TYPE_STRING, "F64BE", "format", G_TYPE_STRING, "F64BE",
"layout", G_TYPE_STRING, "interleaved", NULL); "layout", G_TYPE_STRING, "interleaved", NULL);
stream->alignment = 8;
break; break;
case GST_MAKE_FOURCC ('f', 'l', '3', '2'): case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
_codec ("Raw 32-bit floating-point audio"); _codec ("Raw 32-bit floating-point audio");
caps = gst_caps_new_simple ("audio/x-raw", caps = gst_caps_new_simple ("audio/x-raw",
"format", G_TYPE_STRING, "F32BE", "format", G_TYPE_STRING, "F32BE",
"layout", G_TYPE_STRING, "interleaved", NULL); "layout", G_TYPE_STRING, "interleaved", NULL);
stream->alignment = 4;
break; break;
case FOURCC_in24: case FOURCC_in24:
_codec ("Raw 24-bit PCM audio"); _codec ("Raw 24-bit PCM audio");
@ -13568,12 +13632,14 @@ qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
caps = gst_caps_new_simple ("audio/x-raw", caps = gst_caps_new_simple ("audio/x-raw",
"format", G_TYPE_STRING, "S24BE", "format", G_TYPE_STRING, "S24BE",
"layout", G_TYPE_STRING, "interleaved", NULL); "layout", G_TYPE_STRING, "interleaved", NULL);
stream->alignment = 4;
break; break;
case GST_MAKE_FOURCC ('i', 'n', '3', '2'): case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
_codec ("Raw 32-bit PCM audio"); _codec ("Raw 32-bit PCM audio");
caps = gst_caps_new_simple ("audio/x-raw", caps = gst_caps_new_simple ("audio/x-raw",
"format", G_TYPE_STRING, "S32BE", "format", G_TYPE_STRING, "S32BE",
"layout", G_TYPE_STRING, "interleaved", NULL); "layout", G_TYPE_STRING, "interleaved", NULL);
stream->alignment = 4;
break; break;
case FOURCC_ulaw: case FOURCC_ulaw:
_codec ("Mu-law audio"); _codec ("Mu-law audio");
@ -13753,6 +13819,8 @@ qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
"format", G_TYPE_STRING, gst_audio_format_to_string (format), "format", G_TYPE_STRING, gst_audio_format_to_string (format),
"layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ? "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
"non-interleaved" : "interleaved", NULL); "non-interleaved" : "interleaved", NULL);
stream->alignment = GST_ROUND_UP_8 (depth);
stream->alignment = round_up_pow2 (stream->alignment);
} else { } else {
if (width == 0) if (width == 0)
width = 32; width = 32;
@ -13771,6 +13839,7 @@ qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
"format", G_TYPE_STRING, gst_audio_format_to_string (format), "format", G_TYPE_STRING, gst_audio_format_to_string (format),
"layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ? "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
"non-interleaved" : "interleaved", NULL); "non-interleaved" : "interleaved", NULL);
stream->alignment = width / 8;
} }
break; break;
} }