00001 #include "clip.h"
00002 #include "filexml.h"
00003 #include "brightness.h"
00004 #include "bchash.h"
00005 #include "language.h"
00006 #include "picon_png.h"
00007
00008 #include <stdio.h>
00009 #include <stdint.h>
00010 #include <string.h>
00011
00012 #define SQR(a) ((a) * (a))
00013
00014 REGISTER_PLUGIN(BrightnessMain)
00015
00016
00017
00018 BrightnessConfig::BrightnessConfig()
00019 {
00020 brightness = 0;
00021 contrast = 0;
00022 luma = 1;
00023 }
00024
00025 int BrightnessConfig::equivalent(BrightnessConfig &that)
00026 {
00027 return (brightness == that.brightness &&
00028 contrast == that.contrast &&
00029 luma == that.luma);
00030 }
00031
00032 void BrightnessConfig::copy_from(BrightnessConfig &that)
00033 {
00034 brightness = that.brightness;
00035 contrast = that.contrast;
00036 luma = that.luma;
00037 }
00038
00039 void BrightnessConfig::interpolate(BrightnessConfig &prev,
00040 BrightnessConfig &next,
00041 int64_t prev_frame,
00042 int64_t next_frame,
00043 int64_t current_frame)
00044 {
00045 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
00046 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
00047
00048 this->brightness = prev.brightness * prev_scale + next.brightness * next_scale;
00049 this->contrast = prev.contrast * prev_scale + next.contrast * next_scale;
00050 this->luma = (int)(prev.luma * prev_scale + next.luma * next_scale);
00051 }
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061 YUV BrightnessMain::yuv;
00062
00063 BrightnessMain::BrightnessMain(PluginServer *server)
00064 : PluginVClient(server)
00065 {
00066 redo_buffers = 1;
00067 engine = 0;
00068 PLUGIN_CONSTRUCTOR_MACRO
00069 }
00070
00071 BrightnessMain::~BrightnessMain()
00072 {
00073 PLUGIN_DESTRUCTOR_MACRO
00074 if(engine) delete engine;
00075 }
00076
00077 char* BrightnessMain::plugin_title() { return N_("Brightness/Contrast"); }
00078 int BrightnessMain::is_realtime() { return 1; }
00079
00080 NEW_PICON_MACRO(BrightnessMain)
00081 SHOW_GUI_MACRO(BrightnessMain, BrightnessThread)
00082 RAISE_WINDOW_MACRO(BrightnessMain)
00083 SET_STRING_MACRO(BrightnessMain)
00084 LOAD_CONFIGURATION_MACRO(BrightnessMain, BrightnessConfig)
00085
00086 int BrightnessMain::process_buffer(VFrame *frame,
00087 int64_t start_position,
00088 double frame_rate)
00089 {
00090 load_configuration();
00091
00092 read_frame(frame,
00093 0,
00094 start_position,
00095 frame_rate,
00096 get_use_opengl());
00097
00098
00099
00100 if(get_use_opengl())
00101 {
00102 run_opengl();
00103 return 0;
00104 }
00105
00106
00107
00108
00109 if(!engine) engine = new BrightnessEngine(this, PluginClient::smp + 1);
00110
00111 this->input = frame;
00112 this->output = frame;
00113
00114 if(!EQUIV(config.brightness, 0) || !EQUIV(config.contrast, 0))
00115 {
00116 engine->process_packages();
00117 }
00118
00119 return 0;
00120 }
00121
00122 int BrightnessMain::handle_opengl()
00123 {
00124 #ifdef HAVE_GL
00125 static char *brightness_yuvluma_frag =
00126 "uniform sampler2D tex;\n"
00127 "uniform float brightness;\n"
00128 "uniform float contrast;\n"
00129 "uniform float offset;\n"
00130 "void main()\n"
00131 "{\n"
00132 " vec4 yuva = texture2D(tex, gl_TexCoord[0].st);\n"
00133 " yuva.r += brightness;\n"
00134 " yuva.r = yuva.r * contrast + offset;\n"
00135 " gl_FragColor = yuva;\n"
00136 "}\n";
00137
00138 static char *brightness_yuv_frag =
00139 "uniform sampler2D tex;\n"
00140 "uniform float brightness;\n"
00141 "uniform float contrast;\n"
00142 "uniform float offset;\n"
00143 "void main()\n"
00144 "{\n"
00145 " vec4 yuva = texture2D(tex, gl_TexCoord[0].st);\n"
00146 " yuva.r += brightness;\n"
00147 " yuva.rgb *= vec3(contrast, contrast, contrast);\n"
00148 " yuva.rgb += vec3(offset, offset, offset);\n"
00149 " gl_FragColor = yuva;\n"
00150 "}\n";
00151
00152 static char *brightness_rgb_frag =
00153 "uniform sampler2D tex;\n"
00154 "uniform float brightness;\n"
00155 "uniform float contrast;\n"
00156 "uniform float offset;\n"
00157 "void main()\n"
00158 "{\n"
00159 " vec4 rgba = texture2D(tex, gl_TexCoord[0].st);\n"
00160 " rgba.rgb += vec3(brightness, brightness, brightness);\n"
00161 " rgba.rgb *= vec3(contrast, contrast, contrast);\n"
00162 " rgba.rgb += vec3(offset, offset, offset);\n"
00163 " gl_FragColor = rgba;\n"
00164 "}\n";
00165
00166 static char *brightness_rgbluma_frag =
00167 "uniform sampler2D tex;\n"
00168 "uniform float brightness;\n"
00169 "uniform float contrast;\n"
00170 "uniform float offset;\n"
00171 "void main()\n"
00172 "{\n"
00173 " const mat3 yuv_to_rgb_matrix = mat3(\n"
00174 " 1, 1, 1, \n"
00175 " 0, -0.34414, 1.77200, \n"
00176 " 1.40200, -0.71414, 0);\n"
00177 " const mat3 rgb_to_yuv_matrix = mat3(\n"
00178 " 0.29900, -0.16874, 0.50000, \n"
00179 " 0.58700, -0.33126, -0.41869, \n"
00180 " 0.11400, 0.50000, -0.08131);\n"
00181 " vec4 rgba = texture2D(tex, gl_TexCoord[0].st);\n"
00182 " rgba.rgb = rgb_to_yuv_matrix * rgba.rgb;\n"
00183 " rgba.r += brightness;\n"
00184 " rgba.r = rgba.r * contrast + offset;\n"
00185 " rgba.rgb = yuv_to_rgb_matrix * rgba.rgb;\n"
00186 " gl_FragColor = rgba;\n"
00187 "}\n";
00188
00189 get_output()->to_texture();
00190 get_output()->enable_opengl();
00191
00192 unsigned int shader_id = 0;
00193 switch(get_output()->get_color_model())
00194 {
00195 case BC_YUV888:
00196 case BC_YUVA8888:
00197 if(config.luma)
00198 shader_id = VFrame::make_shader(0,
00199 brightness_yuvluma_frag,
00200 0);
00201 else
00202 shader_id = VFrame::make_shader(0,
00203 brightness_yuv_frag,
00204 0);
00205 break;
00206 default:
00207 if(config.luma)
00208 shader_id = VFrame::make_shader(0,
00209 brightness_rgbluma_frag,
00210 0);
00211 else
00212 shader_id = VFrame::make_shader(0,
00213 brightness_rgb_frag,
00214 0);
00215 break;
00216 }
00217
00218
00219 if(shader_id > 0)
00220 {
00221 glUseProgram(shader_id);
00222 glUniform1i(glGetUniformLocation(shader_id, "tex"), 0);
00223 glUniform1f(glGetUniformLocation(shader_id, "brightness"), config.brightness / 100);
00224 float contrast = (config.contrast < 0) ?
00225 (config.contrast + 100) / 100 :
00226 (config.contrast + 25) / 25;
00227 glUniform1f(glGetUniformLocation(shader_id, "contrast"), contrast);
00228 float offset = 0.5 - contrast / 2;
00229 glUniform1f(glGetUniformLocation(shader_id, "offset"), offset);
00230 }
00231
00232 get_output()->init_screen();
00233 get_output()->bind_texture(0);
00234
00235
00236
00237 get_output()->draw_texture();
00238 glUseProgram(0);
00239 get_output()->set_opengl_state(VFrame::SCREEN);
00240
00241 #endif
00242 }
00243
00244
00245 void BrightnessMain::update_gui()
00246 {
00247 if(thread)
00248 {
00249 if(load_configuration())
00250 {
00251 thread->window->lock_window("BrightnessMain::update_gui");
00252 thread->window->brightness->update(config.brightness);
00253 thread->window->contrast->update(config.contrast);
00254 thread->window->luma->update(config.luma);
00255 thread->window->unlock_window();
00256 }
00257 }
00258 }
00259
00260 int BrightnessMain::load_defaults()
00261 {
00262 char directory[BCTEXTLEN], string[BCTEXTLEN];
00263
00264 sprintf(directory, "%sbrightness.rc", BCASTDIR);
00265
00266
00267 defaults = new BC_Hash(directory);
00268 defaults->load();
00269
00270 config.brightness = defaults->get("BRIGHTNESS", config.brightness);
00271 config.contrast = defaults->get("CONTRAST", config.contrast);
00272 config.luma = defaults->get("LUMA", config.luma);
00273 return 0;
00274 }
00275
00276 int BrightnessMain::save_defaults()
00277 {
00278 defaults->update("BRIGHTNESS", config.brightness);
00279 defaults->update("CONTRAST", config.contrast);
00280 defaults->update("LUMA", config.luma);
00281 defaults->save();
00282 return 0;
00283 }
00284
00285
00286 void BrightnessMain::save_data(KeyFrame *keyframe)
00287 {
00288 FileXML output;
00289
00290
00291 output.set_shared_string(keyframe->data, MESSAGESIZE);
00292 output.tag.set_title("BRIGHTNESS");
00293 output.tag.set_property("BRIGHTNESS", config.brightness);
00294 output.tag.set_property("CONTRAST", config.contrast);
00295 output.tag.set_property("LUMA", config.luma);
00296
00297 output.append_tag();
00298 output.tag.set_title("/BRIGHTNESS");
00299 output.append_tag();
00300 output.terminate_string();
00301 }
00302
00303 void BrightnessMain::read_data(KeyFrame *keyframe)
00304 {
00305 FileXML input;
00306
00307 input.set_shared_string(keyframe->data, strlen(keyframe->data));
00308
00309 int result = 0;
00310
00311 while(!result)
00312 {
00313 result = input.read_tag();
00314
00315 if(!result)
00316 {
00317 if(input.tag.title_is("BRIGHTNESS"))
00318 {
00319 config.brightness = input.tag.get_property("BRIGHTNESS", config.brightness);
00320 config.contrast = input.tag.get_property("CONTRAST", config.contrast);
00321 config.luma = input.tag.get_property("LUMA", config.luma);
00322 }
00323 }
00324 }
00325 }
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339 BrightnessPackage::BrightnessPackage()
00340 : LoadPackage()
00341 {
00342 }
00343
00344
00345
00346
00347 BrightnessUnit::BrightnessUnit(BrightnessEngine *server, BrightnessMain *plugin)
00348 : LoadClient(server)
00349 {
00350 this->plugin = plugin;
00351 }
00352
00353 BrightnessUnit::~BrightnessUnit()
00354 {
00355 }
00356
00357 void BrightnessUnit::process_package(LoadPackage *package)
00358 {
00359 BrightnessPackage *pkg = (BrightnessPackage*)package;
00360
00361
00362 VFrame *output = plugin->output;
00363 VFrame *input = plugin->input;
00364
00365
00366
00367
00368
00369 #define DO_BRIGHTNESS(max, type, components, is_yuv) \
00370 { \
00371 type **input_rows = (type**)input->get_rows(); \
00372 type **output_rows = (type**)output->get_rows(); \
00373 int row1 = pkg->row1; \
00374 int row2 = pkg->row2; \
00375 int width = output->get_w(); \
00376 int r, g, b; \
00377 \
00378 if(!EQUIV(plugin->config.brightness, 0)) \
00379 { \
00380 int offset = (int)(plugin->config.brightness / 100 * max); \
00381 \
00382 \
00383 for(int i = row1; i < row2; i++) \
00384 { \
00385 type *input_row = input_rows[i]; \
00386 type *output_row = output_rows[i]; \
00387 \
00388 for(int j = 0; j < width; j++) \
00389 { \
00390 r = input_row[j * components] + offset; \
00391 \
00392 if(!is_yuv) \
00393 { \
00394 g = input_row[j * components + 1] + offset; \
00395 b = input_row[j * components + 2] + offset; \
00396 } \
00397 \
00398 CLAMP(r, 0, max); \
00399 if(!is_yuv) \
00400 { \
00401 CLAMP(g, 0, max); \
00402 CLAMP(b, 0, max); \
00403 } \
00404 \
00405 output_row[j * components] = r; \
00406 \
00407 if(!is_yuv) \
00408 { \
00409 output_row[j * components + 1] = g; \
00410 output_row[j * components + 2] = b; \
00411 } \
00412 else \
00413 { \
00414 output_row[j * components + 1] = input_row[j * components + 1]; \
00415 output_row[j * components + 2] = input_row[j * components + 2]; \
00416 } \
00417 \
00418 if(components == 4) \
00419 output_row[j * components + 3] = input_row[j * components + 3]; \
00420 } \
00421 } \
00422 \
00423 \
00424 input_rows = output_rows; \
00425 } \
00426 \
00427 if(!EQUIV(plugin->config.contrast, 0)) \
00428 { \
00429 float contrast = (plugin->config.contrast < 0) ? \
00430 (plugin->config.contrast + 100) / 100 : \
00431 (plugin->config.contrast + 25) / 25; \
00432 \
00433 \
00434 int scalar = (int)(contrast * 0x100); \
00435 int offset = (max << 8) / 2 - max * scalar / 2; \
00436 int y, u, v; \
00437 \
00438 for(int i = row1; i < row2; i++) \
00439 { \
00440 type *input_row = input_rows[i]; \
00441 type *output_row = output_rows[i]; \
00442 \
00443 if(plugin->config.luma) \
00444 { \
00445 for(int j = 0; j < width; j++) \
00446 { \
00447 if(is_yuv) \
00448 { \
00449 y = input_row[j * components]; \
00450 } \
00451 else \
00452 { \
00453 r = input_row[j * components]; \
00454 g = input_row[j * components + 1]; \
00455 b = input_row[j * components + 2]; \
00456 if(max == 0xff) \
00457 { \
00458 BrightnessMain::yuv.rgb_to_yuv_8( \
00459 r, \
00460 g, \
00461 b, \
00462 y, \
00463 u, \
00464 v); \
00465 } \
00466 else \
00467 { \
00468 BrightnessMain::yuv.rgb_to_yuv_16( \
00469 r, \
00470 g, \
00471 b, \
00472 y, \
00473 u, \
00474 v); \
00475 } \
00476 \
00477 } \
00478 \
00479 y = (y * scalar + offset) >> 8; \
00480 CLAMP(y, 0, max); \
00481 \
00482 \
00483 if(is_yuv) \
00484 { \
00485 output_row[j * components] = y; \
00486 output_row[j * components + 1] = input_row[j * components + 1]; \
00487 output_row[j * components + 2] = input_row[j * components + 2]; \
00488 } \
00489 else \
00490 { \
00491 if(max == 0xff) \
00492 { \
00493 BrightnessMain::yuv.yuv_to_rgb_8( \
00494 r, \
00495 g, \
00496 b, \
00497 y, \
00498 u, \
00499 v); \
00500 } \
00501 else \
00502 { \
00503 BrightnessMain::yuv.yuv_to_rgb_16( \
00504 r, \
00505 g, \
00506 b, \
00507 y, \
00508 u, \
00509 v); \
00510 } \
00511 input_row[j * components] = r; \
00512 input_row[j * components + 1] = g; \
00513 input_row[j * components + 2] = b; \
00514 } \
00515 \
00516 if(components == 4) \
00517 output_row[j * components + 3] = input_row[j * components + 3]; \
00518 } \
00519 } \
00520 else \
00521 { \
00522 for(int j = 0; j < width; j++) \
00523 { \
00524 r = input_row[j * components]; \
00525 g = input_row[j * components + 1]; \
00526 b = input_row[j * components + 2]; \
00527 \
00528 r = (r * scalar + offset) >> 8; \
00529 g = (g * scalar + offset) >> 8; \
00530 b = (b * scalar + offset) >> 8; \
00531 \
00532 CLAMP(r, 0, max); \
00533 CLAMP(g, 0, max); \
00534 CLAMP(b, 0, max); \
00535 \
00536 output_row[j * components] = r; \
00537 output_row[j * components + 1] = g; \
00538 output_row[j * components + 2] = b; \
00539 \
00540 if(components == 4) \
00541 output_row[j * components + 3] = input_row[j * components + 3]; \
00542 } \
00543 } \
00544 } \
00545 } \
00546 }
00547
00548
00549
00550 #define DO_BRIGHTNESS_F(components) \
00551 { \
00552 float **input_rows = (float**)input->get_rows(); \
00553 float **output_rows = (float**)output->get_rows(); \
00554 int row1 = pkg->row1; \
00555 int row2 = pkg->row2; \
00556 int width = output->get_w(); \
00557 float r, g, b; \
00558 \
00559 if(!EQUIV(plugin->config.brightness, 0)) \
00560 { \
00561 float offset = plugin->config.brightness / 100; \
00562 \
00563 for(int i = row1; i < row2; i++) \
00564 { \
00565 float *input_row = input_rows[i]; \
00566 float *output_row = output_rows[i]; \
00567 \
00568 for(int j = 0; j < width; j++) \
00569 { \
00570 r = input_row[j * components] + offset; \
00571 g = input_row[j * components + 1] + offset; \
00572 b = input_row[j * components + 2] + offset; \
00573 \
00574 output_row[j * components] = r; \
00575 output_row[j * components + 1] = g; \
00576 output_row[j * components + 2] = b; \
00577 if(components == 4) \
00578 output_row[j * components + 3] = input_row[j * components + 3]; \
00579 } \
00580 } \
00581 \
00582 \
00583 input_rows = output_rows; \
00584 } \
00585 \
00586 if(!EQUIV(plugin->config.contrast, 0)) \
00587 { \
00588 float contrast = (plugin->config.contrast < 0) ? \
00589 (plugin->config.contrast + 100) / 100 : \
00590 (plugin->config.contrast + 25) / 25; \
00591 \
00592 \
00593 float offset = 0.5 - contrast / 2; \
00594 float y, u, v; \
00595 \
00596 for(int i = row1; i < row2; i++) \
00597 { \
00598 float *input_row = input_rows[i]; \
00599 float *output_row = output_rows[i]; \
00600 \
00601 if(plugin->config.luma) \
00602 { \
00603 for(int j = 0; j < width; j++) \
00604 { \
00605 r = input_row[j * components]; \
00606 g = input_row[j * components + 1]; \
00607 b = input_row[j * components + 2]; \
00608 YUV::rgb_to_yuv_f( \
00609 r, \
00610 g, \
00611 b, \
00612 y, \
00613 u, \
00614 v); \
00615 \
00616 y = y * contrast + offset; \
00617 \
00618 \
00619 YUV::yuv_to_rgb_f( \
00620 r, \
00621 g, \
00622 b, \
00623 y, \
00624 u, \
00625 v); \
00626 input_row[j * components] = r; \
00627 input_row[j * components + 1] = g; \
00628 input_row[j * components + 2] = b; \
00629 \
00630 if(components == 4) \
00631 output_row[j * components + 3] = input_row[j * components + 3]; \
00632 } \
00633 } \
00634 else \
00635 { \
00636 for(int j = 0; j < width; j++) \
00637 { \
00638 r = input_row[j * components]; \
00639 g = input_row[j * components + 1]; \
00640 b = input_row[j * components + 2]; \
00641 \
00642 r = r * contrast + offset; \
00643 g = g * contrast + offset; \
00644 b = b * contrast + offset; \
00645 \
00646 output_row[j * components] = r; \
00647 output_row[j * components + 1] = g; \
00648 output_row[j * components + 2] = b; \
00649 \
00650 if(components == 4) \
00651 output_row[j * components + 3] = input_row[j * components + 3]; \
00652 } \
00653 } \
00654 } \
00655 } \
00656 }
00657
00658
00659 switch(input->get_color_model())
00660 {
00661 case BC_RGB888:
00662 DO_BRIGHTNESS(0xff, unsigned char, 3, 0)
00663 break;
00664
00665 case BC_RGB_FLOAT:
00666 DO_BRIGHTNESS_F(3)
00667 break;
00668
00669 case BC_YUV888:
00670 DO_BRIGHTNESS(0xff, unsigned char, 3, 1)
00671 break;
00672
00673 case BC_RGBA8888:
00674 DO_BRIGHTNESS(0xff, unsigned char, 4, 0)
00675 break;
00676
00677 case BC_RGBA_FLOAT:
00678 DO_BRIGHTNESS_F(4)
00679 break;
00680
00681 case BC_YUVA8888:
00682 DO_BRIGHTNESS(0xff, unsigned char, 4, 1)
00683 break;
00684
00685 case BC_RGB161616:
00686 DO_BRIGHTNESS(0xffff, uint16_t, 3, 0)
00687 break;
00688
00689 case BC_YUV161616:
00690 DO_BRIGHTNESS(0xffff, uint16_t, 3, 1)
00691 break;
00692
00693 case BC_RGBA16161616:
00694 DO_BRIGHTNESS(0xffff, uint16_t, 4, 0)
00695 break;
00696
00697 case BC_YUVA16161616:
00698 DO_BRIGHTNESS(0xffff, uint16_t, 4, 1)
00699 break;
00700 }
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710 }
00711
00712
00713
00714
00715
00716
00717 BrightnessEngine::BrightnessEngine(BrightnessMain *plugin, int cpus)
00718 : LoadServer(cpus, cpus)
00719 {
00720 this->plugin = plugin;
00721 }
00722
00723 BrightnessEngine::~BrightnessEngine()
00724 {
00725 }
00726
00727
00728 void BrightnessEngine::init_packages()
00729 {
00730 for(int i = 0; i < LoadServer::get_total_packages(); i++)
00731 {
00732 BrightnessPackage *package = (BrightnessPackage*)LoadServer::get_package(i);
00733 package->row1 = plugin->input->get_h() * i / LoadServer::get_total_packages();
00734 package->row2 = plugin->input->get_h() * (i + 1) / LoadServer::get_total_packages();
00735 }
00736 }
00737
00738 LoadClient* BrightnessEngine::new_client()
00739 {
00740 return new BrightnessUnit(this, plugin);
00741 }
00742
00743 LoadPackage* BrightnessEngine::new_package()
00744 {
00745 return new BrightnessPackage;
00746 }
00747
00748
00749
00750
00751