switch from eclipse to android studio
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / brightness / brightness.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 "brightness.h"
23 #include "bccolors.h"
24 #include "bchash.h"
25 #include "clip.h"
26 #include "filexml.h"
27 #include "language.h"
28 #include "playback3d.h"
29
30 #include <stdio.h>
31 #include <stdint.h>
32 #include <string.h>
33
34
35 REGISTER_PLUGIN(BrightnessMain)
36
37
38
39 BrightnessConfig::BrightnessConfig()
40 {
41         brightness = 0;
42         contrast = 0;
43         luma = 1;
44 }
45
46 int BrightnessConfig::equivalent(BrightnessConfig &that)
47 {
48         return (brightness == that.brightness &&
49                 contrast == that.contrast &&
50                 luma == that.luma);
51 }
52
53 void BrightnessConfig::copy_from(BrightnessConfig &that)
54 {
55         brightness = that.brightness;
56         contrast = that.contrast;
57         luma = that.luma;
58 }
59
60 void BrightnessConfig::interpolate(BrightnessConfig &prev,
61         BrightnessConfig &next,
62         int64_t prev_frame,
63         int64_t next_frame,
64         int64_t current_frame)
65 {
66         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
67         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
68
69         this->brightness = prev.brightness * prev_scale + next.brightness * next_scale;
70         this->contrast = prev.contrast * prev_scale + next.contrast * next_scale;
71         this->luma = (int)(prev.luma * prev_scale + next.luma * next_scale);
72 }
73
74
75
76
77
78
79
80
81
82 BrightnessMain::BrightnessMain(PluginServer *server)
83  : PluginVClient(server)
84 {
85     redo_buffers = 1;
86         engine = 0;
87
88 }
89
90 BrightnessMain::~BrightnessMain()
91 {
92
93         if(engine) delete engine;
94 }
95
96 const char* BrightnessMain::plugin_title() { return N_("Brightness/Contrast"); }
97 int BrightnessMain::is_realtime() { return 1; }
98
99 NEW_WINDOW_MACRO(BrightnessMain, BrightnessWindow)
100 LOAD_CONFIGURATION_MACRO(BrightnessMain, BrightnessConfig)
101
102 int BrightnessMain::process_buffer(VFrame *frame,
103         int64_t start_position,
104         double frame_rate)
105 {
106         load_configuration();
107
108         read_frame(frame,
109                 0,
110                 start_position,
111                 frame_rate,
112                 get_use_opengl());
113
114
115 // Use hardware
116         if(get_use_opengl())
117         {
118                 run_opengl();
119                 return 0;
120         }
121
122
123
124
125         if(!engine) engine = new BrightnessEngine(this, PluginClient::smp + 1);
126
127         this->input = frame;
128         this->output = frame;
129
130         if(!EQUIV(config.brightness, 0) || !EQUIV(config.contrast, 0))
131         {
132                 engine->process_packages();
133         }
134
135         return 0;
136 }
137
138 int BrightnessMain::handle_opengl()
139 {
140 #ifdef HAVE_GL
141         static const char *brightness_yuvluma_frag =
142                 "uniform sampler2D tex;\n"
143                 "uniform float brightness;\n"
144                 "uniform float contrast;\n"
145                 "uniform float offset;\n"
146                 "void main()\n"
147                 "{\n"
148                 "       vec4 yuva = texture2D(tex, gl_TexCoord[0].st);\n"
149                 "       yuva.r += brightness;\n"
150                 "       yuva.r = yuva.r * contrast + offset;\n"
151                 "       gl_FragColor = yuva;\n"
152                 "}\n";
153
154         static const char *brightness_yuv_frag =
155                 "uniform sampler2D tex;\n"
156                 "uniform float brightness;\n"
157                 "uniform float contrast;\n"
158                 "uniform float offset;\n"
159                 "void main()\n"
160                 "{\n"
161                 "       vec4 yuva = texture2D(tex, gl_TexCoord[0].st);\n"
162                 "       yuva.r += brightness;\n"
163                 "       yuva.rgb *= vec3(contrast, contrast, contrast);\n"
164                 "       yuva.rgb += vec3(offset, offset, offset);\n"
165                 "       gl_FragColor = yuva;\n"
166                 "}\n";
167
168         static const char *brightness_rgb_frag =
169                 "uniform sampler2D tex;\n"
170                 "uniform float brightness;\n"
171                 "uniform float contrast;\n"
172                 "uniform float offset;\n"
173                 "void main()\n"
174                 "{\n"
175                 "       vec4 rgba = texture2D(tex, gl_TexCoord[0].st);\n"
176                 "       rgba.rgb += vec3(brightness, brightness, brightness);\n"
177                 "       rgba.rgb *= vec3(contrast, contrast, contrast);\n"
178                 "       rgba.rgb += vec3(offset, offset, offset);\n"
179                 "       gl_FragColor = rgba;\n"
180                 "}\n";
181
182         static const char *brightness_rgbluma_frag =
183                 "uniform sampler2D tex;\n"
184                 "uniform float brightness;\n"
185                 "uniform float contrast;\n"
186                 "uniform float offset;\n"
187                 "uniform mat3 yuv_to_rgb_matrix;\n"
188                 "uniform mat3 rgb_to_yuv_matrix;\n"
189
190                 "void main()\n"
191                 "{\n"
192                 "       vec4 rgba = texture2D(tex, gl_TexCoord[0].st);\n"
193                 "       rgba.rgb = rgb_to_yuv_matrix * rgba.rgb;\n"
194                 "       rgba.r += brightness;\n"
195                 "       rgba.r = rgba.r * contrast + offset;\n"
196                 "       rgba.rgb = yuv_to_rgb_matrix * rgba.rgb;\n"
197                 "       gl_FragColor = rgba;\n"
198                 "}\n";
199
200         get_output()->to_texture();
201         get_output()->enable_opengl();
202         int need_matrix = 0;
203         const char *brightness_frag = BC_CModels::is_yuv(get_output()->get_color_model()) ?
204                 (config.luma ? (need_matrix = 0, brightness_yuvluma_frag) : brightness_yuv_frag) :
205                 (config.luma ? (need_matrix = 1, brightness_rgbluma_frag) : brightness_rgb_frag) ;
206
207         unsigned int shader_id = VFrame::make_shader(0, brightness_frag, 0);
208         if( shader_id > 0 ) {
209                 glUseProgram(shader_id);
210                 glUniform1i(glGetUniformLocation(shader_id, "tex"), 0);
211                 glUniform1f(glGetUniformLocation(shader_id, "brightness"), config.brightness / 100);
212                 float contrast = (config.contrast < 0) ?
213                         (config.contrast + 100) / 100 :
214                         (config.contrast + 25) / 25;
215                 glUniform1f(glGetUniformLocation(shader_id, "contrast"), contrast);
216                 float offset = 0.5 - contrast / 2;
217                 glUniform1f(glGetUniformLocation(shader_id, "offset"), offset);
218                 if( need_matrix ) {
219                         BC_GL_MATRIX(shader_id, yuv_to_rgb_matrix);
220                         BC_GL_MATRIX(shader_id, rgb_to_yuv_matrix);
221                 }
222         }
223
224         get_output()->init_screen();
225         get_output()->bind_texture(0);
226
227
228
229         get_output()->draw_texture();
230         glUseProgram(0);
231         get_output()->set_opengl_state(VFrame::SCREEN);
232 //printf("BrightnessMain::handle_opengl 100 %x\n", glGetError());
233 #endif
234         return 0;
235 }
236
237
238 void BrightnessMain::update_gui()
239 {
240         if(thread)
241         {
242                 if(load_configuration())
243                 {
244                         ((BrightnessWindow*)thread->window)->lock_window("BrightnessMain::update_gui");
245                         ((BrightnessWindow*)thread->window)->brightness->update(config.brightness);
246                         ((BrightnessWindow*)thread->window)->contrast->update(config.contrast);
247                         ((BrightnessWindow*)thread->window)->luma->update(config.luma);
248                         ((BrightnessWindow*)thread->window)->unlock_window();
249                 }
250         }
251 }
252
253
254 void BrightnessMain::save_data(KeyFrame *keyframe)
255 {
256         FileXML output;
257
258 // cause data to be stored directly in text
259         output.set_shared_output(keyframe->xbuf);
260         output.tag.set_title("BRIGHTNESS");
261         output.tag.set_property("BRIGHTNESS", config.brightness);
262         output.tag.set_property("CONTRAST",  config.contrast);
263         output.tag.set_property("LUMA",  config.luma);
264         output.append_tag();
265         output.tag.set_title("/BRIGHTNESS");
266         output.append_tag();
267         output.append_newline();
268         output.terminate_string();
269 }
270
271 void BrightnessMain::read_data(KeyFrame *keyframe)
272 {
273         FileXML input;
274
275         input.set_shared_input(keyframe->xbuf);
276
277         int result = 0;
278
279         while(!result)
280         {
281                 result = input.read_tag();
282
283                 if(!result)
284                 {
285                         if(input.tag.title_is("BRIGHTNESS"))
286                         {
287                                 config.brightness = input.tag.get_property("BRIGHTNESS", config.brightness);
288                                 config.contrast = input.tag.get_property("CONTRAST", config.contrast);
289                                 config.luma = input.tag.get_property("LUMA", config.luma);
290                         }
291                 }
292         }
293 }
294
295
296
297
298
299
300
301
302
303
304
305
306
307 BrightnessPackage::BrightnessPackage()
308  : LoadPackage()
309 {
310 }
311
312
313
314
315 BrightnessUnit::BrightnessUnit(BrightnessEngine *server, BrightnessMain *plugin)
316  : LoadClient(server)
317 {
318         this->plugin = plugin;
319 }
320
321 BrightnessUnit::~BrightnessUnit()
322 {
323 }
324
325 void BrightnessUnit::process_package(LoadPackage *package)
326 {
327         BrightnessPackage *pkg = (BrightnessPackage*)package;
328
329
330         VFrame *output = plugin->output;
331         VFrame *input = plugin->input;
332
333
334
335
336
337 #define DO_BRIGHTNESS(max, type, components, is_yuv) \
338 { \
339         type **input_rows = (type**)input->get_rows(); \
340         type **output_rows = (type**)output->get_rows(); \
341         int row1 = pkg->row1; \
342         int row2 = pkg->row2; \
343         int width = output->get_w(); \
344         int r, g, b; \
345  \
346         if(!EQUIV(plugin->config.brightness, 0)) \
347         { \
348                 int offset = (int)(plugin->config.brightness / 100 * max); \
349 /*printf("DO_BRIGHTNESS offset=%d\n", offset);*/ \
350  \
351                 for(int i = row1; i < row2; i++) \
352                 { \
353                         type *input_row = input_rows[i]; \
354                         type *output_row = output_rows[i]; \
355  \
356                         for(int j = 0; j < width; j++) \
357                         { \
358                                 r = input_row[j * components] + offset; \
359  \
360                                 if(!is_yuv) \
361                                 { \
362                                         g = input_row[j * components + 1] + offset; \
363                                         b = input_row[j * components + 2] + offset; \
364                                 } \
365  \
366                                 CLAMP(r, 0, max); \
367                                 if(!is_yuv) \
368                                 { \
369                                         CLAMP(g, 0, max); \
370                                         CLAMP(b, 0, max); \
371                                 } \
372  \
373                                 output_row[j * components] = r; \
374  \
375                                 if(!is_yuv) \
376                                 { \
377                                         output_row[j * components + 1] = g; \
378                                         output_row[j * components + 2] = b; \
379                                 } \
380                                 else \
381                                 { \
382                                         output_row[j * components + 1] = input_row[j * components + 1]; \
383                                         output_row[j * components + 2] = input_row[j * components + 2]; \
384                                 } \
385  \
386                                 if(components == 4)  \
387                                         output_row[j * components + 3] = input_row[j * components + 3]; \
388                         } \
389                 } \
390  \
391 /* Data to be processed is now in the output buffer */ \
392                 input_rows = output_rows; \
393         } \
394  \
395         if(!EQUIV(plugin->config.contrast, 0)) \
396         { \
397                 float contrast = (plugin->config.contrast < 0) ?  \
398                         (plugin->config.contrast + 100) / 100 :  \
399                         (plugin->config.contrast + 25) / 25; \
400 /*printf("DO_BRIGHTNESS contrast=%f\n", contrast);*/ \
401  \
402                 int scalar = (int)(contrast * 0x100); \
403                 int offset = (max << 8) / 2 - max * scalar / 2; \
404                 int y, u, v; \
405  \
406                 for(int i = row1; i < row2; i++) \
407                 { \
408                         type *input_row = input_rows[i]; \
409                         type *output_row = output_rows[i]; \
410  \
411                         if(plugin->config.luma) \
412                         { \
413                                 for(int j = 0; j < width; j++) \
414                                 { \
415                                         if(is_yuv) \
416                                         { \
417                                                 y = input_row[j * components]; \
418                                         } \
419                                         else \
420                                         { \
421                                                 r = input_row[j * components]; \
422                                                 g = input_row[j * components + 1]; \
423                                                 b = input_row[j * components + 2]; \
424                                                 if(max == 0xff) \
425                                                 { \
426                                                         YUV::yuv.rgb_to_yuv_8( \
427                                                                 r,  \
428                                                                 g,  \
429                                                                 b,  \
430                                                                 y,  \
431                                                                 u,  \
432                                                                 v); \
433                                                 } \
434                                                 else \
435                                                 { \
436                                                         YUV::yuv.rgb_to_yuv_16( \
437                                                                 r,  \
438                                                                 g,  \
439                                                                 b,  \
440                                                                 y,  \
441                                                                 u,  \
442                                                                 v); \
443                                                 } \
444          \
445                                         } \
446          \
447                                         y = (y * scalar + offset) >> 8; \
448                                         CLAMP(y, 0, max); \
449          \
450          \
451                                         if(is_yuv) \
452                                         { \
453                                                 output_row[j * components] = y; \
454                                                 output_row[j * components + 1] = input_row[j * components + 1]; \
455                                                 output_row[j * components + 2] = input_row[j * components + 2]; \
456                                         } \
457                                         else \
458                                         { \
459                                                 if(max == 0xff) \
460                                                 { \
461                                                         YUV::yuv.yuv_to_rgb_8( \
462                                                                 r,  \
463                                                                 g,  \
464                                                                 b,  \
465                                                                 y,  \
466                                                                 u,  \
467                                                                 v); \
468                                                 } \
469                                                 else \
470                                                 { \
471                                                         YUV::yuv.yuv_to_rgb_16( \
472                                                                 r,  \
473                                                                 g,  \
474                                                                 b,  \
475                                                                 y,  \
476                                                                 u,  \
477                                                                 v); \
478                                                 } \
479                                                 input_row[j * components] = r; \
480                                                 input_row[j * components + 1] = g; \
481                                                 input_row[j * components + 2] = b; \
482                                         } \
483          \
484                                         if(components == 4)  \
485                                                 output_row[j * components + 3] = input_row[j * components + 3]; \
486                                 } \
487                         } \
488                         else \
489                         { \
490                                 for(int j = 0; j < width; j++) \
491                                 { \
492                                         r = input_row[j * components]; \
493                                         g = input_row[j * components + 1]; \
494                                         b = input_row[j * components + 2]; \
495  \
496                                         r = (r * scalar + offset) >> 8; \
497                                         g = (g * scalar + offset) >> 8; \
498                                         b = (b * scalar + offset) >> 8; \
499  \
500                                         CLAMP(r, 0, max); \
501                                         CLAMP(g, 0, max); \
502                                         CLAMP(b, 0, max); \
503  \
504                                         output_row[j * components] = r; \
505                                         output_row[j * components + 1] = g; \
506                                         output_row[j * components + 2] = b; \
507  \
508                                         if(components == 4)  \
509                                                 output_row[j * components + 3] = input_row[j * components + 3]; \
510                                 } \
511                         } \
512                 } \
513         } \
514 }
515
516
517
518 #define DO_BRIGHTNESS_F(components) \
519 { \
520         float **input_rows = (float**)input->get_rows(); \
521         float **output_rows = (float**)output->get_rows(); \
522         int row1 = pkg->row1; \
523         int row2 = pkg->row2; \
524         int width = output->get_w(); \
525         float r, g, b; \
526  \
527         if(!EQUIV(plugin->config.brightness, 0)) \
528         { \
529                 float offset = plugin->config.brightness / 100; \
530  \
531                 for(int i = row1; i < row2; i++) \
532                 { \
533                         float *input_row = input_rows[i]; \
534                         float *output_row = output_rows[i]; \
535  \
536                         for(int j = 0; j < width; j++) \
537                         { \
538                                 r = input_row[j * components] + offset; \
539                                 g = input_row[j * components + 1] + offset; \
540                                 b = input_row[j * components + 2] + offset; \
541  \
542                                 output_row[j * components] = r; \
543                                 output_row[j * components + 1] = g; \
544                                 output_row[j * components + 2] = b; \
545                                 if(components == 4)  \
546                                         output_row[j * components + 3] = input_row[j * components + 3]; \
547                         } \
548                 } \
549  \
550 /* Data to be processed is now in the output buffer */ \
551                 input_rows = output_rows; \
552         } \
553  \
554         if(!EQUIV(plugin->config.contrast, 0)) \
555         { \
556                 float contrast = (plugin->config.contrast < 0) ?  \
557                         (plugin->config.contrast + 100) / 100 :  \
558                         (plugin->config.contrast + 25) / 25; \
559  \
560 /* Shift black level down so shadows get darker instead of lighter */ \
561                 float offset = 0.5 - contrast / 2; \
562                 float y, u, v; \
563  \
564                 for(int i = row1; i < row2; i++) \
565                 { \
566                         float *input_row = input_rows[i]; \
567                         float *output_row = output_rows[i]; \
568  \
569                         if(plugin->config.luma) \
570                         { \
571                                 for(int j = 0; j < width; j++) \
572                                 { \
573                                         r = input_row[j * components]; \
574                                         g = input_row[j * components + 1]; \
575                                         b = input_row[j * components + 2]; \
576                                         YUV::yuv.rgb_to_yuv_f(r, g, b, y, u, v); \
577                                         y = y * contrast + offset; \
578                                         YUV::yuv.yuv_to_rgb_f(r, g, b, y, u, v); \
579                                         input_row[j * components] = r; \
580                                         input_row[j * components + 1] = g; \
581                                         input_row[j * components + 2] = b; \
582  \
583                                         if(components == 4)  \
584                                                 output_row[j * components + 3] = input_row[j * components + 3]; \
585                                 } \
586                         } \
587                         else \
588                         { \
589                                 for(int j = 0; j < width; j++) \
590                                 { \
591                                         r = input_row[j * components]; \
592                                         g = input_row[j * components + 1]; \
593                                         b = input_row[j * components + 2]; \
594  \
595                                         r = r * contrast + offset; \
596                                         g = g * contrast + offset; \
597                                         b = b * contrast + offset; \
598  \
599                                         output_row[j * components] = r; \
600                                         output_row[j * components + 1] = g; \
601                                         output_row[j * components + 2] = b; \
602  \
603                                         if(components == 4)  \
604                                                 output_row[j * components + 3] = input_row[j * components + 3]; \
605                                 } \
606                         } \
607                 } \
608         } \
609 }
610
611
612         switch(input->get_color_model())
613         {
614                 case BC_RGB888:
615                         DO_BRIGHTNESS(0xff, unsigned char, 3, 0)
616                         break;
617
618                 case BC_RGB_FLOAT:
619                         DO_BRIGHTNESS_F(3)
620                         break;
621
622                 case BC_YUV888:
623                         DO_BRIGHTNESS(0xff, unsigned char, 3, 1)
624                         break;
625
626                 case BC_RGBA8888:
627                         DO_BRIGHTNESS(0xff, unsigned char, 4, 0)
628                         break;
629
630                 case BC_RGBA_FLOAT:
631                         DO_BRIGHTNESS_F(4)
632                         break;
633
634                 case BC_YUVA8888:
635                         DO_BRIGHTNESS(0xff, unsigned char, 4, 1)
636                         break;
637
638                 case BC_RGB161616:
639                         DO_BRIGHTNESS(0xffff, uint16_t, 3, 0)
640                         break;
641
642                 case BC_YUV161616:
643                         DO_BRIGHTNESS(0xffff, uint16_t, 3, 1)
644                         break;
645
646                 case BC_RGBA16161616:
647                         DO_BRIGHTNESS(0xffff, uint16_t, 4, 0)
648                         break;
649
650                 case BC_YUVA16161616:
651                         DO_BRIGHTNESS(0xffff, uint16_t, 4, 1)
652                         break;
653         }
654
655
656
657
658
659
660
661
662
663 }
664
665
666
667
668
669
670 BrightnessEngine::BrightnessEngine(BrightnessMain *plugin, int cpus)
671  : LoadServer(cpus, cpus)
672 {
673         this->plugin = plugin;
674 }
675
676 BrightnessEngine::~BrightnessEngine()
677 {
678 }
679
680
681 void BrightnessEngine::init_packages()
682 {
683         for(int i = 0; i < LoadServer::get_total_packages(); i++)
684         {
685                 BrightnessPackage *package = (BrightnessPackage*)LoadServer::get_package(i);
686                 package->row1 = plugin->input->get_h() * i / LoadServer::get_total_packages();
687                 package->row2 = plugin->input->get_h() * (i + 1) / LoadServer::get_total_packages();
688         }
689 }
690
691 LoadClient* BrightnessEngine::new_client()
692 {
693         return new BrightnessUnit(this, plugin);
694 }
695
696 LoadPackage* BrightnessEngine::new_package()
697 {
698         return new BrightnessPackage;
699 }
700
701
702
703
704