From 3005dbc55ab03ebcf99e4fc97ba4dd48a94e5622 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Wed, 19 Jan 2022 15:53:05 -0500 Subject: [PATCH] v4l2codecs: Add support for multi planar buffers V4L2 have some pixel formats that produces 2 dmabuf, this add support for these format. Part-of: --- .../sys/v4l2codecs/gstv4l2format.c | 59 +++++++++++++++---- 1 file changed, 46 insertions(+), 13 deletions(-) diff --git a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2format.c b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2format.c index 3a6a06f451..ed3f757c0b 100644 --- a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2format.c +++ b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2format.c @@ -102,12 +102,21 @@ gst_v4l2_format_to_video_info (struct v4l2_format *fmt, GstVideoInfo * out_info) struct v4l2_pix_format *pix = &fmt->fmt.pix; gint plane; gsize offset = 0; + gboolean extrapolate = FALSE; if (!entry) return FALSE; - if (entry->num_planes != 1) { - GST_FIXME ("Multi allocation formats are not supported yet"); + /* validate the entry against the format */ + if (V4L2_TYPE_IS_MULTIPLANAR (fmt->type)) { + if (entry->num_planes != pix_mp->num_planes) { + GST_ERROR ("Miss-matched number of planes in internal entry " + "(%i != %i)", entry->num_planes, pix_mp->num_planes); + return FALSE; + } + } else if (entry->num_planes != 1) { + GST_ERROR ("Miss-matched number of planes in internal entry " + "(must be 1 for non-multiplanar, got %i)", entry->num_planes); return FALSE; } @@ -116,28 +125,52 @@ gst_v4l2_format_to_video_info (struct v4l2_format *fmt, GstVideoInfo * out_info) return FALSE; if (V4L2_TYPE_IS_MULTIPLANAR (fmt->type)) { - /* TODO: We don't support multi-allocation yet */ - g_return_val_if_fail (pix_mp->num_planes == 1, FALSE); - out_info->size = pix_mp->plane_fmt[0].sizeimage; + out_info->size = 0; + for (plane = 0; plane < pix_mp->num_planes; plane++) + out_info->size += pix_mp->plane_fmt[plane].sizeimage; } else { out_info->size = pix->sizeimage; } + /* + * When single allocation formats are used for planar formats we need to + * extrapolate the per-plane stride. Do this check once to prevent + * complex inner loop. + */ + if (entry->num_planes == 1 && out_info->finfo->n_planes != entry->num_planes) + extrapolate = TRUE; + for (plane = 0; plane < GST_VIDEO_INFO_N_PLANES (out_info); plane++) { gint stride; - if (V4L2_TYPE_IS_MULTIPLANAR (fmt->type)) - stride = gst_video_format_info_extrapolate_stride (out_info->finfo, plane, - pix_mp->plane_fmt[0].bytesperline); - else - stride = gst_video_format_info_extrapolate_stride (out_info->finfo, plane, - pix->bytesperline); + if (V4L2_TYPE_IS_MULTIPLANAR (fmt->type)) { + if (extrapolate) + stride = gst_video_format_info_extrapolate_stride (out_info->finfo, + plane, pix_mp->plane_fmt[0].bytesperline); + else + stride = pix_mp->plane_fmt[plane].bytesperline; + } else { + if (extrapolate) + stride = gst_video_format_info_extrapolate_stride (out_info->finfo, + plane, pix->bytesperline); + else + stride = pix->bytesperline; + } set_stride (out_info, plane, stride); out_info->offset[plane] = offset; - offset += stride * GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (out_info->finfo, - plane, pix_mp->height); + if ((V4L2_TYPE_IS_MULTIPLANAR (fmt->type) && !extrapolate)) + offset += pix_mp->plane_fmt[plane].sizeimage; + else + offset += stride * GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (out_info->finfo, + plane, pix_mp->height); + } + + /* Check that the extrapolation didn't overflow the reported sizeimage */ + if (extrapolate && offset > out_info->size) { + GST_ERROR ("Extrapolated plane offset overflow the image size."); + return FALSE; } return TRUE;