waylandsink: Validate strides and offset when using FD as SHM

As SHM interface only support 1 stride, and 1 offset, we need to
make sure that there is no padding between planes for planar formats.

https://bugzilla.gnome.org/show_bug.cgi?id=790057
This commit is contained in:
Nicolas Dufresne 2017-11-21 23:18:24 -05:00
parent cc033355ab
commit 1a7363e023
2 changed files with 69 additions and 2 deletions

View file

@ -704,10 +704,12 @@ gst_wayland_sink_show_frame (GstVideoSink * vsink, GstBuffer * buffer)
}
if (!wbuf && gst_wl_display_check_format_for_shm (sink->display, format)) {
if (gst_buffer_n_memory (buffer) == 1 && gst_is_fd_memory (mem)) {
if (gst_buffer_n_memory (buffer) == 1 && gst_is_fd_memory (mem))
wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
&sink->video_info);
} else {
/* If nothing worked, copy into our internal pool */
if (!wbuf) {
GstVideoFrame src, dst;
GstVideoInfo src_info = sink->video_info;

View file

@ -129,6 +129,65 @@ gst_is_wl_shm_memory (GstMemory * mem)
return gst_memory_is_type (mem, GST_ALLOCATOR_WL_SHM);
}
/* Copied from gst_v4l2_object_extrapolate_stride() */
static gint
gst_wl_shm_extrapolate_stride (const GstVideoFormatInfo * finfo, gint plane,
gint stride)
{
gint estride;
switch (finfo->format) {
case GST_VIDEO_FORMAT_NV12:
case GST_VIDEO_FORMAT_NV12_64Z32:
case GST_VIDEO_FORMAT_NV21:
case GST_VIDEO_FORMAT_NV16:
case GST_VIDEO_FORMAT_NV61:
case GST_VIDEO_FORMAT_NV24:
estride = (plane == 0 ? 1 : 2) *
GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (finfo, plane, stride);
break;
default:
estride = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (finfo, plane, stride);
break;
}
return estride;
}
static gboolean
gst_wl_shm_validate_video_info (const GstVideoInfo * vinfo)
{
gint height = GST_VIDEO_INFO_HEIGHT (vinfo);
gint base_stride = GST_VIDEO_INFO_PLANE_STRIDE (vinfo, 0);
gsize base_offs = GST_VIDEO_INFO_PLANE_OFFSET (vinfo, 0);
gint i;
gsize offs = 0;
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (vinfo); i++) {
guint32 estride;
/* Overwrite the video info's stride and offset using the pitch calculcated
* by the kms driver. */
estride = gst_wl_shm_extrapolate_stride (vinfo->finfo, i, base_stride);
if (estride != GST_VIDEO_INFO_PLANE_STRIDE (vinfo, i))
return FALSE;
if (GST_VIDEO_INFO_PLANE_OFFSET (vinfo, i) - base_offs != offs)
return FALSE;
/* Note that we cannot negotiate special padding betweem each planes,
* hence using the display height here. */
offs +=
estride * GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (vinfo->finfo, i, height);
}
if (vinfo->size < offs)
return FALSE;
return TRUE;
}
struct wl_buffer *
gst_wl_shm_memory_construct_wl_buffer (GstMemory * mem, GstWlDisplay * display,
const GstVideoInfo * info)
@ -139,6 +198,11 @@ gst_wl_shm_memory_construct_wl_buffer (GstMemory * mem, GstWlDisplay * display,
struct wl_shm_pool *wl_pool;
struct wl_buffer *wbuffer;
if (!gst_wl_shm_validate_video_info (info)) {
GST_DEBUG_OBJECT (display, "Unsupported strides and offsets.");
return NULL;
}
width = GST_VIDEO_INFO_WIDTH (info);
height = GST_VIDEO_INFO_HEIGHT (info);
stride = GST_VIDEO_INFO_PLANE_STRIDE (info, 0);
@ -146,6 +210,7 @@ gst_wl_shm_memory_construct_wl_buffer (GstMemory * mem, GstWlDisplay * display,
format = gst_video_format_to_wl_shm_format (GST_VIDEO_INFO_FORMAT (info));
memsize = gst_memory_get_sizes (mem, &offset, &maxsize);
offset += GST_VIDEO_INFO_PLANE_OFFSET (info, 0);
g_return_val_if_fail (gst_is_fd_memory (mem), NULL);
g_return_val_if_fail (size <= memsize, NULL);