From 33aafc4a91a59df3be7df65a5c69f3d059d27266 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Wed, 19 Feb 2025 08:55:44 -0500 Subject: [PATCH] v4l2codecs: Sort formats to avoid quality lost When the driver prefered format is not picked by downstream, the decoders needs to select another format from the list. The selection was currently unsorted, resulting in 10bit data often being stripped to 8bit. To solve this, reorder the formats in an HW preference order. This order deviates slightly from the preferred order in libgstvideo. This is to prefer bandwidth saving over better CPU alignment. As an example NV15 is prefered over P010. We also prefer tiled over linear. Part-of: --- .../docs/plugins/gst_plugins_cache.json | 12 ++-- .../sys/v4l2codecs/gstv4l2decoder.c | 1 + .../sys/v4l2codecs/gstv4l2format.c | 56 +++++++++++++++++-- .../sys/v4l2codecs/gstv4l2format.h | 22 +++++++- 4 files changed, 76 insertions(+), 15 deletions(-) diff --git a/subprojects/gst-plugins-bad/docs/plugins/gst_plugins_cache.json b/subprojects/gst-plugins-bad/docs/plugins/gst_plugins_cache.json index 646b7f5ad9..891c3e6433 100644 --- a/subprojects/gst-plugins-bad/docs/plugins/gst_plugins_cache.json +++ b/subprojects/gst-plugins-bad/docs/plugins/gst_plugins_cache.json @@ -249833,7 +249833,7 @@ "presence": "always" }, "src": { - "caps": "video/x-raw(memory:DMABuf):\n format: DMA_DRM\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: { NV12_10LE40, P010_10LE, NV12_10LE40_4L4, MT2110T, MT2110R, NV12, YUY2, NV12_4L4, NV12_32L32, NV12_16L32S, I420 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "caps": "video/x-raw(memory:DMABuf):\n format: DMA_DRM\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: { MT2110R, MT2110T, NV12_10LE40_4L4, NV12_10LE40, P010_10LE, YUY2, NV12_16L32S, NV12_32L32, NV12_4L4, NV12, I420 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", "direction": "src", "presence": "always" } @@ -249886,7 +249886,7 @@ "presence": "always" }, "src": { - "caps": "video/x-raw(memory:DMABuf):\n format: DMA_DRM\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: { NV12_10LE40, P010_10LE, NV12_10LE40_4L4, MT2110T, MT2110R, NV12, YUY2, NV12_4L4, NV12_32L32, NV12_16L32S, I420 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "caps": "video/x-raw(memory:DMABuf):\n format: DMA_DRM\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: { MT2110R, MT2110T, NV12_10LE40_4L4, NV12_10LE40, P010_10LE, YUY2, NV12_16L32S, NV12_32L32, NV12_4L4, NV12, I420 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", "direction": "src", "presence": "always" } @@ -249939,7 +249939,7 @@ "presence": "always" }, "src": { - "caps": "video/x-raw(memory:DMABuf):\n format: DMA_DRM\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: { NV12_10LE40, P010_10LE, NV12_10LE40_4L4, MT2110T, MT2110R, NV12, YUY2, NV12_4L4, NV12_32L32, NV12_16L32S, I420 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "caps": "video/x-raw(memory:DMABuf):\n format: DMA_DRM\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: { MT2110R, MT2110T, NV12_10LE40_4L4, NV12_10LE40, P010_10LE, YUY2, NV12_16L32S, NV12_32L32, NV12_4L4, NV12, I420 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", "direction": "src", "presence": "always" } @@ -249992,7 +249992,7 @@ "presence": "always" }, "src": { - "caps": "video/x-raw(memory:DMABuf):\n format: DMA_DRM\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: { NV12_10LE40, P010_10LE, NV12_10LE40_4L4, MT2110T, MT2110R, NV12, YUY2, NV12_4L4, NV12_32L32, NV12_16L32S, I420 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "caps": "video/x-raw(memory:DMABuf):\n format: DMA_DRM\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: { MT2110R, MT2110T, NV12_10LE40_4L4, NV12_10LE40, P010_10LE, YUY2, NV12_16L32S, NV12_32L32, NV12_4L4, NV12, I420 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", "direction": "src", "presence": "always" } @@ -250075,7 +250075,7 @@ "presence": "always" }, "src": { - "caps": "video/x-raw(memory:DMABuf):\n format: DMA_DRM\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: { NV12_10LE40, P010_10LE, NV12_10LE40_4L4, MT2110T, MT2110R, NV12, YUY2, NV12_4L4, NV12_32L32, NV12_16L32S, I420 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "caps": "video/x-raw(memory:DMABuf):\n format: DMA_DRM\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: { MT2110R, MT2110T, NV12_10LE40_4L4, NV12_10LE40, P010_10LE, YUY2, NV12_16L32S, NV12_32L32, NV12_4L4, NV12, I420 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", "direction": "src", "presence": "always" } @@ -250158,7 +250158,7 @@ "presence": "always" }, "src": { - "caps": "video/x-raw(memory:DMABuf):\n format: DMA_DRM\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: { NV12_10LE40, P010_10LE, NV12_10LE40_4L4, MT2110T, MT2110R, NV12, YUY2, NV12_4L4, NV12_32L32, NV12_16L32S, I420 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "caps": "video/x-raw(memory:DMABuf):\n format: DMA_DRM\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: { MT2110R, MT2110T, NV12_10LE40_4L4, NV12_10LE40, P010_10LE, YUY2, NV12_16L32S, NV12_32L32, NV12_4L4, NV12, I420 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", "direction": "src", "presence": "always" } diff --git a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2decoder.c b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2decoder.c index 4a0c468c94..83958f4e3f 100644 --- a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2decoder.c +++ b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2decoder.c @@ -680,6 +680,7 @@ gst_v4l2_decoder_select_src_format (GstV4l2Decoder * self, GstCaps * caps, } GST_DEBUG_OBJECT (self, "Original caps: %" GST_PTR_FORMAT, caps); + caps = gst_v4l2_format_sort_caps (caps); caps = gst_caps_fixate (caps); GST_DEBUG_OBJECT (self, "Fixated caps: %" GST_PTR_FORMAT, caps); diff --git a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2format.c b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2format.c index 0770151b7d..9b58e7bcc7 100644 --- a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2format.c +++ b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2format.c @@ -17,6 +17,8 @@ * Boston, MA 02110-1301, USA. */ +#include + #include "gstv4l2format.h" #include "linux/drm_fourcc.h" @@ -42,19 +44,20 @@ typedef struct } GstV4l2FormatDesc; /* *INDENT-OFF* */ +/* Keep the same order as GST_V4L2_DEFAULT_VIDEO_FORMATS */ static const GstV4l2FormatDesc gst_v4l2_descriptions[] = { - {V4L2_PIX_FMT_MM21, GST_VIDEO_FORMAT_NV12_16L32S, DRM_FORMAT_INVALID, DRM_FORMAT_MOD_INVALID, 0}, - {V4L2_PIX_FMT_MT2110T, GST_VIDEO_FORMAT_MT2110T, DRM_FORMAT_INVALID, DRM_FORMAT_MOD_INVALID, 0}, {V4L2_PIX_FMT_MT2110R, GST_VIDEO_FORMAT_MT2110R, DRM_FORMAT_INVALID, DRM_FORMAT_MOD_INVALID, 0}, - {V4L2_PIX_FMT_NV12, GST_VIDEO_FORMAT_NV12, DRM_FORMAT_INVALID, DRM_FORMAT_MOD_INVALID, 0}, - {V4L2_PIX_FMT_NV12_4L4, GST_VIDEO_FORMAT_NV12_4L4, DRM_FORMAT_INVALID, DRM_FORMAT_MOD_INVALID, 0}, + {V4L2_PIX_FMT_MT2110T, GST_VIDEO_FORMAT_MT2110T, DRM_FORMAT_INVALID, DRM_FORMAT_MOD_INVALID, 0}, {V4L2_PIX_FMT_NV15_4L4, GST_VIDEO_FORMAT_NV12_10LE40_4L4, DRM_FORMAT_INVALID, DRM_FORMAT_MOD_INVALID, 0}, {V4L2_PIX_FMT_NV15, GST_VIDEO_FORMAT_NV12_10LE40, DRM_FORMAT_INVALID, DRM_FORMAT_MOD_INVALID, 0}, {V4L2_PIX_FMT_P010, GST_VIDEO_FORMAT_P010_10LE, DRM_FORMAT_INVALID, DRM_FORMAT_MOD_INVALID, 0}, - {V4L2_PIX_FMT_SUNXI_TILED_NV12, GST_VIDEO_FORMAT_NV12_32L32, DRM_FORMAT_INVALID, DRM_FORMAT_MOD_INVALID, 0}, - {V4L2_PIX_FMT_YUV420M, GST_VIDEO_FORMAT_I420, DRM_FORMAT_INVALID, DRM_FORMAT_MOD_INVALID, 0}, {V4L2_PIX_FMT_YUYV, GST_VIDEO_FORMAT_YUY2, DRM_FORMAT_INVALID, DRM_FORMAT_MOD_INVALID, 0}, + {V4L2_PIX_FMT_MM21, GST_VIDEO_FORMAT_NV12_16L32S, DRM_FORMAT_INVALID, DRM_FORMAT_MOD_INVALID, 0}, + {V4L2_PIX_FMT_SUNXI_TILED_NV12, GST_VIDEO_FORMAT_NV12_32L32, DRM_FORMAT_INVALID, DRM_FORMAT_MOD_INVALID, 0}, + {V4L2_PIX_FMT_NV12_4L4, GST_VIDEO_FORMAT_NV12_4L4, DRM_FORMAT_INVALID, DRM_FORMAT_MOD_INVALID, 0}, {V4L2_PIX_FMT_NC12, GST_VIDEO_FORMAT_UNKNOWN, DRM_FORMAT_NV12, DRM_FORMAT_MOD_BROADCOM_SAND128, 2}, + {V4L2_PIX_FMT_NV12, GST_VIDEO_FORMAT_NV12, DRM_FORMAT_INVALID, DRM_FORMAT_MOD_INVALID, 0}, + {V4L2_PIX_FMT_YUV420M, GST_VIDEO_FORMAT_I420, DRM_FORMAT_INVALID, DRM_FORMAT_MOD_INVALID, 0}, }; /* *INDENT-ON* */ #define GST_V4L2_FORMAT_DESC_COUNT (G_N_ELEMENTS (gst_v4l2_descriptions)) @@ -337,3 +340,44 @@ gst_v4l2_format_get_n_planes (GstVideoInfoDmaDrm * info) g_warn_if_reached (); return 0; } + + +GstCaps * +gst_v4l2_format_sort_caps (GstCaps * caps) +{ + const GstV4l2FormatDesc *fmt_descs = gst_v4l2_format_get_descriptions (); + GstCaps *sorted_caps = gst_caps_new_empty (); + + for (int i = 0; i < GST_V4L2_FORMAT_DESC_COUNT; i++) { + if (fmt_descs[i].drm_fourcc != DRM_FORMAT_INVALID) { + guint32 drm_fourcc = fmt_descs[i].drm_fourcc; + guint64 drm_modifier = fmt_descs[i].drm_modifier; + GValue fmt = G_VALUE_INIT; + g_value_init (&fmt, G_TYPE_STRING); + g_value_take_string (&fmt, + gst_video_dma_drm_fourcc_to_string (drm_fourcc, drm_modifier)); + + GstStructure *dma_s = gst_structure_new ("video/x-raw", + "format", G_TYPE_STRING, "DMA_DRM", NULL); + gst_structure_take_value (dma_s, "drm-format", &fmt); + gst_caps_append_structure_full (sorted_caps, dma_s, + gst_caps_features_new_static_str (GST_CAPS_FEATURE_MEMORY_DMABUF, + NULL)); + } + } + + for (int i = 0; i < GST_V4L2_FORMAT_DESC_COUNT; i++) { + if (fmt_descs[i].gst_fmt != GST_VIDEO_FORMAT_UNKNOWN) { + GstStructure *s = gst_structure_new ("video/x-raw", + "format", G_TYPE_STRING, + gst_video_format_to_string (fmt_descs[i].gst_fmt), NULL); + gst_caps_append_structure (sorted_caps, s); + } + } + + GstCaps *ret = + gst_caps_intersect_full (sorted_caps, caps, GST_CAPS_INTERSECT_FIRST); + gst_caps_unref (sorted_caps); + + return ret; +} diff --git a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2format.h b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2format.h index b7897aa8e8..7949d0a37d 100644 --- a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2format.h +++ b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2format.h @@ -23,10 +23,24 @@ #include #include "linux/videodev2.h" +/* + * Ordered similar to what libgstvideo does, but keeping tiled formats first, + * and prefering bandwidth over alignment (NV12_10LE40 over P010_LE). + */ #define GST_V4L2_DEFAULT_VIDEO_FORMATS "{ " \ - "NV12_10LE40, P010_10LE, NV12_10LE40_4L4, MT2110T, MT2110R," \ - "NV12, YUY2, NV12_4L4, NV12_32L32, NV12_16L32S, I420" \ - "}" + "MT2110R, " \ + "MT2110T, " \ + "NV12_10LE40_4L4, " \ + "NV12_10LE40, " \ + "P010_10LE, " \ + "YUY2, " \ + "NV12_16L32S, " \ + "NV12_32L32, " \ + "NV12_4L4, " \ + "NV12, " \ + "I420, " \ + "}" + gboolean gst_v4l2_format_to_dma_drm_info (struct v4l2_format * fmt, GstVideoInfoDmaDrm * out_drm_info); @@ -46,3 +60,5 @@ gboolean gst_v4l2_format_from_drm_format (guint32 drm_fourcc, guint32 * out_pix_fmt); guint gst_v4l2_format_get_n_planes (GstVideoInfoDmaDrm * info); + +GstCaps * gst_v4l2_format_sort_caps (GstCaps * caps);