From: Aurélien Zanelli Date: Mon, 6 Oct 2014 15:30:06 +0000 (+0200) Subject: v4l2bufferpool: fix import_userptr() in single-planar API when n_planes > 1 X-Git-Tag: 1.19.3~509^2~3838 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=600027a1ee83ef595cc5598633812c15e6b30db2;p=platform%2Fupstream%2Fgstreamer.git v4l2bufferpool: fix import_userptr() in single-planar API when n_planes > 1 In the V4L2 single-planar API, when format is semi-planar/planar, drivers expect the planes to be contiguous in memory. So this commit change the way we handle semi-planar/planar format (n_planes > 1) when we use the single-planar API (group->n_mem == 1). To check that planes are contiguous and have expected size, ie: no padding. We test the fact that plane 'i' start address + plane 'i' expected size equals to plane 'i + 1' start address. If not, we return in error. Math are done in bufferpool rather than in allocator because the former is aware of video info. https://bugzilla.gnome.org/show_bug.cgi?id=738013 --- diff --git a/sys/v4l2/gstv4l2allocator.c b/sys/v4l2/gstv4l2allocator.c index a2c96a1..b3d02eb 100644 --- a/sys/v4l2/gstv4l2allocator.c +++ b/sys/v4l2/gstv4l2allocator.c @@ -1143,32 +1143,34 @@ gst_v4l2_allocator_import_userptr (GstV4l2Allocator * allocator, g_return_val_if_fail (allocator->memory == V4L2_MEMORY_USERPTR, FALSE); /* TODO Support passing N plane from 1 memory to MPLANE v4l2 format */ - if (n_planes != group->n_mem) + if (V4L2_TYPE_IS_MULTIPLANAR (allocator->type) && n_planes != group->n_mem) goto n_mem_missmatch; for (i = 0; i < group->n_mem; i++) { - gsize maxsize; + gsize maxsize, psize; if (V4L2_TYPE_IS_MULTIPLANAR (allocator->type)) { struct v4l2_pix_format_mplane *pix = &allocator->format.fmt.pix_mp; maxsize = pix->plane_fmt[i].sizeimage; + psize = size[i]; } else { maxsize = allocator->format.fmt.pix.sizeimage; + psize = img_size; } - g_assert (size[i] <= img_size); + g_assert (psize <= img_size); GST_LOG_OBJECT (allocator, "imported USERPTR %p plane %d size %" - G_GSIZE_FORMAT, data[i], i, size[i]); + G_GSIZE_FORMAT, data[i], i, psize); mem = (GstV4l2Memory *) group->mem[i]; mem->mem.maxsize = maxsize; - mem->mem.size = size[i]; + mem->mem.size = psize; mem->data = data[i]; group->planes[i].length = maxsize; - group->planes[i].bytesused = size[i]; + group->planes[i].bytesused = psize; group->planes[i].m.userptr = (unsigned long) data[i]; group->planes[i].data_offset = 0; } diff --git a/sys/v4l2/gstv4l2bufferpool.c b/sys/v4l2/gstv4l2bufferpool.c index 2096423..543ce91 100644 --- a/sys/v4l2/gstv4l2bufferpool.c +++ b/sys/v4l2/gstv4l2bufferpool.c @@ -246,6 +246,25 @@ gst_v4l2_buffer_pool_import_userptr (GstV4l2BufferPool * pool, } } + /* In the single planar API, planes must be contiguous in memory and + * therefore they must have expected size. ie: no padding. + * To check these conditions, we check that plane 'i' start address + * + plane 'i' size equals to plane 'i+1' start address */ + if (!V4L2_TYPE_IS_MULTIPLANAR (pool->obj->type)) { + for (i = 0; i < (GST_VIDEO_FORMAT_INFO_N_PLANES (finfo) - 1); i++) { + const struct v4l2_pix_format *pix_fmt = &pool->obj->format.fmt.pix; + gpointer tmp; + gint estride = gst_v4l2_object_extrapolate_stride (finfo, i, + pix_fmt->bytesperline); + guint eheight = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (finfo, i, + pix_fmt->height); + + tmp = ((guint8 *) data->frame.data[i]) + estride * eheight; + if (tmp != data->frame.data[i + 1]) + goto non_contiguous_mem; + } + } + if (!gst_v4l2_allocator_import_userptr (pool->vallocator, group, data->frame.info.size, finfo->n_planes, data->frame.data, size)) goto import_failed; @@ -284,6 +303,12 @@ invalid_buffer: g_slice_free (struct UserPtrData, data); return GST_FLOW_ERROR; } +non_contiguous_mem: + { + GST_ERROR_OBJECT (pool, "memory is not contiguous or plane size mismatch"); + _unmap_userptr_frame (data); + return GST_FLOW_ERROR; + } import_failed: { GST_ERROR_OBJECT (pool, "failed to import data"); diff --git a/sys/v4l2/gstv4l2object.c b/sys/v4l2/gstv4l2object.c index 6f6b9db..6d1856b 100644 --- a/sys/v4l2/gstv4l2object.c +++ b/sys/v4l2/gstv4l2object.c @@ -2413,19 +2413,7 @@ gst_v4l2_object_extrapolate_info (GstV4l2Object * v4l2object, padded_height = info->height + align->padding_top + align->padding_bottom; for (i = 0; i < finfo->n_planes; i++) { - 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_NV24: - estride = (i == 0 ? 1 : 2) * - GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (finfo, i, stride); - break; - default: - estride = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (finfo, i, stride); - break; - } + estride = gst_v4l2_object_extrapolate_stride (finfo, i, stride); gst_v4l2_object_set_stride (info, align, i, estride); @@ -2568,6 +2556,29 @@ store_info: } } +gint +gst_v4l2_object_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_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; +} + gboolean gst_v4l2_object_set_format (GstV4l2Object * v4l2object, GstCaps * caps) { diff --git a/sys/v4l2/gstv4l2object.h b/sys/v4l2/gstv4l2object.h index 6dbf473..380abfb 100644 --- a/sys/v4l2/gstv4l2object.h +++ b/sys/v4l2/gstv4l2object.h @@ -247,6 +247,9 @@ GstCaps* gst_v4l2_object_get_raw_caps (void); GstCaps* gst_v4l2_object_get_codec_caps (void); +gint gst_v4l2_object_extrapolate_stride (const GstVideoFormatInfo * finfo, + gint plane, gint stride); + gboolean gst_v4l2_object_set_format (GstV4l2Object * v4l2object, GstCaps * caps); gboolean gst_v4l2_object_caps_equal (GstV4l2Object * v4l2object, GstCaps * caps);