no longer need ffmpeg patch0 which was for Termux
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / yuv / yuv.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program 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
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "bcdisplayinfo.h"
23 #include "clip.h"
24 #include "bchash.h"
25 #include "filexml.h"
26 #include "guicast.h"
27 #include "language.h"
28 #include "bccolors.h"
29 #include "pluginvclient.h"
30 #include "theme.h"
31 #include "vframe.h"
32
33 #include <stdint.h>
34 #include <string.h>
35
36 #define MAXVALUE 100
37
38 #define RESET_ALL 0
39 #define RESET_Y_SLIDER 1
40 #define RESET_U_SLIDER 2
41 #define RESET_V_SLIDER 3
42
43 class YUVEffect;
44 class YUVWindow;
45 class YUVFText;
46 class YUVFSlider;
47 class YUVReset;
48 class YUVClr;
49
50
51 class YUVConfig
52 {
53 public:
54         YUVConfig();
55         void reset(int clear);
56
57         void copy_from(YUVConfig &src);
58         int equivalent(YUVConfig &src);
59         void interpolate(YUVConfig &prev,
60                 YUVConfig &next,
61                 long prev_frame,
62                 long next_frame,
63                 long current_frame);
64
65         float y, u, v;
66 };
67
68
69
70
71 class YUVFText : public BC_TumbleTextBox
72 {
73 public:
74         YUVFText(YUVWindow *window, YUVEffect *plugin,
75                 YUVFSlider *slider, float *output, int x, int y, float min, float max);
76         ~YUVFText();
77         int handle_event();
78         YUVWindow *window;
79         YUVEffect *plugin;
80         YUVFSlider *slider;
81         float *output;
82         float min, max;
83 };
84
85
86 class YUVFSlider : public BC_FSlider
87 {
88 public:
89         YUVFSlider(YUVEffect *plugin, YUVFText *text, float *output, int x, int y);
90         ~YUVFSlider();
91         int handle_event();
92         YUVEffect *plugin;
93         YUVFText *text;
94         float *output;
95 };
96
97
98 class YUVReset : public BC_GenericButton
99 {
100 public:
101         YUVReset(YUVEffect *plugin, YUVWindow *window, int x, int y);
102         ~YUVReset();
103         int handle_event();
104         YUVEffect *plugin;
105         YUVWindow *window;
106 };
107
108 class YUVClr : public BC_Button
109 {
110 public:
111         YUVClr(YUVEffect *plugin, YUVWindow *window, int x, int y, int clear);
112         ~YUVClr();
113         int handle_event();
114         YUVEffect *plugin;
115         YUVWindow *window;
116         int clear;
117 };
118
119 class YUVWindow : public PluginClientWindow
120 {
121 public:
122         YUVWindow(YUVEffect *plugin);
123         void create_objects();
124         void update_gui(int clear);
125
126         YUVFText *y_text;
127         YUVFSlider *y_slider;
128         YUVClr *y_Clr;
129
130         YUVFText *u_text;
131         YUVFSlider *u_slider;
132         YUVClr *u_Clr;
133
134         YUVFText *v_text;
135         YUVFSlider *v_slider;
136         YUVClr *v_Clr;
137
138         YUVEffect *plugin;
139         YUVReset *reset;
140 };
141
142
143
144 class YUVEffect : public PluginVClient
145 {
146 public:
147         YUVEffect(PluginServer *server);
148         ~YUVEffect();
149
150
151         PLUGIN_CLASS_MEMBERS(YUVConfig)
152         int process_realtime(VFrame *input, VFrame *output);
153         int is_realtime();
154         void save_data(KeyFrame *keyframe);
155         void read_data(KeyFrame *keyframe);
156         void update_gui();
157 };
158
159
160
161
162
163 REGISTER_PLUGIN(YUVEffect)
164
165
166
167
168
169
170
171 YUVConfig::YUVConfig()
172 {
173         reset(RESET_ALL);
174 }
175
176 void YUVConfig::reset(int clear)
177 {
178         switch(clear) {
179                 case RESET_Y_SLIDER : y = 0;
180                         break;
181                 case RESET_U_SLIDER : u = 0;
182                         break;
183                 case RESET_V_SLIDER : v = 0;
184                         break;
185                 case RESET_ALL :
186                 default:
187                         y = u = v = 0;
188                         break;
189         }
190 }
191
192 void YUVConfig::copy_from(YUVConfig &src)
193 {
194         y = src.y;
195         u = src.u;
196         v = src.v;
197 }
198
199 int YUVConfig::equivalent(YUVConfig &src)
200 {
201         return EQUIV(y, src.y) && EQUIV(u, src.u) && EQUIV(v, src.v);
202 }
203
204 void YUVConfig::interpolate(YUVConfig &prev,
205         YUVConfig &next,
206         long prev_frame,
207         long next_frame,
208         long current_frame)
209 {
210         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
211         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
212
213         y = prev.y * prev_scale + next.y * next_scale;
214         u = prev.u * prev_scale + next.u * next_scale;
215         v = prev.v * prev_scale + next.v * next_scale;
216 }
217
218
219
220
221
222
223
224
225 YUVFText::YUVFText(YUVWindow *window, YUVEffect *plugin,
226         YUVFSlider *slider, float *output, int x, int y, float min, float max)
227  : BC_TumbleTextBox(window, *output,
228         min, max, x, y, xS(60), 2)
229 {
230         this->window = window;
231         this->plugin = plugin;
232         this->output = output;
233         this->slider = slider;
234         this->min = min;
235         this->max = max;
236         set_increment(0.1);
237 }
238
239 YUVFText::~YUVFText()
240 {
241 }
242
243 int YUVFText::handle_event()
244 {
245         *output = atof(get_text());
246         if(*output > max) *output = max;
247         if(*output < min) *output = min;
248         slider->update(*output);
249         plugin->send_configure_change();
250         return 1;
251 }
252
253
254 YUVFSlider::YUVFSlider(YUVEffect *plugin, YUVFText *text, float *output, int x, int y)
255  : BC_FSlider(x, y, 0, xS(200), xS(200), -MAXVALUE, MAXVALUE, *output)
256 {
257         this->plugin = plugin;
258         this->output = output;
259         this->text = text;
260         enable_show_value(0); // Hide caption
261 }
262
263 YUVFSlider::~YUVFSlider()
264 {
265 }
266
267 int YUVFSlider::handle_event()
268 {
269         *output = get_value();
270         text->update(*output);
271         plugin->send_configure_change();
272         return 1;
273 }
274
275
276 YUVReset::YUVReset(YUVEffect *plugin, YUVWindow *window, int x, int y)
277  : BC_GenericButton(x, y, _("Reset"))
278 {
279         this->plugin = plugin;
280         this->window = window;
281 }
282 YUVReset::~YUVReset()
283 {
284 }
285 int YUVReset::handle_event()
286 {
287         plugin->config.reset(RESET_ALL);
288         window->update_gui(RESET_ALL);
289         plugin->send_configure_change();
290         return 1;
291 }
292
293
294 YUVClr::YUVClr(YUVEffect *plugin, YUVWindow *window, int x, int y, int clear)
295  : BC_Button(x, y, plugin->get_theme()->get_image_set("reset_button"))
296 {
297         this->plugin = plugin;
298         this->window = window;
299         this->clear = clear;
300 }
301 YUVClr::~YUVClr()
302 {
303 }
304 int YUVClr::handle_event()
305 {
306         // clear==1 ==> Y slider
307         // clear==2 ==> U slider
308         // clear==3 ==> V slider
309         plugin->config.reset(clear);
310         window->update_gui(clear);
311         plugin->send_configure_change();
312         return 1;
313 }
314
315
316 YUVWindow::YUVWindow(YUVEffect *plugin)
317  : PluginClientWindow(plugin, xS(420), yS(160), xS(420), yS(160), 0)
318 {
319         this->plugin = plugin;
320 }
321
322 void YUVWindow::create_objects()
323 {
324         int xs10 = xS(10);
325         int ys10 = yS(10), ys30 = yS(30), ys40 = yS(40);
326         int x = xs10, y = ys10;
327         int x2 = xS(80), x3 = xS(180);
328         int clr_x = get_w()-x - xS(22); // note: clrBtn_w = 22
329
330         BC_Bar *bar;
331
332         y += ys10;
333         add_subwindow(new BC_Title(x, y, _("Y:")));
334         y_text = new YUVFText(this, plugin,
335                 0, &plugin->config.y, (x + x2), y, -MAXVALUE, MAXVALUE);
336         y_text->create_objects();
337         y_slider = new YUVFSlider(plugin, y_text, &plugin->config.y, x3, y);
338         add_subwindow(y_slider);
339         y_text->slider = y_slider;
340         clr_x = x3 + y_slider->get_w() + x;
341         add_subwindow(y_Clr = new YUVClr(plugin, this, clr_x, y, RESET_Y_SLIDER));
342         y += ys30;
343
344         add_subwindow(new BC_Title(x, y, _("U:")));
345         u_text = new YUVFText(this, plugin,
346                 0, &plugin->config.u, (x + x2), y, -MAXVALUE, MAXVALUE);
347         u_text->create_objects();
348         u_slider = new YUVFSlider(plugin, u_text, &plugin->config.u, x3, y);
349         add_subwindow(u_slider);
350         u_text->slider = u_slider;
351         add_subwindow(u_Clr = new YUVClr(plugin, this, clr_x, y, RESET_U_SLIDER));
352         y += ys30;
353
354         add_subwindow(new BC_Title(x, y, _("V:")));
355         v_text = new YUVFText(this, plugin,
356                 0, &plugin->config.v, (x + x2), y, -MAXVALUE, MAXVALUE);
357         v_text->create_objects();
358         v_slider = new YUVFSlider(plugin, v_text, &plugin->config.v, x3, y);
359         add_subwindow(v_slider);
360         v_text->slider = v_slider;
361         add_subwindow(v_Clr = new YUVClr(plugin, this, clr_x, y, RESET_V_SLIDER));
362         y += ys40;
363
364 // Reset section
365         add_subwindow(bar = new BC_Bar(x, y, get_w()-2*x));
366         y += ys10;
367         add_subwindow(reset = new YUVReset(plugin, this, x, y));
368
369         show_window();
370         flush();
371 }
372
373
374 // for Reset button
375 void YUVWindow::update_gui(int clear)
376 {
377         switch(clear) {
378                 case RESET_Y_SLIDER :
379                         y_text->update(plugin->config.y);
380                         y_slider->update(plugin->config.y);
381                         break;
382                 case RESET_U_SLIDER :
383                         u_text->update(plugin->config.u);
384                         u_slider->update(plugin->config.u);
385                         break;
386                 case RESET_V_SLIDER :
387                         v_text->update(plugin->config.v);
388                         v_slider->update(plugin->config.v);
389                         break;
390                 case RESET_ALL :
391                 default:
392                         y_text->update(plugin->config.y);
393                         y_slider->update(plugin->config.y);
394                         u_text->update(plugin->config.u);
395                         u_slider->update(plugin->config.u);
396                         v_text->update(plugin->config.v);
397                         v_slider->update(plugin->config.v);
398                         break;
399         }
400 }
401
402
403
404
405
406
407 YUVEffect::YUVEffect(PluginServer *server)
408  : PluginVClient(server)
409 {
410
411 }
412 YUVEffect::~YUVEffect()
413 {
414
415 }
416
417 const char* YUVEffect::plugin_title() { return N_("YUV"); }
418 int YUVEffect::is_realtime() { return 1; }
419
420
421 NEW_WINDOW_MACRO(YUVEffect, YUVWindow)
422 LOAD_CONFIGURATION_MACRO(YUVEffect, YUVConfig)
423
424 void YUVEffect::update_gui()
425 {
426         if(thread)
427         {
428                 thread->window->lock_window();
429                 load_configuration();
430                 ((YUVWindow*)thread->window)->y_text->update(config.y);
431                 ((YUVWindow*)thread->window)->y_slider->update(config.y);
432                 ((YUVWindow*)thread->window)->u_text->update(config.u);
433                 ((YUVWindow*)thread->window)->u_slider->update(config.u);
434                 ((YUVWindow*)thread->window)->v_text->update(config.v);
435                 ((YUVWindow*)thread->window)->v_slider->update(config.v);
436                 thread->window->unlock_window();
437         }
438 }
439
440 void YUVEffect::save_data(KeyFrame *keyframe)
441 {
442         FileXML output;
443         output.set_shared_output(keyframe->xbuf);
444         output.tag.set_title("YUV");
445         output.tag.set_property("Y", config.y);
446         output.tag.set_property("U", config.u);
447         output.tag.set_property("V", config.v);
448         output.append_tag();
449         output.tag.set_title("/YUV");
450         output.append_tag();
451         output.append_newline();
452         output.terminate_string();
453 }
454
455 void YUVEffect::read_data(KeyFrame *keyframe)
456 {
457         FileXML input;
458         input.set_shared_input(keyframe->xbuf);
459         while(!input.read_tag())
460         {
461                 if(input.tag.title_is("YUV"))
462                 {
463                         config.y = input.tag.get_property("Y", config.y);
464                         config.u = input.tag.get_property("U", config.u);
465                         config.v = input.tag.get_property("V", config.v);
466                 }
467         }
468 }
469
470
471 #define YUV_MACRO(type, temp_type, max, components, use_yuv) \
472 { \
473         for(int i = 0; i < input->get_h(); i++) \
474         { \
475                 type *in_row = (type*)input->get_rows()[i]; \
476                 type *out_row = (type*)output->get_rows()[i]; \
477                 const float round = (sizeof(type) == 4) ? 0.0 : 0.5; \
478  \
479                 for(int j = 0; j < w; j++) \
480                 { \
481                         if(use_yuv) \
482                         { \
483                                 int y = (int)((float)in_row[0] * y_scale + round); \
484                                 int u = (int)((float)(in_row[1] - (max / 2 + 1)) * u_scale + round) + (max / 2 + 1); \
485                                 int v = (int)((float)(in_row[2] - (max / 2 + 1)) * v_scale + round) + (max / 2 + 1); \
486                                 out_row[0] = CLIP(y, 0, max); \
487                                 out_row[1] = CLIP(u, 0, max); \
488                                 out_row[2] = CLIP(v, 0, max); \
489                         } \
490                         else \
491                         { \
492                                 temp_type y, u, v, r, g, b; \
493                                 if(sizeof(type) == 4) \
494                                 { \
495                                         YUV::yuv.rgb_to_yuv_f(in_row[0], in_row[1], in_row[2], y, u, v); \
496                                 } \
497                                 else \
498                                 if(sizeof(type) == 2) \
499                                 { \
500                                         YUV::yuv.rgb_to_yuv_16(in_row[0], in_row[1], in_row[2], y, u, v); \
501                                 } \
502                                 else \
503                                 { \
504                                         YUV::yuv.rgb_to_yuv_8(in_row[0], in_row[1], in_row[2], y, u, v); \
505                                 } \
506  \
507                                 if(sizeof(type) < 4) \
508                                 { \
509                                         CLAMP(y, 0, max); \
510                                         CLAMP(u, 0, max); \
511                                         CLAMP(v, 0, max); \
512  \
513                                         y = temp_type((float)y * y_scale + round); \
514                                         u = temp_type((float)(u - (max / 2 + 1)) * u_scale + round) + (max / 2 + 1); \
515                                         v = temp_type((float)(v - (max / 2 + 1)) * v_scale + round) + (max / 2 + 1); \
516  \
517                                         CLAMP(y, 0, max); \
518                                         CLAMP(u, 0, max); \
519                                         CLAMP(v, 0, max); \
520                                 } \
521                                 else \
522                                 { \
523                                         y = temp_type((float)y * y_scale + round); \
524                                         u = temp_type((float)u * u_scale + round); \
525                                         v = temp_type((float)v * v_scale + round); \
526                                 } \
527  \
528                                 if(sizeof(type) == 4) \
529                                         YUV::yuv.yuv_to_rgb_f(r, g, b, y, u, v); \
530                                 else \
531                                 if(sizeof(type) == 2) \
532                                         YUV::yuv.yuv_to_rgb_16(r, g, b, y, u, v); \
533                                 else \
534                                         YUV::yuv.yuv_to_rgb_8(r, g, b, y, u, v); \
535  \
536                                 out_row[0] = r; \
537                                 out_row[1] = g; \
538                                 out_row[2] = b; \
539                         } \
540                  \
541                         in_row += components; \
542                         out_row += components; \
543                 } \
544         } \
545 }
546
547 int YUVEffect::process_realtime(VFrame *input, VFrame *output)
548 {
549         load_configuration();
550
551         if(EQUIV(config.y, 0) && EQUIV(config.u, 0) && EQUIV(config.v, 0))
552         {
553                 if(input->get_rows()[0] != output->get_rows()[0])
554                         output->copy_from(input);
555         }
556         else
557         {
558                 int w = input->get_w();
559
560                 float y_scale = (float)(config.y + MAXVALUE) / MAXVALUE;
561                 float u_scale = (float)(config.u + MAXVALUE) / MAXVALUE;
562                 float v_scale = (float)(config.v + MAXVALUE) / MAXVALUE;
563
564                 if(u_scale > 1) u_scale = 1 + (u_scale - 1) * 4;
565                 if(v_scale > 1) v_scale = 1 + (v_scale - 1) * 4;
566
567                 switch(input->get_color_model())
568                 {
569                         case BC_RGB_FLOAT:
570                                 YUV_MACRO(float, float, 1, 3, 0)
571                                 break;
572
573                         case BC_RGB888:
574                                 YUV_MACRO(unsigned char, int, 0xff, 3, 0)
575                                 break;
576
577                         case BC_YUV888:
578                                 YUV_MACRO(unsigned char, int, 0xff, 3, 1)
579                                 break;
580
581                         case BC_RGB161616:
582                                 YUV_MACRO(uint16_t, int, 0xffff, 3, 0)
583                                 break;
584
585                         case BC_YUV161616:
586                                 YUV_MACRO(uint16_t, int, 0xffff, 3, 1)
587                                 break;
588
589                         case BC_RGBA_FLOAT:
590                                 YUV_MACRO(float, float, 1, 4, 0)
591                                 break;
592
593                         case BC_RGBA8888:
594                                 YUV_MACRO(unsigned char, int, 0xff, 4, 0)
595                                 break;
596
597                         case BC_YUVA8888:
598                                 YUV_MACRO(unsigned char, int, 0xff, 4, 1)
599                                 break;
600
601                         case BC_RGBA16161616:
602                                 YUV_MACRO(uint16_t, int, 0xffff, 4, 0)
603                                 break;
604
605                         case BC_YUVA16161616:
606                                 YUV_MACRO(uint16_t, int, 0xffff, 4, 1)
607                                 break;
608                 }
609
610
611
612         }
613         return 0;
614 }
615
616