Fixed initialisation of tf in file_open(). Without setting the memory to 0,
[cinelerra_cv/mob.git] / plugins / brightness / brightness.C
blobe6f46467975857296186e1763bb2171965bd374a
1 #include "clip.h"
2 #include "filexml.h"
3 #include "brightness.h"
4 #include "bchash.h"
5 #include "language.h"
6 #include "picon_png.h"
8 #include <stdio.h>
9 #include <stdint.h>
10 #include <string.h>
12 #define SQR(a) ((a) * (a))
14 REGISTER_PLUGIN(BrightnessMain)
18 BrightnessConfig::BrightnessConfig()
20         brightness = 0;
21         contrast = 0;
22         luma = 1;
25 int BrightnessConfig::equivalent(BrightnessConfig &that)
27         return (brightness == that.brightness && 
28                 contrast == that.contrast &&
29                 luma == that.luma);
32 void BrightnessConfig::copy_from(BrightnessConfig &that)
34         brightness = that.brightness;
35         contrast = that.contrast;
36         luma = that.luma;
39 void BrightnessConfig::interpolate(BrightnessConfig &prev, 
40         BrightnessConfig &next, 
41         int64_t prev_frame, 
42         int64_t next_frame, 
43         int64_t current_frame)
45         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
46         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
48         this->brightness = prev.brightness * prev_scale + next.brightness * next_scale;
49         this->contrast = prev.contrast * prev_scale + next.contrast * next_scale;
50         this->luma = (int)(prev.luma * prev_scale + next.luma * next_scale);
61 YUV BrightnessMain::yuv;
63 BrightnessMain::BrightnessMain(PluginServer *server)
64  : PluginVClient(server)
66     redo_buffers = 1;
67         engine = 0;
68         PLUGIN_CONSTRUCTOR_MACRO
71 BrightnessMain::~BrightnessMain()
73         PLUGIN_DESTRUCTOR_MACRO
74         if(engine) delete engine;
77 char* BrightnessMain::plugin_title() { return N_("Brightness/Contrast"); }
78 int BrightnessMain::is_realtime() { return 1; }
80 NEW_PICON_MACRO(BrightnessMain) 
81 SHOW_GUI_MACRO(BrightnessMain, BrightnessThread)
82 RAISE_WINDOW_MACRO(BrightnessMain)
83 SET_STRING_MACRO(BrightnessMain)
84 LOAD_CONFIGURATION_MACRO(BrightnessMain, BrightnessConfig)
86 int BrightnessMain::process_buffer(VFrame *frame,
87         int64_t start_position,
88         double frame_rate)
90         load_configuration();
92         read_frame(frame, 
93                 0, 
94                 start_position, 
95                 frame_rate,
96                 get_use_opengl());
99 // Use hardware
100         if(get_use_opengl())
101         {
102                 run_opengl();
103                 return 0;
104         }
109         if(!engine) engine = new BrightnessEngine(this, PluginClient::smp + 1);
111         this->input = frame;
112         this->output = frame;
114         if(!EQUIV(config.brightness, 0) || !EQUIV(config.contrast, 0))
115         {
116                 engine->process_packages();
117         }
119         return 0;
122 int BrightnessMain::handle_opengl()
124 #ifdef HAVE_GL
125         static char *brightness_yuvluma_frag = 
126                 "uniform sampler2D tex;\n"
127                 "uniform float brightness;\n"
128                 "uniform float contrast;\n"
129                 "uniform float offset;\n"
130                 "void main()\n"
131                 "{\n"
132                 "       vec4 yuva = texture2D(tex, gl_TexCoord[0].st);\n"
133                 "       yuva.r += brightness;\n"
134                 "       yuva.r = yuva.r * contrast + offset;\n"
135                 "       gl_FragColor = yuva;\n"
136                 "}\n";
138         static char *brightness_yuv_frag = 
139                 "uniform sampler2D tex;\n"
140                 "uniform float brightness;\n"
141                 "uniform float contrast;\n"
142                 "uniform float offset;\n"
143                 "void main()\n"
144                 "{\n"
145                 "       vec4 yuva = texture2D(tex, gl_TexCoord[0].st);\n"
146                 "       yuva.r += brightness;\n"
147                 "       yuva.rgb *= vec3(contrast, contrast, contrast);\n"
148                 "       yuva.rgb += vec3(offset, offset, offset);\n"
149                 "       gl_FragColor = yuva;\n"
150                 "}\n";
152         static char *brightness_rgb_frag =
153                 "uniform sampler2D tex;\n"
154                 "uniform float brightness;\n"
155                 "uniform float contrast;\n"
156                 "uniform float offset;\n"
157                 "void main()\n"
158                 "{\n"
159                 "       vec4 rgba = texture2D(tex, gl_TexCoord[0].st);\n"
160                 "       rgba.rgb += vec3(brightness, brightness, brightness);\n"
161                 "       rgba.rgb *= vec3(contrast, contrast, contrast);\n"
162                 "       rgba.rgb += vec3(offset, offset, offset);\n"
163                 "       gl_FragColor = rgba;\n"
164                 "}\n";
166         static char *brightness_rgbluma_frag =
167                 "uniform sampler2D tex;\n"
168                 "uniform float brightness;\n"
169                 "uniform float contrast;\n"
170                 "uniform float offset;\n"
171                 "void main()\n"
172                 "{\n"
173                 "       const mat3 yuv_to_rgb_matrix = mat3(\n"
174                 "               1,       1,        1, \n"
175                 "               0,       -0.34414, 1.77200, \n"
176                 "               1.40200, -0.71414, 0);\n"
177                 "       const mat3 rgb_to_yuv_matrix = mat3(\n"
178                 "               0.29900, -0.16874, 0.50000, \n"
179                 "               0.58700, -0.33126, -0.41869, \n"
180                 "               0.11400, 0.50000,  -0.08131);\n"
181                 "       vec4 rgba = texture2D(tex, gl_TexCoord[0].st);\n"
182                 "       rgba.rgb = rgb_to_yuv_matrix * rgba.rgb;\n"
183                 "       rgba.r += brightness;\n"
184                 "       rgba.r = rgba.r * contrast + offset;\n"
185                 "       rgba.rgb = yuv_to_rgb_matrix * rgba.rgb;\n"
186                 "       gl_FragColor = rgba;\n"
187                 "}\n";
189         get_output()->to_texture();
190         get_output()->enable_opengl();
192         unsigned int shader_id = 0;
193         switch(get_output()->get_color_model())
194         {
195                 case BC_YUV888:
196                 case BC_YUVA8888:
197                         if(config.luma)
198                                 shader_id = VFrame::make_shader(0,
199                                         brightness_yuvluma_frag,
200                                         0);
201                         else
202                                 shader_id = VFrame::make_shader(0,
203                                         brightness_yuv_frag,
204                                         0);
205                         break;
206                 default:
207                         if(config.luma)
208                                 shader_id = VFrame::make_shader(0,
209                                         brightness_rgbluma_frag,
210                                         0);
211                         else
212                                 shader_id = VFrame::make_shader(0,
213                                         brightness_rgb_frag,
214                                         0);
215                         break;
216         }
219         if(shader_id > 0) 
220         {
221                 glUseProgram(shader_id);
222                 glUniform1i(glGetUniformLocation(shader_id, "tex"), 0);
223                 glUniform1f(glGetUniformLocation(shader_id, "brightness"), config.brightness / 100);
224                 float contrast = (config.contrast < 0) ? 
225                         (config.contrast + 100) / 100 : 
226                         (config.contrast + 25) / 25;
227                 glUniform1f(glGetUniformLocation(shader_id, "contrast"), contrast);
228                 float offset = 0.5 - contrast / 2;
229                 glUniform1f(glGetUniformLocation(shader_id, "offset"), offset);
230         }
232         get_output()->init_screen();
233         get_output()->bind_texture(0);
235         
237         get_output()->draw_texture();
238         glUseProgram(0);
239         get_output()->set_opengl_state(VFrame::SCREEN);
240 //printf("BrightnessMain::handle_opengl 100 %x\n", glGetError());
241 #endif
245 void BrightnessMain::update_gui()
247         if(thread)
248         {
249                 if(load_configuration())
250                 {
251                         thread->window->lock_window("BrightnessMain::update_gui");
252                         thread->window->brightness->update(config.brightness);
253                         thread->window->contrast->update(config.contrast);
254                         thread->window->luma->update(config.luma);
255                         thread->window->unlock_window();
256                 }
257         }
260 int BrightnessMain::load_defaults()
262         char directory[BCTEXTLEN], string[BCTEXTLEN];
263 // set the default directory
264         sprintf(directory, "%sbrightness.rc", BCASTDIR);
266 // load the defaults
267         defaults = new BC_Hash(directory);
268         defaults->load();
270         config.brightness = defaults->get("BRIGHTNESS", config.brightness);
271         config.contrast = defaults->get("CONTRAST", config.contrast);
272         config.luma = defaults->get("LUMA", config.luma);
273         return 0;
276 int BrightnessMain::save_defaults()
278         defaults->update("BRIGHTNESS", config.brightness);
279         defaults->update("CONTRAST", config.contrast);
280         defaults->update("LUMA", config.luma);
281         defaults->save();
282         return 0;
286 void BrightnessMain::save_data(KeyFrame *keyframe)
288         FileXML output;
290 // cause data to be stored directly in text
291         output.set_shared_string(keyframe->data, MESSAGESIZE);
292         output.tag.set_title("BRIGHTNESS");
293         output.tag.set_property("BRIGHTNESS", config.brightness);
294         output.tag.set_property("CONTRAST",  config.contrast);
295         output.tag.set_property("LUMA",  config.luma);
296 //printf("BrightnessMain::save_data %d\n", config.luma);
297         output.append_tag();
298         output.terminate_string();
301 void BrightnessMain::read_data(KeyFrame *keyframe)
303         FileXML input;
305         input.set_shared_string(keyframe->data, strlen(keyframe->data));
307         int result = 0;
309         while(!result)
310         {
311                 result = input.read_tag();
313                 if(!result)
314                 {
315                         if(input.tag.title_is("BRIGHTNESS"))
316                         {
317                                 config.brightness = input.tag.get_property("BRIGHTNESS", config.brightness);
318                                 config.contrast = input.tag.get_property("CONTRAST", config.contrast);
319                                 config.luma = input.tag.get_property("LUMA", config.luma);
320                         }
321                 }
322         }
337 BrightnessPackage::BrightnessPackage()
338  : LoadPackage()
345 BrightnessUnit::BrightnessUnit(BrightnessEngine *server, BrightnessMain *plugin)
346  : LoadClient(server)
348         this->plugin = plugin;
351 BrightnessUnit::~BrightnessUnit()
354         
355 void BrightnessUnit::process_package(LoadPackage *package)
357         BrightnessPackage *pkg = (BrightnessPackage*)package;
360         VFrame *output = plugin->output;
361         VFrame *input = plugin->input;
362         
367 #define DO_BRIGHTNESS(max, type, components, is_yuv) \
368 { \
369         type **input_rows = (type**)input->get_rows(); \
370         type **output_rows = (type**)output->get_rows(); \
371         int row1 = pkg->row1; \
372         int row2 = pkg->row2; \
373         int width = output->get_w(); \
374         int r, g, b; \
376         if(!EQUIV(plugin->config.brightness, 0)) \
377         { \
378                 int offset = (int)(plugin->config.brightness / 100 * max); \
379 /*printf("DO_BRIGHTNESS offset=%d\n", offset);*/ \
381                 for(int i = row1; i < row2; i++) \
382                 { \
383                         type *input_row = input_rows[i]; \
384                         type *output_row = output_rows[i]; \
386                         for(int j = 0; j < width; j++) \
387                         { \
388                                 r = input_row[j * components] + offset; \
390                                 if(!is_yuv) \
391                                 { \
392                                         g = input_row[j * components + 1] + offset; \
393                                         b = input_row[j * components + 2] + offset; \
394                                 } \
396                                 CLAMP(r, 0, max); \
397                                 if(!is_yuv) \
398                                 { \
399                                         CLAMP(g, 0, max); \
400                                         CLAMP(b, 0, max); \
401                                 } \
403                                 output_row[j * components] = r; \
405                                 if(!is_yuv) \
406                                 { \
407                                         output_row[j * components + 1] = g; \
408                                         output_row[j * components + 2] = b; \
409                                 } \
410                                 else \
411                                 { \
412                                         output_row[j * components + 1] = input_row[j * components + 1]; \
413                                         output_row[j * components + 2] = input_row[j * components + 2]; \
414                                 } \
416                                 if(components == 4)  \
417                                         output_row[j * components + 3] = input_row[j * components + 3]; \
418                         } \
419                 } \
421 /* Data to be processed is now in the output buffer */ \
422                 input_rows = output_rows; \
423         } \
425         if(!EQUIV(plugin->config.contrast, 0)) \
426         { \
427                 float contrast = (plugin->config.contrast < 0) ?  \
428                         (plugin->config.contrast + 100) / 100 :  \
429                         (plugin->config.contrast + 25) / 25; \
430 /*printf("DO_BRIGHTNESS contrast=%f\n", contrast);*/ \
432                 int scalar = (int)(contrast * 0x100); \
433                 int offset = (max << 8) / 2 - max * scalar / 2; \
434                 int y, u, v; \
436                 for(int i = row1; i < row2; i++) \
437                 { \
438                         type *input_row = input_rows[i]; \
439                         type *output_row = output_rows[i]; \
441                         if(plugin->config.luma) \
442                         { \
443                                 for(int j = 0; j < width; j++) \
444                                 { \
445                                         if(is_yuv) \
446                                         { \
447                                                 y = input_row[j * components]; \
448                                         } \
449                                         else \
450                                         { \
451                                                 r = input_row[j * components]; \
452                                                 g = input_row[j * components + 1]; \
453                                                 b = input_row[j * components + 2]; \
454                                                 if(max == 0xff) \
455                                                 { \
456                                                         BrightnessMain::yuv.rgb_to_yuv_8( \
457                                                                 r,  \
458                                                                 g,  \
459                                                                 b,  \
460                                                                 y,  \
461                                                                 u,  \
462                                                                 v); \
463                                                 } \
464                                                 else \
465                                                 { \
466                                                         BrightnessMain::yuv.rgb_to_yuv_16( \
467                                                                 r,  \
468                                                                 g,  \
469                                                                 b,  \
470                                                                 y,  \
471                                                                 u,  \
472                                                                 v); \
473                                                 } \
474          \
475                                         } \
476          \
477                                         y = (y * scalar + offset) >> 8; \
478                                         CLAMP(y, 0, max); \
479          \
480          \
481                                         if(is_yuv) \
482                                         { \
483                                                 output_row[j * components] = y; \
484                                                 output_row[j * components + 1] = input_row[j * components + 1]; \
485                                                 output_row[j * components + 2] = input_row[j * components + 2]; \
486                                         } \
487                                         else \
488                                         { \
489                                                 if(max == 0xff) \
490                                                 { \
491                                                         BrightnessMain::yuv.yuv_to_rgb_8( \
492                                                                 r,  \
493                                                                 g,  \
494                                                                 b,  \
495                                                                 y,  \
496                                                                 u,  \
497                                                                 v); \
498                                                 } \
499                                                 else \
500                                                 { \
501                                                         BrightnessMain::yuv.yuv_to_rgb_16( \
502                                                                 r,  \
503                                                                 g,  \
504                                                                 b,  \
505                                                                 y,  \
506                                                                 u,  \
507                                                                 v); \
508                                                 } \
509                                                 input_row[j * components] = r; \
510                                                 input_row[j * components + 1] = g; \
511                                                 input_row[j * components + 2] = b; \
512                                         } \
513          \
514                                         if(components == 4)  \
515                                                 output_row[j * components + 3] = input_row[j * components + 3]; \
516                                 } \
517                         } \
518                         else \
519                         { \
520                                 for(int j = 0; j < width; j++) \
521                                 { \
522                                         r = input_row[j * components]; \
523                                         g = input_row[j * components + 1]; \
524                                         b = input_row[j * components + 2]; \
526                                         r = (r * scalar + offset) >> 8; \
527                                         g = (g * scalar + offset) >> 8; \
528                                         b = (b * scalar + offset) >> 8; \
530                                         CLAMP(r, 0, max); \
531                                         CLAMP(g, 0, max); \
532                                         CLAMP(b, 0, max); \
534                                         output_row[j * components] = r; \
535                                         output_row[j * components + 1] = g; \
536                                         output_row[j * components + 2] = b; \
538                                         if(components == 4)  \
539                                                 output_row[j * components + 3] = input_row[j * components + 3]; \
540                                 } \
541                         } \
542                 } \
543         } \
548 #define DO_BRIGHTNESS_F(components) \
549 { \
550         float **input_rows = (float**)input->get_rows(); \
551         float **output_rows = (float**)output->get_rows(); \
552         int row1 = pkg->row1; \
553         int row2 = pkg->row2; \
554         int width = output->get_w(); \
555         float r, g, b; \
557         if(!EQUIV(plugin->config.brightness, 0)) \
558         { \
559                 float offset = plugin->config.brightness / 100; \
561                 for(int i = row1; i < row2; i++) \
562                 { \
563                         float *input_row = input_rows[i]; \
564                         float *output_row = output_rows[i]; \
566                         for(int j = 0; j < width; j++) \
567                         { \
568                                 r = input_row[j * components] + offset; \
569                                 g = input_row[j * components + 1] + offset; \
570                                 b = input_row[j * components + 2] + offset; \
572                                 output_row[j * components] = r; \
573                                 output_row[j * components + 1] = g; \
574                                 output_row[j * components + 2] = b; \
575                                 if(components == 4)  \
576                                         output_row[j * components + 3] = input_row[j * components + 3]; \
577                         } \
578                 } \
580 /* Data to be processed is now in the output buffer */ \
581                 input_rows = output_rows; \
582         } \
584         if(!EQUIV(plugin->config.contrast, 0)) \
585         { \
586                 float contrast = (plugin->config.contrast < 0) ?  \
587                         (plugin->config.contrast + 100) / 100 :  \
588                         (plugin->config.contrast + 25) / 25; \
590 /* Shift black level down so shadows get darker instead of lighter */ \
591                 float offset = 0.5 - contrast / 2; \
592                 float y, u, v; \
594                 for(int i = row1; i < row2; i++) \
595                 { \
596                         float *input_row = input_rows[i]; \
597                         float *output_row = output_rows[i]; \
599                         if(plugin->config.luma) \
600                         { \
601                                 for(int j = 0; j < width; j++) \
602                                 { \
603                                         r = input_row[j * components]; \
604                                         g = input_row[j * components + 1]; \
605                                         b = input_row[j * components + 2]; \
606                                         YUV::rgb_to_yuv_f( \
607                                                 r,  \
608                                                 g,  \
609                                                 b,  \
610                                                 y,  \
611                                                 u,  \
612                                                 v); \
614                                         y = y * contrast + offset; \
617                                         YUV::yuv_to_rgb_f( \
618                                                 r,  \
619                                                 g,  \
620                                                 b,  \
621                                                 y,  \
622                                                 u,  \
623                                                 v); \
624                                         input_row[j * components] = r; \
625                                         input_row[j * components + 1] = g; \
626                                         input_row[j * components + 2] = b; \
628                                         if(components == 4)  \
629                                                 output_row[j * components + 3] = input_row[j * components + 3]; \
630                                 } \
631                         } \
632                         else \
633                         { \
634                                 for(int j = 0; j < width; j++) \
635                                 { \
636                                         r = input_row[j * components]; \
637                                         g = input_row[j * components + 1]; \
638                                         b = input_row[j * components + 2]; \
640                                         r = r * contrast + offset; \
641                                         g = g * contrast + offset; \
642                                         b = b * contrast + offset; \
644                                         output_row[j * components] = r; \
645                                         output_row[j * components + 1] = g; \
646                                         output_row[j * components + 2] = b; \
648                                         if(components == 4)  \
649                                                 output_row[j * components + 3] = input_row[j * components + 3]; \
650                                 } \
651                         } \
652                 } \
653         } \
657         switch(input->get_color_model())
658         {
659                 case BC_RGB888:
660                         DO_BRIGHTNESS(0xff, unsigned char, 3, 0)
661                         break;
663                 case BC_RGB_FLOAT:
664                         DO_BRIGHTNESS_F(3)
665                         break;
667                 case BC_YUV888:
668                         DO_BRIGHTNESS(0xff, unsigned char, 3, 1)
669                         break;
671                 case BC_RGBA8888:
672                         DO_BRIGHTNESS(0xff, unsigned char, 4, 0)
673                         break;
675                 case BC_RGBA_FLOAT:
676                         DO_BRIGHTNESS_F(4)
677                         break;
679                 case BC_YUVA8888:
680                         DO_BRIGHTNESS(0xff, unsigned char, 4, 1)
681                         break;
683                 case BC_RGB161616:
684                         DO_BRIGHTNESS(0xffff, uint16_t, 3, 0)
685                         break;
687                 case BC_YUV161616:
688                         DO_BRIGHTNESS(0xffff, uint16_t, 3, 1)
689                         break;
691                 case BC_RGBA16161616:
692                         DO_BRIGHTNESS(0xffff, uint16_t, 4, 0)
693                         break;
695                 case BC_YUVA16161616:
696                         DO_BRIGHTNESS(0xffff, uint16_t, 4, 1)
697                         break;
698         }
715 BrightnessEngine::BrightnessEngine(BrightnessMain *plugin, int cpus)
716  : LoadServer(cpus, cpus)
718         this->plugin = plugin;
721 BrightnessEngine::~BrightnessEngine()
726 void BrightnessEngine::init_packages()
728         for(int i = 0; i < LoadServer::get_total_packages(); i++)
729         {
730                 BrightnessPackage *package = (BrightnessPackage*)LoadServer::get_package(i);
731                 package->row1 = plugin->input->get_h() * i / LoadServer::get_total_packages();
732                 package->row2 = plugin->input->get_h() * (i + 1) / LoadServer::get_total_packages();
733         }
736 LoadClient* BrightnessEngine::new_client()
738         return new BrightnessUnit(this, plugin);
741 LoadPackage* BrightnessEngine::new_package()
743         return new BrightnessPackage;