video: fix some GIR annotations
[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 #include <math.h>
29
30 #include "video-color.h"
31
32 #ifndef GST_DISABLE_GST_DEBUG
33 #define GST_CAT_DEFAULT ensure_debug_category()
34 static GstDebugCategory *
35 ensure_debug_category (void)
36 {
37   static gsize cat_gonce = 0;
38
39   if (g_once_init_enter (&cat_gonce)) {
40     gsize cat_done;
41
42     cat_done = (gsize) _gst_debug_category_new ("video-color", 0,
43         "video-color object");
44
45     g_once_init_leave (&cat_gonce, cat_done);
46   }
47
48   return (GstDebugCategory *) cat_gonce;
49 }
50 #else
51 #define ensure_debug_category() /* NOOP */
52 #endif /* GST_DISABLE_GST_DEBUG */
53
54 typedef struct
55 {
56   const gchar *name;
57   GstVideoColorimetry color;
58 } ColorimetryInfo;
59
60 #define MAKE_COLORIMETRY(n,r,m,t,p) { GST_VIDEO_COLORIMETRY_ ##n, \
61   { GST_VIDEO_COLOR_RANGE ##r, GST_VIDEO_COLOR_MATRIX_ ##m, \
62   GST_VIDEO_TRANSFER_ ##t, GST_VIDEO_COLOR_PRIMARIES_ ##p } }
63
64 #define GST_VIDEO_COLORIMETRY_NONAME  NULL
65
66 #define DEFAULT_YUV_SD  0
67 #define DEFAULT_YUV_HD  1
68 #define DEFAULT_RGB     3
69 #define DEFAULT_YUV_UHD 4
70 #define DEFAULT_GRAY    5
71 #define DEFAULT_UNKNOWN 6
72
73 static const ColorimetryInfo colorimetry[] = {
74   MAKE_COLORIMETRY (BT601, _16_235, BT601, BT709, SMPTE170M),
75   MAKE_COLORIMETRY (BT709, _16_235, BT709, BT709, BT709),
76   MAKE_COLORIMETRY (SMPTE240M, _16_235, SMPTE240M, SMPTE240M, SMPTE240M),
77   MAKE_COLORIMETRY (SRGB, _0_255, RGB, SRGB, BT709),
78   MAKE_COLORIMETRY (BT2020, _16_235, BT2020, BT2020_12, BT2020),
79   MAKE_COLORIMETRY (NONAME, _0_255, BT601, UNKNOWN, UNKNOWN),
80   MAKE_COLORIMETRY (NONAME, _UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN),
81 };
82
83 static const ColorimetryInfo *
84 gst_video_get_colorimetry (const gchar * s)
85 {
86   gint i;
87
88   for (i = 0; colorimetry[i].name; i++) {
89     if (g_str_equal (colorimetry[i].name, s))
90       return &colorimetry[i];
91   }
92   return NULL;
93 }
94
95 #define CI_IS_EQUAL(ci,i) (((ci)->range == (i)->range) && \
96                         ((ci)->matrix == (i)->matrix) && \
97                         ((ci)->transfer == (i)->transfer) && \
98                         ((ci)->primaries == (i)->primaries))
99
100 #define IS_EQUAL(ci,i) CI_IS_EQUAL(&(ci)->color, (i))
101
102 #define IS_UNKNOWN(ci) (IS_EQUAL (&colorimetry[DEFAULT_UNKNOWN], ci))
103
104 /**
105  * gst_video_colorimetry_from_string:
106  * @cinfo: a #GstVideoColorimetry
107  * @color: a colorimetry string
108  *
109  * Parse the colorimetry string and update @cinfo with the parsed
110  * values.
111  *
112  * Returns: %TRUE if @color points to valid colorimetry info.
113  */
114 gboolean
115 gst_video_colorimetry_from_string (GstVideoColorimetry * cinfo,
116     const gchar * color)
117 {
118   const ColorimetryInfo *ci;
119   gboolean res = FALSE;
120
121   if ((ci = gst_video_get_colorimetry (color))) {
122     *cinfo = ci->color;
123     res = TRUE;
124   } else {
125     gint r, m, t, p;
126
127     if (sscanf (color, "%d:%d:%d:%d", &r, &m, &t, &p) == 4) {
128       cinfo->range = r;
129       cinfo->matrix = m;
130       cinfo->transfer = t;
131       cinfo->primaries = p;
132       res = TRUE;
133     }
134   }
135   return res;
136 }
137
138 /**
139  * gst_video_colorimetry_to_string:
140  * @cinfo: a #GstVideoColorimetry
141  *
142  * Make a string representation of @cinfo.
143  *
144  * Returns: a string representation of @cinfo.
145  */
146 gchar *
147 gst_video_colorimetry_to_string (const GstVideoColorimetry * cinfo)
148 {
149   gint i;
150
151   for (i = 0; colorimetry[i].name; i++) {
152     if (IS_EQUAL (&colorimetry[i], cinfo)) {
153       return g_strdup (colorimetry[i].name);
154     }
155   }
156   if (!IS_UNKNOWN (cinfo)) {
157     return g_strdup_printf ("%d:%d:%d:%d", cinfo->range, cinfo->matrix,
158         cinfo->transfer, cinfo->primaries);
159   }
160   return NULL;
161 }
162
163 /**
164  * gst_video_colorimetry_matches:
165  * @cinfo: a #GstVideoInfo
166  * @color: a colorimetry string
167  *
168  * Check if the colorimetry information in @info matches that of the
169  * string @color.
170  *
171  * Returns: %TRUE if @color conveys the same colorimetry info as the color
172  * information in @info.
173  */
174 gboolean
175 gst_video_colorimetry_matches (const GstVideoColorimetry * cinfo,
176     const gchar * color)
177 {
178   const ColorimetryInfo *ci;
179
180   if ((ci = gst_video_get_colorimetry (color)))
181     return IS_EQUAL (ci, cinfo);
182
183   return FALSE;
184 }
185
186 /**
187  * gst_video_color_range_offsets:
188  * @range: a #GstVideoColorRange
189  * @info: a #GstVideoFormatInfo
190  * @offset: (out) (array fixed-size=4): output offsets
191  * @scale: (out) (array fixed-size=4): output scale
192  *
193  * Compute the offset and scale values for each component of @info. For each
194  * component, (c[i] - offset[i]) / scale[i] will scale the component c[i] to the
195  * range [0.0 .. 1.0].
196  *
197  * The reverse operation (c[i] * scale[i]) + offset[i] can be used to convert
198  * the component values in range [0.0 .. 1.0] back to their representation in
199  * @info and @range.
200  */
201 void
202 gst_video_color_range_offsets (GstVideoColorRange range,
203     const GstVideoFormatInfo * info, gint offset[GST_VIDEO_MAX_COMPONENTS],
204     gint scale[GST_VIDEO_MAX_COMPONENTS])
205 {
206   gboolean yuv;
207
208   yuv = GST_VIDEO_FORMAT_INFO_IS_YUV (info);
209
210   switch (range) {
211     default:
212     case GST_VIDEO_COLOR_RANGE_0_255:
213       offset[0] = 0;
214       if (yuv) {
215         offset[1] = 1 << (info->depth[1] - 1);
216         offset[2] = 1 << (info->depth[2] - 1);
217       } else {
218         offset[1] = 0;
219         offset[2] = 0;
220       }
221       scale[0] = (1 << info->depth[0]) - 1;
222       scale[1] = (1 << info->depth[1]) - 1;
223       scale[2] = (1 << info->depth[2]) - 1;
224       break;
225     case GST_VIDEO_COLOR_RANGE_16_235:
226       offset[0] = 1 << (info->depth[0] - 4);
227       scale[0] = 219 << (info->depth[0] - 8);
228       if (yuv) {
229         offset[1] = 1 << (info->depth[1] - 1);
230         offset[2] = 1 << (info->depth[2] - 1);
231         scale[1] = 224 << (info->depth[1] - 8);
232         scale[2] = 224 << (info->depth[2] - 8);
233       } else {
234         offset[1] = 1 << (info->depth[1] - 4);
235         offset[2] = 1 << (info->depth[2] - 4);
236         scale[1] = 219 << (info->depth[1] - 8);
237         scale[2] = 219 << (info->depth[2] - 8);
238       }
239       break;
240   }
241   /* alpha channel is always full range */
242   offset[3] = 0;
243   scale[3] = (1 << info->depth[3]) - 1;
244
245   GST_DEBUG ("scale: %d %d %d %d", scale[0], scale[1], scale[2], scale[3]);
246   GST_DEBUG ("offset: %d %d %d %d", offset[0], offset[1], offset[2], offset[3]);
247 }
248
249 /**
250  * gst_video_colorimetry_is_equal:
251  * @cinfo: a #GstVideoColorimetry
252  * @other: another #GstVideoColorimetry
253  *
254  * Compare the 2 colorimetry sets for equality
255  *
256  * Returns: %TRUE if @cinfo and @other are equal.
257  *
258  * Since: 1.6
259  */
260 gboolean
261 gst_video_colorimetry_is_equal (const GstVideoColorimetry * cinfo,
262     const GstVideoColorimetry * other)
263 {
264   g_return_val_if_fail (cinfo != NULL, FALSE);
265   g_return_val_if_fail (other != NULL, FALSE);
266
267   return CI_IS_EQUAL (cinfo, other);
268 }
269
270 #define WP_C    0.31006, 0.31616
271 #define WP_D65  0.31271, 0.32902
272
273 static const GstVideoColorPrimariesInfo color_primaries[] = {
274   {GST_VIDEO_COLOR_PRIMARIES_UNKNOWN, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
275   {GST_VIDEO_COLOR_PRIMARIES_BT709, WP_D65, 0.64, 0.33, 0.30, 0.60, 0.15, 0.06},
276   {GST_VIDEO_COLOR_PRIMARIES_BT470M, WP_C, 0.67, 0.33, 0.21, 0.71, 0.14, 0.08},
277   {GST_VIDEO_COLOR_PRIMARIES_BT470BG, WP_D65, 0.64, 0.33, 0.29, 0.60, 0.15,
278       0.06},
279   {GST_VIDEO_COLOR_PRIMARIES_SMPTE170M, WP_D65, 0.63, 0.34, 0.31, 0.595, 0.155,
280       0.07},
281   {GST_VIDEO_COLOR_PRIMARIES_SMPTE240M, WP_D65, 0.63, 0.34, 0.31, 0.595, 0.155,
282       0.07},
283   {GST_VIDEO_COLOR_PRIMARIES_FILM, WP_C, 0.681, 0.319, 0.243, 0.692, 0.145,
284       0.049},
285   {GST_VIDEO_COLOR_PRIMARIES_BT2020, WP_D65, 0.708, 0.292, 0.170, 0.797, 0.131,
286       0.046},
287   {GST_VIDEO_COLOR_PRIMARIES_ADOBERGB, WP_D65, 0.64, 0.33, 0.21, 0.71, 0.15,
288       0.06}
289 };
290
291 /**
292  * gst_video_color_primaries_get_info:
293  * @primaries: a #GstVideoColorPrimaries
294  *
295  * Get information about the chromaticity coordinates of @primaries.
296  *
297  * Returns: a #GstVideoColorPrimariesInfo for @primaries.
298  *
299  * Since: 1.6
300  */
301 const GstVideoColorPrimariesInfo *
302 gst_video_color_primaries_get_info (GstVideoColorPrimaries primaries)
303 {
304   g_return_val_if_fail ((gint) primaries <
305       G_N_ELEMENTS (color_primaries), NULL);
306
307   return &color_primaries[primaries];
308 }
309
310 /**
311  * gst_video_color_matrix_get_Kr_Kb:
312  * @matrix: a #GstVideoColorMatrix
313  * @Kr: (out): result red channel coefficient
314  * @Kb: (out): result blue channel coefficient
315  *
316  * Get the coefficients used to convert between Y'PbPr and R'G'B' using @matrix.
317  *
318  * When:
319  *
320  * |[
321  *   0.0 <= [Y',R',G',B'] <= 1.0)
322  *   (-0.5 <= [Pb,Pr] <= 0.5)
323  * ]|
324  *
325  * the general conversion is given by:
326  *
327  * |[
328  *   Y' = Kr*R' + (1-Kr-Kb)*G' + Kb*B'
329  *   Pb = (B'-Y')/(2*(1-Kb))
330  *   Pr = (R'-Y')/(2*(1-Kr))
331  * ]|
332  *
333  * and the other way around:
334  *
335  * |[
336  *   R' = Y' + Cr*2*(1-Kr)
337  *   G' = Y' - Cb*2*(1-Kb)*Kb/(1-Kr-Kb) - Cr*2*(1-Kr)*Kr/(1-Kr-Kb)
338  *   B' = Y' + Cb*2*(1-Kb)
339  * ]|
340  *
341  * Returns: TRUE if @matrix was a YUV color format and @Kr and @Kb contain valid
342  *    values.
343  *
344  * Since: 1.6
345  */
346 gboolean
347 gst_video_color_matrix_get_Kr_Kb (GstVideoColorMatrix matrix, gdouble * Kr,
348     gdouble * Kb)
349 {
350   gboolean res = TRUE;
351
352   switch (matrix) {
353       /* RGB */
354     default:
355     case GST_VIDEO_COLOR_MATRIX_RGB:
356       res = FALSE;
357       break;
358       /* YUV */
359     case GST_VIDEO_COLOR_MATRIX_FCC:
360       *Kr = 0.30;
361       *Kb = 0.11;
362       break;
363     case GST_VIDEO_COLOR_MATRIX_BT709:
364       *Kr = 0.2126;
365       *Kb = 0.0722;
366       break;
367     case GST_VIDEO_COLOR_MATRIX_BT601:
368       *Kr = 0.2990;
369       *Kb = 0.1140;
370       break;
371     case GST_VIDEO_COLOR_MATRIX_SMPTE240M:
372       *Kr = 0.212;
373       *Kb = 0.087;
374       break;
375     case GST_VIDEO_COLOR_MATRIX_BT2020:
376       *Kr = 0.2627;
377       *Kb = 0.0593;
378       break;
379   }
380   GST_DEBUG ("matrix: %d, Kr %f, Kb %f", matrix, *Kr, *Kb);
381
382   return res;
383 }
384
385 /**
386  * gst_video_color_transfer_encode:
387  * @func: a #GstVideoTransferFunction
388  * @val: a value
389  *
390  * Convert @val to its gamma encoded value.
391  *
392  * For a linear value L in the range [0..1], conversion to the non-linear
393  * (gamma encoded) L' is in general performed with a power function like:
394  *
395  * |[
396  *    L' = L ^ (1 / gamma)
397  * ]|
398  *
399  * Depending on @func, different formulas might be applied. Some formulas
400  * encode a linear segment in the lower range.
401  *
402  * Returns: the gamme encoded value of @val
403  *
404  * Since: 1.6
405  */
406 gdouble
407 gst_video_color_transfer_encode (GstVideoTransferFunction func, gdouble val)
408 {
409   gdouble res;
410
411   switch (func) {
412     case GST_VIDEO_TRANSFER_UNKNOWN:
413     case GST_VIDEO_TRANSFER_GAMMA10:
414     default:
415       res = val;
416       break;
417     case GST_VIDEO_TRANSFER_GAMMA18:
418       res = pow (val, 1.0 / 1.8);
419       break;
420     case GST_VIDEO_TRANSFER_GAMMA20:
421       res = pow (val, 1.0 / 2.0);
422       break;
423     case GST_VIDEO_TRANSFER_GAMMA22:
424       res = pow (val, 1.0 / 2.2);
425       break;
426     case GST_VIDEO_TRANSFER_BT709:
427       if (val < 0.018)
428         res = 4.5 * val;
429       else
430         res = 1.099 * pow (val, 0.45) - 0.099;
431       break;
432     case GST_VIDEO_TRANSFER_SMPTE240M:
433       if (val < 0.0228)
434         res = val * 4.0;
435       else
436         res = 1.1115 * pow (val, 0.45) - 0.1115;
437       break;
438     case GST_VIDEO_TRANSFER_SRGB:
439       if (val <= 0.0031308)
440         res = 12.92 * val;
441       else
442         res = 1.055 * pow (val, 1.0 / 2.4) - 0.055;
443       break;
444     case GST_VIDEO_TRANSFER_GAMMA28:
445       res = pow (val, 1 / 2.8);
446       break;
447     case GST_VIDEO_TRANSFER_LOG100:
448       if (val < 0.01)
449         res = 0.0;
450       else
451         res = 1.0 + log10 (val) / 2.0;
452       break;
453     case GST_VIDEO_TRANSFER_LOG316:
454       if (val < 0.0031622777)
455         res = 0.0;
456       else
457         res = 1.0 + log10 (val) / 2.5;
458       break;
459     case GST_VIDEO_TRANSFER_BT2020_12:
460       if (val < 0.0181)
461         res = 4.5 * val;
462       else
463         res = 1.0993 * pow (val, 0.45) - 0.0993;
464       break;
465     case GST_VIDEO_TRANSFER_ADOBERGB:
466       res = pow (val, 1.0 / 2.19921875);
467       break;
468   }
469   return res;
470 }
471
472 /**
473  * gst_video_color_transfer_decode:
474  * @func: a #GstVideoTransferFunction
475  * @val: a value
476  *
477  * Convert @val to its gamma decoded value. This is the inverse operation of
478  * @gst_video_color_transfer_encode().
479  *
480  * For a non-linear value L' in the range [0..1], conversion to the linear
481  * L is in general performed with a power function like:
482  *
483  * |[
484  *    L = L' ^ gamma
485  * ]|
486  *
487  * Depending on @func, different formulas might be applied. Some formulas
488  * encode a linear segment in the lower range.
489  *
490  * Returns: the gamme decoded value of @val
491  *
492  * Since: 1.6
493  */
494 gdouble
495 gst_video_color_transfer_decode (GstVideoTransferFunction func, gdouble val)
496 {
497   gdouble res;
498
499   switch (func) {
500     case GST_VIDEO_TRANSFER_UNKNOWN:
501     case GST_VIDEO_TRANSFER_GAMMA10:
502     default:
503       res = val;
504       break;
505     case GST_VIDEO_TRANSFER_GAMMA18:
506       res = pow (val, 1.8);
507       break;
508     case GST_VIDEO_TRANSFER_GAMMA20:
509       res = pow (val, 2.0);
510       break;
511     case GST_VIDEO_TRANSFER_GAMMA22:
512       res = pow (val, 2.2);
513       break;
514     case GST_VIDEO_TRANSFER_BT709:
515       if (val < 0.081)
516         res = val / 4.5;
517       else
518         res = pow ((val + 0.099) / 1.099, 1.0 / 0.45);
519       break;
520     case GST_VIDEO_TRANSFER_SMPTE240M:
521       if (val < 0.0913)
522         res = val / 4.0;
523       else
524         res = pow ((val + 0.1115) / 1.1115, 1.0 / 0.45);
525       break;
526     case GST_VIDEO_TRANSFER_SRGB:
527       if (val <= 0.04045)
528         res = val / 12.92;
529       else
530         res = pow ((val + 0.055) / 1.055, 2.4);
531       break;
532     case GST_VIDEO_TRANSFER_GAMMA28:
533       res = pow (val, 2.8);
534       break;
535     case GST_VIDEO_TRANSFER_LOG100:
536       if (val == 0.0)
537         res = 0.0;
538       else
539         res = pow (10.0, 2.0 * (val - 1.0));
540       break;
541     case GST_VIDEO_TRANSFER_LOG316:
542       if (val == 0.0)
543         res = 0.0;
544       else
545         res = pow (10.0, 2.5 * (val - 1.0));
546       break;
547     case GST_VIDEO_TRANSFER_BT2020_12:
548       if (val < 0.08145)
549         res = val / 4.5;
550       else
551         res = pow ((val + 0.0993) / 1.0993, 1.0 / 0.45);
552       break;
553     case GST_VIDEO_TRANSFER_ADOBERGB:
554       res = pow (val, 2.19921875);
555       break;
556   }
557   return res;
558 }