2 #include "colorbalance.h"
6 #include "playback3d.h"
8 #include "aggregated.h"
9 #include "../interpolate/aggregated.h"
10 #include "../gamma/aggregated.h"
15 // 1000 corresponds to (1.0 + MAX_COLOR) * input
17 #define SQR(a) ((a) * (a))
19 REGISTER_PLUGIN(ColorBalanceMain)
23 ColorBalanceConfig::ColorBalanceConfig()
32 int ColorBalanceConfig::equivalent(ColorBalanceConfig &that)
34 return (cyan == that.cyan &&
35 magenta == that.magenta &&
36 yellow == that.yellow &&
37 lock_params == that.lock_params &&
38 preserve == that.preserve);
41 void ColorBalanceConfig::copy_from(ColorBalanceConfig &that)
44 magenta = that.magenta;
46 lock_params = that.lock_params;
47 preserve = that.preserve;
50 void ColorBalanceConfig::interpolate(ColorBalanceConfig &prev,
51 ColorBalanceConfig &next,
54 int64_t current_frame)
56 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
57 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
59 this->cyan = prev.cyan * prev_scale + next.cyan * next_scale;
60 this->magenta = prev.magenta * prev_scale + next.magenta * next_scale;
61 this->yellow = prev.yellow * prev_scale + next.yellow * next_scale;
62 this->preserve = prev.preserve;
63 this->lock_params = prev.lock_params;
75 ColorBalanceEngine::ColorBalanceEngine(ColorBalanceMain *plugin)
78 this->plugin = plugin;
83 ColorBalanceEngine::~ColorBalanceEngine()
91 int ColorBalanceEngine::start_process_frame(VFrame *output, VFrame *input, int row_start, int row_end)
93 this->output = output;
95 this->row_start = row_start;
96 this->row_end = row_end;
102 int ColorBalanceEngine::wait_process_frame()
104 output_lock.lock("ColorBalanceEngine::wait_process_frame");
108 void ColorBalanceEngine::run()
112 input_lock.lock("ColorBalanceEngine::run");
115 output_lock.unlock();
119 #define PROCESS(yuvtorgb, \
130 int y, cb, cr, r, g, b, r_n, g_n, b_n; \
131 float h, s, v, h_old, s_old, r_f, g_f, b_f; \
132 type **input_rows, **output_rows; \
133 input_rows = (type**)input->get_rows(); \
134 output_rows = (type**)output->get_rows(); \
136 for(j = row_start; j < row_end; j++) \
138 for(k = 0; k < input->get_w() * components; k += components) \
142 y = input_rows[j][k]; \
143 cb = input_rows[j][k + 1]; \
144 cr = input_rows[j][k + 2]; \
145 yuvtorgb(r, g, b, y, cb, cr); \
149 r = input_rows[j][k]; \
150 g = input_rows[j][k + 1]; \
151 b = input_rows[j][k + 2]; \
154 r = CLAMP(r, 0, max-1); g = CLAMP(g, 0, max-1); b = CLAMP(b, 0, max-1); \
155 r_n = plugin->r_lookup[r]; \
156 g_n = plugin->g_lookup[g]; \
157 b_n = plugin->b_lookup[b]; \
159 if(plugin->config.preserve) \
161 HSV::rgb_to_hsv((float)r_n, (float)g_n, (float)b_n, h, s, v); \
162 HSV::rgb_to_hsv((float)r, (float)g, (float)b, h_old, s_old, v); \
163 HSV::hsv_to_rgb(r_f, g_f, b_f, h, s, v); \
177 rgbtoyuv(CLAMP(r, 0, max), CLAMP(g, 0, max), CLAMP(b, 0, max), y, cb, cr); \
178 output_rows[j][k] = y; \
179 output_rows[j][k + 1] = cb; \
180 output_rows[j][k + 2] = cr; \
184 output_rows[j][k] = CLAMP(r, 0, max); \
185 output_rows[j][k + 1] = CLAMP(g, 0, max); \
186 output_rows[j][k + 2] = CLAMP(b, 0, max); \
192 #define PROCESS_F(components) \
195 float y, cb, cr, r, g, b, r_n, g_n, b_n; \
196 float h, s, v, h_old, s_old, r_f, g_f, b_f; \
197 float **input_rows, **output_rows; \
198 input_rows = (float**)input->get_rows(); \
199 output_rows = (float**)output->get_rows(); \
200 cyan_f = plugin->calculate_transfer(plugin->config.cyan); \
201 magenta_f = plugin->calculate_transfer(plugin->config.magenta); \
202 yellow_f = plugin->calculate_transfer(plugin->config.yellow); \
204 for(j = row_start; j < row_end; j++) \
206 for(k = 0; k < input->get_w() * components; k += components) \
208 r = input_rows[j][k]; \
209 g = input_rows[j][k + 1]; \
210 b = input_rows[j][k + 2]; \
213 g_n = g * magenta_f; \
214 b_n = b * yellow_f; \
216 if(plugin->config.preserve) \
218 HSV::rgb_to_hsv(r_n, g_n, b_n, h, s, v); \
219 HSV::rgb_to_hsv(r, g, b, h_old, s_old, v); \
220 HSV::hsv_to_rgb(r_f, g_f, b_f, h, s, v); \
232 output_rows[j][k] = r; \
233 output_rows[j][k + 1] = g; \
234 output_rows[j][k + 2] = b; \
239 switch(input->get_color_model())
242 PROCESS(yuv.yuv_to_rgb_8,
258 PROCESS(yuv.yuv_to_rgb_8,
274 PROCESS(yuv.yuv_to_rgb_8,
286 PROCESS(yuv.yuv_to_rgb_8,
298 PROCESS(yuv.yuv_to_rgb_16,
309 case BC_YUVA16161616:
310 PROCESS(yuv.yuv_to_rgb_16,
324 output_lock.unlock();
331 ColorBalanceMain::ColorBalanceMain(PluginServer *server)
332 : PluginVClient(server)
334 need_reconfigure = 1;
336 PLUGIN_CONSTRUCTOR_MACRO
339 ColorBalanceMain::~ColorBalanceMain()
341 PLUGIN_DESTRUCTOR_MACRO
346 for(int i = 0; i < total_engines; i++)
354 char* ColorBalanceMain::plugin_title() { return N_("Color Balance"); }
355 int ColorBalanceMain::is_realtime() { return 1; }
358 int ColorBalanceMain::reconfigure()
361 float r_scale = calculate_transfer(config.cyan);
362 float g_scale = calculate_transfer(config.magenta);
363 float b_scale = calculate_transfer(config.yellow);
367 #define RECONFIGURE(r_lookup, g_lookup, b_lookup, max) \
368 for(int i = 0; i <= max; i++) \
370 r_lookup[i] = CLIP((int)(r_scale * i), 0, max); \
371 g_lookup[i] = CLIP((int)(g_scale * i), 0, max); \
372 b_lookup[i] = CLIP((int)(b_scale * i), 0, max); \
375 RECONFIGURE(r_lookup_8, g_lookup_8, b_lookup_8, 0xff);
376 RECONFIGURE(r_lookup_16, g_lookup_16, b_lookup_16, 0xffff);
381 int64_t ColorBalanceMain::calculate_slider(float in)
385 return (int64_t)(in * 1000 - 1000.0);
390 return (int64_t)(1000 * (in - 1.0) / MAX_COLOR);
396 float ColorBalanceMain::calculate_transfer(float in)
400 return (1000.0 + in) / 1000.0;
405 return 1.0 + in / 1000.0 * MAX_COLOR;
414 int ColorBalanceMain::test_boundary(float &value)
417 if(value < -1000) value = -1000;
418 if(value > 1000) value = 1000;
422 int ColorBalanceMain::synchronize_params(ColorBalanceSlider *slider, float difference)
424 if(thread && config.lock_params)
426 if(slider != thread->window->cyan)
428 config.cyan += difference;
429 test_boundary(config.cyan);
430 thread->window->cyan->update((int64_t)config.cyan);
432 if(slider != thread->window->magenta)
434 config.magenta += difference;
435 test_boundary(config.magenta);
436 thread->window->magenta->update((int64_t)config.magenta);
438 if(slider != thread->window->yellow)
440 config.yellow += difference;
441 test_boundary(config.yellow);
442 thread->window->yellow->update((int64_t)config.yellow);
453 NEW_PICON_MACRO(ColorBalanceMain)
454 LOAD_CONFIGURATION_MACRO(ColorBalanceMain, ColorBalanceConfig)
455 SHOW_GUI_MACRO(ColorBalanceMain, ColorBalanceThread)
456 RAISE_WINDOW_MACRO(ColorBalanceMain)
457 SET_STRING_MACRO(ColorBalanceMain)
463 int ColorBalanceMain::process_buffer(VFrame *frame,
464 int64_t start_position,
467 need_reconfigure |= load_configuration();
469 //printf("ColorBalanceMain::process_realtime 1 %d\n", need_reconfigure);
476 total_engines = PluginClient::smp > 1 ? 2 : 1;
477 engine = new ColorBalanceEngine*[total_engines];
478 for(int i = 0; i < total_engines; i++)
480 engine[i] = new ColorBalanceEngine(this);
486 need_reconfigure = 0;
489 frame->get_params()->update("COLORBALANCE_PRESERVE", config.preserve);
490 frame->get_params()->update("COLORBALANCE_CYAN", calculate_transfer(config.cyan));
491 frame->get_params()->update("COLORBALANCE_MAGENTA", calculate_transfer(config.magenta));
492 frame->get_params()->update("COLORBALANCE_YELLOW", calculate_transfer(config.yellow));
497 get_source_position(),
501 int aggregate_interpolate = 0;
502 int aggregate_gamma = 0;
503 get_aggregation(&aggregate_interpolate,
506 if(!EQUIV(config.cyan, 0) ||
507 !EQUIV(config.magenta, 0) ||
508 !EQUIV(config.yellow, 0) ||
510 (aggregate_interpolate ||
515 get_output()->dump_stacks();
517 if(next_effect_is("Histogram")) return 0;
521 for(int i = 0; i < total_engines; i++)
523 engine[i]->start_process_frame(frame,
525 frame->get_h() * i / total_engines,
526 frame->get_h() * (i + 1) / total_engines);
529 for(int i = 0; i < total_engines; i++)
531 engine[i]->wait_process_frame();
540 void ColorBalanceMain::update_gui()
544 load_configuration();
545 thread->window->lock_window("ColorBalanceMain::update_gui");
546 thread->window->cyan->update((int64_t)config.cyan);
547 thread->window->magenta->update((int64_t)config.magenta);
548 thread->window->yellow->update((int64_t)config.yellow);
549 thread->window->preserve->update(config.preserve);
550 thread->window->lock_params->update(config.lock_params);
551 thread->window->unlock_window();
557 int ColorBalanceMain::load_defaults()
559 char directory[1024], string[1024];
560 // set the default directory
561 sprintf(directory, "%scolorbalance.rc", BCASTDIR);
564 defaults = new BC_Hash(directory);
567 config.cyan = defaults->get("CYAN", config.cyan);
568 config.magenta = defaults->get("MAGENTA", config.magenta);
569 config.yellow = defaults->get("YELLOW", config.yellow);
570 config.preserve = defaults->get("PRESERVELUMINOSITY", config.preserve);
571 config.lock_params = defaults->get("LOCKPARAMS", config.lock_params);
575 int ColorBalanceMain::save_defaults()
577 defaults->update("CYAN", config.cyan);
578 defaults->update("MAGENTA", config.magenta);
579 defaults->update("YELLOW", config.yellow);
580 defaults->update("PRESERVELUMINOSITY", config.preserve);
581 defaults->update("LOCKPARAMS", config.lock_params);
586 void ColorBalanceMain::save_data(KeyFrame *keyframe)
590 // cause data to be stored directly in text
591 output.set_shared_string(keyframe->data, MESSAGESIZE);
592 output.tag.set_title("COLORBALANCE");
593 output.tag.set_property("CYAN", config.cyan);
594 output.tag.set_property("MAGENTA", config.magenta);
595 output.tag.set_property("YELLOW", config.yellow);
596 output.tag.set_property("PRESERVELUMINOSITY", config.preserve);
597 output.tag.set_property("LOCKPARAMS", config.lock_params);
599 output.terminate_string();
602 void ColorBalanceMain::read_data(KeyFrame *keyframe)
606 input.set_shared_string(keyframe->data, strlen(keyframe->data));
612 result = input.read_tag();
616 if(input.tag.title_is("COLORBALANCE"))
618 config.cyan = input.tag.get_property("CYAN", config.cyan);
619 config.magenta = input.tag.get_property("MAGENTA", config.magenta);
620 config.yellow = input.tag.get_property("YELLOW", config.yellow);
621 config.preserve = input.tag.get_property("PRESERVELUMINOSITY", config.preserve);
622 config.lock_params = input.tag.get_property("LOCKPARAMS", config.lock_params);
628 void ColorBalanceMain::get_aggregation(int *aggregate_interpolate,
629 int *aggregate_gamma)
631 if(!strcmp(get_output()->get_prev_effect(1), "Interpolate Pixels") &&
632 !strcmp(get_output()->get_prev_effect(0), "Gamma"))
634 *aggregate_interpolate = 1;
635 *aggregate_gamma = 1;
638 if(!strcmp(get_output()->get_prev_effect(0), "Interpolate Pixels"))
640 *aggregate_interpolate = 1;
643 if(!strcmp(get_output()->get_prev_effect(0), "Gamma"))
645 *aggregate_gamma = 1;
649 int ColorBalanceMain::handle_opengl()
653 get_output()->to_texture();
654 get_output()->enable_opengl();
656 unsigned int shader = 0;
657 char *shader_stack[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
658 int current_shader = 0;
659 int aggregate_interpolate = 0;
660 int aggregate_gamma = 0;
662 get_aggregation(&aggregate_interpolate,
665 printf("ColorBalanceMain::handle_opengl %d %d\n", aggregate_interpolate, aggregate_gamma);
666 if(aggregate_interpolate)
667 INTERPOLATE_COMPILE(shader_stack, current_shader)
670 GAMMA_COMPILE(shader_stack, current_shader, aggregate_interpolate)
672 COLORBALANCE_COMPILE(shader_stack,
674 aggregate_gamma || aggregate_interpolate)
676 shader = VFrame::make_shader(0,
689 glUseProgram(shader);
690 glUniform1i(glGetUniformLocation(shader, "tex"), 0);
692 if(aggregate_interpolate) INTERPOLATE_UNIFORMS(shader);
693 if(aggregate_gamma) GAMMA_UNIFORMS(shader);
695 COLORBALANCE_UNIFORMS(shader);
699 get_output()->init_screen();
700 get_output()->bind_texture(0);
701 get_output()->draw_texture();
703 get_output()->set_opengl_state(VFrame::SCREEN);