2 #include "colorbalance.h"
10 #define SQR(a) ((a) * (a))
12 REGISTER_PLUGIN(ColorBalanceMain)
16 ColorBalanceConfig::ColorBalanceConfig()
25 int ColorBalanceConfig::equivalent(ColorBalanceConfig &that)
27 return (cyan == that.cyan &&
28 magenta == that.magenta &&
29 yellow == that.yellow &&
30 lock_params == that.lock_params &&
31 preserve == that.preserve);
34 void ColorBalanceConfig::copy_from(ColorBalanceConfig &that)
37 magenta = that.magenta;
39 lock_params = that.lock_params;
40 preserve = that.preserve;
43 void ColorBalanceConfig::interpolate(ColorBalanceConfig &prev,
44 ColorBalanceConfig &next,
47 int64_t current_frame)
49 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
50 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
52 this->cyan = prev.cyan * prev_scale + next.cyan * next_scale;
53 this->magenta = prev.magenta * prev_scale + next.magenta * next_scale;
54 this->yellow = prev.yellow * prev_scale + next.yellow * next_scale;
66 ColorBalanceEngine::ColorBalanceEngine(ColorBalanceMain *plugin)
69 this->plugin = plugin;
76 ColorBalanceEngine::~ColorBalanceEngine()
84 int ColorBalanceEngine::start_process_frame(VFrame *output, VFrame *input, int row_start, int row_end)
86 this->output = output;
88 this->row_start = row_start;
89 this->row_end = row_end;
95 int ColorBalanceEngine::wait_process_frame()
101 float ColorBalanceEngine::calculate_highlight(float in)
103 return 0.667 * (1.0 - SQR((in - 0.5) / 0.5));
106 float ColorBalanceEngine::calculate_r(float r)
108 return r + cyan_f * calculate_highlight(r);
111 float ColorBalanceEngine::calculate_g(float g)
113 return g + magenta_f * calculate_highlight(g);
116 float ColorBalanceEngine::calculate_b(float b)
118 return b + yellow_f * calculate_highlight(b);
121 void ColorBalanceEngine::run()
128 output_lock.unlock();
132 #define PROCESS(yuvtorgb, \
143 int y, cb, cr, r, g, b, r_n, g_n, b_n; \
144 float h, s, v, h_old, s_old, r_f, g_f, b_f; \
145 type **input_rows, **output_rows; \
146 input_rows = (type**)input->get_rows(); \
147 output_rows = (type**)output->get_rows(); \
149 for(j = row_start; j < row_end; j++) \
151 for(k = 0; k < input->get_w() * components; k += components) \
155 y = input_rows[j][k]; \
156 cb = input_rows[j][k + 1]; \
157 cr = input_rows[j][k + 2]; \
158 yuvtorgb(r, g, b, y, cb, cr); \
162 r = input_rows[j][k]; \
163 g = input_rows[j][k + 1]; \
164 b = input_rows[j][k + 2]; \
167 r = CLAMP(r, 0, max-1); g = CLAMP(g, 0, max-1); b = CLAMP(b, 0, max-1); \
168 r_n = plugin->r_lookup[r]; \
169 g_n = plugin->g_lookup[g]; \
170 b_n = plugin->b_lookup[b]; \
172 if(plugin->config.preserve) \
174 HSV::rgb_to_hsv((float)r_n, (float)g_n, (float)b_n, h, s, v); \
175 HSV::rgb_to_hsv((float)r, (float)g, (float)b, h_old, s_old, v); \
176 HSV::hsv_to_rgb(r_f, g_f, b_f, h, s, v); \
190 rgbtoyuv(CLAMP(r, 0, max), CLAMP(g, 0, max), CLAMP(b, 0, max), y, cb, cr); \
191 output_rows[j][k] = y; \
192 output_rows[j][k + 1] = cb; \
193 output_rows[j][k + 2] = cr; \
197 output_rows[j][k] = CLAMP(r, 0, max); \
198 output_rows[j][k + 1] = CLAMP(g, 0, max); \
199 output_rows[j][k + 2] = CLAMP(b, 0, max); \
205 #define PROCESS_F(components) \
208 float y, cb, cr, r, g, b, r_n, g_n, b_n; \
209 float h, s, v, h_old, s_old, r_f, g_f, b_f; \
210 float **input_rows, **output_rows; \
211 input_rows = (float**)input->get_rows(); \
212 output_rows = (float**)output->get_rows(); \
213 cyan_f = (float)plugin->config.cyan / 100; \
214 magenta_f = (float)plugin->config.magenta / 100; \
215 yellow_f = (float)plugin->config.yellow / 100; \
217 for(j = row_start; j < row_end; j++) \
219 for(k = 0; k < input->get_w() * components; k += components) \
221 r = input_rows[j][k]; \
222 g = input_rows[j][k + 1]; \
223 b = input_rows[j][k + 2]; \
225 r_n = calculate_r(r); \
226 g_n = calculate_g(g); \
227 b_n = calculate_b(b); \
229 if(plugin->config.preserve) \
231 HSV::rgb_to_hsv(r_n, g_n, b_n, h, s, v); \
232 HSV::rgb_to_hsv(r, g, b, h_old, s_old, v); \
233 HSV::hsv_to_rgb(r_f, g_f, b_f, h, s, v); \
245 output_rows[j][k] = r; \
246 output_rows[j][k + 1] = g; \
247 output_rows[j][k + 2] = b; \
252 switch(input->get_color_model())
255 PROCESS(yuv.yuv_to_rgb_8,
271 PROCESS(yuv.yuv_to_rgb_8,
287 PROCESS(yuv.yuv_to_rgb_8,
299 PROCESS(yuv.yuv_to_rgb_8,
311 PROCESS(yuv.yuv_to_rgb_16,
323 PROCESS(yuv.yuv_to_rgb_16,
334 case BC_RGBA16161616:
335 PROCESS(yuv.yuv_to_rgb_16,
346 case BC_YUVA16161616:
347 PROCESS(yuv.yuv_to_rgb_16,
361 output_lock.unlock();
368 ColorBalanceMain::ColorBalanceMain(PluginServer *server)
369 : PluginVClient(server)
371 need_reconfigure = 1;
373 PLUGIN_CONSTRUCTOR_MACRO
376 ColorBalanceMain::~ColorBalanceMain()
378 PLUGIN_DESTRUCTOR_MACRO
383 for(int i = 0; i < total_engines; i++)
391 char* ColorBalanceMain::plugin_title() { return N_("Color Balance"); }
392 int ColorBalanceMain::is_realtime() { return 1; }
395 int ColorBalanceMain::reconfigure()
398 double *cyan_red_transfer;
399 double *magenta_green_transfer;
400 double *yellow_blue_transfer;
403 #define RECONFIGURE(highlights_add, highlights_sub, r_lookup, g_lookup, b_lookup, max) \
404 cyan_red_transfer = config.cyan > 0 ? highlights_add : highlights_sub; \
405 magenta_green_transfer = config.magenta > 0 ? highlights_add : highlights_sub; \
406 yellow_blue_transfer = config.yellow > 0 ? highlights_add : highlights_sub; \
407 for(int i = 0; i <= max; i++) \
409 r_n = g_n = b_n = i; \
410 r_n += (int)(config.cyan / 100 * max * cyan_red_transfer[r_n]); \
411 g_n += (int)(config.magenta / 100 * max * magenta_green_transfer[g_n]); \
412 b_n += (int)(config.yellow / 100 * max * yellow_blue_transfer[b_n]); \
414 if(r_n > max) r_n = max; \
416 if(r_n < 0) r_n = 0; \
417 if(g_n > max) g_n = max; \
419 if(g_n < 0) g_n = 0; \
420 if(b_n > max) b_n = max; \
422 if(b_n < 0) b_n = 0; \
430 RECONFIGURE(highlights_add_8, highlights_sub_8, r_lookup_8, g_lookup_8, b_lookup_8, 0xff);
431 RECONFIGURE(highlights_add_16, highlights_sub_16, r_lookup_16, g_lookup_16, b_lookup_16, 0xffff);
436 int ColorBalanceMain::test_boundary(float &value)
438 if(value < -100) value = -100;
439 if(value > 100) value = 100;
443 int ColorBalanceMain::synchronize_params(ColorBalanceSlider *slider, float difference)
445 if(thread && config.lock_params)
447 if(slider != thread->window->cyan)
449 config.cyan += difference;
450 test_boundary(config.cyan);
451 thread->window->cyan->update((int64_t)config.cyan);
453 if(slider != thread->window->magenta)
455 config.magenta += difference;
456 test_boundary(config.magenta);
457 thread->window->magenta->update((int64_t)config.magenta);
459 if(slider != thread->window->yellow)
461 config.yellow += difference;
462 test_boundary(config.yellow);
463 thread->window->yellow->update((int64_t)config.yellow);
474 NEW_PICON_MACRO(ColorBalanceMain)
475 LOAD_CONFIGURATION_MACRO(ColorBalanceMain, ColorBalanceConfig)
476 SHOW_GUI_MACRO(ColorBalanceMain, ColorBalanceThread)
477 RAISE_WINDOW_MACRO(ColorBalanceMain)
478 SET_STRING_MACRO(ColorBalanceMain)
484 int ColorBalanceMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
486 need_reconfigure |= load_configuration();
488 //printf("ColorBalanceMain::process_realtime 1 %d\n", need_reconfigure);
495 #define CALCULATE_HIGHLIGHTS(add, sub, max) \
496 for(i = 0; i < max; i++) \
498 add[i] = sub[i] = 0.667 * (1 - SQR(((double)i - (max / 2)) / (max / 2))); \
501 CALCULATE_HIGHLIGHTS(highlights_add_8, highlights_sub_8, 0xff);
502 CALCULATE_HIGHLIGHTS(highlights_add_16, highlights_sub_16, 0xffff);
504 total_engines = PluginClient::smp > 1 ? 2 : 1;
505 engine = new ColorBalanceEngine*[total_engines];
506 for(int i = 0; i < total_engines; i++)
508 engine[i] = new ColorBalanceEngine(this);
514 need_reconfigure = 0;
518 if(config.cyan != 0 || config.magenta != 0 || config.yellow != 0)
520 int64_t row_step = input_ptr->get_h() / total_engines + 1;
521 for(int i = 0; i < input_ptr->get_h(); i += row_step)
523 if(i + row_step > input_ptr->get_h())
524 row_step = input_ptr->get_h() - i;
525 engine[i]->start_process_frame(output_ptr,
531 for(int i = 0; i < total_engines; i++)
533 engine[i]->wait_process_frame();
537 // Data never processed so copy if necessary
538 if(input_ptr->get_rows()[0] != output_ptr->get_rows()[0])
540 output_ptr->copy_from(input_ptr);
542 //printf("ColorBalanceMain::process_realtime 2\n");
548 int ColorBalanceMain::load_defaults()
550 char directory[1024], string[1024];
551 // set the default directory
552 sprintf(directory, "%scolorbalance.rc", BCASTDIR);
555 defaults = new Defaults(directory);
558 config.cyan = defaults->get("CYAN", config.cyan);
559 config.magenta = defaults->get("MAGENTA", config.magenta);
560 config.yellow = defaults->get("YELLOW", config.yellow);
561 config.preserve = defaults->get("PRESERVELUMINOSITY", config.preserve);
562 config.lock_params = defaults->get("LOCKPARAMS", config.lock_params);
566 int ColorBalanceMain::save_defaults()
568 defaults->update("CYAN", config.cyan);
569 defaults->update("MAGENTA", config.magenta);
570 defaults->update("YELLOW", config.yellow);
571 defaults->update("PRESERVELUMINOSITY", config.preserve);
572 defaults->update("LOCKPARAMS", config.lock_params);
577 void ColorBalanceMain::save_data(KeyFrame *keyframe)
581 // cause data to be stored directly in text
582 output.set_shared_string(keyframe->data, MESSAGESIZE);
583 output.tag.set_title("COLORBALANCE");
584 output.tag.set_property("CYAN", config.cyan);
585 output.tag.set_property("MAGENTA", config.magenta);
586 output.tag.set_property("YELLOW", config.yellow);
587 output.tag.set_property("PRESERVELUMINOSITY", config.preserve);
588 output.tag.set_property("LOCKPARAMS", config.lock_params);
590 output.terminate_string();
593 void ColorBalanceMain::read_data(KeyFrame *keyframe)
597 //printf("ColorBalanceMain::read_data 1\n");
598 input.set_shared_string(keyframe->data, strlen(keyframe->data));
599 //printf("ColorBalanceMain::read_data 1\n");
602 //printf("ColorBalanceMain::read_data 1\n");
606 result = input.read_tag();
610 if(input.tag.title_is("COLORBALANCE"))
612 config.cyan = input.tag.get_property("CYAN", config.cyan);
613 config.magenta = input.tag.get_property("MAGENTA", config.magenta);
614 config.yellow = input.tag.get_property("YELLOW", config.yellow);
615 config.preserve = input.tag.get_property("PRESERVELUMINOSITY", config.preserve);
616 config.lock_params = input.tag.get_property("LOCKPARAMS", config.lock_params);
620 //printf("ColorBalanceMain::read_data 2\n");