From 451b32574fc5a6645be6e18e47df104ad7f11ca1 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 20 Jun 2024 16:52:46 +0200 Subject: [PATCH] v4l2codecs: dynamically discovers supported pixels formats If the driver allows it, for each stateless decoder, enumerate all the pixels formats and use this list for source pad instead of a static template. Part-of: --- .../sys/v4l2codecs/gstv4l2codecav1dec.c | 14 +++--- .../sys/v4l2codecs/gstv4l2codecdevice.h | 1 + .../sys/v4l2codecs/gstv4l2codech264dec.c | 16 ++++--- .../sys/v4l2codecs/gstv4l2codech265dec.c | 16 ++++--- .../sys/v4l2codecs/gstv4l2codecmpeg2dec.c | 16 ++++--- .../sys/v4l2codecs/gstv4l2codecvp8dec.c | 18 ++++--- .../sys/v4l2codecs/gstv4l2codecvp9dec.c | 18 ++++--- .../sys/v4l2codecs/gstv4l2decoder.c | 47 +++++++++++++++++-- .../sys/v4l2codecs/gstv4l2decoder.h | 3 ++ 9 files changed, 108 insertions(+), 41 deletions(-) diff --git a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecav1dec.c b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecav1dec.c index c031bebd3c..2278f8ba50 100644 --- a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecav1dec.c +++ b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecav1dec.c @@ -62,11 +62,6 @@ GST_STATIC_PAD_TEMPLATE (GST_VIDEO_DECODER_SINK_NAME, static GstStaticCaps static_src_caps = GST_STATIC_CAPS (SRC_CAPS); static GstStaticCaps static_src_caps_no_drm = GST_STATIC_CAPS (SRC_CAPS_NO_DRM); -static GstStaticPadTemplate src_template = -GST_STATIC_PAD_TEMPLATE (GST_VIDEO_DECODER_SRC_NAME, - GST_PAD_SRC, GST_PAD_ALWAYS, - GST_STATIC_CAPS (SRC_CAPS)); - struct _GstV4l2CodecAV1Dec { GstAV1Decoder parent; @@ -1537,7 +1532,9 @@ gst_v4l2_codec_av1_dec_subclass_init (GstV4l2CodecAV1DecClass * klass, "Daniel Almeida "); gst_element_class_add_static_pad_template (element_class, &sink_template); - gst_element_class_add_static_pad_template (element_class, &src_template); + gst_element_class_add_pad_template (element_class, + gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, + device->src_caps)); element_class->change_state = GST_DEBUG_FUNCPTR (gst_v4l2_codec_av1_dec_change_state); @@ -1608,6 +1605,7 @@ gst_v4l2_codec_av1_dec_register (GstPlugin * plugin, GstV4l2Decoder * decoder, 320, 240, 8)) return; + /* Make sure that decoder support stateless AV1 */ src_caps = gst_v4l2_decoder_enum_src_formats (decoder, &static_src_caps); if (gst_caps_is_empty (src_caps)) { @@ -1616,6 +1614,10 @@ gst_v4l2_codec_av1_dec_register (GstPlugin * plugin, GstV4l2Decoder * decoder, goto done; } + /* Get all supported pixel formats for AV1 */ + device->src_caps = + gst_v4l2_decoder_enum_all_src_formats (decoder, &static_src_caps); + /* TODO uncomment this when AV1 get included in Linus tree */ #if 0 version = gst_v4l2_decoder_get_version (decoder); diff --git a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecdevice.h b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecdevice.h index a48088c3d4..3703563cb1 100644 --- a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecdevice.h +++ b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecdevice.h @@ -34,6 +34,7 @@ typedef struct { guint32 function; gchar *media_device_path; gchar *video_device_path; + GstCaps *src_caps; } GstV4l2CodecDevice; GType gst_v4l2_codec_device_get_type (void); diff --git a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codech264dec.c b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codech264dec.c index 2368e52de8..6b2939c91a 100644 --- a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codech264dec.c +++ b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codech264dec.c @@ -60,11 +60,6 @@ GST_STATIC_PAD_TEMPLATE (GST_VIDEO_DECODER_SINK_NAME, static GstStaticCaps static_src_caps = GST_STATIC_CAPS (SRC_CAPS); static GstStaticCaps static_src_caps_no_drm = GST_STATIC_CAPS (SRC_CAPS_NO_DRM); -static GstStaticPadTemplate src_template = -GST_STATIC_PAD_TEMPLATE (GST_VIDEO_DECODER_SRC_NAME, - GST_PAD_SRC, GST_PAD_ALWAYS, - GST_STATIC_CAPS (SRC_CAPS)); - struct _GstV4l2CodecH264Dec { GstH264Decoder parent; @@ -1554,7 +1549,10 @@ gst_v4l2_codec_h264_dec_subclass_init (GstV4l2CodecH264DecClass * klass, "Nicolas Dufresne "); gst_element_class_add_static_pad_template (element_class, &sink_template); - gst_element_class_add_static_pad_template (element_class, &src_template); + gst_element_class_add_pad_template (element_class, + gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, + device->src_caps)); + element_class->change_state = GST_DEBUG_FUNCPTR (gst_v4l2_codec_h264_dec_change_state); @@ -1601,6 +1599,8 @@ gst_v4l2_codec_h264_dec_register (GstPlugin * plugin, GstV4l2Decoder * decoder, if (!gst_v4l2_decoder_set_sink_fmt (decoder, V4L2_PIX_FMT_H264_SLICE, 320, 240, 8)) return; + + /* Make sure that decoder support stateless H264 */ src_caps = gst_v4l2_decoder_enum_src_formats (decoder, &static_src_caps); if (gst_caps_is_empty (src_caps)) { @@ -1609,6 +1609,10 @@ gst_v4l2_codec_h264_dec_register (GstPlugin * plugin, GstV4l2Decoder * decoder, goto done; } + /* Get all supported pixel formats for H264 */ + device->src_caps = + gst_v4l2_decoder_enum_all_src_formats (decoder, &static_src_caps); + version = gst_v4l2_decoder_get_version (decoder); if (version < V4L2_MIN_KERNEL_VERSION) GST_WARNING ("V4L2 API v%u.%u too old, at least v%u.%u required", diff --git a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codech265dec.c b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codech265dec.c index 331659a702..2e085f52f7 100644 --- a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codech265dec.c +++ b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codech265dec.c @@ -61,11 +61,6 @@ GST_STATIC_PAD_TEMPLATE (GST_VIDEO_DECODER_SINK_NAME, static GstStaticCaps static_src_caps = GST_STATIC_CAPS (SRC_CAPS); static GstStaticCaps static_src_caps_no_drm = GST_STATIC_CAPS (SRC_CAPS_NO_DRM); -static GstStaticPadTemplate src_template = -GST_STATIC_PAD_TEMPLATE (GST_VIDEO_DECODER_SRC_NAME, - GST_PAD_SRC, GST_PAD_ALWAYS, - GST_STATIC_CAPS (SRC_CAPS)); - struct _GstV4l2CodecH265Dec { GstH265Decoder parent; @@ -1687,7 +1682,10 @@ gst_v4l2_codec_h265_dec_subclass_init (GstV4l2CodecH265DecClass * klass, "Nicolas Dufresne "); gst_element_class_add_static_pad_template (element_class, &sink_template); - gst_element_class_add_static_pad_template (element_class, &src_template); + gst_element_class_add_pad_template (element_class, + gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, + device->src_caps)); + element_class->change_state = GST_DEBUG_FUNCPTR (gst_v4l2_codec_h265_dec_change_state); @@ -1732,6 +1730,8 @@ gst_v4l2_codec_h265_dec_register (GstPlugin * plugin, GstV4l2Decoder * decoder, if (!gst_v4l2_decoder_set_sink_fmt (decoder, V4L2_PIX_FMT_HEVC_SLICE, 320, 240, 8)) return; + + /* Make sure that decoder support stateless H265 */ src_caps = gst_v4l2_decoder_enum_src_formats (decoder, &static_src_caps); if (gst_caps_is_empty (src_caps)) { @@ -1740,6 +1740,10 @@ gst_v4l2_codec_h265_dec_register (GstPlugin * plugin, GstV4l2Decoder * decoder, goto done; } + /* Get all supported pixel formats for H265 */ + device->src_caps = + gst_v4l2_decoder_enum_all_src_formats (decoder, &static_src_caps); + version = gst_v4l2_decoder_get_version (decoder); if (version < V4L2_MIN_KERNEL_VERSION) GST_WARNING ("V4L2 API v%u.%u too old, at least v%u.%u required", diff --git a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecmpeg2dec.c b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecmpeg2dec.c index df68f1a662..1e2902d9dd 100644 --- a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecmpeg2dec.c +++ b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecmpeg2dec.c @@ -63,11 +63,6 @@ GST_STATIC_PAD_TEMPLATE (GST_VIDEO_DECODER_SINK_NAME, static GstStaticCaps static_src_caps = GST_STATIC_CAPS (SRC_CAPS); static GstStaticCaps static_src_caps_no_drm = GST_STATIC_CAPS (SRC_CAPS_NO_DRM); -static GstStaticPadTemplate src_template = -GST_STATIC_PAD_TEMPLATE (GST_VIDEO_DECODER_SRC_NAME, - GST_PAD_SRC, GST_PAD_ALWAYS, - GST_STATIC_CAPS (SRC_CAPS)); - struct _GstV4l2CodecMpeg2Dec { GstMpeg2Decoder parent; @@ -1074,7 +1069,10 @@ gst_v4l2_codec_mpeg2_dec_subclass_init (GstV4l2CodecMpeg2DecClass * klass, "Daniel Almeida "); gst_element_class_add_static_pad_template (element_class, &sink_template); - gst_element_class_add_static_pad_template (element_class, &src_template); + gst_element_class_add_pad_template (element_class, + gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, + device->src_caps)); + element_class->change_state = GST_DEBUG_FUNCPTR (gst_v4l2_codec_mpeg2_dec_change_state); @@ -1118,6 +1116,8 @@ gst_v4l2_codec_mpeg2_dec_register (GstPlugin * plugin, GstV4l2Decoder * decoder, if (!gst_v4l2_decoder_set_sink_fmt (decoder, V4L2_PIX_FMT_MPEG2_SLICE, 320, 240, 8)) return; + + /* Make sure that decoder support stateless MPEG2 */ src_caps = gst_v4l2_decoder_enum_src_formats (decoder, &static_src_caps); if (gst_caps_is_empty (src_caps)) { @@ -1126,6 +1126,10 @@ gst_v4l2_codec_mpeg2_dec_register (GstPlugin * plugin, GstV4l2Decoder * decoder, goto done; } + /* Get all supported pixel formats for MPEG2 */ + device->src_caps = + gst_v4l2_decoder_enum_all_src_formats (decoder, &static_src_caps); + gst_v4l2_decoder_register (plugin, GST_TYPE_V4L2_CODEC_MPEG2_DEC, (GClassInitFunc) gst_v4l2_codec_mpeg2_dec_subclass_init, gst_mini_object_ref (GST_MINI_OBJECT (device)), diff --git a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecvp8dec.c b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecvp8dec.c index 285f699c68..5b8932a8f9 100644 --- a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecvp8dec.c +++ b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecvp8dec.c @@ -64,11 +64,6 @@ GST_STATIC_PAD_TEMPLATE (GST_VIDEO_DECODER_SINK_NAME, static GstStaticCaps static_src_caps = GST_STATIC_CAPS (SRC_CAPS); static GstStaticCaps static_src_caps_no_drm = GST_STATIC_CAPS (SRC_CAPS_NO_DRM); -static GstStaticPadTemplate src_template = -GST_STATIC_PAD_TEMPLATE (GST_VIDEO_DECODER_SRC_NAME, - GST_PAD_SRC, GST_PAD_ALWAYS, - GST_STATIC_CAPS (SRC_CAPS)); - struct _GstV4l2CodecVp8Dec { GstVp8Decoder parent; @@ -934,7 +929,10 @@ gst_v4l2_codec_vp8_dec_subclass_init (GstV4l2CodecVp8DecClass * klass, "Nicolas Dufresne "); gst_element_class_add_static_pad_template (element_class, &sink_template); - gst_element_class_add_static_pad_template (element_class, &src_template); + gst_element_class_add_pad_template (element_class, + gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, + device->src_caps)); + element_class->change_state = GST_DEBUG_FUNCPTR (gst_v4l2_codec_vp8_dec_change_state); @@ -995,6 +993,8 @@ gst_v4l2_codec_vp8_dec_register (GstPlugin * plugin, GstV4l2Decoder * decoder, if (!gst_v4l2_decoder_set_sink_fmt (decoder, V4L2_PIX_FMT_VP8_FRAME, 320, 240, 8)) return; + + /* Make sure that decoder support stateless VP8 */ src_caps = gst_v4l2_decoder_enum_src_formats (decoder, &static_src_caps); if (gst_caps_is_empty (src_caps)) { @@ -1003,6 +1003,10 @@ gst_v4l2_codec_vp8_dec_register (GstPlugin * plugin, GstV4l2Decoder * decoder, goto done; } + /* Get all supported pixel formats for VP8 */ + device->src_caps = + gst_v4l2_decoder_enum_all_src_formats (decoder, &static_src_caps); + gst_v4l2_decoder_register (plugin, GST_TYPE_V4L2_CODEC_VP8_DEC, (GClassInitFunc) gst_v4l2_codec_vp8_dec_subclass_init, gst_mini_object_ref (GST_MINI_OBJECT (device)), @@ -1014,7 +1018,7 @@ gst_v4l2_codec_vp8_dec_register (GstPlugin * plugin, GstV4l2Decoder * decoder, alpha_caps = gst_caps_from_string ("video/x-raw,format={I420, NV12}"); - if (gst_caps_can_intersect (src_caps, alpha_caps)) + if (gst_caps_can_intersect (device->src_caps, alpha_caps)) gst_v4l2_codec_alpha_decode_bin_register (plugin, (GClassInitFunc) gst_v4l2_codec_vp8_alpha_decode_bin_subclass_init, element_name, "v4l2slvp8%salphadecodebin", device, rank); diff --git a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecvp9dec.c b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecvp9dec.c index b741b4ef14..a26d10f974 100644 --- a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecvp9dec.c +++ b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecvp9dec.c @@ -65,11 +65,6 @@ GST_STATIC_PAD_TEMPLATE (GST_VIDEO_DECODER_SINK_NAME, static GstStaticCaps static_src_caps = GST_STATIC_CAPS (SRC_CAPS); static GstStaticCaps static_src_caps_no_drm = GST_STATIC_CAPS (SRC_CAPS_NO_DRM); -static GstStaticPadTemplate src_template = -GST_STATIC_PAD_TEMPLATE (GST_VIDEO_DECODER_SRC_NAME, - GST_PAD_SRC, GST_PAD_ALWAYS, - GST_STATIC_CAPS (SRC_CAPS)); - struct _GstV4l2CodecVp9Dec { GstVp9Decoder parent; @@ -1210,7 +1205,10 @@ gst_v4l2_codec_vp9_dec_subclass_init (GstV4l2CodecVp9DecClass * klass, "Daniel Almeida "); gst_element_class_add_static_pad_template (element_class, &sink_template); - gst_element_class_add_static_pad_template (element_class, &src_template); + gst_element_class_add_pad_template (element_class, + gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, + device->src_caps)); + element_class->change_state = GST_DEBUG_FUNCPTR (gst_v4l2_codec_vp9_dec_change_state); @@ -1275,6 +1273,8 @@ gst_v4l2_codec_vp9_dec_register (GstPlugin * plugin, GstV4l2Decoder * decoder, if (!gst_v4l2_decoder_set_sink_fmt (decoder, V4L2_PIX_FMT_VP9_FRAME, 320, 240, 8)) return; + + /* Make sure that decoder support stateless VP9 */ src_caps = gst_v4l2_decoder_enum_src_formats (decoder, &static_src_caps); if (gst_caps_is_empty (src_caps)) { @@ -1283,6 +1283,10 @@ gst_v4l2_codec_vp9_dec_register (GstPlugin * plugin, GstV4l2Decoder * decoder, goto done; } + /* Get all supported pixel formats for VP9 */ + device->src_caps = + gst_v4l2_decoder_enum_all_src_formats (decoder, &static_src_caps); + gst_v4l2_decoder_register (plugin, GST_TYPE_V4L2_CODEC_VP9_DEC, (GClassInitFunc) gst_v4l2_codec_vp9_dec_subclass_init, gst_mini_object_ref (GST_MINI_OBJECT (device)), @@ -1294,7 +1298,7 @@ gst_v4l2_codec_vp9_dec_register (GstPlugin * plugin, GstV4l2Decoder * decoder, alpha_caps = gst_caps_from_string ("video/x-raw,format={I420, NV12}"); - if (gst_caps_can_intersect (src_caps, alpha_caps)) + if (gst_caps_can_intersect (device->src_caps, alpha_caps)) gst_v4l2_codec_alpha_decode_bin_register (plugin, (GClassInitFunc) gst_v4l2_codec_vp9_alpha_decode_bin_subclass_init, element_name, "v4l2slvp9%salphadecodebin", device, rank); diff --git a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2decoder.c b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2decoder.c index b22d6a41e9..71a6df16bf 100644 --- a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2decoder.c +++ b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2decoder.c @@ -41,6 +41,12 @@ GST_DEBUG_CATEGORY (v4l2_decoder_debug); #define GST_CAT_DEFAULT v4l2_decoder_debug +#define SRC_CAPS \ + GST_VIDEO_DMA_DRM_CAPS_MAKE " ; " \ + GST_VIDEO_CAPS_MAKE (GST_V4L2_DEFAULT_VIDEO_FORMATS) + +static GstStaticCaps default_src_caps = GST_STATIC_CAPS (SRC_CAPS); + enum { PROP_0, @@ -499,9 +505,9 @@ filter_non_dmabuf_caps (GstCapsFeatures * features, return !gst_caps_features_contains (features, GST_CAPS_FEATURE_MEMORY_DMABUF); } -GstCaps * -gst_v4l2_decoder_enum_src_formats (GstV4l2Decoder * self, - GstStaticCaps * static_filter) +static GstCaps * +gst_v4l2_decoder_enum_src_formats_full (GstV4l2Decoder * self, + GstStaticCaps * static_filter, gboolean enum_all) { gint ret; struct v4l2_format fmt = { @@ -527,7 +533,17 @@ gst_v4l2_decoder_enum_src_formats (GstV4l2Decoder * self, for (i = 0; ret >= 0; i++) { struct v4l2_fmtdesc fmtdesc = { i, self->src_buf_type, }; + if (enum_all) + fmtdesc.index |= V4L2_FMTDESC_FLAG_ENUM_ALL; + ret = ioctl (self->video_fd, VIDIOC_ENUM_FMT, &fmtdesc); + /* If the driver can't enumerate all the pixels formats + * return empty caps */ + if (enum_all && ret == -EINVAL) { + gst_caps_unref (caps); + return gst_static_caps_get (&default_src_caps); + } + if (ret < 0) { if (errno != EINVAL) GST_ERROR_OBJECT (self, "VIDIOC_ENUM_FMT failed: %s", @@ -551,11 +567,36 @@ gst_v4l2_decoder_enum_src_formats (GstV4l2Decoder * self, gst_caps_filter_and_map_in_place (tmp, filter_non_dmabuf_caps, NULL); gst_caps_append (caps, tmp); + if (enum_all) { + /* When enumerating all the formats we don't need yet resolution + * so remove width, height and framerate fields */ + guint n = gst_caps_get_size (caps); + for (i = 0; i < n; i++) { + GstStructure *s = gst_caps_get_structure (caps, i); + + gst_structure_remove_fields (s, "width", "height", "framerate", NULL); + } + caps = gst_caps_simplify (caps); + } GST_DEBUG_OBJECT (self, "Probed caps: %" GST_PTR_FORMAT, caps); return caps; } +GstCaps * +gst_v4l2_decoder_enum_src_formats (GstV4l2Decoder * self, + GstStaticCaps * static_filter) +{ + return gst_v4l2_decoder_enum_src_formats_full (self, static_filter, FALSE); +} + +GstCaps * +gst_v4l2_decoder_enum_all_src_formats (GstV4l2Decoder * self, + GstStaticCaps * static_filter) +{ + return gst_v4l2_decoder_enum_src_formats_full (self, static_filter, TRUE); +} + gboolean gst_v4l2_decoder_remove_buffers (GstV4l2Decoder * self, GstPadDirection direction, guint index, guint num_buffers) diff --git a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2decoder.h b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2decoder.h index 09d2bb66df..f48b6bba00 100644 --- a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2decoder.h +++ b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2decoder.h @@ -70,6 +70,9 @@ gboolean gst_v4l2_decoder_set_sink_fmt (GstV4l2Decoder * self, guint32 GstCaps * gst_v4l2_decoder_enum_src_formats (GstV4l2Decoder * self, GstStaticCaps * static_filter); +GstCaps * gst_v4l2_decoder_enum_all_src_formats (GstV4l2Decoder * self, + GstStaticCaps * static_filter); + gboolean gst_v4l2_decoder_select_src_format (GstV4l2Decoder * self, GstCaps * caps, GstVideoInfo * vinfo,