1 /*****************************************************************
2  * gmerlin - a general purpose multimedia framework and applications
3  *
4  * Copyright (c) 2001 - 2011 Members of the Gmerlin project
5  * gmerlin-general@lists.sourceforge.net
6  * http://gmerlin.sourceforge.net
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  * *****************************************************************/
21 
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdio.h>
25 
26 #include <config.h>
27 #include <gmerlin/translation.h>
28 #include <gmerlin/plugin.h>
29 #include <gmerlin/utils.h>
30 #include <gmerlin/log.h>
31 
32 #include "colormatrix.h"
33 
34 #define LOG_DOMAIN "fv_colormatrix_rgb"
35 
36 typedef struct
37   {
38   bg_colormatrix_t * mat;
39 
40   bg_read_video_func_t read_func;
41   void * read_data;
42   int read_stream;
43 
44   gavl_video_format_t format;
45 
46   float coeffs[4][5];
47   int force_alpha;
48   int need_restart;
49   gavl_video_options_t * global_opt;
50 
51   } colormatrix_priv_t;
52 
need_restart_colormatrix(void * priv)53 static int need_restart_colormatrix(void * priv)
54   {
55   colormatrix_priv_t * vp;
56   vp = priv;
57   return vp->need_restart;
58   }
59 
create_colormatrix()60 static void * create_colormatrix()
61   {
62   colormatrix_priv_t * ret;
63   ret = calloc(1, sizeof(*ret));
64   ret->mat = bg_colormatrix_create();
65   ret->global_opt = gavl_video_options_create();
66   return ret;
67   }
68 
get_options_colormatrix(void * priv)69 static gavl_video_options_t * get_options_colormatrix(void * priv)
70   {
71   colormatrix_priv_t * vp = priv;
72   return vp->global_opt;
73   }
74 
destroy_colormatrix(void * priv)75 static void destroy_colormatrix(void * priv)
76   {
77   colormatrix_priv_t * vp;
78   vp = priv;
79   bg_colormatrix_destroy(vp->mat);
80   gavl_video_options_destroy(vp->global_opt);
81   free(vp);
82   }
83 
84 static const bg_parameter_info_t parameters[] =
85   {
86     {
87       .gettext_domain = PACKAGE,
88       .gettext_directory = LOCALE_DIR,
89       .name = "Luminance",
90       .long_name = TRS("Luminance"),
91       .type = BG_PARAMETER_SECTION,
92       .flags = BG_PARAMETER_SYNC,
93     },
94     {
95       .name = "y_to_y",
96       .long_name = TRS("Luminance -> Luminance"),
97       .type = BG_PARAMETER_SLIDER_FLOAT,
98       .flags = BG_PARAMETER_SYNC,
99       .val_min =     { .val_f = -2.0 },
100       .val_max =     { .val_f =  2.0 },
101       .val_default = { .val_f =   1.0 },
102       .num_digits =  3,
103     },
104     {
105       .name = "u_to_y",
106       .long_name = TRS("Cb -> Luminance"),
107       .type = BG_PARAMETER_SLIDER_FLOAT,
108       .flags = BG_PARAMETER_SYNC,
109       .val_min =     { .val_f = -2.0 },
110       .val_max =     { .val_f =  2.0 },
111       .val_default = { .val_f =   0.0 },
112       .num_digits =  3,
113     },
114     {
115       .name = "v_to_y",
116       .long_name = TRS("Cr -> Luminance"),
117       .type = BG_PARAMETER_SLIDER_FLOAT,
118       .flags = BG_PARAMETER_SYNC,
119       .val_min =     { .val_f = -2.0 },
120       .val_max =     { .val_f =  2.0 },
121       .val_default = { .val_f =   0.0 },
122       .num_digits =  3,
123     },
124     {
125       .name = "a_to_y",
126       .long_name = TRS("Alpha -> Luminance"),
127       .type = BG_PARAMETER_SLIDER_FLOAT,
128       .flags = BG_PARAMETER_SYNC,
129       .val_min =     { .val_f = -2.0 },
130       .val_max =     { .val_f =  2.0 },
131       .val_default = { .val_f =   0.0 },
132       .num_digits =  3,
133     },
134     {
135       .name = "off_y",
136       .long_name = TRS("Luminance offset"),
137       .type = BG_PARAMETER_SLIDER_FLOAT,
138       .flags = BG_PARAMETER_SYNC,
139       .val_min =     { .val_f = -2.0 },
140       .val_max =     { .val_f =  2.0 },
141       .val_default = { .val_f =   0.0 },
142       .num_digits =  3,
143     },
144     {
145       .gettext_domain = PACKAGE,
146       .gettext_directory = LOCALE_DIR,
147       .name = "Cb",
148       .long_name = TRS("Cb"),
149       .type = BG_PARAMETER_SECTION,
150       .flags = BG_PARAMETER_SYNC,
151     },
152     {
153       .name = "r_to_u",
154       .long_name = TRS("Luminance -> Cb"),
155       .type = BG_PARAMETER_SLIDER_FLOAT,
156       .flags = BG_PARAMETER_SYNC,
157       .val_min =     { .val_f = -2.0 },
158       .val_max =     { .val_f =  2.0 },
159       .val_default = { .val_f =   0.0 },
160       .num_digits =  3,
161     },
162     {
163       .name = "u_to_u",
164       .long_name = TRS("Cb -> Cb"),
165       .type = BG_PARAMETER_SLIDER_FLOAT,
166       .flags = BG_PARAMETER_SYNC,
167       .val_min =     { .val_f = -2.0 },
168       .val_max =     { .val_f =  2.0 },
169       .val_default = { .val_f =   1.0 },
170       .num_digits =  3,
171     },
172     {
173       .name = "b_to_u",
174       .long_name = TRS("Cr -> Cb"),
175       .type = BG_PARAMETER_SLIDER_FLOAT,
176       .flags = BG_PARAMETER_SYNC,
177       .val_min =     { .val_f = -2.0 },
178       .val_max =     { .val_f =  2.0 },
179       .val_default = { .val_f =   0.0 },
180       .num_digits =  3,
181     },
182     {
183       .name = "a_to_u",
184       .long_name = TRS("Alpha -> Cb"),
185       .type = BG_PARAMETER_SLIDER_FLOAT,
186       .flags = BG_PARAMETER_SYNC,
187       .val_min =     { .val_f = -2.0 },
188       .val_max =     { .val_f =  2.0 },
189       .val_default = { .val_f =   0.0 },
190       .num_digits =  3,
191     },
192     {
193       .name = "off_u",
194       .long_name = TRS("Cb offset"),
195       .type = BG_PARAMETER_SLIDER_FLOAT,
196       .flags = BG_PARAMETER_SYNC,
197       .val_min =     { .val_f = -2.0 },
198       .val_max =     { .val_f =  2.0 },
199       .val_default = { .val_f =   0.0 },
200       .num_digits =  3,
201     },
202     {
203       .gettext_domain = PACKAGE,
204       .gettext_directory = LOCALE_DIR,
205       .name = "Cr",
206       .long_name = TRS("Cr"),
207       .type = BG_PARAMETER_SECTION,
208       .flags = BG_PARAMETER_SYNC,
209     },
210     {
211       .name = "y_to_v",
212       .long_name = TRS("Luminance -> Cr"),
213       .type = BG_PARAMETER_SLIDER_FLOAT,
214       .flags = BG_PARAMETER_SYNC,
215       .val_min =     { .val_f = -2.0 },
216       .val_max =     { .val_f =  2.0 },
217       .val_default = { .val_f =   0.0 },
218       .num_digits =  3,
219     },
220     {
221       .name = "u_to_v",
222       .long_name = TRS("Cb -> Cr"),
223       .type = BG_PARAMETER_SLIDER_FLOAT,
224       .flags = BG_PARAMETER_SYNC,
225       .val_min =     { .val_f = -2.0 },
226       .val_max =     { .val_f =  2.0 },
227       .val_default = { .val_f =   0.0 },
228       .num_digits =  3,
229     },
230     {
231       .name = "v_to_v",
232       .long_name = TRS("Cr -> Cr"),
233       .type = BG_PARAMETER_SLIDER_FLOAT,
234       .flags = BG_PARAMETER_SYNC,
235       .val_min =     { .val_f = -2.0 },
236       .val_max =     { .val_f =  2.0 },
237       .val_default = { .val_f =   1.0 },
238       .num_digits =  3,
239     },
240     {
241       .name = "a_to_v",
242       .long_name = TRS("Alpha -> Cr"),
243       .type = BG_PARAMETER_SLIDER_FLOAT,
244       .flags = BG_PARAMETER_SYNC,
245       .val_min =     { .val_f = -2.0 },
246       .val_max =     { .val_f =  2.0 },
247       .val_default = { .val_f =   0.0 },
248       .num_digits =  3,
249     },
250     {
251       .name = "off_v",
252       .long_name = TRS("Cr offset"),
253       .type = BG_PARAMETER_SLIDER_FLOAT,
254       .flags = BG_PARAMETER_SYNC,
255       .val_min =     { .val_f = -2.0 },
256       .val_max =     { .val_f =  2.0 },
257       .val_default = { .val_f =   0.0 },
258       .num_digits =  3,
259     },
260     {
261       .gettext_domain = PACKAGE,
262       .gettext_directory = LOCALE_DIR,
263       .name = "Alpha",
264       .long_name = TRS("Alpha"),
265       .type = BG_PARAMETER_SECTION,
266       .flags = BG_PARAMETER_SYNC,
267     },
268     {
269       .name = "y_to_a",
270       .long_name = TRS("Luminance -> Alpha"),
271       .type = BG_PARAMETER_SLIDER_FLOAT,
272       .flags = BG_PARAMETER_SYNC,
273       .val_min =     { .val_f = -2.0 },
274       .val_max =     { .val_f =  2.0 },
275       .val_default = { .val_f =   0.0 },
276       .num_digits =  3,
277     },
278     {
279       .name = "u_to_a",
280       .long_name = TRS("Cb -> Alpha"),
281       .type = BG_PARAMETER_SLIDER_FLOAT,
282       .flags = BG_PARAMETER_SYNC,
283       .val_min =     { .val_f = -2.0 },
284       .val_max =     { .val_f =  2.0 },
285       .val_default = { .val_f =   0.0 },
286       .num_digits =  3,
287     },
288     {
289       .name = "v_to_a",
290       .long_name = TRS("Cr -> Alpha"),
291       .type = BG_PARAMETER_SLIDER_FLOAT,
292       .flags = BG_PARAMETER_SYNC,
293       .val_min =     { .val_f = -2.0 },
294       .val_max =     { .val_f =  2.0 },
295       .val_default = { .val_f =   0.0 },
296       .num_digits =  3,
297     },
298     {
299       .name = "a_to_a",
300       .long_name = TRS("Alpha -> Alpha"),
301       .type = BG_PARAMETER_SLIDER_FLOAT,
302       .flags = BG_PARAMETER_SYNC,
303       .val_min =     { .val_f = -2.0 },
304       .val_max =     { .val_f =  2.0 },
305       .val_default = { .val_f =   1.0 },
306       .num_digits =  3,
307     },
308     {
309       .name = "off_a",
310       .long_name = TRS("Alpha offset"),
311       .type = BG_PARAMETER_SLIDER_FLOAT,
312       .flags = BG_PARAMETER_SYNC,
313       .val_min =     { .val_f = -2.0 },
314       .val_max =     { .val_f =  2.0 },
315       .val_default = { .val_f =   0.0 },
316       .num_digits =  3,
317     },
318     {
319       .name = "misc",
320       .long_name = TRS("Misc"),
321       .type = BG_PARAMETER_SECTION,
322     },
323     {
324       .name = "force_alpha",
325       .long_name = TRS("Force alpha"),
326       .type = BG_PARAMETER_CHECKBUTTON,
327       .flags = BG_PARAMETER_SYNC,
328       .help_string = TRS("Create video with alpha channel even if the input format has no alpha channel. Use this to generate the alpha channel from other channels using the colormatrix."),
329     },
330     { /* End of parameters */ },
331   };
332 
get_parameters_colormatrix(void * priv)333 static const bg_parameter_info_t * get_parameters_colormatrix(void * priv)
334   {
335   return parameters;
336   }
337 
338 #define MATRIX_PARAM(n, r, c) \
339   else if(!strcmp(name, n)) \
340     { \
341     if(vp->coeffs[r][c] != val->val_f) \
342       { \
343       vp->coeffs[r][c] = val->val_f; \
344       changed = 1; \
345       } \
346     }
347 
set_parameter_colormatrix(void * priv,const char * name,const bg_parameter_value_t * val)348 static void set_parameter_colormatrix(void * priv, const char * name,
349                                const bg_parameter_value_t * val)
350   {
351   int changed = 0;
352   colormatrix_priv_t * vp;
353   vp = priv;
354 
355   if(!name)
356     return;
357   MATRIX_PARAM("y_to_y", 0, 0)
358   MATRIX_PARAM("u_to_y", 0, 1)
359   MATRIX_PARAM("v_to_y", 0, 2)
360   MATRIX_PARAM("a_to_y", 0, 3)
361   MATRIX_PARAM( "off_y", 0, 4)
362 
363   MATRIX_PARAM("y_to_u", 1, 0)
364   MATRIX_PARAM("u_to_u", 1, 1)
365   MATRIX_PARAM("v_to_u", 1, 2)
366   MATRIX_PARAM("a_to_u", 1, 3)
367   MATRIX_PARAM( "off_u", 1, 4)
368 
369   MATRIX_PARAM("y_to_v", 2, 0)
370   MATRIX_PARAM("u_to_v", 2, 1)
371   MATRIX_PARAM("v_to_v", 2, 2)
372   MATRIX_PARAM("a_to_v", 2, 3)
373   MATRIX_PARAM( "off_v", 2, 4)
374 
375   MATRIX_PARAM("y_to_a", 3, 0)
376   MATRIX_PARAM("u_to_a", 3, 1)
377   MATRIX_PARAM("v_to_a", 3, 2)
378   MATRIX_PARAM("a_to_a", 3, 3)
379   MATRIX_PARAM( "off_a", 3, 4)
380 
381   else if(!strcmp(name, "force_alpha"))
382     {
383     if(vp->force_alpha != val->val_i)
384       {
385       vp->force_alpha = val->val_i;
386       vp->need_restart = 1;
387       }
388     }
389 
390   if(changed)
391     bg_colormatrix_set_yuva(vp->mat, vp->coeffs);
392   }
393 
connect_input_port_colormatrix(void * priv,bg_read_video_func_t func,void * data,int stream,int port)394 static void connect_input_port_colormatrix(void * priv,
395                                     bg_read_video_func_t func,
396                                     void * data, int stream, int port)
397   {
398   colormatrix_priv_t * vp;
399   vp = priv;
400 
401   if(!port)
402     {
403     vp->read_func = func;
404     vp->read_data = data;
405     vp->read_stream = stream;
406     }
407   }
408 
409 static void
set_input_format_colormatrix(void * priv,gavl_video_format_t * format,int port)410 set_input_format_colormatrix(void * priv,
411                              gavl_video_format_t * format, int port)
412   {
413   colormatrix_priv_t * vp;
414   int flags = 0;
415   vp = priv;
416   if(vp->force_alpha)
417     flags |= BG_COLORMATRIX_FORCE_ALPHA;
418 
419   if(!port)
420     {
421     bg_colormatrix_init(vp->mat, format, flags, vp->global_opt);
422     gavl_video_format_copy(&vp->format, format);
423     }
424   vp->need_restart = 0;
425   }
426 
get_output_format_colormatrix(void * priv,gavl_video_format_t * format)427 static void get_output_format_colormatrix(void * priv,
428                                           gavl_video_format_t * format)
429   {
430   colormatrix_priv_t * vp;
431   vp = priv;
432   gavl_video_format_copy(format, &vp->format);
433   }
434 
read_video_colormatrix(void * priv,gavl_video_frame_t * frame,int stream)435 static int read_video_colormatrix(void * priv,
436                                   gavl_video_frame_t * frame, int stream)
437   {
438   colormatrix_priv_t * vp;
439   vp = priv;
440 
441 #if 0
442   if(!vp->colormatrix_h && !vp->colormatrix_v)
443     {
444     return vp->read_func(vp->read_data, frame, vp->read_stream);
445     }
446 #endif
447   if(!vp->read_func(vp->read_data, frame, vp->read_stream))
448     return 0;
449 
450   bg_colormatrix_process(vp->mat, frame);
451   return 1;
452   }
453 
454 const const bg_fv_plugin_t the_plugin =
455   {
456     .common =
457     {
458       BG_LOCALE,
459       .name =      "fv_colormatrix_yuv",
460       .long_name = TRS("Y'CbCr(A) Colormatrix"),
461       .description = TRS("Generic colormatrix (Y'CbCrA). You pass the coefficients in Y'CbCr(A) coordinates, but the processing will work in RGB(A) as well."),
462       .type =     BG_PLUGIN_FILTER_VIDEO,
463       .flags =    BG_PLUGIN_FILTER_1,
464       .create =   create_colormatrix,
465       .destroy =   destroy_colormatrix,
466       .get_parameters =   get_parameters_colormatrix,
467       .set_parameter =    set_parameter_colormatrix,
468       .priority =         1,
469     },
470 
471     .connect_input_port = connect_input_port_colormatrix,
472 
473     .set_input_format = set_input_format_colormatrix,
474     .get_output_format = get_output_format_colormatrix,
475 
476     .read_video = read_video_colormatrix,
477     .need_restart = need_restart_colormatrix,
478     .get_options = get_options_colormatrix,
479 
480   };
481 
482 /* Include this into all plugin modules exactly once
483    to let the plugin loader obtain the API version */
484 BG_GET_PLUGIN_API_VERSION;
485