r370: Heroine Virutal's official release 1.2.1
[cinelerra_cv/mob.git] / hvirtual / plugins / brightness / brightness.C
blob28a87ec0233d0940aff24866c6ebf308b09b12b2
1 #include "clip.h"
2 #include "filexml.h"
3 #include "brightness.h"
4 #include "defaults.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_realtime(VFrame *input_ptr, VFrame *output_ptr)
88         load_configuration();
89         if(!engine) engine = new BrightnessEngine(this, PluginClient::smp + 1);
91         this->input = input_ptr;
92         this->output = output_ptr;
94         if(!EQUIV(config.brightness, 0) || !EQUIV(config.contrast, 0))
95         {
96                 engine->process_packages();
97         }
98         else
99 // Data never processed so copy if necessary
100         if(input_ptr->get_rows()[0] != output_ptr->get_rows()[0])
101         {
102                 output_ptr->copy_from(input_ptr);
103         }
105         return 0;
110 void BrightnessMain::update_gui()
112         if(thread)
113         {
114                 load_configuration();
115                 thread->window->lock_window();
116                 thread->window->brightness->update(config.brightness);
117                 thread->window->contrast->update(config.contrast);
118                 thread->window->luma->update(config.luma);
119                 thread->window->unlock_window();
120         }
123 int BrightnessMain::load_defaults()
125         char directory[1024], string[1024];
126 // set the default directory
127         sprintf(directory, "%sbrightness.rc", BCASTDIR);
129 // load the defaults
130         defaults = new Defaults(directory);
131         defaults->load();
133         config.brightness = defaults->get("BRIGHTNESS", config.brightness);
134         config.contrast = defaults->get("CONTRAST", config.contrast);
135         config.luma = defaults->get("LUMA", config.luma);
136         return 0;
139 int BrightnessMain::save_defaults()
141         defaults->update("BRIGHTNESS", config.brightness);
142         defaults->update("CONTRAST", config.contrast);
143         defaults->update("LUMA", config.luma);
144         defaults->save();
145         return 0;
149 void BrightnessMain::save_data(KeyFrame *keyframe)
151         FileXML output;
153 // cause data to be stored directly in text
154         output.set_shared_string(keyframe->data, MESSAGESIZE);
155         output.tag.set_title("BRIGHTNESS");
156         output.tag.set_property("BRIGHTNESS", config.brightness);
157         output.tag.set_property("CONTRAST",  config.contrast);
158         output.tag.set_property("LUMA",  config.luma);
159 //printf("BrightnessMain::save_data %d\n", config.luma);
160         output.append_tag();
161         output.terminate_string();
164 void BrightnessMain::read_data(KeyFrame *keyframe)
166         FileXML input;
168         input.set_shared_string(keyframe->data, strlen(keyframe->data));
170         int result = 0;
172         while(!result)
173         {
174                 result = input.read_tag();
176                 if(!result)
177                 {
178                         if(input.tag.title_is("BRIGHTNESS"))
179                         {
180                                 config.brightness = input.tag.get_property("BRIGHTNESS", config.brightness);
181                                 config.contrast = input.tag.get_property("CONTRAST", config.contrast);
182                                 config.luma = input.tag.get_property("LUMA", config.luma);
183                         }
184                 }
185         }
200 BrightnessPackage::BrightnessPackage()
201  : LoadPackage()
208 BrightnessUnit::BrightnessUnit(BrightnessEngine *server, BrightnessMain *plugin)
209  : LoadClient(server)
211         this->plugin = plugin;
214 BrightnessUnit::~BrightnessUnit()
217         
218 void BrightnessUnit::process_package(LoadPackage *package)
220         BrightnessPackage *pkg = (BrightnessPackage*)package;
223         VFrame *output = plugin->output;
224         VFrame *input = plugin->input;
225         
230 #define DO_BRIGHTNESS(max, type, components, is_yuv) \
231 { \
232         type **input_rows = (type**)input->get_rows(); \
233         type **output_rows = (type**)output->get_rows(); \
234         int row1 = pkg->row1; \
235         int row2 = pkg->row2; \
236         int width = output->get_w(); \
237         int r, g, b; \
239         if(!EQUIV(plugin->config.brightness, 0)) \
240         { \
241                 int offset = (int)(plugin->config.brightness / 100 * max); \
242 /*printf("DO_BRIGHTNESS offset=%d\n", offset);*/ \
244                 for(int i = row1; i < row2; i++) \
245                 { \
246                         type *input_row = input_rows[i]; \
247                         type *output_row = output_rows[i]; \
249                         for(int j = 0; j < width; j++) \
250                         { \
251                                 r = input_row[j * components] + offset; \
253                                 if(!is_yuv) \
254                                 { \
255                                         g = input_row[j * components + 1] + offset; \
256                                         b = input_row[j * components + 2] + offset; \
257                                 } \
259                                 CLAMP(r, 0, max); \
260                                 if(!is_yuv) \
261                                 { \
262                                         CLAMP(g, 0, max); \
263                                         CLAMP(b, 0, max); \
264                                 } \
266                                 output_row[j * components] = r; \
268                                 if(!is_yuv) \
269                                 { \
270                                         output_row[j * components + 1] = g; \
271                                         output_row[j * components + 2] = b; \
272                                 } \
273                                 else \
274                                 { \
275                                         output_row[j * components + 1] = input_row[j * components + 1]; \
276                                         output_row[j * components + 2] = input_row[j * components + 2]; \
277                                 } \
279                                 if(components == 4)  \
280                                         output_row[j * components + 3] = input_row[j * components + 3]; \
281                         } \
282                 } \
284 /* Data to be processed is now in the output buffer */ \
285                 input_rows = output_rows; \
286         } \
288         if(!EQUIV(plugin->config.contrast, 0)) \
289         { \
290                 float contrast = (plugin->config.contrast < 0) ?  \
291                         (plugin->config.contrast + 100) / 100 :  \
292                         (plugin->config.contrast + 25) / 25; \
293 /*printf("DO_BRIGHTNESS contrast=%f\n", contrast);*/ \
295                 int scalar = (int)(contrast * 0x100); \
296                 int offset = (max << 8) / 2 - max * scalar / 2; \
297                 int y, u, v; \
299                 for(int i = row1; i < row2; i++) \
300                 { \
301                         type *input_row = input_rows[i]; \
302                         type *output_row = output_rows[i]; \
304                         if(plugin->config.luma) \
305                         { \
306                                 for(int j = 0; j < width; j++) \
307                                 { \
308                                         if(is_yuv) \
309                                         { \
310                                                 y = input_row[j * components]; \
311                                         } \
312                                         else \
313                                         { \
314                                                 r = input_row[j * components]; \
315                                                 g = input_row[j * components + 1]; \
316                                                 b = input_row[j * components + 2]; \
317                                                 if(max == 0xff) \
318                                                 { \
319                                                         BrightnessMain::yuv.rgb_to_yuv_8( \
320                                                                 r,  \
321                                                                 g,  \
322                                                                 b,  \
323                                                                 y,  \
324                                                                 u,  \
325                                                                 v); \
326                                                 } \
327                                                 else \
328                                                 { \
329                                                         BrightnessMain::yuv.rgb_to_yuv_16( \
330                                                                 r,  \
331                                                                 g,  \
332                                                                 b,  \
333                                                                 y,  \
334                                                                 u,  \
335                                                                 v); \
336                                                 } \
337          \
338                                         } \
339          \
340                                         y = (y * scalar + offset) >> 8; \
341                                         CLAMP(y, 0, max); \
342          \
343          \
344                                         if(is_yuv) \
345                                         { \
346                                                 output_row[j * components] = y; \
347                                                 output_row[j * components + 1] = input_row[j * components + 1]; \
348                                                 output_row[j * components + 2] = input_row[j * components + 2]; \
349                                         } \
350                                         else \
351                                         { \
352                                                 if(max == 0xff) \
353                                                 { \
354                                                         BrightnessMain::yuv.yuv_to_rgb_8( \
355                                                                 r,  \
356                                                                 g,  \
357                                                                 b,  \
358                                                                 y,  \
359                                                                 u,  \
360                                                                 v); \
361                                                 } \
362                                                 else \
363                                                 { \
364                                                         BrightnessMain::yuv.yuv_to_rgb_16( \
365                                                                 r,  \
366                                                                 g,  \
367                                                                 b,  \
368                                                                 y,  \
369                                                                 u,  \
370                                                                 v); \
371                                                 } \
372                                                 input_row[j * components] = r; \
373                                                 input_row[j * components + 1] = g; \
374                                                 input_row[j * components + 2] = b; \
375                                         } \
376          \
377                                         if(components == 4)  \
378                                                 output_row[j * components + 3] = input_row[j * components + 3]; \
379                                 } \
380                         } \
381                         else \
382                         { \
383                                 for(int j = 0; j < width; j++) \
384                                 { \
385                                         r = input_row[j * components]; \
386                                         g = input_row[j * components + 1]; \
387                                         b = input_row[j * components + 2]; \
389                                         r = (r * scalar + offset) >> 8; \
390                                         g = (g * scalar + offset) >> 8; \
391                                         b = (b * scalar + offset) >> 8; \
393                                         CLAMP(r, 0, max); \
394                                         CLAMP(g, 0, max); \
395                                         CLAMP(b, 0, max); \
397                                         output_row[j * components] = r; \
398                                         output_row[j * components + 1] = g; \
399                                         output_row[j * components + 2] = b; \
401                                         if(components == 4)  \
402                                                 output_row[j * components + 3] = input_row[j * components + 3]; \
403                                 } \
404                         } \
405                 } \
406         } \
411 #define DO_BRIGHTNESS_F(components) \
412 { \
413         float **input_rows = (float**)input->get_rows(); \
414         float **output_rows = (float**)output->get_rows(); \
415         int row1 = pkg->row1; \
416         int row2 = pkg->row2; \
417         int width = output->get_w(); \
418         float r, g, b; \
420         if(!EQUIV(plugin->config.brightness, 0)) \
421         { \
422                 float offset = plugin->config.brightness / 100; \
424                 for(int i = row1; i < row2; i++) \
425                 { \
426                         float *input_row = input_rows[i]; \
427                         float *output_row = output_rows[i]; \
429                         for(int j = 0; j < width; j++) \
430                         { \
431                                 r = input_row[j * components] + offset; \
432                                 g = input_row[j * components + 1] + offset; \
433                                 b = input_row[j * components + 2] + offset; \
435                                 output_row[j * components] = r; \
436                                 output_row[j * components + 1] = g; \
437                                 output_row[j * components + 2] = b; \
438                                 if(components == 4)  \
439                                         output_row[j * components + 3] = input_row[j * components + 3]; \
440                         } \
441                 } \
443 /* Data to be processed is now in the output buffer */ \
444                 input_rows = output_rows; \
445         } \
447         if(!EQUIV(plugin->config.contrast, 0)) \
448         { \
449                 float contrast = (plugin->config.contrast < 0) ?  \
450                         (plugin->config.contrast + 100) / 100 :  \
451                         (plugin->config.contrast + 25) / 25; \
453 /* Shift black level down so shadows get darker instead of lighter */ \
454                 float offset = 0.5 - contrast / 2; \
455                 float y, u, v; \
457                 for(int i = row1; i < row2; i++) \
458                 { \
459                         float *input_row = input_rows[i]; \
460                         float *output_row = output_rows[i]; \
462                         if(plugin->config.luma) \
463                         { \
464                                 for(int j = 0; j < width; j++) \
465                                 { \
466                                         r = input_row[j * components]; \
467                                         g = input_row[j * components + 1]; \
468                                         b = input_row[j * components + 2]; \
469                                         YUV::rgb_to_yuv_f( \
470                                                 r,  \
471                                                 g,  \
472                                                 b,  \
473                                                 y,  \
474                                                 u,  \
475                                                 v); \
477                                         y = y * contrast + offset; \
480                                         YUV::yuv_to_rgb_f( \
481                                                 r,  \
482                                                 g,  \
483                                                 b,  \
484                                                 y,  \
485                                                 u,  \
486                                                 v); \
487                                         input_row[j * components] = r; \
488                                         input_row[j * components + 1] = g; \
489                                         input_row[j * components + 2] = b; \
491                                         if(components == 4)  \
492                                                 output_row[j * components + 3] = input_row[j * components + 3]; \
493                                 } \
494                         } \
495                         else \
496                         { \
497                                 for(int j = 0; j < width; j++) \
498                                 { \
499                                         r = input_row[j * components]; \
500                                         g = input_row[j * components + 1]; \
501                                         b = input_row[j * components + 2]; \
503                                         r = r * contrast + offset; \
504                                         g = g * contrast + offset; \
505                                         b = b * contrast + offset; \
507                                         output_row[j * components] = r; \
508                                         output_row[j * components + 1] = g; \
509                                         output_row[j * components + 2] = b; \
511                                         if(components == 4)  \
512                                                 output_row[j * components + 3] = input_row[j * components + 3]; \
513                                 } \
514                         } \
515                 } \
516         } \
520         switch(input->get_color_model())
521         {
522                 case BC_RGB888:
523                         DO_BRIGHTNESS(0xff, unsigned char, 3, 0)
524                         break;
526                 case BC_RGB_FLOAT:
527                         DO_BRIGHTNESS_F(3)
528                         break;
530                 case BC_YUV888:
531                         DO_BRIGHTNESS(0xff, unsigned char, 3, 1)
532                         break;
534                 case BC_RGBA8888:
535                         DO_BRIGHTNESS(0xff, unsigned char, 4, 0)
536                         break;
538                 case BC_RGBA_FLOAT:
539                         DO_BRIGHTNESS_F(4)
540                         break;
542                 case BC_YUVA8888:
543                         DO_BRIGHTNESS(0xff, unsigned char, 4, 1)
544                         break;
546                 case BC_RGB161616:
547                         DO_BRIGHTNESS(0xffff, uint16_t, 3, 0)
548                         break;
550                 case BC_YUV161616:
551                         DO_BRIGHTNESS(0xffff, uint16_t, 3, 1)
552                         break;
554                 case BC_RGBA16161616:
555                         DO_BRIGHTNESS(0xffff, uint16_t, 4, 0)
556                         break;
558                 case BC_YUVA16161616:
559                         DO_BRIGHTNESS(0xffff, uint16_t, 4, 1)
560                         break;
561         }
578 BrightnessEngine::BrightnessEngine(BrightnessMain *plugin, int cpus)
579  : LoadServer(cpus, cpus)
581         this->plugin = plugin;
584 BrightnessEngine::~BrightnessEngine()
589 void BrightnessEngine::init_packages()
591         for(int i = 0; i < LoadServer::total_packages; i++)
592         {
593                 BrightnessPackage *package = (BrightnessPackage*)LoadServer::packages[i];
594                 package->row1 = (int)(plugin->input->get_h() / 
595                         LoadServer::total_packages * 
596                         i);
597                 package->row2 = package->row1 + 
598                         (int)(plugin->input->get_h() / 
599                         LoadServer::total_packages);
601                 if(i >= LoadServer::total_packages - 1)
602                         package->row2 = plugin->input->get_h();
603         }
606 LoadClient* BrightnessEngine::new_client()
608         return new BrightnessUnit(this, plugin);
611 LoadPackage* BrightnessEngine::new_package()
613         return new BrightnessPackage;