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;
}
}
}
+ /* 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;
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");
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);
}
}
+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)
{
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);