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