2 #include "colorbalance.h"
10 // 1000 corresponds to (1.0 + MAX_COLOR) * input
12 #define SQR(a) ((a) * (a))
14 REGISTER_PLUGIN(ColorBalanceMain)
18 ColorBalanceConfig::ColorBalanceConfig()
27 int ColorBalanceConfig::equivalent(ColorBalanceConfig &that)
29 return (cyan == that.cyan &&
30 magenta == that.magenta &&
31 yellow == that.yellow &&
32 lock_params == that.lock_params &&
33 preserve == that.preserve);
36 void ColorBalanceConfig::copy_from(ColorBalanceConfig &that)
39 magenta = that.magenta;
41 lock_params = that.lock_params;
42 preserve = that.preserve;
45 void ColorBalanceConfig::interpolate(ColorBalanceConfig &prev,
46 ColorBalanceConfig &next,
49 int64_t current_frame)
51 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
52 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
54 this->cyan = prev.cyan * prev_scale + next.cyan * next_scale;
55 this->magenta = prev.magenta * prev_scale + next.magenta * next_scale;
56 this->yellow = prev.yellow * prev_scale + next.yellow * next_scale;
57 this->preserve = prev.preserve;
58 this->lock_params = prev.lock_params;
70 ColorBalanceEngine::ColorBalanceEngine(ColorBalanceMain *plugin)
73 this->plugin = plugin;
78 ColorBalanceEngine::~ColorBalanceEngine()
86 int ColorBalanceEngine::start_process_frame(VFrame *output, VFrame *input, int row_start, int row_end)
88 this->output = output;
90 this->row_start = row_start;
91 this->row_end = row_end;
97 int ColorBalanceEngine::wait_process_frame()
99 output_lock.lock("ColorBalanceEngine::wait_process_frame");
103 void ColorBalanceEngine::run()
107 input_lock.lock("ColorBalanceEngine::run");
110 output_lock.unlock();
114 #define PROCESS(yuvtorgb, \
125 int y, cb, cr, r, g, b, r_n, g_n, b_n; \
126 float h, s, v, h_old, s_old, r_f, g_f, b_f; \
127 type **input_rows, **output_rows; \
128 input_rows = (type**)input->get_rows(); \
129 output_rows = (type**)output->get_rows(); \
131 for(j = row_start; j < row_end; j++) \
133 for(k = 0; k < input->get_w() * components; k += components) \
137 y = input_rows[j][k]; \
138 cb = input_rows[j][k + 1]; \
139 cr = input_rows[j][k + 2]; \
140 yuvtorgb(r, g, b, y, cb, cr); \
144 r = input_rows[j][k]; \
145 g = input_rows[j][k + 1]; \
146 b = input_rows[j][k + 2]; \
149 r = CLAMP(r, 0, max-1); g = CLAMP(g, 0, max-1); b = CLAMP(b, 0, max-1); \
150 r_n = plugin->r_lookup[r]; \
151 g_n = plugin->g_lookup[g]; \
152 b_n = plugin->b_lookup[b]; \
154 if(plugin->config.preserve) \
156 HSV::rgb_to_hsv((float)r_n, (float)g_n, (float)b_n, h, s, v); \
157 HSV::rgb_to_hsv((float)r, (float)g, (float)b, h_old, s_old, v); \
158 HSV::hsv_to_rgb(r_f, g_f, b_f, h, s, v); \
172 rgbtoyuv(CLAMP(r, 0, max), CLAMP(g, 0, max), CLAMP(b, 0, max), y, cb, cr); \
173 output_rows[j][k] = y; \
174 output_rows[j][k + 1] = cb; \
175 output_rows[j][k + 2] = cr; \
179 output_rows[j][k] = CLAMP(r, 0, max); \
180 output_rows[j][k + 1] = CLAMP(g, 0, max); \
181 output_rows[j][k + 2] = CLAMP(b, 0, max); \
187 #define PROCESS_F(components) \
190 float y, cb, cr, r, g, b, r_n, g_n, b_n; \
191 float h, s, v, h_old, s_old, r_f, g_f, b_f; \
192 float **input_rows, **output_rows; \
193 input_rows = (float**)input->get_rows(); \
194 output_rows = (float**)output->get_rows(); \
195 cyan_f = plugin->calculate_transfer(plugin->config.cyan); \
196 magenta_f = plugin->calculate_transfer(plugin->config.magenta); \
197 yellow_f = plugin->calculate_transfer(plugin->config.yellow); \
199 for(j = row_start; j < row_end; j++) \
201 for(k = 0; k < input->get_w() * components; k += components) \
203 r = input_rows[j][k]; \
204 g = input_rows[j][k + 1]; \
205 b = input_rows[j][k + 2]; \
208 g_n = g * magenta_f; \
209 b_n = b * yellow_f; \
211 if(plugin->config.preserve) \
213 HSV::rgb_to_hsv(r_n, g_n, b_n, h, s, v); \
214 HSV::rgb_to_hsv(r, g, b, h_old, s_old, v); \
215 HSV::hsv_to_rgb(r_f, g_f, b_f, h, s, v); \
227 output_rows[j][k] = r; \
228 output_rows[j][k + 1] = g; \
229 output_rows[j][k + 2] = b; \
234 switch(input->get_color_model())
237 PROCESS(yuv.yuv_to_rgb_8,
253 PROCESS(yuv.yuv_to_rgb_8,
269 PROCESS(yuv.yuv_to_rgb_8,
281 PROCESS(yuv.yuv_to_rgb_8,
293 PROCESS(yuv.yuv_to_rgb_16,
304 case BC_YUVA16161616:
305 PROCESS(yuv.yuv_to_rgb_16,
319 output_lock.unlock();
326 ColorBalanceMain::ColorBalanceMain(PluginServer *server)
327 : PluginVClient(server)
329 need_reconfigure = 1;
331 PLUGIN_CONSTRUCTOR_MACRO
334 ColorBalanceMain::~ColorBalanceMain()
336 PLUGIN_DESTRUCTOR_MACRO
341 for(int i = 0; i < total_engines; i++)
349 char* ColorBalanceMain::plugin_title() { return N_("Color Balance"); }
350 int ColorBalanceMain::is_realtime() { return 1; }
353 int ColorBalanceMain::reconfigure()
356 float r_scale = calculate_transfer(config.cyan);
357 float g_scale = calculate_transfer(config.magenta);
358 float b_scale = calculate_transfer(config.yellow);
362 #define RECONFIGURE(r_lookup, g_lookup, b_lookup, max) \
363 for(int i = 0; i <= max; i++) \
365 r_lookup[i] = CLIP((int)(r_scale * i), 0, max); \
366 g_lookup[i] = CLIP((int)(g_scale * i), 0, max); \
367 b_lookup[i] = CLIP((int)(b_scale * i), 0, max); \
370 RECONFIGURE(r_lookup_8, g_lookup_8, b_lookup_8, 0xff);
371 RECONFIGURE(r_lookup_16, g_lookup_16, b_lookup_16, 0xffff);
376 int64_t ColorBalanceMain::calculate_slider(float in)
380 return (int64_t)(in * 1000 - 1000.0);
385 return (int64_t)(1000 * (in - 1.0) / MAX_COLOR);
391 float ColorBalanceMain::calculate_transfer(float in)
395 return (1000.0 + in) / 1000.0;
400 return 1.0 + in / 1000.0 * MAX_COLOR;
409 int ColorBalanceMain::test_boundary(float &value)
412 if(value < -1000) value = -1000;
413 if(value > 1000) value = 1000;
417 int ColorBalanceMain::synchronize_params(ColorBalanceSlider *slider, float difference)
419 if(thread && config.lock_params)
421 if(slider != thread->window->cyan)
423 config.cyan += difference;
424 test_boundary(config.cyan);
425 thread->window->cyan->update((int64_t)config.cyan);
427 if(slider != thread->window->magenta)
429 config.magenta += difference;
430 test_boundary(config.magenta);
431 thread->window->magenta->update((int64_t)config.magenta);
433 if(slider != thread->window->yellow)
435 config.yellow += difference;
436 test_boundary(config.yellow);
437 thread->window->yellow->update((int64_t)config.yellow);
448 NEW_PICON_MACRO(ColorBalanceMain)
449 LOAD_CONFIGURATION_MACRO(ColorBalanceMain, ColorBalanceConfig)
450 SHOW_GUI_MACRO(ColorBalanceMain, ColorBalanceThread)
451 RAISE_WINDOW_MACRO(ColorBalanceMain)
452 SET_STRING_MACRO(ColorBalanceMain)
458 int ColorBalanceMain::process_buffer(VFrame *frame,
459 int64_t start_position,
462 need_reconfigure |= load_configuration();
464 //printf("ColorBalanceMain::process_realtime 1 %d\n", need_reconfigure);
471 total_engines = PluginClient::smp > 1 ? 2 : 1;
472 engine = new ColorBalanceEngine*[total_engines];
473 for(int i = 0; i < total_engines; i++)
475 engine[i] = new ColorBalanceEngine(this);
481 need_reconfigure = 0;
486 get_source_position(),
489 if(!EQUIV(config.cyan, 0) || !EQUIV(config.magenta, 0) || !EQUIV(config.yellow, 0))
491 for(int i = 0; i < total_engines; i++)
493 engine[i]->start_process_frame(frame,
495 frame->get_h() * i / total_engines,
496 frame->get_h() * (i + 1) / total_engines);
499 for(int i = 0; i < total_engines; i++)
501 engine[i]->wait_process_frame();
510 void ColorBalanceMain::update_gui()
514 load_configuration();
515 thread->window->lock_window("ColorBalanceMain::update_gui");
516 thread->window->cyan->update((int64_t)config.cyan);
517 thread->window->magenta->update((int64_t)config.magenta);
518 thread->window->yellow->update((int64_t)config.yellow);
519 thread->window->preserve->update(config.preserve);
520 thread->window->lock_params->update(config.lock_params);
521 thread->window->unlock_window();
528 int ColorBalanceMain::load_defaults()
530 char directory[1024], string[1024];
531 // set the default directory
532 sprintf(directory, "%scolorbalance.rc", BCASTDIR);
535 defaults = new BC_Hash(directory);
538 config.cyan = defaults->get("CYAN", config.cyan);
539 config.magenta = defaults->get("MAGENTA", config.magenta);
540 config.yellow = defaults->get("YELLOW", config.yellow);
541 config.preserve = defaults->get("PRESERVELUMINOSITY", config.preserve);
542 config.lock_params = defaults->get("LOCKPARAMS", config.lock_params);
546 int ColorBalanceMain::save_defaults()
548 defaults->update("CYAN", config.cyan);
549 defaults->update("MAGENTA", config.magenta);
550 defaults->update("YELLOW", config.yellow);
551 defaults->update("PRESERVELUMINOSITY", config.preserve);
552 defaults->update("LOCKPARAMS", config.lock_params);
557 void ColorBalanceMain::save_data(KeyFrame *keyframe)
561 // cause data to be stored directly in text
562 output.set_shared_string(keyframe->data, MESSAGESIZE);
563 output.tag.set_title("COLORBALANCE");
564 output.tag.set_property("CYAN", config.cyan);
565 output.tag.set_property("MAGENTA", config.magenta);
566 output.tag.set_property("YELLOW", config.yellow);
567 output.tag.set_property("PRESERVELUMINOSITY", config.preserve);
568 output.tag.set_property("LOCKPARAMS", config.lock_params);
570 output.terminate_string();
573 void ColorBalanceMain::read_data(KeyFrame *keyframe)
577 input.set_shared_string(keyframe->data, strlen(keyframe->data));
583 result = input.read_tag();
587 if(input.tag.title_is("COLORBALANCE"))
589 config.cyan = input.tag.get_property("CYAN", config.cyan);
590 config.magenta = input.tag.get_property("MAGENTA", config.magenta);
591 config.yellow = input.tag.get_property("YELLOW", config.yellow);
592 config.preserve = input.tag.get_property("PRESERVELUMINOSITY", config.preserve);
593 config.lock_params = input.tag.get_property("LOCKPARAMS", config.lock_params);