mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-09-19 10:30:30 +00:00
0c40b83ed4
Move the function to get the color matrix coefficients from videoconvert to the video library.
316 lines
8.5 KiB
C
316 lines
8.5 KiB
C
/* GStreamer
|
|
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
|
* Library <2002> Ronald Bultje <rbultje@ronald.bitfreak.net>
|
|
* Copyright (C) 2007 David A. Schleef <ds@schleef.org>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
|
|
#include "video-color.h"
|
|
|
|
typedef struct
|
|
{
|
|
const gchar *name;
|
|
GstVideoColorimetry color;
|
|
} ColorimetryInfo;
|
|
|
|
#define MAKE_COLORIMETRY(n,r,m,t,p) { GST_VIDEO_COLORIMETRY_ ##n, \
|
|
{ GST_VIDEO_COLOR_RANGE ##r, GST_VIDEO_COLOR_MATRIX_ ##m, \
|
|
GST_VIDEO_TRANSFER_ ##t, GST_VIDEO_COLOR_PRIMARIES_ ##p } }
|
|
|
|
#define GST_VIDEO_COLORIMETRY_NONAME NULL
|
|
|
|
#define DEFAULT_YUV_SD 0
|
|
#define DEFAULT_YUV_HD 1
|
|
#define DEFAULT_RGB 3
|
|
#define DEFAULT_GRAY 4
|
|
#define DEFAULT_UNKNOWN 5
|
|
|
|
static const ColorimetryInfo colorimetry[] = {
|
|
MAKE_COLORIMETRY (BT601, _16_235, BT601, BT709, BT470M),
|
|
MAKE_COLORIMETRY (BT709, _16_235, BT709, BT709, BT709),
|
|
MAKE_COLORIMETRY (SMPTE240M, _16_235, SMPTE240M, SMPTE240M, SMPTE240M),
|
|
MAKE_COLORIMETRY (NONAME, _0_255, RGB, UNKNOWN, UNKNOWN),
|
|
MAKE_COLORIMETRY (NONAME, _0_255, BT601, UNKNOWN, UNKNOWN),
|
|
MAKE_COLORIMETRY (NONAME, _UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN),
|
|
};
|
|
|
|
static const ColorimetryInfo *
|
|
gst_video_get_colorimetry (const gchar * s)
|
|
{
|
|
gint i;
|
|
|
|
for (i = 0; colorimetry[i].name; i++) {
|
|
if (g_str_equal (colorimetry[i].name, s))
|
|
return &colorimetry[i];
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
#define IS_EQUAL(ci,i) (((ci)->color.range == (i)->range) && \
|
|
((ci)->color.matrix == (i)->matrix) && \
|
|
((ci)->color.transfer == (i)->transfer) && \
|
|
((ci)->color.primaries == (i)->primaries))
|
|
|
|
#define IS_UNKNOWN(ci) (IS_EQUAL (&colorimetry[DEFAULT_UNKNOWN], ci))
|
|
|
|
/**
|
|
* gst_video_colorimetry_from_string:
|
|
* @cinfo: a #GstVideoColorimetry
|
|
* @color: a colorimetry string
|
|
*
|
|
* Parse the colorimetry string and update @cinfo with the parsed
|
|
* values.
|
|
*
|
|
* Returns: #TRUE if @color points to valid colorimetry info.
|
|
*/
|
|
gboolean
|
|
gst_video_colorimetry_from_string (GstVideoColorimetry * cinfo,
|
|
const gchar * color)
|
|
{
|
|
const ColorimetryInfo *ci;
|
|
|
|
if ((ci = gst_video_get_colorimetry (color))) {
|
|
*cinfo = ci->color;
|
|
} else {
|
|
gint r, m, t, p;
|
|
|
|
if (sscanf (color, "%d:%d:%d:%d", &r, &m, &t, &p) == 4) {
|
|
cinfo->range = r;
|
|
cinfo->matrix = m;
|
|
cinfo->transfer = t;
|
|
cinfo->primaries = p;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* gst_video_colorimetry_to_string:
|
|
* @cinfo: a #GstVideoColorimetry
|
|
*
|
|
* Make a string representation of @cinfo.
|
|
*
|
|
* Returns: a string representation of @cinfo.
|
|
*/
|
|
gchar *
|
|
gst_video_colorimetry_to_string (GstVideoColorimetry * cinfo)
|
|
{
|
|
gint i;
|
|
|
|
for (i = 0; colorimetry[i].name; i++) {
|
|
if (IS_EQUAL (&colorimetry[i], cinfo)) {
|
|
return g_strdup (colorimetry[i].name);
|
|
}
|
|
}
|
|
if (!IS_UNKNOWN (cinfo)) {
|
|
return g_strdup_printf ("%d:%d:%d:%d", cinfo->range, cinfo->matrix,
|
|
cinfo->transfer, cinfo->primaries);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* gst_video_colorimetry_matches:
|
|
* @cinfo: a #GstVideoInfo
|
|
* @color: a colorimetry string
|
|
*
|
|
* Check if the colorimetry information in @info matches that of the
|
|
* string @color.
|
|
*
|
|
* Returns: #TRUE if @color conveys the same colorimetry info as the color
|
|
* information in @info.
|
|
*/
|
|
gboolean
|
|
gst_video_colorimetry_matches (GstVideoColorimetry * cinfo, const gchar * color)
|
|
{
|
|
const ColorimetryInfo *ci;
|
|
|
|
if ((ci = gst_video_get_colorimetry (color)))
|
|
return IS_EQUAL (ci, cinfo);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* gst_video_color_range_offsets:
|
|
* @range: a #GstVideoColorRange
|
|
* @info: a #GstVideoFormatInfo
|
|
* @offset: (out): output offsets
|
|
* @scale: (out): output scale
|
|
*
|
|
* Compute the offset and scale values for each component of @info. For each
|
|
* component, (c[i] - offset[i]) / scale[i] will scale the component c[i] to the
|
|
* range [0.0 .. 1.0].
|
|
*
|
|
* The reverse operation (c[i] * scale[i]) + offset[i] can be used to convert
|
|
* the component values in range [0.0 .. 1.0] back to their representation in
|
|
* @info and @range.
|
|
*/
|
|
void
|
|
gst_video_color_range_offsets (GstVideoColorRange range,
|
|
const GstVideoFormatInfo * info, gint offset[GST_VIDEO_MAX_COMPONENTS],
|
|
gint scale[GST_VIDEO_MAX_COMPONENTS])
|
|
{
|
|
gboolean yuv;
|
|
|
|
yuv = GST_VIDEO_FORMAT_INFO_IS_YUV (info);
|
|
|
|
switch (range) {
|
|
default:
|
|
case GST_VIDEO_COLOR_RANGE_0_255:
|
|
offset[0] = 0;
|
|
if (yuv) {
|
|
offset[1] = 1 << (info->depth[1] - 1);
|
|
offset[2] = 1 << (info->depth[2] - 1);
|
|
} else {
|
|
offset[1] = 0;
|
|
offset[2] = 0;
|
|
}
|
|
scale[0] = (1 << info->depth[0]) - 1;
|
|
scale[1] = (1 << info->depth[1]) - 1;
|
|
scale[2] = (1 << info->depth[2]) - 1;
|
|
break;
|
|
case GST_VIDEO_COLOR_RANGE_16_235:
|
|
offset[0] = 1 << (info->depth[0] - 4);
|
|
scale[0] = 219 << (info->depth[0] - 8);
|
|
if (yuv) {
|
|
offset[1] = 1 << (info->depth[1] - 1);
|
|
offset[2] = 1 << (info->depth[2] - 1);
|
|
scale[1] = 224 << (info->depth[1] - 8);
|
|
scale[2] = 224 << (info->depth[2] - 8);
|
|
} else {
|
|
offset[1] = 1 << (info->depth[1] - 4);
|
|
offset[2] = 1 << (info->depth[2] - 4);
|
|
scale[1] = 219 << (info->depth[1] - 8);
|
|
scale[2] = 219 << (info->depth[2] - 8);
|
|
}
|
|
break;
|
|
}
|
|
/* alpha channel is always full range */
|
|
offset[3] = 0;
|
|
scale[3] = (1 << info->depth[3]) - 1;
|
|
|
|
GST_DEBUG ("scale: %d %d %d %d", scale[0], scale[1], scale[2], scale[3]);
|
|
GST_DEBUG ("offset: %d %d %d %d", offset[0], offset[1], offset[2], offset[3]);
|
|
}
|
|
|
|
|
|
#if 0
|
|
typedef struct
|
|
{
|
|
GstVideoColorPrimaries primaries;
|
|
gdouble xW, yW;
|
|
gdouble xR, yR;
|
|
gdouble xG, yG;
|
|
gdouble xB, yB;
|
|
} PrimariesInfo;
|
|
|
|
#define WP_C 0.31006, 0.31616
|
|
#define WP_D65 0.31271, 0.32902
|
|
|
|
static const PrimariesInfo primaries[] = {
|
|
{GST_VIDEO_COLOR_PRIMARIES_UNKNOWN, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
|
{GST_VIDEO_COLOR_PRIMARIES_BT709, WP_D65, 0.64, 0.33, 0.30, 0.60, 0.15, 0.06},
|
|
{GST_VIDEO_COLOR_PRIMARIES_BT470M, WP_C, 0.67, 0.33, 0.21, 0.71, 0.14, 0.08},
|
|
{GST_VIDEO_COLOR_PRIMARIES_BT470BG, WP_D65, 0.64, 0.33, 0.29, 0.60, 0.15,
|
|
0.06},
|
|
{GST_VIDEO_COLOR_PRIMARIES_SMPTE170M, WP_D65, 0.63, 0.34, 0.31, 0.595, 0.155,
|
|
0.07},
|
|
{GST_VIDEO_COLOR_PRIMARIES_SMPTE240M, WP_D65, 0.63, 0.34, 0.31, 0.595, 0.155,
|
|
0.07},
|
|
{GST_VIDEO_COLOR_PRIMARIES_FILM, WP_C, 0.681, 0.319, 0.243, 0.692, 0.145,
|
|
0.049}
|
|
};
|
|
#endif
|
|
|
|
/**
|
|
* gst_video_color_matrix_get_Kr_Kb:
|
|
* @matrix: a #GstVideoColorMatrix
|
|
* @Kr: result red channel coefficient
|
|
* @Kb: result blue channel coefficient
|
|
*
|
|
* Get the coefficients used to convert between Y'PbPr and R'G'B' using @matrix.
|
|
*
|
|
* When:
|
|
*
|
|
* |[
|
|
* 0.0 <= [Y',R',G',B'] <= 1.0)
|
|
* (-0.5 <= [Pb,Pr] <= 0.5)
|
|
* ]|
|
|
*
|
|
* the general conversion is given by:
|
|
*
|
|
* |[
|
|
* Y' = Kr*R' + (1-Kr-Kb)*G' + Kb*B'
|
|
* Pb = (B'-Y')/(2*(1-Kb))
|
|
* Pr = (R'-Y')/(2*(1-Kr))
|
|
* ]|
|
|
*
|
|
* and the other way around:
|
|
*
|
|
* |[
|
|
* R' = Y' + Cr*2*(1-Kr)
|
|
* G' = Y' - Cb*2*(1-Kb)*Kb/(1-Kr-Kb) - Cr*2*(1-Kr)*Kr/(1-Kr-Kb)
|
|
* B' = Y' + Cb*2*(1-Kb)
|
|
* ]|
|
|
*
|
|
* Returns: TRUE if @matrix was a YUV color format and @Kr and @Kb contain valid
|
|
* values.
|
|
*
|
|
* Since: 1.6
|
|
*/
|
|
gboolean
|
|
gst_video_color_matrix_get_Kr_Kb (GstVideoColorMatrix matrix, gdouble * Kr,
|
|
gdouble * Kb)
|
|
{
|
|
gboolean res = TRUE;
|
|
|
|
switch (matrix) {
|
|
/* RGB */
|
|
default:
|
|
case GST_VIDEO_COLOR_MATRIX_RGB:
|
|
res = FALSE;
|
|
break;
|
|
/* YUV */
|
|
case GST_VIDEO_COLOR_MATRIX_FCC:
|
|
*Kr = 0.30;
|
|
*Kb = 0.11;
|
|
break;
|
|
case GST_VIDEO_COLOR_MATRIX_BT709:
|
|
*Kr = 0.2126;
|
|
*Kb = 0.0722;
|
|
break;
|
|
case GST_VIDEO_COLOR_MATRIX_BT601:
|
|
*Kr = 0.2990;
|
|
*Kb = 0.1140;
|
|
break;
|
|
case GST_VIDEO_COLOR_MATRIX_SMPTE240M:
|
|
*Kr = 0.212;
|
|
*Kb = 0.087;
|
|
break;
|
|
}
|
|
GST_DEBUG ("matrix: %d, Kr %f, Kb %f", matrix, *Kr, *Kb);
|
|
|
|
return res;
|
|
}
|