Skip to content

Commit

Permalink
video-chroma: Add support for any combination of chroma-site flags
Browse files Browse the repository at this point in the history
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: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/-/merge_requests/927>
  • Loading branch information
seungha-yang authored and GStreamer Merge Bot committed Dec 8, 2020
1 parent 6434db5 commit 410efd1
Show file tree
Hide file tree
Showing 3 changed files with 193 additions and 5 deletions.
112 changes: 109 additions & 3 deletions gst-libs/gst/video/video-chroma.c
Expand Up @@ -26,7 +26,7 @@

#include "video-orc.h"
#include "video-format.h"

#include <gst/video/video-enumtypes.h>

/**
* SECTION:gstvideochroma
Expand Down Expand Up @@ -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},
};

/**
Expand All @@ -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;
}

/**
Expand All @@ -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 *
Expand All @@ -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;
Expand Down
10 changes: 8 additions & 2 deletions gst-libs/gst/video/video-chroma.h
Expand Up @@ -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
Expand Down
76 changes: 76 additions & 0 deletions tests/check/libs/video.c
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 410efd1

Please sign in to comment.