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: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7686>
This commit is contained in:
Benjamin Gaignard 2024-06-20 16:52:46 +02:00 committed by GStreamer Marge Bot
parent 3a52cbcc67
commit 451b32574f
9 changed files with 108 additions and 41 deletions

View file

@ -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 <daniel.almeida@collabora.com>");
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);

View file

@ -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);

View file

@ -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 <nicolas.dufresne@collabora.com>");
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",

View file

@ -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 <nicolas.dufresne@collabora.com>");
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",

View file

@ -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 <daniel.almeida@collabora.com>");
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)),

View file

@ -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 <nicolas.dufresne@collabora.com>");
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);

View file

@ -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 <daniel.almeida@collabora.com>");
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);

View file

@ -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)

View file

@ -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,