From 410efd196a00fafe6997f98abcd6c656d5ac0e4c Mon Sep 17 00:00:00 2001 From: Seungha Yang Date: Tue, 10 Nov 2020 18:01:12 +0900 Subject: [PATCH] video-chroma: Add support for any combination of chroma-site flags We've been allowing only a few known chroma-site values such as jpeg (not co-sited), mpeg2 (horizontally co-sited) and dv (co-sited on alternate lines). That's insufficient for representing all possible chroma-site values. By this commit, we can represent any combination of chroma-site flags. But, an exception here is that any combination with GST_VIDEO_CHROMA_SITE_NONE will be considered as invalid value. For any combination of chroma-site flags, gst_video_chroma_to_string() method is deprecated in order to return newly allocated string via a new gst_video_chroma_site_to_string() method. And for consistent API naming, gst_video_chroma_from_string() is also deprecated. Newly written code should use gst_video_chroma_site_from_string() instead. Part-of: --- gst-libs/gst/video/video-chroma.c | 112 +++++++++++++++++++++++++++++++++++++- gst-libs/gst/video/video-chroma.h | 10 +++- tests/check/libs/video.c | 76 ++++++++++++++++++++++++++ 3 files changed, 193 insertions(+), 5 deletions(-) diff --git a/gst-libs/gst/video/video-chroma.c b/gst-libs/gst/video/video-chroma.c index f761b44..3d7f07c 100644 --- a/gst-libs/gst/video/video-chroma.c +++ b/gst-libs/gst/video/video-chroma.c @@ -26,7 +26,7 @@ #include "video-orc.h" #include "video-format.h" - +#include /** * SECTION:gstvideochroma @@ -72,7 +72,9 @@ typedef struct static const ChromaSiteInfo chromasite[] = { {"jpeg", GST_VIDEO_CHROMA_SITE_JPEG}, {"mpeg2", GST_VIDEO_CHROMA_SITE_MPEG2}, - {"dv", GST_VIDEO_CHROMA_SITE_DV} + {"dv", GST_VIDEO_CHROMA_SITE_DV}, + {"alt-line", GST_VIDEO_CHROMA_SITE_ALT_LINE}, + {"cosited", GST_VIDEO_CHROMA_SITE_COSITED}, }; /** @@ -81,18 +83,66 @@ static const ChromaSiteInfo chromasite[] = { * * Convert @s to a #GstVideoChromaSite * + * Deprecated: 1.20: Use gst_video_chroma_site_from_string() instead. + * * Returns: a #GstVideoChromaSite or %GST_VIDEO_CHROMA_SITE_UNKNOWN when @s does * not contain a valid chroma description. */ GstVideoChromaSite gst_video_chroma_from_string (const gchar * s) { + return gst_video_chroma_site_from_string (s); +} + +/** + * gst_video_chroma_site_from_string: + * @s: a chromasite string + * + * Convert @s to a #GstVideoChromaSite + * + * Returns: a #GstVideoChromaSite or %GST_VIDEO_CHROMA_SITE_UNKNOWN when @s does + * not contain a valid chroma-site description. + * + * Since: 1.20 + */ +GstVideoChromaSite +gst_video_chroma_site_from_string (const gchar * s) +{ gint i; + gchar **split; + gchar **iter; + GstVideoChromaSite ret = GST_VIDEO_CHROMA_SITE_UNKNOWN; + GFlagsClass *klass; + for (i = 0; i < G_N_ELEMENTS (chromasite); i++) { if (g_str_equal (chromasite[i].name, s)) return chromasite[i].site; } - return GST_VIDEO_CHROMA_SITE_UNKNOWN; + + klass = (GFlagsClass *) g_type_class_ref (GST_TYPE_VIDEO_CHROMA_SITE); + split = g_strsplit (s, "+", 0); + for (iter = split; *iter; iter++) { + GFlagsValue *value; + + value = g_flags_get_value_by_nick (klass, *iter); + if (!value) { + ret = GST_VIDEO_CHROMA_SITE_UNKNOWN; + goto out; + } + + ret |= value->value; + } + +out: + g_type_class_unref (klass); + g_strfreev (split); + + /* Doesn't make sense */ + if ((ret & GST_VIDEO_CHROMA_SITE_NONE) != 0 && + ret != GST_VIDEO_CHROMA_SITE_NONE) + return GST_VIDEO_CHROMA_SITE_UNKNOWN; + + return ret; } /** @@ -101,6 +151,8 @@ gst_video_chroma_from_string (const gchar * s) * * Converts @site to its string representation. * + * Deprecated: 1.20: Use gst_video_chroma_site_to_string() instead. + * * Returns: a string describing @site. */ const gchar * @@ -114,6 +166,60 @@ gst_video_chroma_to_string (GstVideoChromaSite site) return NULL; } +/** + * gst_video_chroma_site_to_string: + * @site: a #GstVideoChromaSite + * + * Converts @site to its string representation. + * + * Returns: (transfer full) (nullable): a string representation of @site + * or %NULL if @site contains undefined value or + * is equal to %GST_VIDEO_CHROMA_SITE_UNKNOWN + * + * Since: 1.20 + */ +gchar * +gst_video_chroma_site_to_string (GstVideoChromaSite site) +{ + gint i; + GString *str; + GFlagsValue *value; + GFlagsClass *klass; + + /* return null string for GST_VIDEO_CHROMA_SITE_UNKNOWN */ + if (site == 0) + return NULL; + + for (i = 0; i < G_N_ELEMENTS (chromasite); i++) { + if (chromasite[i].site == site) + return g_strdup (chromasite[i].name); + } + + /* Doesn't make sense */ + if ((site & GST_VIDEO_CHROMA_SITE_NONE) != 0 && + site != GST_VIDEO_CHROMA_SITE_NONE) + return NULL; + + /* Construct new string */ + klass = (GFlagsClass *) g_type_class_ref (GST_TYPE_VIDEO_CHROMA_SITE); + str = g_string_new (NULL); + while (site != GST_VIDEO_CHROMA_SITE_UNKNOWN && + (value = g_flags_get_first_value (klass, site))) { + if (str->len > 0) + g_string_append (str, "+"); + + g_string_append (str, value->value_nick); + site &= ~value->value; + } + g_type_class_unref (klass); + + /* This means given chroma-site has unknown value */ + if (site != 0) + return g_string_free (str, TRUE); + + return g_string_free (str, FALSE); +} + struct _GstVideoChromaResample { GstVideoChromaMethod method; diff --git a/gst-libs/gst/video/video-chroma.h b/gst-libs/gst/video/video-chroma.h index 5240078..16720b4 100644 --- a/gst-libs/gst/video/video-chroma.h +++ b/gst-libs/gst/video/video-chroma.h @@ -52,12 +52,18 @@ typedef enum { GST_VIDEO_CHROMA_SITE_DV = (GST_VIDEO_CHROMA_SITE_COSITED | GST_VIDEO_CHROMA_SITE_ALT_LINE), } GstVideoChromaSite; -GST_VIDEO_API +GST_VIDEO_DEPRECATED_FOR(gst_video_chroma_site_from_string) GstVideoChromaSite gst_video_chroma_from_string (const gchar * s); -GST_VIDEO_API +GST_VIDEO_DEPRECATED_FOR(gst_video_chroma_site_to_string) const gchar * gst_video_chroma_to_string (GstVideoChromaSite site); +GST_VIDEO_API +GstVideoChromaSite gst_video_chroma_site_from_string (const gchar * s); + +GST_VIDEO_API +gchar * gst_video_chroma_site_to_string (GstVideoChromaSite site); + /** * GstVideoChromaMethod: * @GST_VIDEO_CHROMA_METHOD_NEAREST: Duplicates the chroma samples when diff --git a/tests/check/libs/video.c b/tests/check/libs/video.c index b9b9ec7..897d9d7 100644 --- a/tests/check/libs/video.c +++ b/tests/check/libs/video.c @@ -2398,6 +2398,81 @@ GST_END_TEST; #undef HEIGHT #undef TIME +typedef struct +{ + const gchar *name; + GstVideoChromaSite site; +} ChromaSiteElem; + +GST_START_TEST (test_video_chroma_site) +{ + ChromaSiteElem valid_sites[] = { + /* pre-defined flags */ + {"jpeg", GST_VIDEO_CHROMA_SITE_JPEG}, + {"mpeg2", GST_VIDEO_CHROMA_SITE_MPEG2}, + {"dv", GST_VIDEO_CHROMA_SITE_DV}, + {"alt-line", GST_VIDEO_CHROMA_SITE_ALT_LINE}, + {"cosited", GST_VIDEO_CHROMA_SITE_COSITED}, + /* new values */ + {"v-cosited", GST_VIDEO_CHROMA_SITE_V_COSITED}, + {"v-cosited+alt-line", + GST_VIDEO_CHROMA_SITE_V_COSITED | GST_VIDEO_CHROMA_SITE_ALT_LINE}, + }; + ChromaSiteElem unknown_sites[] = { + {NULL, GST_VIDEO_CHROMA_SITE_UNKNOWN}, + /* Any combination with GST_VIDEO_CHROMA_SITE_NONE doesn' make sense */ + {NULL, GST_VIDEO_CHROMA_SITE_NONE | GST_VIDEO_CHROMA_SITE_H_COSITED}, + }; + gint i; + + for (i = 0; i < G_N_ELEMENTS (valid_sites); i++) { + gchar *site = gst_video_chroma_site_to_string (valid_sites[i].site); + + fail_unless (site != NULL); + fail_unless (g_strcmp0 (site, valid_sites[i].name) == 0); + fail_unless (gst_video_chroma_site_from_string (site) == + valid_sites[i].site); + g_free (site); + } + + for (i = 0; i < G_N_ELEMENTS (unknown_sites); i++) { + gchar *site = gst_video_chroma_site_to_string (unknown_sites[i].site); + fail_unless (site == NULL); + } + + /* totally wrong string */ + fail_unless (gst_video_chroma_site_from_string ("foo/bar") == + GST_VIDEO_CHROMA_SITE_UNKNOWN); + + /* valid ones */ + fail_unless (gst_video_chroma_site_from_string ("jpeg") == + GST_VIDEO_CHROMA_SITE_NONE); + fail_unless (gst_video_chroma_site_from_string ("none") == + GST_VIDEO_CHROMA_SITE_NONE); + + fail_unless (gst_video_chroma_site_from_string ("mpeg2") == + GST_VIDEO_CHROMA_SITE_H_COSITED); + fail_unless (gst_video_chroma_site_from_string ("h-cosited") == + GST_VIDEO_CHROMA_SITE_H_COSITED); + + /* Equal to "cosited" */ + fail_unless (gst_video_chroma_site_from_string ("v-cosited+h-cosited") == + GST_VIDEO_CHROMA_SITE_COSITED); + + fail_unless (gst_video_chroma_site_from_string ("v-cosited") == + GST_VIDEO_CHROMA_SITE_V_COSITED); + + /* none + something doesn't make sense */ + fail_unless (gst_video_chroma_site_from_string ("none+v-cosited") == + GST_VIDEO_CHROMA_SITE_UNKNOWN); + + /* mix of valid and invalid strings */ + fail_unless (gst_video_chroma_site_from_string ("mpeg2+foo/bar") == + GST_VIDEO_CHROMA_SITE_UNKNOWN); +} + +GST_END_TEST; + GST_START_TEST (test_video_scaler) { GstVideoScaler *scale; @@ -3959,6 +4034,7 @@ video_suite (void) tcase_add_test (tc_chain, test_overlay_composition_global_alpha); tcase_add_test (tc_chain, test_video_pack_unpack2); tcase_add_test (tc_chain, test_video_chroma); + tcase_add_test (tc_chain, test_video_chroma_site); tcase_add_test (tc_chain, test_video_scaler); tcase_add_test (tc_chain, test_video_color_convert_rgb_rgb); tcase_add_test (tc_chain, test_video_color_convert_rgb_yuv); -- 2.7.4