r864: Merge 2.1:
[cinelerra_cv.git] / plugins / brightness / brightness.C
blob6d8b70a219c2398398cdbf0eb55167682400b282
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);
98         if(0)
99         {
100                 return 0;
101         }
106         if(!engine) engine = new BrightnessEngine(this, PluginClient::smp + 1);
108         this->input = frame;
109         this->output = frame;
111         if(!EQUIV(config.brightness, 0) || !EQUIV(config.contrast, 0))
112         {
113                 engine->process_packages();
114         }
116         return 0;
121 void BrightnessMain::update_gui()
123         if(thread)
124         {
125                 if(load_configuration())
126                 {
127                         thread->window->lock_window("BrightnessMain::update_gui");
128                         thread->window->brightness->update(config.brightness);
129                         thread->window->contrast->update(config.contrast);
130                         thread->window->luma->update(config.luma);
131                         thread->window->unlock_window();
132                 }
133         }
136 int BrightnessMain::load_defaults()
138         char directory[BCTEXTLEN], string[BCTEXTLEN];
139 // set the default directory
140         sprintf(directory, "%sbrightness.rc", BCASTDIR);
142 // load the defaults
143         defaults = new BC_Hash(directory);
144         defaults->load();
146         config.brightness = defaults->get("BRIGHTNESS", config.brightness);
147         config.contrast = defaults->get("CONTRAST", config.contrast);
148         config.luma = defaults->get("LUMA", config.luma);
149         return 0;
152 int BrightnessMain::save_defaults()
154         defaults->update("BRIGHTNESS", config.brightness);
155         defaults->update("CONTRAST", config.contrast);
156         defaults->update("LUMA", config.luma);
157         defaults->save();
158         return 0;
162 void BrightnessMain::save_data(KeyFrame *keyframe)
164         FileXML output;
166 // cause data to be stored directly in text
167         output.set_shared_string(keyframe->data, MESSAGESIZE);
168         output.tag.set_title("BRIGHTNESS");
169         output.tag.set_property("BRIGHTNESS", config.brightness);
170         output.tag.set_property("CONTRAST",  config.contrast);
171         output.tag.set_property("LUMA",  config.luma);
172 //printf("BrightnessMain::save_data %d\n", config.luma);
173         output.append_tag();
174         output.terminate_string();
177 void BrightnessMain::read_data(KeyFrame *keyframe)
179         FileXML input;
181         input.set_shared_string(keyframe->data, strlen(keyframe->data));
183         int result = 0;
185         while(!result)
186         {
187                 result = input.read_tag();
189                 if(!result)
190                 {
191                         if(input.tag.title_is("BRIGHTNESS"))
192                         {
193                                 config.brightness = input.tag.get_property("BRIGHTNESS", config.brightness);
194                                 config.contrast = input.tag.get_property("CONTRAST", config.contrast);
195                                 config.luma = input.tag.get_property("LUMA", config.luma);
196                         }
197                 }
198         }
213 BrightnessPackage::BrightnessPackage()
214  : LoadPackage()
221 BrightnessUnit::BrightnessUnit(BrightnessEngine *server, BrightnessMain *plugin)
222  : LoadClient(server)
224         this->plugin = plugin;
227 BrightnessUnit::~BrightnessUnit()
230         
231 void BrightnessUnit::process_package(LoadPackage *package)
233         BrightnessPackage *pkg = (BrightnessPackage*)package;
236         VFrame *output = plugin->output;
237         VFrame *input = plugin->input;
238         
243 #define DO_BRIGHTNESS(max, type, components, is_yuv) \
244 { \
245         type **input_rows = (type**)input->get_rows(); \
246         type **output_rows = (type**)output->get_rows(); \
247         int row1 = pkg->row1; \
248         int row2 = pkg->row2; \
249         int width = output->get_w(); \
250         int r, g, b; \
252         if(!EQUIV(plugin->config.brightness, 0)) \
253         { \
254                 int offset = (int)(plugin->config.brightness / 100 * max); \
255 /*printf("DO_BRIGHTNESS offset=%d\n", offset);*/ \
257                 for(int i = row1; i < row2; i++) \
258                 { \
259                         type *input_row = input_rows[i]; \
260                         type *output_row = output_rows[i]; \
262                         for(int j = 0; j < width; j++) \
263                         { \
264                                 r = input_row[j * components] + offset; \
266                                 if(!is_yuv) \
267                                 { \
268                                         g = input_row[j * components + 1] + offset; \
269                                         b = input_row[j * components + 2] + offset; \
270                                 } \
272                                 CLAMP(r, 0, max); \
273                                 if(!is_yuv) \
274                                 { \
275                                         CLAMP(g, 0, max); \
276                                         CLAMP(b, 0, max); \
277                                 } \
279                                 output_row[j * components] = r; \
281                                 if(!is_yuv) \
282                                 { \
283                                         output_row[j * components + 1] = g; \
284                                         output_row[j * components + 2] = b; \
285                                 } \
286                                 else \
287                                 { \
288                                         output_row[j * components + 1] = input_row[j * components + 1]; \
289                                         output_row[j * components + 2] = input_row[j * components + 2]; \
290                                 } \
292                                 if(components == 4)  \
293                                         output_row[j * components + 3] = input_row[j * components + 3]; \
294                         } \
295                 } \
297 /* Data to be processed is now in the output buffer */ \
298                 input_rows = output_rows; \
299         } \
301         if(!EQUIV(plugin->config.contrast, 0)) \
302         { \
303                 float contrast = (plugin->config.contrast < 0) ?  \
304                         (plugin->config.contrast + 100) / 100 :  \
305                         (plugin->config.contrast + 25) / 25; \
306 /*printf("DO_BRIGHTNESS contrast=%f\n", contrast);*/ \
308                 int scalar = (int)(contrast * 0x100); \
309                 int offset = (max << 8) / 2 - max * scalar / 2; \
310                 int y, u, v; \
312                 for(int i = row1; i < row2; i++) \
313                 { \
314                         type *input_row = input_rows[i]; \
315                         type *output_row = output_rows[i]; \
317                         if(plugin->config.luma) \
318                         { \
319                                 for(int j = 0; j < width; j++) \
320                                 { \
321                                         if(is_yuv) \
322                                         { \
323                                                 y = input_row[j * components]; \
324                                         } \
325                                         else \
326                                         { \
327                                                 r = input_row[j * components]; \
328                                                 g = input_row[j * components + 1]; \
329                                                 b = input_row[j * components + 2]; \
330                                                 if(max == 0xff) \
331                                                 { \
332                                                         BrightnessMain::yuv.rgb_to_yuv_8( \
333                                                                 r,  \
334                                                                 g,  \
335                                                                 b,  \
336                                                                 y,  \
337                                                                 u,  \
338                                                                 v); \
339                                                 } \
340                                                 else \
341                                                 { \
342                                                         BrightnessMain::yuv.rgb_to_yuv_16( \
343                                                                 r,  \
344                                                                 g,  \
345                                                                 b,  \
346                                                                 y,  \
347                                                                 u,  \
348                                                                 v); \
349                                                 } \
350          \
351                                         } \
352          \
353                                         y = (y * scalar + offset) >> 8; \
354                                         CLAMP(y, 0, max); \
355          \
356          \
357                                         if(is_yuv) \
358                                         { \
359                                                 output_row[j * components] = y; \
360                                                 output_row[j * components + 1] = input_row[j * components + 1]; \
361                                                 output_row[j * components + 2] = input_row[j * components + 2]; \
362                                         } \
363                                         else \
364                                         { \
365                                                 if(max == 0xff) \
366                                                 { \
367                                                         BrightnessMain::yuv.yuv_to_rgb_8( \
368                                                                 r,  \
369                                                                 g,  \
370                                                                 b,  \
371                                                                 y,  \
372                                                                 u,  \
373                                                                 v); \
374                                                 } \
375                                                 else \
376                                                 { \
377                                                         BrightnessMain::yuv.yuv_to_rgb_16( \
378                                                                 r,  \
379                                                                 g,  \
380                                                                 b,  \
381                                                                 y,  \
382                                                                 u,  \
383                                                                 v); \
384                                                 } \
385                                                 input_row[j * components] = r; \
386                                                 input_row[j * components + 1] = g; \
387                                                 input_row[j * components + 2] = b; \
388                                         } \
389          \
390                                         if(components == 4)  \
391                                                 output_row[j * components + 3] = input_row[j * components + 3]; \
392                                 } \
393                         } \
394                         else \
395                         { \
396                                 for(int j = 0; j < width; j++) \
397                                 { \
398                                         r = input_row[j * components]; \
399                                         g = input_row[j * components + 1]; \
400                                         b = input_row[j * components + 2]; \
402                                         r = (r * scalar + offset) >> 8; \
403                                         g = (g * scalar + offset) >> 8; \
404                                         b = (b * scalar + offset) >> 8; \
406                                         CLAMP(r, 0, max); \
407                                         CLAMP(g, 0, max); \
408                                         CLAMP(b, 0, max); \
410                                         output_row[j * components] = r; \
411                                         output_row[j * components + 1] = g; \
412                                         output_row[j * components + 2] = b; \
414                                         if(components == 4)  \
415                                                 output_row[j * components + 3] = input_row[j * components + 3]; \
416                                 } \
417                         } \
418                 } \
419         } \
424 #define DO_BRIGHTNESS_F(components) \
425 { \
426         float **input_rows = (float**)input->get_rows(); \
427         float **output_rows = (float**)output->get_rows(); \
428         int row1 = pkg->row1; \
429         int row2 = pkg->row2; \
430         int width = output->get_w(); \
431         float r, g, b; \
433         if(!EQUIV(plugin->config.brightness, 0)) \
434         { \
435                 float offset = plugin->config.brightness / 100; \
437                 for(int i = row1; i < row2; i++) \
438                 { \
439                         float *input_row = input_rows[i]; \
440                         float *output_row = output_rows[i]; \
442                         for(int j = 0; j < width; j++) \
443                         { \
444                                 r = input_row[j * components] + offset; \
445                                 g = input_row[j * components + 1] + offset; \
446                                 b = input_row[j * components + 2] + offset; \
448                                 output_row[j * components] = r; \
449                                 output_row[j * components + 1] = g; \
450                                 output_row[j * components + 2] = b; \
451                                 if(components == 4)  \
452                                         output_row[j * components + 3] = input_row[j * components + 3]; \
453                         } \
454                 } \
456 /* Data to be processed is now in the output buffer */ \
457                 input_rows = output_rows; \
458         } \
460         if(!EQUIV(plugin->config.contrast, 0)) \
461         { \
462                 float contrast = (plugin->config.contrast < 0) ?  \
463                         (plugin->config.contrast + 100) / 100 :  \
464                         (plugin->config.contrast + 25) / 25; \
466 /* Shift black level down so shadows get darker instead of lighter */ \
467                 float offset = 0.5 - contrast / 2; \
468                 float y, u, v; \
470                 for(int i = row1; i < row2; i++) \
471                 { \
472                         float *input_row = input_rows[i]; \
473                         float *output_row = output_rows[i]; \
475                         if(plugin->config.luma) \
476                         { \
477                                 for(int j = 0; j < width; j++) \
478                                 { \
479                                         r = input_row[j * components]; \
480                                         g = input_row[j * components + 1]; \
481                                         b = input_row[j * components + 2]; \
482                                         YUV::rgb_to_yuv_f( \
483                                                 r,  \
484                                                 g,  \
485                                                 b,  \
486                                                 y,  \
487                                                 u,  \
488                                                 v); \
490                                         y = y * contrast + offset; \
493                                         YUV::yuv_to_rgb_f( \
494                                                 r,  \
495                                                 g,  \
496                                                 b,  \
497                                                 y,  \
498                                                 u,  \
499                                                 v); \
500                                         input_row[j * components] = r; \
501                                         input_row[j * components + 1] = g; \
502                                         input_row[j * components + 2] = b; \
504                                         if(components == 4)  \
505                                                 output_row[j * components + 3] = input_row[j * components + 3]; \
506                                 } \
507                         } \
508                         else \
509                         { \
510                                 for(int j = 0; j < width; j++) \
511                                 { \
512                                         r = input_row[j * components]; \
513                                         g = input_row[j * components + 1]; \
514                                         b = input_row[j * components + 2]; \
516                                         r = r * contrast + offset; \
517                                         g = g * contrast + offset; \
518                                         b = b * contrast + offset; \
520                                         output_row[j * components] = r; \
521                                         output_row[j * components + 1] = g; \
522                                         output_row[j * components + 2] = b; \
524                                         if(components == 4)  \
525                                                 output_row[j * components + 3] = input_row[j * components + 3]; \
526                                 } \
527                         } \
528                 } \
529         } \
533         switch(input->get_color_model())
534         {
535                 case BC_RGB888:
536                         DO_BRIGHTNESS(0xff, unsigned char, 3, 0)
537                         break;
539                 case BC_RGB_FLOAT:
540                         DO_BRIGHTNESS_F(3)
541                         break;
543                 case BC_YUV888:
544                         DO_BRIGHTNESS(0xff, unsigned char, 3, 1)
545                         break;
547                 case BC_RGBA8888:
548                         DO_BRIGHTNESS(0xff, unsigned char, 4, 0)
549                         break;
551                 case BC_RGBA_FLOAT:
552                         DO_BRIGHTNESS_F(4)
553                         break;
555                 case BC_YUVA8888:
556                         DO_BRIGHTNESS(0xff, unsigned char, 4, 1)
557                         break;
559                 case BC_RGB161616:
560                         DO_BRIGHTNESS(0xffff, uint16_t, 3, 0)
561                         break;
563                 case BC_YUV161616:
564                         DO_BRIGHTNESS(0xffff, uint16_t, 3, 1)
565                         break;
567                 case BC_RGBA16161616:
568                         DO_BRIGHTNESS(0xffff, uint16_t, 4, 0)
569                         break;
571                 case BC_YUVA16161616:
572                         DO_BRIGHTNESS(0xffff, uint16_t, 4, 1)
573                         break;
574         }
591 BrightnessEngine::BrightnessEngine(BrightnessMain *plugin, int cpus)
592  : LoadServer(cpus, cpus)
594         this->plugin = plugin;
597 BrightnessEngine::~BrightnessEngine()
602 void BrightnessEngine::init_packages()
604         for(int i = 0; i < LoadServer::get_total_packages(); i++)
605         {
606                 BrightnessPackage *package = (BrightnessPackage*)LoadServer::get_package(i);
607                 package->row1 = plugin->input->get_h() * i / LoadServer::get_total_packages();
608                 package->row2 = plugin->input->get_h() * (i + 1) / LoadServer::get_total_packages();
609         }
612 LoadClient* BrightnessEngine::new_client()
614         return new BrightnessUnit(this, plugin);
617 LoadPackage* BrightnessEngine::new_package()
619         return new BrightnessPackage;