3 #include "brightness.h"
12 #define SQR(a) ((a) * (a))
14 REGISTER_PLUGIN(BrightnessMain)
18 BrightnessConfig::BrightnessConfig()
25 int BrightnessConfig::equivalent(BrightnessConfig &that)
27 return (brightness == that.brightness &&
28 contrast == that.contrast &&
32 void BrightnessConfig::copy_from(BrightnessConfig &that)
34 brightness = that.brightness;
35 contrast = that.contrast;
39 void BrightnessConfig::interpolate(BrightnessConfig &prev,
40 BrightnessConfig &next,
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)
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,
109 if(!engine) engine = new BrightnessEngine(this, PluginClient::smp + 1);
112 this->output = frame;
114 if(!EQUIV(config.brightness, 0) || !EQUIV(config.contrast, 0))
116 engine->process_packages();
122 int BrightnessMain::handle_opengl()
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"
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"
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"
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"
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"
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"
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"
173 " const mat3 yuv_to_rgb_matrix = mat3(\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"
189 get_output()->to_texture();
190 get_output()->enable_opengl();
192 unsigned int shader_id = 0;
193 switch(get_output()->get_color_model())
198 shader_id = VFrame::make_shader(0,
199 brightness_yuvluma_frag,
202 shader_id = VFrame::make_shader(0,
208 shader_id = VFrame::make_shader(0,
209 brightness_rgbluma_frag,
212 shader_id = VFrame::make_shader(0,
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);
232 get_output()->init_screen();
233 get_output()->bind_texture(0);
237 get_output()->draw_texture();
239 get_output()->set_opengl_state(VFrame::SCREEN);
240 //printf("BrightnessMain::handle_opengl 100 %x\n", glGetError());
245 void BrightnessMain::update_gui()
249 if(load_configuration())
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();
260 int BrightnessMain::load_defaults()
262 char directory[BCTEXTLEN], string[BCTEXTLEN];
263 // set the default directory
264 sprintf(directory, "%sbrightness.rc", BCASTDIR);
267 defaults = new BC_Hash(directory);
270 config.brightness = defaults->get("BRIGHTNESS", config.brightness);
271 config.contrast = defaults->get("CONTRAST", config.contrast);
272 config.luma = defaults->get("LUMA", config.luma);
276 int BrightnessMain::save_defaults()
278 defaults->update("BRIGHTNESS", config.brightness);
279 defaults->update("CONTRAST", config.contrast);
280 defaults->update("LUMA", config.luma);
286 void BrightnessMain::save_data(KeyFrame *keyframe)
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);
298 output.terminate_string();
301 void BrightnessMain::read_data(KeyFrame *keyframe)
305 input.set_shared_string(keyframe->data, strlen(keyframe->data));
311 result = input.read_tag();
315 if(input.tag.title_is("BRIGHTNESS"))
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);
337 BrightnessPackage::BrightnessPackage()
345 BrightnessUnit::BrightnessUnit(BrightnessEngine *server, BrightnessMain *plugin)
348 this->plugin = plugin;
351 BrightnessUnit::~BrightnessUnit()
355 void BrightnessUnit::process_package(LoadPackage *package)
357 BrightnessPackage *pkg = (BrightnessPackage*)package;
360 VFrame *output = plugin->output;
361 VFrame *input = plugin->input;
367 #define DO_BRIGHTNESS(max, type, components, is_yuv) \
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(); \
376 if(!EQUIV(plugin->config.brightness, 0)) \
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++) \
383 type *input_row = input_rows[i]; \
384 type *output_row = output_rows[i]; \
386 for(int j = 0; j < width; j++) \
388 r = input_row[j * components] + offset; \
392 g = input_row[j * components + 1] + offset; \
393 b = input_row[j * components + 2] + offset; \
403 output_row[j * components] = r; \
407 output_row[j * components + 1] = g; \
408 output_row[j * components + 2] = b; \
412 output_row[j * components + 1] = input_row[j * components + 1]; \
413 output_row[j * components + 2] = input_row[j * components + 2]; \
416 if(components == 4) \
417 output_row[j * components + 3] = input_row[j * components + 3]; \
421 /* Data to be processed is now in the output buffer */ \
422 input_rows = output_rows; \
425 if(!EQUIV(plugin->config.contrast, 0)) \
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; \
436 for(int i = row1; i < row2; i++) \
438 type *input_row = input_rows[i]; \
439 type *output_row = output_rows[i]; \
441 if(plugin->config.luma) \
443 for(int j = 0; j < width; j++) \
447 y = input_row[j * components]; \
451 r = input_row[j * components]; \
452 g = input_row[j * components + 1]; \
453 b = input_row[j * components + 2]; \
456 BrightnessMain::yuv.rgb_to_yuv_8( \
466 BrightnessMain::yuv.rgb_to_yuv_16( \
477 y = (y * scalar + offset) >> 8; \
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]; \
491 BrightnessMain::yuv.yuv_to_rgb_8( \
501 BrightnessMain::yuv.yuv_to_rgb_16( \
509 input_row[j * components] = r; \
510 input_row[j * components + 1] = g; \
511 input_row[j * components + 2] = b; \
514 if(components == 4) \
515 output_row[j * components + 3] = input_row[j * components + 3]; \
520 for(int j = 0; j < width; j++) \
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; \
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]; \
548 #define DO_BRIGHTNESS_F(components) \
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(); \
557 if(!EQUIV(plugin->config.brightness, 0)) \
559 float offset = plugin->config.brightness / 100; \
561 for(int i = row1; i < row2; i++) \
563 float *input_row = input_rows[i]; \
564 float *output_row = output_rows[i]; \
566 for(int j = 0; j < width; j++) \
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]; \
580 /* Data to be processed is now in the output buffer */ \
581 input_rows = output_rows; \
584 if(!EQUIV(plugin->config.contrast, 0)) \
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; \
594 for(int i = row1; i < row2; i++) \
596 float *input_row = input_rows[i]; \
597 float *output_row = output_rows[i]; \
599 if(plugin->config.luma) \
601 for(int j = 0; j < width; j++) \
603 r = input_row[j * components]; \
604 g = input_row[j * components + 1]; \
605 b = input_row[j * components + 2]; \
614 y = y * contrast + offset; \
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]; \
634 for(int j = 0; j < width; j++) \
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]; \
657 switch(input->get_color_model())
660 DO_BRIGHTNESS(0xff, unsigned char, 3, 0)
668 DO_BRIGHTNESS(0xff, unsigned char, 3, 1)
672 DO_BRIGHTNESS(0xff, unsigned char, 4, 0)
680 DO_BRIGHTNESS(0xff, unsigned char, 4, 1)
684 DO_BRIGHTNESS(0xffff, uint16_t, 3, 0)
688 DO_BRIGHTNESS(0xffff, uint16_t, 3, 1)
691 case BC_RGBA16161616:
692 DO_BRIGHTNESS(0xffff, uint16_t, 4, 0)
695 case BC_YUVA16161616:
696 DO_BRIGHTNESS(0xffff, uint16_t, 4, 1)
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++)
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();
736 LoadClient* BrightnessEngine::new_client()
738 return new BrightnessUnit(this, plugin);
741 LoadPackage* BrightnessEngine::new_package()
743 return new BrightnessPackage;