video: Add support for big endian DRM formats

When a format is big endian, the 8bith of the fourcc is set. Handle this by
using a "_BE" suffix in serialization. The patch also update the design document
and introduce a unit test.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/8404>
This commit is contained in:
Nicolas Dufresne 2025-02-03 15:31:47 +01:00
parent a960985d18
commit 9eec7ddf19
3 changed files with 58 additions and 9 deletions

View file

@ -121,10 +121,11 @@ format. For example, `NV12:0x0100000000000002` is a new video format
combined by video format NV12 and the modifier `0x0100000000000002`. It's
not NV12 and it's not its subset either.
*DRM_FORMAT* can be printed by using
`GST_FOURCC_FORMAT` and `GST_FOURCC_ARGS` macros from the
`DRM_FORMAT_*` constants, it is NOT a `GstVideoFormat`, so it would be
different from the content of the `format` field in a non-dmabuf caps.
The 7 least significant bits of *DRM_FORMAT* is a fourcc. That fourcc is used
to serialize it into a string. The result is different from the serialization of
gstreamer video formats. The 8th bit is used to indicate that tis is a big
endian format. In this case, the serializer will postfix the name with `_BE`.
A modifier must always be present, except if the modifier is linear,
then it should not be included, so `NV12:0x0000000000000000` is
invalid, it must be `drm-format=NV12`. DRM fourcc are used

View file

@ -434,12 +434,18 @@ gst_video_dma_drm_fourcc_from_string (const gchar * format_str,
const gchar *mod_str;
guint32 fourcc = DRM_FORMAT_INVALID;
guint64 m = DRM_FORMAT_MOD_INVALID;
gboolean big_endian = FALSE;
g_return_val_if_fail (format_str != NULL, 0);
mod_str = strchr (format_str, ':');
if (mod_str) {
if (mod_str - format_str != 4) {
gint fmt_len = mod_str - format_str;
/* Handle big endian (FOURCC_BE) case */
if (fmt_len == 7 && strstr (format_str + 4, "_BE")) {
big_endian = TRUE;
} else if (fmt_len != 4) {
/* fourcc always has 4 characters. */
GST_DEBUG ("%s is not a drm string", format_str);
return DRM_FORMAT_INVALID;
@ -458,7 +464,12 @@ gst_video_dma_drm_fourcc_from_string (const gchar * format_str,
return DRM_FORMAT_INVALID;
}
} else {
if (strlen (format_str) != 4) {
gint fmt_len = strlen (format_str);
/* Handle big endian (FOURCC_BE) case */
if (fmt_len == 7 && strstr (format_str + 4, "_BE")) {
big_endian = TRUE;
} else if (fmt_len != 4) {
/* fourcc always has 4 characters. */
GST_DEBUG ("%s is not a drm string", format_str);
return DRM_FORMAT_INVALID;
@ -470,6 +481,9 @@ gst_video_dma_drm_fourcc_from_string (const gchar * format_str,
fourcc = GST_MAKE_FOURCC (format_str[0], format_str[1],
format_str[2], format_str[3]);
if (big_endian)
fourcc |= DRM_FORMAT_BIG_ENDIAN;
if (modifier)
*modifier = m;
@ -492,16 +506,23 @@ gst_video_dma_drm_fourcc_from_string (const gchar * format_str,
gchar *
gst_video_dma_drm_fourcc_to_string (guint32 fourcc, guint64 modifier)
{
gboolean big_endian = FALSE;
gchar *s;
g_return_val_if_fail (fourcc != DRM_FORMAT_INVALID, NULL);
g_return_val_if_fail (modifier != DRM_FORMAT_MOD_INVALID, NULL);
if (fourcc & DRM_FORMAT_BIG_ENDIAN) {
big_endian = TRUE;
fourcc &= ~DRM_FORMAT_BIG_ENDIAN;
}
if (modifier == DRM_FORMAT_MOD_LINEAR) {
s = g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
s = g_strdup_printf ("%" GST_FOURCC_FORMAT "%s", GST_FOURCC_ARGS (fourcc),
big_endian ? "_BE" : "");
} else {
s = g_strdup_printf ("%" GST_FOURCC_FORMAT ":0x%016" G_GINT64_MODIFIER "x",
GST_FOURCC_ARGS (fourcc), modifier);
s = g_strdup_printf ("%" GST_FOURCC_FORMAT "%s:0x%016" G_GINT64_MODIFIER
"x", GST_FOURCC_ARGS (fourcc), big_endian ? "_BE" : "", modifier);
}
return s;

View file

@ -4310,6 +4310,32 @@ GST_START_TEST (test_video_meta_serialize)
GST_END_TEST;
GST_START_TEST (test_dma_drm_big_engian)
{
const guint32 fourcc = GST_MAKE_FOURCC ('A', 'B', 'C', 'D') | 1U << 31;
gchar *fmt = gst_video_dma_drm_fourcc_to_string (fourcc, 0);
fail_unless (g_strcmp0 (fmt, "ABCD_BE") == 0);
gchar *fmt_mod = gst_video_dma_drm_fourcc_to_string (fourcc, 1);
fail_unless (g_strcmp0 (fmt_mod, "ABCD_BE:0x0000000000000001") == 0);
guint64 parsed_mod;
guint32 parsed_fourcc =
gst_video_dma_drm_fourcc_from_string (fmt, &parsed_mod);
g_assert_cmpuint (parsed_fourcc, ==, fourcc);
g_assert_cmpuint (parsed_mod, ==, G_GUINT64_CONSTANT (0));
parsed_fourcc = gst_video_dma_drm_fourcc_from_string (fmt_mod, &parsed_mod);
g_assert_cmpuint (parsed_fourcc, ==, fourcc);
g_assert_cmpuint (parsed_mod, ==, G_GUINT64_CONSTANT (1));
g_free (fmt);
g_free (fmt_mod);
}
GST_END_TEST;
static Suite *
video_suite (void)
{
@ -4370,6 +4396,7 @@ video_suite (void)
tcase_add_test (tc_chain, test_info_dma_drm);
tcase_add_test (tc_chain, test_video_meta_serialize);
tcase_add_test (tc_chain, test_video_convert_with_config_update);
tcase_add_test (tc_chain, test_dma_drm_big_engian);
return s;
}