From 77744c3d638847367545a6df96b48154ddd72235 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Thu, 22 Aug 2024 16:08:03 -0400 Subject: [PATCH] v4l2: Add support for setting memory:DMABuf caps This is the final step to allow negotiation of this caps features. Limiting the features based on the io-mode shall come next. Part-of: --- .../sys/v4l2/gstv4l2bufferpool.c | 12 +- .../gst-plugins-good/sys/v4l2/gstv4l2object.c | 316 +++++++++++------- .../gst-plugins-good/sys/v4l2/gstv4l2object.h | 19 +- .../gst-plugins-good/sys/v4l2/gstv4l2src.c | 10 +- .../sys/v4l2/gstv4l2transform.c | 50 ++- .../sys/v4l2/gstv4l2videodec.c | 73 ++-- .../sys/v4l2/gstv4l2videoenc.c | 4 +- 7 files changed, 306 insertions(+), 178 deletions(-) diff --git a/subprojects/gst-plugins-good/sys/v4l2/gstv4l2bufferpool.c b/subprojects/gst-plugins-good/sys/v4l2/gstv4l2bufferpool.c index f422ce7a47..98c7dbe084 100644 --- a/subprojects/gst-plugins-good/sys/v4l2/gstv4l2bufferpool.c +++ b/subprojects/gst-plugins-good/sys/v4l2/gstv4l2bufferpool.c @@ -449,7 +449,7 @@ gst_v4l2_buffer_pool_alloc_buffer (GstBufferPool * bpool, GstBuffer ** buffer, GstVideoInfo *info; obj = pool->obj; - info = &obj->info; + info = &obj->info.vinfo; switch (obj->mode) { case GST_V4L2_IO_RW: @@ -622,8 +622,8 @@ gst_v4l2_buffer_pool_set_config (GstBufferPool * bpool, GstStructure * config) } /* Always update the config to ensure the configured size matches */ - gst_buffer_pool_config_set_params (config, caps, obj->info.size, min_buffers, - max_buffers); + gst_buffer_pool_config_set_params (config, caps, obj->info.vinfo.size, + min_buffers, max_buffers); /* keep a GstVideoInfo with defaults for the when we need to copy */ gst_video_info_from_caps (&pool->caps_info, caps); @@ -1244,7 +1244,7 @@ gst_v4l2_buffer_pool_dqbuf (GstV4l2BufferPool * pool, GstBuffer ** buffer, GstV4l2Object *obj = pool->obj; GstClockTime timestamp; GstV4l2MemoryGroup *group; - const GstVideoInfo *info = &obj->info; + const GstVideoInfo *info = &obj->info.vinfo; gint i; gint old_buffer_state; @@ -1797,7 +1797,7 @@ gst_v4l2_buffer_pool_new (GstV4l2Object * obj, GstCaps * caps) gst_object_ref (obj->element); config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool)); - gst_buffer_pool_config_set_params (config, caps, obj->info.size, 0, 0); + gst_buffer_pool_config_set_params (config, caps, obj->info.vinfo.size, 0, 0); /* This will simply set a default config, but will not configure the pool * because min and max are not valid */ gst_buffer_pool_set_config (GST_BUFFER_POOL_CAST (pool), config); @@ -1827,7 +1827,7 @@ gst_v4l2_do_read (GstV4l2BufferPool * pool, GstBuffer * buf) GstMapInfo map; gint toread; - toread = obj->info.size; + toread = obj->info.vinfo.size; GST_LOG_OBJECT (pool, "reading %d bytes into buffer %p", toread, buf); diff --git a/subprojects/gst-plugins-good/sys/v4l2/gstv4l2object.c b/subprojects/gst-plugins-good/sys/v4l2/gstv4l2object.c index 0b439aedde..4730df42ba 100644 --- a/subprojects/gst-plugins-good/sys/v4l2/gstv4l2object.c +++ b/subprojects/gst-plugins-good/sys/v4l2/gstv4l2object.c @@ -1443,6 +1443,31 @@ gst_v4l2_object_get_desc_from_video_format (GstVideoFormat format, return ret; } +static const GstV4L2FormatDesc * +gst_v4l2_object_get_desc_from_drm_fourcc (guint32 drm_fourcc, + guint64 drm_modifier, const GstV4L2FormatDesc ** fallback) +{ + const GstV4L2FormatDesc *ret = NULL; + gint i; + + if (fallback) + *fallback = NULL; + + for (i = 0; i < GST_V4L2_FORMAT_COUNT; i++) { + if (gst_v4l2_formats[i].drm_fourcc == drm_fourcc + && gst_v4l2_formats[i].drm_modifier == drm_modifier) { + if (!ret) + ret = &gst_v4l2_formats[i]; + else if (fallback && !*fallback) + *fallback = &gst_v4l2_formats[i]; + else + break; + } + } + + return ret; +} + static gboolean gst_v4l2_object_v4l2fourcc_is_codec (guint32 fourcc) { @@ -1642,7 +1667,8 @@ gst_v4l2_object_is_raw (GstV4l2Object * v4l2object) { gint i; - if (GST_VIDEO_INFO_FORMAT (&v4l2object->info) != GST_VIDEO_FORMAT_ENCODED) + if (GST_VIDEO_INFO_FORMAT (&v4l2object->info.vinfo) != + GST_VIDEO_FORMAT_ENCODED) return TRUE; for (i = 0; i < GST_V4L2_FORMAT_COUNT; i++) { @@ -1876,6 +1902,8 @@ gst_v4l2_object_probe_template_caps (const gchar * device, gint video_fd, } /* collect data for the given caps + * @v4l2object: the associated GstV4l2Object + * @info: the format information as GstVideoInfoDmaDrm * @caps: given input caps * @format: location for the v4l format * @w/@h: location for width and height @@ -1884,7 +1912,7 @@ gst_v4l2_object_probe_template_caps (const gchar * device, gint video_fd, */ static gboolean gst_v4l2_object_get_caps_info (GstV4l2Object * v4l2object, GstCaps * caps, - struct v4l2_fmtdesc **format, GstVideoInfo * info) + struct v4l2_fmtdesc **format, GstVideoInfoDmaDrm * info) { GstStructure *structure; guint32 fourcc = 0, fourcc_nc = 0; @@ -1895,13 +1923,27 @@ gst_v4l2_object_get_caps_info (GstV4l2Object * v4l2object, GstCaps * caps, mimetype = gst_structure_get_name (structure); - if (!gst_video_info_from_caps (info, caps)) + if (!gst_video_info_dma_drm_from_caps (info, caps) && + !gst_video_info_from_caps (&info->vinfo, caps)) goto invalid_format; if (g_str_equal (mimetype, "video/x-raw")) { - const GstV4L2FormatDesc *desc, *fallback_desc; - GstVideoFormat format = GST_VIDEO_INFO_FORMAT (info); - desc = gst_v4l2_object_get_desc_from_video_format (format, &fallback_desc); + const GstV4L2FormatDesc *desc, *fallback_desc = NULL; + GstVideoFormat format = GST_VIDEO_INFO_FORMAT (&info->vinfo); + if (format == GST_VIDEO_FORMAT_DMA_DRM) { + const GstStructure *s = gst_caps_get_structure (caps, 0); + guint64 drm_modifier; + guint32 drm_fourcc = + gst_video_dma_drm_fourcc_from_string (gst_structure_get_string (s, + "drm-format"), &drm_modifier); + /* we can't support single plane fallback with opaque DRM fourcc since we + * don't know how to extrapolate the missing strides and offsets. */ + desc = gst_v4l2_object_get_desc_from_drm_fourcc (drm_fourcc, drm_modifier, + NULL); + } else { + desc = + gst_v4l2_object_get_desc_from_video_format (format, &fallback_desc); + } if (desc) fourcc_nc = desc->v4l2_format; if (fallback_desc) @@ -3149,11 +3191,12 @@ default_frame_sizes: if (!v4l2object->skip_try_fmt_probes) { gint probed_w, probed_h; - if (v4l2object->info.width >= min_w && v4l2object->info.width <= max_w && - v4l2object->info.height >= min_h - && v4l2object->info.height <= max_h) { - probed_w = v4l2object->info.width; - probed_h = v4l2object->info.height; + if (v4l2object->info.vinfo.width >= min_w && + v4l2object->info.vinfo.width <= max_w && + v4l2object->info.vinfo.height >= min_h + && v4l2object->info.vinfo.height <= max_h) { + probed_w = v4l2object->info.vinfo.width; + probed_h = v4l2object->info.vinfo.height; } else { probed_w = max_w; probed_h = max_h; @@ -3430,15 +3473,15 @@ gst_v4l2_object_extrapolate_info (GstV4l2Object * v4l2object, static void gst_v4l2_object_save_format (GstV4l2Object * v4l2object, struct v4l2_fmtdesc *fmtdesc, struct v4l2_format *format, - GstVideoInfo * info, GstVideoAlignment * align) + GstVideoInfoDmaDrm * info, GstVideoAlignment * align) { - const GstVideoFormatInfo *finfo = info->finfo; + const GstVideoFormatInfo *finfo = info->vinfo.finfo; gboolean standard_stride = TRUE; gint stride, pstride, padded_width, padded_height, i; - if (GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_FORMAT_ENCODED) { + if (GST_VIDEO_INFO_FORMAT (&info->vinfo) == GST_VIDEO_FORMAT_ENCODED) { v4l2object->n_v4l2_planes = 1; - info->size = format->fmt.pix.sizeimage; + info->vinfo.size = format->fmt.pix.sizeimage; goto store_info; } @@ -3455,7 +3498,7 @@ gst_v4l2_object_save_format (GstV4l2Object * v4l2object, /* pstride can be 0 for complex formats */ GST_WARNING_OBJECT (v4l2object->dbg_obj, "format %s has a pstride of 0, cannot compute padded with", - gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (info))); + gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (&info->vinfo))); padded_width = format->fmt.pix.width; } @@ -3464,7 +3507,7 @@ gst_v4l2_object_save_format (GstV4l2Object * v4l2object, "Driver bug detected, stride (%d) is too small for the width (%d)", padded_width, format->fmt.pix.width); - align->padding_right = padded_width - info->width - align->padding_left; + align->padding_right = padded_width - info->vinfo.width - align->padding_left; /* adjust bottom padding */ padded_height = format->fmt.pix.height; @@ -3477,8 +3520,8 @@ gst_v4l2_object_save_format (GstV4l2Object * v4l2object, (padded_height + tile_height - 1) / tile_height * tile_height; } - align->padding_bottom = - padded_height - GST_VIDEO_INFO_FIELD_HEIGHT (info) - align->padding_top; + align->padding_bottom = padded_height - + GST_VIDEO_INFO_FIELD_HEIGHT (&info->vinfo) - align->padding_top; /* setup the strides and offset */ if (V4L2_TYPE_IS_MULTIPLANAR (v4l2object->type)) { @@ -3486,33 +3529,40 @@ gst_v4l2_object_save_format (GstV4l2Object * v4l2object, /* figure out the frame layout */ v4l2object->n_v4l2_planes = MAX (1, pix_mp->num_planes); - info->size = 0; + info->vinfo.size = 0; for (i = 0; i < v4l2object->n_v4l2_planes; i++) { stride = pix_mp->plane_fmt[i].bytesperline; - if (info->stride[i] != stride) + if (info->vinfo.stride[i] != stride) standard_stride = FALSE; - gst_v4l2_object_set_stride (info, align, i, stride); - info->offset[i] = info->size; - info->size += pix_mp->plane_fmt[i].sizeimage; + gst_v4l2_object_set_stride (&info->vinfo, align, i, stride); + info->vinfo.offset[i] = info->vinfo.size; + info->vinfo.size += pix_mp->plane_fmt[i].sizeimage; } /* Extrapolate stride if planar format are being set in 1 v4l2 plane */ if (v4l2object->n_v4l2_planes < finfo->n_planes) { + /* We should never negotiate single plane variant of formats unless the + * formats is mapped into libgstvideo, otherwise we don't know how to + * guess the missing strides and offsets. If you hit this assertion, + * please remove the mapping from V4L2 to DRM formats. */ + g_assert (GST_VIDEO_INFO_FORMAT (&info->vinfo) != + GST_VIDEO_FORMAT_UNKNOWN); stride = format->fmt.pix_mp.plane_fmt[0].bytesperline; - gst_v4l2_object_extrapolate_info (v4l2object, info, align, stride); + gst_v4l2_object_extrapolate_info (v4l2object, &info->vinfo, align, + stride); } } else { /* only one plane in non-MPLANE mode */ v4l2object->n_v4l2_planes = 1; - info->size = format->fmt.pix.sizeimage; + info->vinfo.size = format->fmt.pix.sizeimage; stride = format->fmt.pix.bytesperline; - if (info->stride[0] != stride) + if (info->vinfo.stride[0] != stride) standard_stride = FALSE; - gst_v4l2_object_extrapolate_info (v4l2object, info, align, stride); + gst_v4l2_object_extrapolate_info (v4l2object, &info->vinfo, align, stride); } /* adjust the offset to take into account left and top */ @@ -3522,14 +3572,15 @@ gst_v4l2_object_save_format (GstV4l2Object * v4l2object, "Left and top padding is not permitted for tiled formats"); memset (v4l2object->plane_size, 0, sizeof (v4l2object->plane_size)); } else { - if (!gst_video_info_align_full (info, align, v4l2object->plane_size)) { + if (!gst_video_info_align_full (&info->vinfo, align, + v4l2object->plane_size)) { GST_WARNING_OBJECT (v4l2object->dbg_obj, "Failed to align video info"); } } store_info: GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Got sizeimage %" G_GSIZE_FORMAT, - info->size); + info->vinfo.size); /* to avoid copies we need video meta if there is padding */ v4l2object->need_video_meta = @@ -3550,10 +3601,10 @@ store_info: v4l2object->fmtdesc = fmtdesc; /* if we have a framerate pre-calculate duration */ - if (info->fps_n > 0 && info->fps_d > 0) { - v4l2object->duration = gst_util_uint64_scale_int (GST_SECOND, info->fps_d, - info->fps_n); - if (GST_VIDEO_INFO_INTERLACE_MODE (info) == + if (info->vinfo.fps_n > 0 && info->vinfo.fps_d > 0) { + v4l2object->duration = gst_util_uint64_scale_int (GST_SECOND, + info->vinfo.fps_d, info->vinfo.fps_n); + if (GST_VIDEO_INFO_INTERLACE_MODE (&info->vinfo) == GST_VIDEO_INTERLACE_MODE_ALTERNATE) v4l2object->duration /= 2; } else { @@ -3696,7 +3747,7 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps, enum v4l2_field field; guint32 pixelformat; struct v4l2_fmtdesc *fmtdesc; - GstVideoInfo info; + GstVideoInfoDmaDrm info; GstVideoAlignment align; gint width, height, fps_n, fps_d; guint pixel_bitdepth = 8; @@ -3720,7 +3771,7 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps, is_mplane = V4L2_TYPE_IS_MULTIPLANAR (v4l2object->type); - gst_video_info_init (&info); + gst_video_info_dma_drm_init (&info); gst_video_alignment_reset (&align); v4l2object->transfer = GST_VIDEO_TRANSFER_UNKNOWN; v4l2object->matrix = GST_VIDEO_COLOR_MATRIX_UNKNOWN; @@ -3729,35 +3780,43 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps, goto invalid_caps; pixelformat = fmtdesc->pixelformat; - width = GST_VIDEO_INFO_WIDTH (&info); - height = GST_VIDEO_INFO_FIELD_HEIGHT (&info); + width = GST_VIDEO_INFO_WIDTH (&info.vinfo); + height = GST_VIDEO_INFO_FIELD_HEIGHT (&info.vinfo); /* if caps has no width and height info, use default value */ if (V4L2_TYPE_IS_OUTPUT (v4l2object->type) && width == 0 && height == 0) { width = GST_V4L2_DEFAULT_WIDTH; height = GST_V4L2_DEFAULT_HEIGHT; } - fps_n = GST_VIDEO_INFO_FPS_N (&info); - fps_d = GST_VIDEO_INFO_FPS_D (&info); + fps_n = GST_VIDEO_INFO_FPS_N (&info.vinfo); + fps_d = GST_VIDEO_INFO_FPS_D (&info.vinfo); - /* if encoded format (GST_VIDEO_INFO_N_PLANES return 0) - * or if contiguous is preferred */ - n_v4l_planes = GST_VIDEO_INFO_N_PLANES (&info); - if (!n_v4l_planes || !v4l2object->prefered_non_contiguous) + n_v4l_planes = GST_VIDEO_INFO_N_PLANES (&info.vinfo); + if (!n_v4l_planes) { + /* For opaque DRM format we let the driver tell us how many planes + * otherwise its an encoded format and we will have 1 plane */ + if (GST_VIDEO_INFO_FORMAT (&info.vinfo) == GST_VIDEO_FORMAT_DMA_DRM) + n_v4l_planes = GST_VIDEO_MAX_PLANES; + else + n_v4l_planes = 1; + } + + /* If our preference is single plane, then set te number of plane to 1 */ + if (!v4l2object->prefered_non_contiguous) n_v4l_planes = 1; - field = get_v4l2_field_for_info (&info); + field = get_v4l2_field_for_info (&info.vinfo); if (field != V4L2_FIELD_NONE) GST_DEBUG_OBJECT (v4l2object->dbg_obj, "interlaced video"); else GST_DEBUG_OBJECT (v4l2object->dbg_obj, "progressive video"); /* We first pick the main colorspace from the primaries */ - switch (info.colorimetry.primaries) { + switch (info.vinfo.colorimetry.primaries) { case GST_VIDEO_COLOR_PRIMARIES_BT709: /* There is three colorspaces using these primaries, use the range * and format type to differentiate them */ - if (info.colorimetry.range == GST_VIDEO_COLOR_RANGE_16_235) { - if (GST_VIDEO_INFO_IS_RGB (&info)) + if (info.vinfo.colorimetry.range == GST_VIDEO_COLOR_RANGE_16_235) { + if (GST_VIDEO_INFO_IS_RGB (&info.vinfo)) colorspace = V4L2_COLORSPACE_SRGB; else colorspace = V4L2_COLORSPACE_REC709; @@ -3788,11 +3847,11 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps, default: GST_WARNING_OBJECT (v4l2object->dbg_obj, - "Unknown colorimetry primaries %d", info.colorimetry.primaries); + "Unknown colorimetry primaries %d", info.vinfo.colorimetry.primaries); break; } - switch (info.colorimetry.range) { + switch (info.vinfo.colorimetry.range) { case GST_VIDEO_COLOR_RANGE_0_255: range = V4L2_QUANTIZATION_FULL_RANGE; break; @@ -3804,11 +3863,11 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps, break; default: GST_WARNING_OBJECT (v4l2object->dbg_obj, - "Unknown colorimetry range %d", info.colorimetry.range); + "Unknown colorimetry range %d", info.vinfo.colorimetry.range); break; } - switch (info.colorimetry.matrix) { + switch (info.vinfo.colorimetry.matrix) { case GST_VIDEO_COLOR_MATRIX_RGB: /* save the matrix so we can restore it on get() call from default */ v4l2object->matrix = GST_VIDEO_COLOR_MATRIX_RGB; @@ -3833,11 +3892,11 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps, break; default: GST_WARNING_OBJECT (v4l2object->dbg_obj, - "Unknown colorimetry matrix %d", info.colorimetry.matrix); + "Unknown colorimetry matrix %d", info.vinfo.colorimetry.matrix); break; } - switch (info.colorimetry.transfer) { + switch (info.vinfo.colorimetry.transfer) { case GST_VIDEO_TRANSFER_GAMMA18: case GST_VIDEO_TRANSFER_GAMMA20: case GST_VIDEO_TRANSFER_GAMMA22: @@ -3855,7 +3914,7 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps, case GST_VIDEO_TRANSFER_BT2020_12: case GST_VIDEO_TRANSFER_BT2020_10: case GST_VIDEO_TRANSFER_BT709: - v4l2object->transfer = info.colorimetry.transfer; + v4l2object->transfer = info.vinfo.colorimetry.transfer; transfer = V4L2_XFER_FUNC_709; break; case GST_VIDEO_TRANSFER_SMPTE240M: @@ -3875,13 +3934,13 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps, break; default: GST_WARNING_OBJECT (v4l2object->dbg_obj, - "Unknown colorimetry transfer %d", info.colorimetry.transfer); + "Unknown colorimetry transfer %d", info.vinfo.colorimetry.transfer); break; } if (colorspace == 0) { /* Try to guess colorspace according to pixelformat and size */ - if (GST_VIDEO_INFO_IS_YUV (&info)) { + if (GST_VIDEO_INFO_IS_YUV (&info.vinfo)) { if (range == V4L2_QUANTIZATION_FULL_RANGE && matrix == V4L2_YCBCR_ENC_601 && transfer == 0) { /* Full range BT.601 YCbCr encoding with unknown primaries and transfer @@ -3890,12 +3949,12 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps, transfer = V4L2_XFER_FUNC_SRGB; } else { /* SD streams likely use SMPTE170M and HD streams REC709 */ - if (width <= 720 && GST_VIDEO_INFO_HEIGHT (&info) <= 576) + if (width <= 720 && GST_VIDEO_INFO_HEIGHT (&info.vinfo) <= 576) colorspace = V4L2_COLORSPACE_SMPTE170M; else colorspace = V4L2_COLORSPACE_REC709; } - } else if (GST_VIDEO_INFO_IS_RGB (&info)) { + } else if (GST_VIDEO_INFO_IS_RGB (&info.vinfo)) { colorspace = V4L2_COLORSPACE_SRGB; transfer = V4L2_XFER_FUNC_NONE; } @@ -3903,7 +3962,8 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps, GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Desired format %dx%d, format " "%" GST_FOURCC_FORMAT " stride: %d", width, height, - GST_FOURCC_ARGS (pixelformat), GST_VIDEO_INFO_PLANE_STRIDE (&info, 0)); + GST_FOURCC_ARGS (pixelformat), + GST_VIDEO_INFO_PLANE_STRIDE (&info.vinfo, 0)); s = gst_caps_get_structure (caps, 0); @@ -3927,20 +3987,20 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps, /* try to ask our preferred stride but it's not a failure if not * accepted */ for (i = 0; i < n_v4l_planes; i++) { - gint stride = GST_VIDEO_INFO_PLANE_STRIDE (&info, i); + gint stride = GST_VIDEO_INFO_PLANE_STRIDE (&info.vinfo, i); - if (GST_VIDEO_FORMAT_INFO_IS_TILED (info.finfo)) + if (GST_VIDEO_FORMAT_INFO_IS_TILED (info.vinfo.finfo)) stride = GST_VIDEO_TILE_X_TILES (stride) * - GST_VIDEO_FORMAT_INFO_TILE_STRIDE (info.finfo, i); + GST_VIDEO_FORMAT_INFO_TILE_STRIDE (info.vinfo.finfo, i); format.fmt.pix_mp.plane_fmt[i].bytesperline = stride; } - if (GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_ENCODED) + if (GST_VIDEO_INFO_FORMAT (&info.vinfo) == GST_VIDEO_FORMAT_ENCODED) format.fmt.pix_mp.plane_fmt[0].sizeimage = calculate_max_sizeimage (v4l2object, pixel_bitdepth); } else { - gint stride = GST_VIDEO_INFO_PLANE_STRIDE (&info, 0); + gint stride = GST_VIDEO_INFO_PLANE_STRIDE (&info.vinfo, 0); format.type = v4l2object->type; @@ -3949,14 +4009,14 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps, format.fmt.pix.pixelformat = pixelformat; format.fmt.pix.field = field; - if (GST_VIDEO_FORMAT_INFO_IS_TILED (info.finfo)) + if (GST_VIDEO_FORMAT_INFO_IS_TILED (info.vinfo.finfo)) stride = GST_VIDEO_TILE_X_TILES (stride) * - GST_VIDEO_FORMAT_INFO_TILE_STRIDE (info.finfo, i); + GST_VIDEO_FORMAT_INFO_TILE_STRIDE (info.vinfo.finfo, i); /* try to ask our preferred stride */ format.fmt.pix.bytesperline = stride; - if (GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_ENCODED) + if (GST_VIDEO_INFO_FORMAT (&info.vinfo) == GST_VIDEO_FORMAT_ENCODED) format.fmt.pix.sizeimage = calculate_max_sizeimage (v4l2object, pixel_bitdepth); } @@ -4139,7 +4199,7 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps, * For some codecs the dimensions are *not* in the bitstream, IIRC VC1 * in ASF mode for example, there is also not reason for a driver to * change the size. */ - if (info.finfo->format != GST_VIDEO_FORMAT_ENCODED) { + if (GST_VIDEO_INFO_FORMAT (&info.vinfo) != GST_VIDEO_FORMAT_ENCODED) { /* We can crop larger images */ if (format.fmt.pix.width < width || format.fmt.pix.height < height) goto invalid_dimensions; @@ -4156,7 +4216,7 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps, /* used to check colorimetry and interlace mode fields presence */ if (gst_v4l2_object_get_interlace_mode (format.fmt.pix.field, - &info.interlace_mode)) { + &info.vinfo.interlace_mode)) { if (gst_structure_has_field (s, "interlace-mode")) { if (format.fmt.pix.field != field) goto invalid_field; @@ -4169,9 +4229,10 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps, gst_structure_remove_field (s, "interlace-mode"); } - if (gst_v4l2_object_get_colorspace (v4l2object, &format, &info.colorimetry)) { + if (gst_v4l2_object_get_colorspace (v4l2object, &format, + &info.vinfo.colorimetry)) { if (gst_structure_has_field (s, "colorimetry")) { - if (!gst_v4l2_video_colorimetry_matches (&info.colorimetry, caps)) + if (!gst_v4l2_video_colorimetry_matches (&info.vinfo.colorimetry, caps)) goto invalid_colorimetry; } } else { @@ -4187,10 +4248,10 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps, if (v4l2object->skip_try_fmt_probes) { if (!disable_interlacing && !gst_structure_has_field (s, "interlace-mode")) { gst_structure_set (s, "interlace-mode", G_TYPE_STRING, - gst_video_interlace_mode_to_string (info.interlace_mode), NULL); + gst_video_interlace_mode_to_string (info.vinfo.interlace_mode), NULL); } if (!disable_colorimetry && !gst_structure_has_field (s, "colorimetry")) { - gchar *str = gst_video_colorimetry_to_string (&info.colorimetry); + gchar *str = gst_video_colorimetry_to_string (&info.vinfo.colorimetry); gst_structure_set (s, "colorimetry", G_TYPE_STRING, str, NULL); g_free (str); } @@ -4281,7 +4342,7 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps, if (try_only) /* good enough for trying only */ return TRUE; - if (GST_VIDEO_INFO_HAS_ALPHA (&info)) { + if (GST_VIDEO_INFO_HAS_ALPHA (&info.vinfo)) { struct v4l2_control ctl = { 0, }; ctl.id = V4L2_CID_ALPHA_COMPONENT; ctl.value = 0xff; @@ -4303,9 +4364,9 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps, if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE || v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - GST_VIDEO_INFO_FPS_N (&info) = + GST_VIDEO_INFO_FPS_N (&info.vinfo) = streamparm.parm.capture.timeperframe.denominator; - GST_VIDEO_INFO_FPS_D (&info) = + GST_VIDEO_INFO_FPS_D (&info.vinfo) = streamparm.parm.capture.timeperframe.numerator; GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Got capture framerate: %u/%u", @@ -4374,13 +4435,13 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps, "Reuse caps framerate %u/%u - fix v4l2 capture driver", fps_n, fps_d); } - GST_VIDEO_INFO_FPS_N (&info) = fps_n; - GST_VIDEO_INFO_FPS_D (&info) = fps_d; + GST_VIDEO_INFO_FPS_N (&info.vinfo) = fps_n; + GST_VIDEO_INFO_FPS_D (&info.vinfo) = fps_d; } else if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_OUTPUT || v4l2object->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - GST_VIDEO_INFO_FPS_N (&info) = + GST_VIDEO_INFO_FPS_N (&info.vinfo) = streamparm.parm.output.timeperframe.denominator; - GST_VIDEO_INFO_FPS_D (&info) = + GST_VIDEO_INFO_FPS_D (&info.vinfo) = streamparm.parm.output.timeperframe.numerator; GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Got output framerate: %u/%u", @@ -4426,8 +4487,8 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps, "Reuse caps framerate %u/%u - fix v4l2 output driver", fps_n, fps_d); } - GST_VIDEO_INFO_FPS_N (&info) = fps_n; - GST_VIDEO_INFO_FPS_D (&info) = fps_d; + GST_VIDEO_INFO_FPS_N (&info.vinfo) = fps_n; + GST_VIDEO_INFO_FPS_D (&info.vinfo) = fps_d; } done: @@ -4544,7 +4605,8 @@ invalid_colorimetry: { gchar *wanted_colorimetry; - wanted_colorimetry = gst_video_colorimetry_to_string (&info.colorimetry); + wanted_colorimetry = + gst_video_colorimetry_to_string (&info.vinfo.colorimetry); GST_V4L2_ERROR (error, RESOURCE, SETTINGS, (_("Device '%s' does not support %s colorimetry"), @@ -4607,7 +4669,8 @@ gst_v4l2_object_try_format (GstV4l2Object * v4l2object, GstCaps * caps, * Returns: %TRUE on success, %FALSE on failure. */ gboolean -gst_v4l2_object_acquire_format (GstV4l2Object * v4l2object, GstVideoInfo * info) +gst_v4l2_object_acquire_format (GstV4l2Object * v4l2object, + GstVideoInfoDmaDrm * info) { struct v4l2_fmtdesc *fmtdesc; struct v4l2_format fmt; @@ -4618,8 +4681,9 @@ gst_v4l2_object_acquire_format (GstV4l2Object * v4l2object, GstVideoInfo * info) guint width, height; GstVideoAlignment align; GstVideoInterlaceMode interlace_mode; + const GstV4L2FormatDesc *desc; - gst_video_info_init (info); + gst_video_info_dma_drm_init (info); gst_video_alignment_reset (&align); v4l2object->transfer = GST_VIDEO_TRANSFER_UNKNOWN; v4l2object->matrix = GST_VIDEO_COLOR_MATRIX_UNKNOWN; @@ -4635,12 +4699,18 @@ gst_v4l2_object_acquire_format (GstV4l2Object * v4l2object, GstVideoInfo * info) goto unsupported_format; /* No need to care about mplane, the four first params are the same */ - format = gst_v4l2_object_v4l2fourcc_to_video_format (fmt.fmt.pix.pixelformat); - - /* fails if we do no translate the fmt.pix.pixelformat to GstVideoFormat */ - if (format == GST_VIDEO_FORMAT_UNKNOWN) + desc = gst_v4l2_object_get_desc_from_v4l2fourcc (fmt.fmt.pix.pixelformat); + if (!desc) goto unsupported_format; + if (desc->gst_format == GST_VIDEO_FORMAT_UNKNOWN) { + if (!desc->drm_fourcc) + goto unsupported_format; + format = GST_VIDEO_FORMAT_DMA_DRM; + } else { + format = desc->gst_format; + } + if (fmt.fmt.pix.width == 0 || fmt.fmt.pix.height == 0) goto invalid_dimensions; @@ -4686,19 +4756,22 @@ gst_v4l2_object_acquire_format (GstV4l2Object * v4l2object, GstVideoInfo * info) goto unsupported_field; } - if (!gst_video_info_set_interlaced_format (info, format, interlace_mode, - width, height)) + info->drm_fourcc = desc->drm_fourcc; + info->drm_modifier = desc->drm_modifier; + + if (!gst_video_info_set_interlaced_format (&info->vinfo, format, + interlace_mode, width, height)) goto invalid_dimensions; - gst_v4l2_object_get_colorspace (v4l2object, &fmt, &info->colorimetry); - gst_v4l2_object_get_streamparm (v4l2object, info); - if ((info->fps_n == 0 && v4l2object->info.fps_d != 0) + gst_v4l2_object_get_colorspace (v4l2object, &fmt, &info->vinfo.colorimetry); + gst_v4l2_object_get_streamparm (v4l2object, &info->vinfo); + if ((info->vinfo.fps_n == 0 && GST_V4L2_FPS_D (v4l2object) != 0) && (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE || v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) { - info->fps_d = v4l2object->info.fps_d; - info->fps_n = v4l2object->info.fps_n; + info->vinfo.fps_d = GST_V4L2_FPS_D (v4l2object); + info->vinfo.fps_n = GST_V4L2_FPS_N (v4l2object); GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Set capture fps to %d/%d", - info->fps_n, info->fps_d); + info->vinfo.fps_n, info->vinfo.fps_d); } gst_v4l2_object_save_format (v4l2object, fmtdesc, &fmt, info, &align); @@ -4886,8 +4959,8 @@ gst_v4l2_object_setup_padding (GstV4l2Object * obj) rect.left = align->padding_left; rect.top = align->padding_top; - rect.width = obj->info.width; - rect.height = GST_VIDEO_INFO_FIELD_HEIGHT (&obj->info); + rect.width = GST_V4L2_WIDTH (obj); + rect.height = GST_V4L2_FIELD_HEIGHT (obj); if (V4L2_TYPE_IS_OUTPUT (obj->type)) { return gst_v4l2_object_set_crop (obj, &rect); @@ -5309,39 +5382,40 @@ gst_v4l2_object_match_buffer_layout (GstV4l2Object * obj, guint n_planes, gsize offset[GST_VIDEO_MAX_PLANES], gint stride[GST_VIDEO_MAX_PLANES], gsize buffer_size, guint padded_height) { - guint p; gboolean need_fmt_update = FALSE; + GstVideoInfo *info = &obj->info.vinfo; + guint p; - if (n_planes != GST_VIDEO_INFO_N_PLANES (&obj->info)) { + if (n_planes != GST_V4L2_N_PLANES (obj)) { GST_WARNING_OBJECT (obj->dbg_obj, "Cannot match buffers with different number planes"); return FALSE; } for (p = 0; p < n_planes; p++) { - if (stride[p] < obj->info.stride[p]) { + if (stride[p] < info->stride[p]) { GST_DEBUG_OBJECT (obj->dbg_obj, "Not matching as remote stride %i is smaller than %i on plane %u", - stride[p], obj->info.stride[p], p); + stride[p], info->stride[p], p); return FALSE; - } else if (stride[p] > obj->info.stride[p]) { + } else if (stride[p] > info->stride[p]) { GST_LOG_OBJECT (obj->dbg_obj, "Remote stride %i is higher than %i on plane %u", - stride[p], obj->info.stride[p], p); + stride[p], info->stride[p], p); need_fmt_update = TRUE; } - if (offset[p] < obj->info.offset[p]) { + if (offset[p] < info->offset[p]) { GST_DEBUG_OBJECT (obj->dbg_obj, "Not matching as offset %" G_GSIZE_FORMAT " is smaller than %" G_GSIZE_FORMAT " on plane %u", - offset[p], obj->info.offset[p], p); + offset[p], info->offset[p], p); return FALSE; - } else if (offset[p] > obj->info.offset[p]) { + } else if (offset[p] > info->offset[p]) { GST_LOG_OBJECT (obj->dbg_obj, "Remote offset %" G_GSIZE_FORMAT " is higher than %" G_GSIZE_FORMAT " on plane %u", - offset[p], obj->info.offset[p], p); + offset[p], info->offset[p], p); need_fmt_update = TRUE; } } @@ -5372,7 +5446,7 @@ gst_v4l2_object_match_buffer_layout (GstV4l2Object * obj, guint n_planes, GST_DEBUG_OBJECT (obj->dbg_obj, "Padded height %u", padded_height); obj->align.padding_bottom = - padded_height - GST_VIDEO_INFO_FIELD_HEIGHT (&obj->info); + padded_height - GST_VIDEO_INFO_FIELD_HEIGHT (info); } else { GST_WARNING_OBJECT (obj->dbg_obj, "Failed to compute padded height; keep the default one"); @@ -5388,9 +5462,9 @@ gst_v4l2_object_match_buffer_layout (GstV4l2Object * obj, guint n_planes, for (i = 0; i < obj->n_v4l2_planes; i++) { gint plane_stride = stride[i]; - if (GST_VIDEO_FORMAT_INFO_IS_TILED (obj->info.finfo)) + if (GST_VIDEO_FORMAT_INFO_IS_TILED (info->finfo)) plane_stride = GST_VIDEO_TILE_X_TILES (plane_stride) * - GST_VIDEO_FORMAT_INFO_TILE_STRIDE (obj->info.finfo, i); + GST_VIDEO_FORMAT_INFO_TILE_STRIDE (info->finfo, i); format.fmt.pix_mp.plane_fmt[i].bytesperline = plane_stride; wanted_stride[i] = plane_stride; @@ -5403,9 +5477,9 @@ gst_v4l2_object_match_buffer_layout (GstV4l2Object * obj, guint n_planes, GST_DEBUG_OBJECT (obj->dbg_obj, "Wanted stride: %i", plane_stride); - if (GST_VIDEO_FORMAT_INFO_IS_TILED (obj->info.finfo)) + if (GST_VIDEO_FORMAT_INFO_IS_TILED (info->finfo)) plane_stride = GST_VIDEO_TILE_X_TILES (plane_stride) * - GST_VIDEO_FORMAT_INFO_TILE_STRIDE (obj->info.finfo, 0); + GST_VIDEO_FORMAT_INFO_TILE_STRIDE (info->finfo, 0); format.fmt.pix.bytesperline = plane_stride; format.fmt.pix.height = padded_height; @@ -5620,13 +5694,13 @@ gst_v4l2_object_decide_allocation (GstV4l2Object * obj, GstQuery * query) /* use the bigest size, when we use our own pool we can't really do any * other size than what the hardware gives us but for downstream pools * we can try */ - size = MAX (size, obj->info.size); + size = MAX (size, GST_V4L2_SIZE (obj)); } else if (can_share_own_pool) { /* no downstream pool, use our own then */ GST_DEBUG_OBJECT (obj->dbg_obj, "read/write mode: no downstream pool, using our own"); pool = gst_object_ref (obj_pool); - size = obj->info.size; + size = GST_V4L2_SIZE (obj); pushing_from_our_pool = TRUE; } break; @@ -5642,7 +5716,7 @@ gst_v4l2_object_decide_allocation (GstV4l2Object * obj, GstQuery * query) other_pool = pool; gst_object_unref (pool); pool = gst_object_ref (obj_pool); - size = obj->info.size; + size = GST_V4L2_SIZE (obj); break; case GST_V4L2_IO_MMAP: @@ -5653,7 +5727,7 @@ gst_v4l2_object_decide_allocation (GstV4l2Object * obj, GstQuery * query) if (pool) gst_object_unref (pool); pool = gst_object_ref (obj_pool); - size = obj->info.size; + size = GST_V4L2_SIZE (obj); GST_DEBUG_OBJECT (obj->dbg_obj, "streaming mode: using our own pool %" GST_PTR_FORMAT, pool); pushing_from_our_pool = TRUE; @@ -5664,7 +5738,7 @@ gst_v4l2_object_decide_allocation (GstV4l2Object * obj, GstQuery * query) } else { GST_DEBUG_OBJECT (obj->dbg_obj, "streaming mode: no usable pool, copying to generic pool"); - size = MAX (size, obj->info.size); + size = MAX (size, GST_V4L2_SIZE (obj)); } break; case GST_V4L2_IO_AUTO: @@ -5851,7 +5925,7 @@ gst_v4l2_object_propose_allocation (GstV4l2Object * obj, GstQuery * query) GstStructure *allocation_meta = NULL; /* Set defaults allocation parameters */ - size = obj->info.size; + size = GST_V4L2_SIZE (obj); min = GST_V4L2_MIN_BUFFERS (obj); max = VIDEO_MAX_FRAME; diff --git a/subprojects/gst-plugins-good/sys/v4l2/gstv4l2object.h b/subprojects/gst-plugins-good/sys/v4l2/gstv4l2object.h index 1127139e10..4b14b7e625 100644 --- a/subprojects/gst-plugins-good/sys/v4l2/gstv4l2object.h +++ b/subprojects/gst-plugins-good/sys/v4l2/gstv4l2object.h @@ -44,7 +44,7 @@ typedef struct _GstV4l2ObjectClassHelper GstV4l2ObjectClassHelper; /* size of v4l2 buffer pool in streaming case, obj->info needs to be valid */ #define GST_V4L2_MIN_BUFFERS(obj) \ - ((GST_VIDEO_INFO_INTERLACE_MODE (&obj->info) == \ + ((GST_VIDEO_INFO_INTERLACE_MODE (&obj->info.vinfo) == \ GST_VIDEO_INTERLACE_MODE_ALTERNATE) ? \ /* 2x buffers needed with each field in its own buffer */ \ 4 : 2) @@ -82,11 +82,14 @@ typedef int ioctl_req_t; typedef gulong ioctl_req_t; #endif -#define GST_V4L2_WIDTH(o) (GST_VIDEO_INFO_WIDTH (&(o)->info)) -#define GST_V4L2_HEIGHT(o) (GST_VIDEO_INFO_HEIGHT (&(o)->info)) +#define GST_V4L2_WIDTH(o) (GST_VIDEO_INFO_WIDTH (&(o)->info.vinfo)) +#define GST_V4L2_HEIGHT(o) (GST_VIDEO_INFO_HEIGHT (&(o)->info.vinfo)) +#define GST_V4L2_FIELD_HEIGHT(o) (GST_VIDEO_INFO_FIELD_HEIGHT (&(o)->info.vinfo)) #define GST_V4L2_PIXELFORMAT(o) ((o)->fmtdesc->pixelformat) -#define GST_V4L2_FPS_N(o) (GST_VIDEO_INFO_FPS_N (&(o)->info)) -#define GST_V4L2_FPS_D(o) (GST_VIDEO_INFO_FPS_D (&(o)->info)) +#define GST_V4L2_FPS_N(o) (GST_VIDEO_INFO_FPS_N (&(o)->info.vinfo)) +#define GST_V4L2_FPS_D(o) (GST_VIDEO_INFO_FPS_D (&(o)->info.vinfo)) +#define GST_V4L2_SIZE(o) (GST_VIDEO_INFO_SIZE (&(o)->info.vinfo)) +#define GST_V4L2_N_PLANES(o) (GST_VIDEO_INFO_N_PLANES (&(o)->info.vinfo)) /* simple check whether the device is open */ #define GST_V4L2_IS_OPEN(o) ((o)->video_fd > 0) @@ -145,7 +148,7 @@ struct _GstV4l2Object { /* the current format */ struct v4l2_fmtdesc *fmtdesc; struct v4l2_format format; - GstVideoInfo info; + GstVideoInfoDmaDrm info; GstVideoAlignment align; GstVideoTransferFunction transfer; gsize plane_size[GST_VIDEO_MAX_PLANES]; @@ -229,7 +232,7 @@ struct _GstV4l2Object { * on slow USB firmwares. When this is set, gst_v4l2_set_format() will modify * the caps to reflect what was negotiated during fixation */ gboolean skip_try_fmt_probes; - + guint max_width; guint max_height; }; @@ -315,7 +318,7 @@ gboolean gst_v4l2_object_stop (GstV4l2Object * v4l2object); GstCaps * gst_v4l2_object_probe_caps (GstV4l2Object * v4l2object, GstCaps * filter); GstCaps * gst_v4l2_object_get_caps (GstV4l2Object * v4l2object, GstCaps * filter); -gboolean gst_v4l2_object_acquire_format (GstV4l2Object * v4l2object, GstVideoInfo * info); +gboolean gst_v4l2_object_acquire_format (GstV4l2Object * v4l2object, GstVideoInfoDmaDrm * info); gboolean gst_v4l2_object_setup_padding (GstV4l2Object * obj); diff --git a/subprojects/gst-plugins-good/sys/v4l2/gstv4l2src.c b/subprojects/gst-plugins-good/sys/v4l2/gstv4l2src.c index 0a65b2c7d3..cc1bbbf842 100644 --- a/subprojects/gst-plugins-good/sys/v4l2/gstv4l2src.c +++ b/subprojects/gst-plugins-good/sys/v4l2/gstv4l2src.c @@ -922,10 +922,10 @@ gst_v4l2src_decide_allocation (GstBaseSrc * bsrc, GstQuery * query) if (gst_query_get_n_allocation_pools (query)) gst_query_set_nth_allocation_pool (query, 0, pool, - src->v4l2object->info.size, 1, 0); + src->v4l2object->info.vinfo.size, 1, 0); else - gst_query_add_allocation_pool (query, pool, src->v4l2object->info.size, 1, - 0); + gst_query_add_allocation_pool (query, pool, + src->v4l2object->info.vinfo.size, 1, 0); if (pool) gst_object_unref (pool); @@ -998,7 +998,7 @@ gst_v4l2src_query (GstBaseSrc * bsrc, GstQuery * query) /* min latency is the time to capture one frame/field */ min_latency = gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n); - if (GST_VIDEO_INFO_INTERLACE_MODE (&obj->info) == + if (GST_VIDEO_INFO_INTERLACE_MODE (&obj->info.vinfo) == GST_VIDEO_INTERLACE_MODE_ALTERNATE) min_latency /= 2; @@ -1160,7 +1160,7 @@ gst_v4l2src_create (GstPushSrc * src, GstBuffer ** buf) do { ret = GST_BASE_SRC_CLASS (parent_class)->alloc (GST_BASE_SRC (src), 0, - obj->info.size, buf); + obj->info.vinfo.size, buf); if (G_UNLIKELY (ret != GST_FLOW_OK)) { if (ret == GST_V4L2_FLOW_RESOLUTION_CHANGE) { diff --git a/subprojects/gst-plugins-good/sys/v4l2/gstv4l2transform.c b/subprojects/gst-plugins-good/sys/v4l2/gstv4l2transform.c index 38805489df..97688fd299 100644 --- a/subprojects/gst-plugins-good/sys/v4l2/gstv4l2transform.c +++ b/subprojects/gst-plugins-good/sys/v4l2/gstv4l2transform.c @@ -29,6 +29,8 @@ #include #include +#include + #include "gstv4l2object.h" #include "gstv4l2transform.h" @@ -373,23 +375,45 @@ gst_v4l2_transform_caps_remove_format_info (GstCaps * caps) n = gst_caps_get_size (caps); for (i = 0; i < n; i++) { - st = gst_caps_get_structure (caps, i); + GstCapsFeatures *alt_f = NULL; + + st = gst_structure_copy (gst_caps_get_structure (caps, i)); f = gst_caps_get_features (caps, i); + alt_f = gst_caps_features_copy (f); + + /* remove all the features we support, if anything is left it means we + * cannot convert */ + if (!gst_caps_features_is_any (f)) { + gst_caps_features_remove (alt_f, GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY); + gst_caps_features_remove (alt_f, GST_CAPS_FEATURE_MEMORY_DMABUF); + gst_caps_features_remove (alt_f, GST_CAPS_FEATURE_FORMAT_INTERLACED); + } + + /* Only remove format info for the cases when we can actually convert */ + if (!gst_caps_features_is_any (f) + && (gst_caps_features_get_size (alt_f) == 0)) { + gst_structure_remove_fields (st, "format", "drm-format", "colorimetry", + "chroma-site", "width", "height", "pixel-aspect-ratio", NULL); + + /* create an alternate feature, so that we allow converting between system + * memory and dmabuf */ + if (gst_caps_features_contains (f, GST_CAPS_FEATURE_FORMAT_INTERLACED)) + gst_caps_features_add (alt_f, GST_CAPS_FEATURE_FORMAT_INTERLACED); + if (!gst_caps_features_contains (f, GST_CAPS_FEATURE_MEMORY_DMABUF)) + gst_caps_features_add (alt_f, GST_CAPS_FEATURE_MEMORY_DMABUF); + } /* If this is already expressed by the existing caps * skip this structure */ - if (i > 0 && gst_caps_is_subset_structure_full (res, st, f)) - continue; + if (!gst_caps_is_subset_structure_full (res, st, f)) + gst_caps_append_structure_full (res, gst_structure_copy (st), + gst_caps_features_copy (f)); + if (!gst_caps_is_subset_structure_full (res, st, alt_f)) + gst_caps_append_structure_full (res, gst_structure_copy (st), + gst_caps_features_copy (alt_f)); - st = gst_structure_copy (st); - /* Only remove format info for the cases when we can actually convert */ - if (!gst_caps_features_is_any (f) - && gst_caps_features_is_equal (f, - GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY)) - gst_structure_remove_fields (st, "format", "colorimetry", "chroma-site", - "width", "height", "pixel-aspect-ratio", NULL); - - gst_caps_append_structure_full (res, st, gst_caps_features_copy (f)); + gst_structure_free (st); + gst_caps_features_free (alt_f); } return res; @@ -920,7 +944,7 @@ gst_v4l2_transform_prepare_output_buffer (GstBaseTransform * trans, } gst_buffer_pool_config_set_params (config, self->incaps, - self->v4l2output->info.size, min, min); + self->v4l2output->info.vinfo.size, min, min); /* There is no reason to refuse this config */ if (!gst_buffer_pool_set_config (pool, config)) diff --git a/subprojects/gst-plugins-good/sys/v4l2/gstv4l2videodec.c b/subprojects/gst-plugins-good/sys/v4l2/gstv4l2videodec.c index 5c137cf7da..dc91c90dbf 100644 --- a/subprojects/gst-plugins-good/sys/v4l2/gstv4l2videodec.c +++ b/subprojects/gst-plugins-good/sys/v4l2/gstv4l2videodec.c @@ -364,7 +364,7 @@ gst_v4l2_video_remove_padding (GstCapsFeatures * features, { GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (user_data); GstVideoAlignment *align = &self->v4l2capture->align; - GstVideoInfo *info = &self->v4l2capture->info; + GstVideoInfo *info = &self->v4l2capture->info.vinfo; int width, height; if (!gst_structure_get_int (structure, "width", &width)) @@ -397,13 +397,14 @@ gst_v4l2_video_dec_negotiate (GstVideoDecoder * decoder) { GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder); GstV4l2Error error = GST_V4L2_ERROR_INIT; - GstVideoInfo info; + GstVideoInfoDmaDrm info; GstVideoCodecState *output_state; - GstCaps *acquired_caps, *fixation_caps, *available_caps, *caps, *filter; - GstStructure *st; + GstCaps *acquired_caps, *acquired_drm_caps; + GstCaps *fixation_caps, *available_caps, *caps, *filter; gboolean active; GstBufferPool *cpool; gboolean ret; + gint i; /* We don't allow renegotiation without careful disabling the pool */ cpool = gst_v4l2_object_get_buffer_pool (self->v4l2capture); @@ -415,8 +416,8 @@ gst_v4l2_video_dec_negotiate (GstVideoDecoder * decoder) } /* init capture fps according to output */ - self->v4l2capture->info.fps_d = self->v4l2output->info.fps_d; - self->v4l2capture->info.fps_n = self->v4l2output->info.fps_n; + GST_V4L2_FPS_D (self->v4l2capture) = GST_V4L2_FPS_D (self->v4l2output); + GST_V4L2_FPS_N (self->v4l2capture) = GST_V4L2_FPS_N (self->v4l2output); /* For decoders G_FMT returns coded size, G_SELECTION returns visible size * in the compose rectangle. gst_v4l2_object_acquire_format() checks both @@ -426,19 +427,34 @@ gst_v4l2_video_dec_negotiate (GstVideoDecoder * decoder) goto not_negotiated; /* gst_v4l2_object_acquire_format() does not set fps, copy from sink */ - info.fps_n = self->v4l2output->info.fps_n; - info.fps_d = self->v4l2output->info.fps_d; + info.vinfo.fps_n = GST_V4L2_FPS_N (self->v4l2output); + info.vinfo.fps_d = GST_V4L2_FPS_D (self->v4l2output); gst_caps_replace (&self->probed_srccaps, NULL); self->probed_srccaps = gst_v4l2_object_probe_caps (self->v4l2capture, gst_v4l2_object_get_raw_caps ()); - /* Create caps from the acquired format, remove the format field */ - acquired_caps = gst_video_info_to_caps (&info); - GST_DEBUG_OBJECT (self, "Acquired caps: %" GST_PTR_FORMAT, acquired_caps); - fixation_caps = gst_caps_copy (acquired_caps); - st = gst_caps_get_structure (fixation_caps, 0); - gst_structure_remove_fields (st, "format", "colorimetry", "chroma-site", - NULL); + + /* Create caps from the acquired format, removing the format fields */ + fixation_caps = gst_caps_new_empty (); + + acquired_drm_caps = gst_video_info_dma_drm_to_caps (&info); + if (acquired_drm_caps) { + GST_DEBUG_OBJECT (self, "Acquired DRM caps: %" GST_PTR_FORMAT, + acquired_drm_caps); + gst_caps_append (fixation_caps, gst_caps_copy (acquired_drm_caps)); + } + + acquired_caps = gst_video_info_to_caps (&info.vinfo); + if (acquired_caps) { + GST_DEBUG_OBJECT (self, "Acquired caps: %" GST_PTR_FORMAT, acquired_caps); + gst_caps_append (fixation_caps, gst_caps_copy (acquired_drm_caps)); + } + + for (i = 0; i < gst_caps_get_size (fixation_caps); i++) { + GstStructure *st = gst_caps_get_structure (fixation_caps, i); + gst_structure_remove_fields (st, "format", "drm-format", "colorimetry", + "chroma-site", NULL); + } /* Probe currently available pixel formats */ available_caps = gst_caps_copy (self->probed_srccaps); @@ -465,6 +481,16 @@ gst_v4l2_video_dec_negotiate (GstVideoDecoder * decoder) /* Prefer the acquired caps over anything suggested downstream, this ensure * that we preserves the bit depth, as we don't have any fancy fixation * process */ + if (acquired_drm_caps) { + if (gst_caps_is_subset (acquired_drm_caps, caps)) { + gst_caps_replace (&acquired_caps, acquired_drm_caps); + acquired_drm_caps = NULL; + goto use_acquired_caps; + } + + gst_clear_caps (&acquired_drm_caps); + } + if (gst_caps_is_subset (acquired_caps, caps)) goto use_acquired_caps; @@ -475,12 +501,11 @@ gst_v4l2_video_dec_negotiate (GstVideoDecoder * decoder) /* Try to set negotiated format, on success replace acquired format */ if (gst_v4l2_object_set_format (self->v4l2capture, caps, &error)) - gst_video_info_from_caps (&info, caps); + info = self->v4l2capture->info; else gst_v4l2_clear_error (&error); use_acquired_caps: - gst_caps_unref (acquired_caps); gst_caps_unref (caps); /* catch possible bogus driver that don't enumerate the format it actually @@ -488,12 +513,13 @@ use_acquired_caps: if (!self->v4l2capture->fmtdesc) goto not_negotiated; - output_state = gst_video_decoder_set_output_state (decoder, - info.finfo->format, info.width, info.height, self->input_state); + output_state = gst_video_decoder_set_interlaced_output_state (decoder, + info.vinfo.finfo->format, info.vinfo.interlace_mode, info.vinfo.width, + info.vinfo.height, self->input_state); /* Copy the rest of the information, there might be more in the future */ - output_state->info.interlace_mode = info.interlace_mode; - output_state->info.colorimetry = info.colorimetry; + output_state->info.colorimetry = info.vinfo.colorimetry; + output_state->caps = acquired_caps; gst_video_codec_state_unref (output_state); ret = GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder); @@ -945,14 +971,15 @@ gst_v4l2_video_dec_handle_frame (GstVideoDecoder * decoder, /* Ensure input internal pool is active */ gst_buffer_pool_config_set_params (config, self->input_state->caps, - self->v4l2output->info.size, min, max); + self->v4l2output->info.vinfo.size, min, max); /* There is no reason to refuse this config */ if (!gst_buffer_pool_set_config (pool, config)) { config = gst_buffer_pool_get_config (pool); if (!gst_buffer_pool_config_validate_params (config, - self->input_state->caps, self->v4l2output->info.size, min, max)) { + self->input_state->caps, + self->v4l2output->info.vinfo.size, min, max)) { gst_structure_free (config); goto activate_failed; } diff --git a/subprojects/gst-plugins-good/sys/v4l2/gstv4l2videoenc.c b/subprojects/gst-plugins-good/sys/v4l2/gstv4l2videoenc.c index ac382fbc94..e1f98a0515 100644 --- a/subprojects/gst-plugins-good/sys/v4l2/gstv4l2videoenc.c +++ b/subprojects/gst-plugins-good/sys/v4l2/gstv4l2videoenc.c @@ -779,14 +779,14 @@ gst_v4l2_video_enc_handle_frame (GstVideoEncoder * encoder, GST_V4L2_MIN_BUFFERS (self->v4l2output)); gst_buffer_pool_config_set_params (config, self->input_state->caps, - self->v4l2output->info.size, min, min); + self->v4l2output->info.vinfo.size, min, min); /* There is no reason to refuse this config */ if (!gst_buffer_pool_set_config (opool, config)) { config = gst_buffer_pool_get_config (opool); if (gst_buffer_pool_config_validate_params (config, - self->input_state->caps, self->v4l2output->info.size, min, + self->input_state->caps, self->v4l2output->info.vinfo.size, min, min)) { gst_structure_free (config); if (opool)