Fix FSF address
[platform/upstream/gstreamer.git] / gst-libs / gst / video / video-color.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  * Library       <2002> Ronald Bultje <rbultje@ronald.bitfreak.net>
4  * Copyright (C) 2007 David A. Schleef <ds@schleef.org>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #  include "config.h"
24 #endif
25
26 #include <string.h>
27 #include <stdio.h>
28
29 #include "video-color.h"
30
31 typedef struct
32 {
33   const gchar *name;
34   GstVideoColorimetry color;
35 } ColorimetryInfo;
36
37 #define MAKE_COLORIMETRY(n,r,m,t,p) { GST_VIDEO_COLORIMETRY_ ##n, \
38   { GST_VIDEO_COLOR_RANGE ##r, GST_VIDEO_COLOR_MATRIX_ ##m, \
39   GST_VIDEO_TRANSFER_ ##t, GST_VIDEO_COLOR_PRIMARIES_ ##p } }
40
41 #define GST_VIDEO_COLORIMETRY_NONAME  NULL
42
43 #define DEFAULT_YUV_SD  0
44 #define DEFAULT_YUV_HD  1
45 #define DEFAULT_RGB     3
46 #define DEFAULT_GRAY    4
47 #define DEFAULT_UNKNOWN 5
48
49 static const ColorimetryInfo colorimetry[] = {
50   MAKE_COLORIMETRY (BT601, _16_235, BT601, BT709, BT470M),
51   MAKE_COLORIMETRY (BT709, _16_235, BT709, BT709, BT709),
52   MAKE_COLORIMETRY (SMPTE240M, _16_235, SMPTE240M, SMPTE240M, SMPTE240M),
53   MAKE_COLORIMETRY (NONAME, _0_255, RGB, UNKNOWN, UNKNOWN),
54   MAKE_COLORIMETRY (NONAME, _0_255, BT601, UNKNOWN, UNKNOWN),
55   MAKE_COLORIMETRY (NONAME, _UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN),
56 };
57
58 static const ColorimetryInfo *
59 gst_video_get_colorimetry (const gchar * s)
60 {
61   gint i;
62
63   for (i = 0; colorimetry[i].name; i++) {
64     if (g_str_equal (colorimetry[i].name, s))
65       return &colorimetry[i];
66   }
67   return NULL;
68 }
69
70 #define IS_EQUAL(ci,i) (((ci)->color.range == (i)->range) && \
71                         ((ci)->color.matrix == (i)->matrix) && \
72                         ((ci)->color.transfer == (i)->transfer) && \
73                         ((ci)->color.primaries == (i)->primaries))
74
75 #define IS_UNKNOWN(ci) (IS_EQUAL (&colorimetry[DEFAULT_UNKNOWN], ci))
76
77 /**
78  * gst_video_colorimetry_from_string:
79  * @cinfo: a #GstVideoColorimetry
80  * @color: a colorimetry string
81  *
82  * Parse the colorimetry string and update @cinfo with the parsed
83  * values.
84  *
85  * Returns: #TRUE if @color points to valid colorimetry info.
86  */
87 gboolean
88 gst_video_colorimetry_from_string (GstVideoColorimetry * cinfo,
89     const gchar * color)
90 {
91   const ColorimetryInfo *ci;
92
93   if ((ci = gst_video_get_colorimetry (color))) {
94     *cinfo = ci->color;
95   } else {
96     gint r, m, t, p;
97
98     if (sscanf (color, "%d:%d:%d:%d", &r, &m, &t, &p) == 4) {
99       cinfo->range = r;
100       cinfo->matrix = m;
101       cinfo->transfer = t;
102       cinfo->primaries = p;
103     }
104   }
105   return TRUE;
106 }
107
108 /**
109  * gst_video_colorimetry_to_string:
110  * @cinfo: a #GstVideoColorimetry
111  *
112  * Make a string representation of @cinfo.
113  *
114  * Returns: a string representation of @cinfo.
115  */
116 gchar *
117 gst_video_colorimetry_to_string (GstVideoColorimetry * cinfo)
118 {
119   gint i;
120
121   for (i = 0; colorimetry[i].name; i++) {
122     if (IS_EQUAL (&colorimetry[i], cinfo)) {
123       return g_strdup (colorimetry[i].name);
124     }
125   }
126   if (!IS_UNKNOWN (cinfo)) {
127     return g_strdup_printf ("%d:%d:%d:%d", cinfo->range, cinfo->matrix,
128         cinfo->transfer, cinfo->primaries);
129   }
130   return NULL;
131 }
132
133 /**
134  * gst_video_colorimetry_matches:
135  * @info: a #GstVideoInfo
136  * @color: a colorimetry string
137  *
138  * Check if the colorimetry information in @info matches that of the
139  * string @color.
140  *
141  * Returns: #TRUE if @color conveys the same colorimetry info as the color
142  * information in @info.
143  */
144 gboolean
145 gst_video_colorimetry_matches (GstVideoColorimetry * cinfo, const gchar * color)
146 {
147   const ColorimetryInfo *ci;
148
149   if ((ci = gst_video_get_colorimetry (color)))
150     return IS_EQUAL (ci, cinfo);
151
152   return FALSE;
153 }
154
155 /**
156  * gst_video_color_range_offsets:
157  * @range: a #GstVideoColorRange
158  * @info: a #GstVideoFormatInfo
159  * @offsets: (out): output offsets
160  * @scale: (out): output scale
161  *
162  * Compute the offset and scale values for each component of @info. For each
163  * component, (c[i] - offset[i]) / scale[i] will scale the component c[i] to the
164  * range [0.0 .. 1.0].
165  *
166  * The reverse operation (c[i] * scale[i]) + offset[i] can be used to convert
167  * the component values in range [0.0 .. 1.0] back to their representation in
168  * @info and @range.
169  */
170 void
171 gst_video_color_range_offsets (GstVideoColorRange range,
172     const GstVideoFormatInfo * info, gint offset[GST_VIDEO_MAX_COMPONENTS],
173     gint scale[GST_VIDEO_MAX_COMPONENTS])
174 {
175   gboolean yuv;
176
177   yuv = GST_VIDEO_FORMAT_INFO_IS_YUV (info);
178
179   switch (range) {
180     default:
181     case GST_VIDEO_COLOR_RANGE_0_255:
182       offset[0] = 0;
183       if (yuv) {
184         offset[1] = 1 << (info->depth[1] - 1);
185         offset[2] = 1 << (info->depth[2] - 1);
186       } else {
187         offset[1] = 0;
188         offset[2] = 0;
189       }
190       scale[0] = (1 << info->depth[0]) - 1;
191       scale[1] = (1 << info->depth[1]) - 1;
192       scale[2] = (1 << info->depth[2]) - 1;
193       break;
194     case GST_VIDEO_COLOR_RANGE_16_235:
195       offset[0] = 1 << (info->depth[0] - 4);
196       scale[0] = 219 << (info->depth[0] - 8);
197       if (yuv) {
198         offset[1] = 1 << (info->depth[1] - 1);
199         offset[2] = 1 << (info->depth[2] - 1);
200         scale[1] = 224 << (info->depth[1] - 8);
201         scale[2] = 224 << (info->depth[2] - 8);
202       } else {
203         offset[1] = 1 << (info->depth[1] - 4);
204         offset[2] = 1 << (info->depth[2] - 4);
205         scale[1] = 219 << (info->depth[1] - 8);
206         scale[2] = 219 << (info->depth[2] - 8);
207       }
208       break;
209   }
210   /* alpha channel is always full range */
211   offset[3] = 0;
212   scale[3] = (1 << info->depth[3]) - 1;
213
214   GST_DEBUG ("scale: %d %d %d %d", scale[0], scale[1], scale[2], scale[3]);
215   GST_DEBUG ("offset: %d %d %d %d", offset[0], offset[1], offset[2], offset[3]);
216 }
217
218
219 #if 0
220 typedef struct
221 {
222   GstVideoColorPrimaries primaries;
223   gdouble xW, yW;
224   gdouble xR, yR;
225   gdouble xG, yG;
226   gdouble xB, yB;
227 } PrimariesInfo;
228
229 #define WP_C    0.31006, 0.31616
230 #define WP_D65  0.31271, 0.32902
231
232 static const PrimariesInfo primaries[] = {
233   {GST_VIDEO_COLOR_PRIMARIES_UNKNOWN, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
234   {GST_VIDEO_COLOR_PRIMARIES_BT709, WP_D65, 0.64, 0.33, 0.30, 0.60, 0.15, 0.06},
235   {GST_VIDEO_COLOR_PRIMARIES_BT470M, WP_C, 0.67, 0.33, 0.21, 0.71, 0.14, 0.08},
236   {GST_VIDEO_COLOR_PRIMARIES_BT470BG, WP_D65, 0.64, 0.33, 0.29, 0.60, 0.15,
237       0.06},
238   {GST_VIDEO_COLOR_PRIMARIES_SMPTE170M, WP_D65, 0.63, 0.34, 0.31, 0.595, 0.155,
239       0.07},
240   {GST_VIDEO_COLOR_PRIMARIES_SMPTE240M, WP_D65, 0.63, 0.34, 0.31, 0.595, 0.155,
241       0.07},
242   {GST_VIDEO_COLOR_PRIMARIES_FILM, WP_C, 0.681, 0.319, 0.243, 0.692, 0.145,
243       0.049}
244 };
245 #endif