mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-26 00:58:12 +00:00
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
This commit is contained in:
parent
ac3cb8817e
commit
600027a1ee
4 changed files with 60 additions and 19 deletions
|
@ -1143,32 +1143,34 @@ gst_v4l2_allocator_import_userptr (GstV4l2Allocator * allocator,
|
||||||
g_return_val_if_fail (allocator->memory == V4L2_MEMORY_USERPTR, FALSE);
|
g_return_val_if_fail (allocator->memory == V4L2_MEMORY_USERPTR, FALSE);
|
||||||
|
|
||||||
/* TODO Support passing N plane from 1 memory to MPLANE v4l2 format */
|
/* 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;
|
goto n_mem_missmatch;
|
||||||
|
|
||||||
for (i = 0; i < group->n_mem; i++) {
|
for (i = 0; i < group->n_mem; i++) {
|
||||||
gsize maxsize;
|
gsize maxsize, psize;
|
||||||
|
|
||||||
if (V4L2_TYPE_IS_MULTIPLANAR (allocator->type)) {
|
if (V4L2_TYPE_IS_MULTIPLANAR (allocator->type)) {
|
||||||
struct v4l2_pix_format_mplane *pix = &allocator->format.fmt.pix_mp;
|
struct v4l2_pix_format_mplane *pix = &allocator->format.fmt.pix_mp;
|
||||||
maxsize = pix->plane_fmt[i].sizeimage;
|
maxsize = pix->plane_fmt[i].sizeimage;
|
||||||
|
psize = size[i];
|
||||||
} else {
|
} else {
|
||||||
maxsize = allocator->format.fmt.pix.sizeimage;
|
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 %"
|
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 = (GstV4l2Memory *) group->mem[i];
|
||||||
|
|
||||||
mem->mem.maxsize = maxsize;
|
mem->mem.maxsize = maxsize;
|
||||||
mem->mem.size = size[i];
|
mem->mem.size = psize;
|
||||||
mem->data = data[i];
|
mem->data = data[i];
|
||||||
|
|
||||||
group->planes[i].length = maxsize;
|
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].m.userptr = (unsigned long) data[i];
|
||||||
group->planes[i].data_offset = 0;
|
group->planes[i].data_offset = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
if (!gst_v4l2_allocator_import_userptr (pool->vallocator, group,
|
||||||
data->frame.info.size, finfo->n_planes, data->frame.data, size))
|
data->frame.info.size, finfo->n_planes, data->frame.data, size))
|
||||||
goto import_failed;
|
goto import_failed;
|
||||||
|
@ -284,6 +303,12 @@ invalid_buffer:
|
||||||
g_slice_free (struct UserPtrData, data);
|
g_slice_free (struct UserPtrData, data);
|
||||||
return GST_FLOW_ERROR;
|
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:
|
import_failed:
|
||||||
{
|
{
|
||||||
GST_ERROR_OBJECT (pool, "failed to import data");
|
GST_ERROR_OBJECT (pool, "failed to import data");
|
||||||
|
|
|
@ -2413,19 +2413,7 @@ gst_v4l2_object_extrapolate_info (GstV4l2Object * v4l2object,
|
||||||
padded_height = info->height + align->padding_top + align->padding_bottom;
|
padded_height = info->height + align->padding_top + align->padding_bottom;
|
||||||
|
|
||||||
for (i = 0; i < finfo->n_planes; i++) {
|
for (i = 0; i < finfo->n_planes; i++) {
|
||||||
switch (finfo->format) {
|
estride = gst_v4l2_object_extrapolate_stride (finfo, i, stride);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
gst_v4l2_object_set_stride (info, align, i, estride);
|
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
|
gboolean
|
||||||
gst_v4l2_object_set_format (GstV4l2Object * v4l2object, GstCaps * caps)
|
gst_v4l2_object_set_format (GstV4l2Object * v4l2object, GstCaps * caps)
|
||||||
{
|
{
|
||||||
|
|
|
@ -247,6 +247,9 @@ GstCaps* gst_v4l2_object_get_raw_caps (void);
|
||||||
|
|
||||||
GstCaps* gst_v4l2_object_get_codec_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_set_format (GstV4l2Object * v4l2object, GstCaps * caps);
|
||||||
|
|
||||||
gboolean gst_v4l2_object_caps_equal (GstV4l2Object * v4l2object, GstCaps * caps);
|
gboolean gst_v4l2_object_caps_equal (GstV4l2Object * v4l2object, GstCaps * caps);
|
||||||
|
|
Loading…
Reference in a new issue