videoaggregator: Create a new GstVideoAggregator baseclass
[platform/upstream/gstreamer.git] / gst-libs / gst / video / gstcms.c
1 /* GStreamer
2  * Copyright (C) 2008 David Schleef <ds@entropywave.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <gst/gst.h>
25 #include <gst/math-compat.h>
26 #include "gstcms.h"
27
28 #include <stdio.h>
29 #include <string.h>
30 #include <math.h>
31
32
33 /* our simple CMS */
34
35 void
36 color_xyY_to_XYZ (Color * c)
37 {
38   if (c->v[1] == 0) {
39     c->v[0] = 0;
40     c->v[1] = 0;
41     c->v[2] = 0;
42   } else {
43     double X, Y, Z;
44     X = c->v[0] * c->v[2] / c->v[1];
45     Y = c->v[2];
46     Z = (1.0 - c->v[0] - c->v[1]) * c->v[2] / c->v[1];
47     c->v[0] = X;
48     c->v[1] = Y;
49     c->v[2] = Z;
50   }
51 }
52
53 void
54 color_XYZ_to_xyY (Color * c)
55 {
56   double d;
57   d = c->v[0] + c->v[1] + c->v[2];
58   if (d == 0) {
59     c->v[0] = 0.3128;
60     c->v[1] = 0.3290;
61     c->v[2] = 0;
62   } else {
63     double x, y, Y;
64     x = c->v[0] / d;
65     y = c->v[1] / d;
66     Y = c->v[1];
67     c->v[0] = x;
68     c->v[1] = y;
69     c->v[2] = Y;
70   }
71 }
72
73 void
74 color_set (Color * c, double x, double y, double z)
75 {
76   c->v[0] = x;
77   c->v[1] = y;
78   c->v[2] = z;
79 }
80
81 void
82 color_matrix_set_identity (ColorMatrix * m)
83 {
84   int i, j;
85
86   for (i = 0; i < 4; i++) {
87     for (j = 0; j < 4; j++) {
88       m->m[i][j] = (i == j);
89     }
90   }
91 }
92
93 /* Prettyprint a 4x4 matrix @m@ */
94 void
95 color_matrix_dump (ColorMatrix * m)
96 {
97   int i, j;
98
99   printf ("[\n");
100   for (i = 0; i < 4; i++) {
101     printf ("  ");
102     for (j = 0; j < 4; j++) {
103       printf (" %8.5g", m->m[i][j]);
104     }
105     printf ("\n");
106   }
107   printf ("]\n");
108 }
109
110 /* Perform 4x4 matrix multiplication:
111  *  - @dst@ = @a@ * @b@
112  *  - @dst@ may be a pointer to @a@ andor @b@
113  */
114 void
115 color_matrix_multiply (ColorMatrix * dst, ColorMatrix * a, ColorMatrix * b)
116 {
117   ColorMatrix tmp;
118   int i, j, k;
119
120   for (i = 0; i < 4; i++) {
121     for (j = 0; j < 4; j++) {
122       double x = 0;
123       for (k = 0; k < 4; k++) {
124         x += a->m[i][k] * b->m[k][j];
125       }
126       tmp.m[i][j] = x;
127     }
128   }
129
130   memcpy (dst, &tmp, sizeof (ColorMatrix));
131 }
132
133 void
134 color_matrix_apply (ColorMatrix * m, Color * dest, Color * src)
135 {
136   int i;
137   Color tmp;
138
139   for (i = 0; i < 3; i++) {
140     double x = 0;
141     x += m->m[i][0] * src->v[0];
142     x += m->m[i][1] * src->v[1];
143     x += m->m[i][2] * src->v[2];
144     x += m->m[i][3];
145     tmp.v[i] = x;
146   }
147   memcpy (dest, &tmp, sizeof (tmp));
148 }
149
150 void
151 color_matrix_offset_components (ColorMatrix * m, double a1, double a2,
152     double a3)
153 {
154   ColorMatrix a;
155
156   color_matrix_set_identity (&a);
157   a.m[0][3] = a1;
158   a.m[1][3] = a2;
159   a.m[2][3] = a3;
160   color_matrix_multiply (m, &a, m);
161 }
162
163 void
164 color_matrix_scale_components (ColorMatrix * m, double a1, double a2, double a3)
165 {
166   ColorMatrix a;
167
168   color_matrix_set_identity (&a);
169   a.m[0][0] = a1;
170   a.m[1][1] = a2;
171   a.m[2][2] = a3;
172   color_matrix_multiply (m, &a, m);
173 }
174
175 void
176 color_matrix_YCbCr_to_RGB (ColorMatrix * m, double Kr, double Kb)
177 {
178   double Kg = 1.0 - Kr - Kb;
179   ColorMatrix k = {
180     {
181           {1., 0., 2 * (1 - Kr), 0.},
182           {1., -2 * Kb * (1 - Kb) / Kg, -2 * Kr * (1 - Kr) / Kg, 0.},
183           {1., 2 * (1 - Kb), 0., 0.},
184           {0., 0., 0., 1.},
185         }
186   };
187
188   color_matrix_multiply (m, &k, m);
189 }
190
191 void
192 color_matrix_RGB_to_YCbCr (ColorMatrix * m, double Kr, double Kb)
193 {
194   double Kg = 1.0 - Kr - Kb;
195   ColorMatrix k;
196   double x;
197
198   k.m[0][0] = Kr;
199   k.m[0][1] = Kg;
200   k.m[0][2] = Kb;
201   k.m[0][3] = 0;
202
203   x = 1 / (2 * (1 - Kb));
204   k.m[1][0] = -x * Kr;
205   k.m[1][1] = -x * Kg;
206   k.m[1][2] = x * (1 - Kb);
207   k.m[1][3] = 0;
208
209   x = 1 / (2 * (1 - Kr));
210   k.m[2][0] = x * (1 - Kr);
211   k.m[2][1] = -x * Kg;
212   k.m[2][2] = -x * Kb;
213   k.m[2][3] = 0;
214
215   k.m[3][0] = 0;
216   k.m[3][1] = 0;
217   k.m[3][2] = 0;
218   k.m[3][3] = 1;
219
220   color_matrix_multiply (m, &k, m);
221 }
222
223 void
224 color_matrix_build_yuv_to_rgb_601 (ColorMatrix * dst)
225 {
226   /*
227    * At this point, everything is in YCbCr
228    * All components are in the range [0,255]
229    */
230   color_matrix_set_identity (dst);
231
232   /* offset required to get input video black to (0.,0.,0.) */
233   color_matrix_offset_components (dst, -16, -128, -128);
234
235   /* scale required to get input video black to (0.,0.,0.) */
236   color_matrix_scale_components (dst, (1 / 219.0), (1 / 224.0), (1 / 224.0));
237
238   /* colour matrix, YCbCr -> RGB */
239   /* Requires Y in [0,1.0], Cb&Cr in [-0.5,0.5] */
240   color_matrix_YCbCr_to_RGB (dst, 0.2990, 0.1140);      /* SD */
241
242   /*
243    * We are now in RGB space
244    */
245
246 #if 0
247   /* scale to output range. */
248   color_matrix_scale_components (dst, 255.0, 255.0, 255.0);
249 #endif
250 }
251
252 void
253 color_matrix_build_bt709_to_bt601 (ColorMatrix * dst)
254 {
255   color_matrix_set_identity (dst);
256
257   /* offset required to get input video black to (0.,0.,0.) */
258   color_matrix_offset_components (dst, -16, -128, -128);
259
260   /* scale required to get input video black to (0.,0.,0.) */
261   color_matrix_scale_components (dst, (1 / 219.0), (1 / 224.0), (1 / 224.0));
262
263   /* colour matrix, YCbCr -> RGB */
264   /* Requires Y in [0,1.0], Cb&Cr in [-0.5,0.5] */
265   color_matrix_YCbCr_to_RGB (dst, 0.2126, 0.0722);      /* HD */
266
267   color_matrix_RGB_to_YCbCr (dst, 0.2990, 0.1140);      /* SD */
268
269   color_matrix_scale_components (dst, 219.0, 224.0, 224.0);
270
271   color_matrix_offset_components (dst, 16, 128, 128);
272 }
273
274 void
275 color_matrix_build_rgb_to_yuv_601 (ColorMatrix * dst)
276 {
277   color_matrix_set_identity (dst);
278
279   color_matrix_RGB_to_YCbCr (dst, 0.2990, 0.1140);      /* SD */
280
281   color_matrix_scale_components (dst, 219.0, 224.0, 224.0);
282
283   color_matrix_offset_components (dst, 16, 128, 128);
284
285   {
286     Color c;
287     int i;
288     for (i = 7; i >= 0; i--) {
289       color_set (&c, (i & 2) ? 0.75 : 0.0, (i & 4) ? 0.75 : 0.0,
290           (i & 1) ? 0.75 : 0.0);
291       color_matrix_apply (dst, &c, &c);
292       g_print ("  { %g, %g, %g },\n", rint (c.v[0]), rint (c.v[1]),
293           rint (c.v[2]));
294     }
295     color_set (&c, -0.075, -0.075, -0.075);
296     color_matrix_apply (dst, &c, &c);
297     g_print ("  { %g, %g, %g },\n", rint (c.v[0]), rint (c.v[1]),
298         rint (c.v[2]));
299     color_set (&c, 0.075, 0.075, 0.075);
300     color_matrix_apply (dst, &c, &c);
301     g_print ("  { %g, %g, %g },\n", rint (c.v[0]), rint (c.v[1]),
302         rint (c.v[2]));
303   }
304 }
305
306 void
307 color_matrix_invert (ColorMatrix * m)
308 {
309   ColorMatrix tmp;
310   int i, j;
311   double det;
312
313   color_matrix_set_identity (&tmp);
314   for (j = 0; j < 3; j++) {
315     for (i = 0; i < 3; i++) {
316       tmp.m[j][i] =
317           m->m[(i + 1) % 3][(j + 1) % 3] * m->m[(i + 2) % 3][(j + 2) % 3] -
318           m->m[(i + 1) % 3][(j + 2) % 3] * m->m[(i + 2) % 3][(j + 1) % 3];
319     }
320   }
321   det =
322       tmp.m[0][0] * m->m[0][0] + tmp.m[0][1] * m->m[1][0] +
323       tmp.m[0][2] * m->m[2][0];
324   for (j = 0; j < 3; j++) {
325     for (i = 0; i < 3; i++) {
326       tmp.m[i][j] /= det;
327     }
328   }
329   memcpy (m, &tmp, sizeof (tmp));
330 }
331
332 void
333 color_matrix_copy (ColorMatrix * dest, ColorMatrix * src)
334 {
335   memcpy (dest, src, sizeof (ColorMatrix));
336 }
337
338 void
339 color_matrix_transpose (ColorMatrix * m)
340 {
341   int i, j;
342   ColorMatrix tmp;
343
344   color_matrix_set_identity (&tmp);
345   for (i = 0; i < 3; i++) {
346     for (j = 0; j < 3; j++) {
347       tmp.m[i][j] = m->m[j][i];
348     }
349   }
350   memcpy (m, &tmp, sizeof (ColorMatrix));
351 }
352
353 void
354 color_matrix_build_XYZ (ColorMatrix * dst,
355     double rx, double ry,
356     double gx, double gy, double bx, double by, double wx, double wy)
357 {
358   Color r, g, b, w, scale;
359   ColorMatrix m;
360
361   color_set (&r, rx, ry, 1.0);
362   color_xyY_to_XYZ (&r);
363   color_set (&g, gx, gy, 1.0);
364   color_xyY_to_XYZ (&g);
365   color_set (&b, bx, by, 1.0);
366   color_xyY_to_XYZ (&b);
367   color_set (&w, wx, wy, 1.0);
368   color_xyY_to_XYZ (&w);
369
370   color_matrix_set_identity (dst);
371
372   dst->m[0][0] = r.v[0];
373   dst->m[0][1] = r.v[1];
374   dst->m[0][2] = r.v[2];
375   dst->m[1][0] = g.v[0];
376   dst->m[1][1] = g.v[1];
377   dst->m[1][2] = g.v[2];
378   dst->m[2][0] = b.v[0];
379   dst->m[2][1] = b.v[1];
380   dst->m[2][2] = b.v[2];
381
382   color_matrix_dump (dst);
383   color_matrix_copy (&m, dst);
384   color_matrix_invert (&m);
385   color_matrix_dump (&m);
386
387   color_matrix_transpose (&m);
388   color_matrix_apply (&m, &scale, &w);
389   g_print ("%g %g %g\n", scale.v[0], scale.v[1], scale.v[2]);
390
391   dst->m[0][0] = r.v[0] * scale.v[0];
392   dst->m[0][1] = r.v[1] * scale.v[0];
393   dst->m[0][2] = r.v[2] * scale.v[0];
394   dst->m[1][0] = g.v[0] * scale.v[1];
395   dst->m[1][1] = g.v[1] * scale.v[1];
396   dst->m[1][2] = g.v[2] * scale.v[1];
397   dst->m[2][0] = b.v[0] * scale.v[2];
398   dst->m[2][1] = b.v[1] * scale.v[2];
399   dst->m[2][2] = b.v[2] * scale.v[2];
400
401   color_matrix_transpose (dst);
402   color_matrix_dump (dst);
403
404   color_set (&scale, 1, 1, 1);
405   color_matrix_apply (dst, &scale, &scale);
406   color_XYZ_to_xyY (&scale);
407   g_print ("white %g %g %g\n", scale.v[0], scale.v[1], scale.v[2]);
408
409 }
410
411 void
412 color_matrix_build_rgb_to_XYZ_601 (ColorMatrix * dst)
413 {
414   /* SMPTE C primaries, SMPTE 170M-2004 */
415   color_matrix_build_XYZ (dst,
416       0.630, 0.340, 0.310, 0.595, 0.155, 0.070, 0.3127, 0.3290);
417 #if 0
418   /* NTSC 1953 primaries, SMPTE 170M-2004 */
419   color_matrix_build_XYZ (dst,
420       0.67, 0.33, 0.21, 0.71, 0.14, 0.08, 0.3127, 0.3290);
421 #endif
422 }
423
424 void
425 color_matrix_build_XYZ_to_rgb_709 (ColorMatrix * dst)
426 {
427   /* Rec. ITU-R BT.709-5 */
428   color_matrix_build_XYZ (dst,
429       0.640, 0.330, 0.300, 0.600, 0.150, 0.060, 0.3127, 0.3290);
430 }
431
432 void
433 color_matrix_build_XYZ_to_rgb_dell (ColorMatrix * dst)
434 {
435   /* Dell monitor */
436 #if 1
437   color_matrix_build_XYZ (dst,
438       0.662, 0.329, 0.205, 0.683, 0.146, 0.077, 0.3135, 0.3290);
439 #endif
440 #if 0
441   color_matrix_build_XYZ (dst,
442       0.630, 0.340, 0.310, 0.595, 0.155, 0.070, 0.3127, 0.3290);
443 #endif
444   color_matrix_invert (dst);
445 }
446
447 void
448 color_transfer_function_apply (Color * dest, Color * src)
449 {
450   int i;
451
452   for (i = 0; i < 3; i++) {
453     if (src->v[i] < 0.0812) {
454       dest->v[i] = src->v[i] / 4.500;
455     } else {
456       dest->v[i] = pow (src->v[i] + 0.099, 1 / 0.4500);
457     }
458   }
459 }
460
461 void
462 color_transfer_function_unapply (Color * dest, Color * src)
463 {
464   int i;
465
466   for (i = 0; i < 3; i++) {
467     if (src->v[i] < 0.0812 / 4.500) {
468       dest->v[i] = src->v[i] * 4.500;
469     } else {
470       dest->v[i] = pow (src->v[i], 0.4500) - 0.099;
471     }
472   }
473 }
474
475 void
476 color_gamut_clamp (Color * dest, Color * src)
477 {
478   dest->v[0] = CLAMP (src->v[0], 0.0, 1.0);
479   dest->v[1] = CLAMP (src->v[1], 0.0, 1.0);
480   dest->v[2] = CLAMP (src->v[2], 0.0, 1.0);
481 }
482
483 #if 0
484 static guint8 *
485 get_color_transform_table (void)
486 {
487   static guint8 *color_transform_table = NULL;
488
489 #if 1
490   if (!color_transform_table) {
491     ColorMatrix bt601_to_rgb;
492     ColorMatrix bt601_to_yuv;
493     ColorMatrix bt601_rgb_to_XYZ;
494     ColorMatrix dell_XYZ_to_rgb;
495     guint8 *table_y;
496     guint8 *table_u;
497     guint8 *table_v;
498     int y, u, v;
499
500     color_matrix_build_yuv_to_rgb_601 (&bt601_to_rgb);
501     color_matrix_build_rgb_to_yuv_601 (&bt601_to_yuv);
502     color_matrix_build_rgb_to_XYZ_601 (&bt601_rgb_to_XYZ);
503     color_matrix_build_XYZ_to_rgb_dell (&dell_XYZ_to_rgb);
504
505     color_transform_table = g_malloc (0x1000000 * 3);
506
507     table_y = COG_OFFSET (color_transform_table, 0 * 0x1000000);
508     table_u = COG_OFFSET (color_transform_table, 1 * 0x1000000);
509     table_v = COG_OFFSET (color_transform_table, 2 * 0x1000000);
510
511     for (y = 0; y < 256; y++) {
512       for (u = 0; u < 256; u++) {
513         for (v = 0; v < 256; v++) {
514           Color c;
515
516           c.v[0] = y;
517           c.v[1] = u;
518           c.v[2] = v;
519           color_matrix_apply (&bt601_to_rgb, &c, &c);
520           color_gamut_clamp (&c, &c);
521           color_transfer_function_apply (&c, &c);
522           color_matrix_apply (&bt601_rgb_to_XYZ, &c, &c);
523           color_matrix_apply (&dell_XYZ_to_rgb, &c, &c);
524           color_transfer_function_unapply (&c, &c);
525           color_gamut_clamp (&c, &c);
526           color_matrix_apply (&bt601_to_yuv, &c, &c);
527
528           table_y[(y << 16) | (u << 8) | (v)] = rint (c.v[0]);
529           table_u[(y << 16) | (u << 8) | (v)] = rint (c.v[1]);
530           table_v[(y << 16) | (u << 8) | (v)] = rint (c.v[2]);
531         }
532       }
533     }
534   }
535 #endif
536 #if 0
537   if (!color_transform_table) {
538     ColorMatrix bt709_to_bt601;
539     guint8 *table_y;
540     guint8 *table_u;
541     guint8 *table_v;
542     int y, u, v;
543
544     color_matrix_build_bt709_to_bt601 (&bt709_to_bt601);
545
546     color_transform_table = g_malloc (0x1000000 * 3);
547
548     table_y = COG_OFFSET (color_transform_table, 0 * 0x1000000);
549     table_u = COG_OFFSET (color_transform_table, 1 * 0x1000000);
550     table_v = COG_OFFSET (color_transform_table, 2 * 0x1000000);
551
552     for (y = 0; y < 256; y++) {
553       for (u = 0; u < 256; u++) {
554         for (v = 0; v < 256; v++) {
555           Color c;
556
557           c.v[0] = y;
558           c.v[1] = u;
559           c.v[2] = v;
560           color_matrix_apply (&bt709_to_bt601, &c, &c);
561
562           table_y[(y << 16) | (u << 8) | (v)] = rint (c.v[0]);
563           table_u[(y << 16) | (u << 8) | (v)] = rint (c.v[1]);
564           table_v[(y << 16) | (u << 8) | (v)] = rint (c.v[2]);
565         }
566       }
567     }
568   }
569 #endif
570
571   return color_transform_table;
572 }
573 #endif