+++ /dev/null
-
-/*
- * CINELERRA
- * Copyright (C) 2008-2012 Adam Williams <broadcast at earthling dot net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <math.h>
-#include <stdint.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "bcdisplayinfo.h"
-#include "bcsignals.h"
-#include "clip.h"
-#include "bchash.h"
-#include "filexml.h"
-#include "histogram.h"
-#include "histogramconfig.h"
-#include "histogramwindow.h"
-#include "keyframe.h"
-#include "language.h"
-#include "loadbalance.h"
-#include "playback3d.h"
-#include "cicolors.h"
-#include "vframe.h"
-#include "workarounds.h"
-
-#include "aggregated.h"
-#include "../colorbalance/aggregated.h"
-#include "../interpolate/aggregated.h"
-#include "../gamma/aggregated.h"
-
-class HistogramMain;
-class HistogramEngine;
-class HistogramWindow;
-
-
-
-
-
-REGISTER_PLUGIN(HistogramMain)
-
-
-
-
-
-
-
-
-
-HistogramMain::HistogramMain(PluginServer *server)
- : PluginVClient(server)
-{
-
- engine = 0;
- for(int i = 0; i < HISTOGRAM_MODES; i++)
- {
- lookup[i] = 0;
- accum[i] = 0;
- preview_lookup[i] = 0;
- }
- current_point = -1;
- mode = HISTOGRAM_VALUE;
- dragging_point = 0;
- input = 0;
- output = 0;
- w = 440;
- h = 500;
- parade = 0;
-}
-
-HistogramMain::~HistogramMain()
-{
-
- for(int i = 0; i < HISTOGRAM_MODES;i++)
- {
- delete [] lookup[i];
- delete [] accum[i];
- delete [] preview_lookup[i];
- }
- delete engine;
-}
-
-const char* HistogramMain::plugin_title() { return _("Histogram"); }
-int HistogramMain::is_realtime() { return 1; }
-
-
-
-NEW_WINDOW_MACRO(HistogramMain, HistogramWindow)
-
-LOAD_CONFIGURATION_MACRO(HistogramMain, HistogramConfig)
-
-void HistogramMain::render_gui(void *data)
-{
- if(thread)
- {
-// Process just the RGB values to determine the automatic points or
-// all the points if manual
- if(!config.automatic)
- {
-// Generate curves for value histogram
-// Lock out changes to curves
- ((HistogramWindow*)thread->window)->lock_window("HistogramMain::render_gui 1");
- tabulate_curve(HISTOGRAM_RED, 0);
- tabulate_curve(HISTOGRAM_GREEN, 0);
- tabulate_curve(HISTOGRAM_BLUE, 0);
- ((HistogramWindow*)thread->window)->unlock_window();
- }
-
- calculate_histogram((VFrame*)data, !config.automatic);
-
-
- if(config.automatic)
- {
- calculate_automatic((VFrame*)data);
-
-// Generate curves for value histogram
-// Lock out changes to curves
- ((HistogramWindow*)thread->window)->lock_window("HistogramMain::render_gui 1");
- tabulate_curve(HISTOGRAM_RED, 0);
- tabulate_curve(HISTOGRAM_GREEN, 0);
- tabulate_curve(HISTOGRAM_BLUE, 0);
- ((HistogramWindow*)thread->window)->unlock_window();
-
-
-// Need a second pass to get the luminance values.
- calculate_histogram((VFrame*)data, 1);
- }
-
- ((HistogramWindow*)thread->window)->lock_window("HistogramMain::render_gui 2");
-// Always draw the histogram but don't update widgets if automatic
- ((HistogramWindow*)thread->window)->update(1,
- config.automatic && mode != HISTOGRAM_VALUE,
- config.automatic && mode != HISTOGRAM_VALUE,
- 0);
-
- ((HistogramWindow*)thread->window)->unlock_window();
- }
-}
-
-void HistogramMain::update_gui()
-{
- if(thread)
- {
- ((HistogramWindow*)thread->window)->lock_window("HistogramMain::update_gui");
- int reconfigure = load_configuration();
- if(reconfigure)
- {
- ((HistogramWindow*)thread->window)->update(1,
- 1,
- 1,
- 1);
- }
- ((HistogramWindow*)thread->window)->unlock_window();
- }
-}
-
-
-
-
-void HistogramMain::save_data(KeyFrame *keyframe)
-{
- FileXML output;
-
-// cause data to be stored directly in text
- output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
- output.tag.set_title("HISTOGRAM");
-
- char string[BCTEXTLEN];
-
- output.tag.set_property("AUTOMATIC", config.automatic);
- output.tag.set_property("THRESHOLD", config.threshold);
- output.tag.set_property("PLOT", config.plot);
- output.tag.set_property("SPLIT", config.split);
- output.tag.set_property("W", w);
- output.tag.set_property("H", h);
- output.tag.set_property("PARADE", parade);
- output.tag.set_property("MODE", mode);
-
- for(int i = 0; i < HISTOGRAM_MODES; i++)
- {
- sprintf(string, "LOW_OUTPUT_%d", i);
- output.tag.set_property(string, config.low_output[i]);
- sprintf(string, "HIGH_OUTPUT_%d", i);
- output.tag.set_property(string, config.high_output[i]);
- sprintf(string, "LOW_INPUT_%d", i);
- output.tag.set_property(string, config.low_input[i]);
- sprintf(string, "HIGH_INPUT_%d", i);
- output.tag.set_property(string, config.high_input[i]);
- sprintf(string, "GAMMA_%d", i);
- output.tag.set_property(string, config.gamma[i]);
-//printf("HistogramMain::save_data %d %f %d\n", config.input_min[i], config.input_mid[i], config.input_max[i]);
- }
-
- output.append_tag();
- output.tag.set_title("/HISTOGRAM");
- output.append_tag();
- output.append_newline();
- output.terminate_string();
-}
-
-void HistogramMain::read_data(KeyFrame *keyframe)
-{
- FileXML input;
-
- input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
-
- int result = 0;
-
-
- while(!result)
- {
- result = input.read_tag();
-
- if(!result)
- {
- if(input.tag.title_is("HISTOGRAM"))
- {
- config.automatic = input.tag.get_property("AUTOMATIC", config.automatic);
- config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
- config.plot = input.tag.get_property("PLOT", config.plot);
- config.split = input.tag.get_property("SPLIT", config.split);
-
- if(is_defaults())
- {
- w = input.tag.get_property("W", w);
- h = input.tag.get_property("H", h);
- parade = input.tag.get_property("PARADE", parade);
- mode = input.tag.get_property("MODE", mode);
- }
-
- char string[BCTEXTLEN];
- for(int i = 0; i < HISTOGRAM_MODES; i++)
- {
- sprintf(string, "LOW_OUTPUT_%d", i);
- config.low_output[i] = input.tag.get_property(string, config.low_output[i]);
- sprintf(string, "HIGH_OUTPUT_%d", i);
- config.high_output[i] = input.tag.get_property(string, config.high_output[i]);
- sprintf(string, "GAMMA_%d", i);
- config.gamma[i] = input.tag.get_property(string, config.gamma[i]);
-
- if(i == HISTOGRAM_VALUE || !config.automatic)
- {
- sprintf(string, "LOW_INPUT_%d", i);
- config.low_input[i] = input.tag.get_property(string, config.low_input[i]);
- sprintf(string, "HIGH_INPUT_%d", i);
- config.high_input[i] = input.tag.get_property(string, config.high_input[i]);
- }
-//printf("HistogramMain::read_data %d %f %d\n", config.input_min[i], config.input_mid[i], config.input_max[i]);
- }
- }
- }
- }
-
- config.boundaries();
-
-}
-
-float HistogramMain::calculate_level(float input,
- int mode,
- int use_value)
-{
- float output = 0.0;
-
-// Scale to input range
- if(!EQUIV(config.high_input[mode], config.low_input[mode]))
- {
- output = (input - config.low_input[mode]) /
- (config.high_input[mode] - config.low_input[mode]);
- }
- else
- {
- output = input;
- }
-
-
-
- if(!EQUIV(config.gamma[mode], 0))
- {
- output = pow(output, 1.0 / config.gamma[mode]);
- CLAMP(output, 0, 1.0);
- }
-
-// Apply value curve
- if(use_value && mode != HISTOGRAM_VALUE)
- {
- output = calculate_level(output, HISTOGRAM_VALUE, 0);
- }
-
-
-
-
-// scale to output range
- if(!EQUIV(config.low_output[mode], config.high_output[mode]))
- {
- output = output * (config.high_output[mode] - config.low_output[mode]) +
- config.low_output[mode];
- }
-
- CLAMP(output, 0, 1.0);
-
- return output;
-}
-
-
-
-void HistogramMain::calculate_histogram(VFrame *data, int do_value)
-{
-
- if(!engine) engine = new HistogramEngine(this,
- get_project_smp() + 1,
- get_project_smp() + 1);
-
- if(!accum[0])
- {
- for(int i = 0; i < HISTOGRAM_MODES; i++)
- accum[i] = new int[HISTOGRAM_SLOTS];
- }
-
- engine->process_packages(HistogramEngine::HISTOGRAM, data, do_value);
-
- for(int i = 0; i < engine->get_total_clients(); i++)
- {
- HistogramUnit *unit = (HistogramUnit*)engine->get_client(i);
-
- if(i == 0)
- {
- for(int j = 0; j < HISTOGRAM_MODES; j++)
- {
- memcpy(accum[j], unit->accum[j], sizeof(int) * HISTOGRAM_SLOTS);
- }
- }
- else
- {
- for(int j = 0; j < HISTOGRAM_MODES; j++)
- {
- int *out = accum[j];
- int *in = unit->accum[j];
- for(int k = 0; k < HISTOGRAM_SLOTS; k++)
- out[k] += in[k];
- }
- }
- }
-
-// Remove top and bottom from calculations. Doesn't work in high
-// precision colormodels.
- for(int i = 0; i < HISTOGRAM_MODES; i++)
- {
- accum[i][0] = 0;
- accum[i][HISTOGRAM_SLOTS - 1] = 0;
- }
-}
-
-
-void HistogramMain::calculate_automatic(VFrame *data)
-{
- calculate_histogram(data, 0);
- config.reset_points(1);
-
-// Do each channel
- for(int i = 0; i < 3; i++)
- {
- int *accum = this->accum[i];
- int pixels = data->get_w() * data->get_h();
- float white_fraction = 1.0 - (1.0 - config.threshold) / 2;
- int threshold = (int)(white_fraction * pixels);
- int total = 0;
- float max_level = 1.0;
- float min_level = 0.0;
-
-// Get histogram slot above threshold of pixels
- for(int j = 0; j < HISTOGRAM_SLOTS; j++)
- {
- total += accum[j];
- if(total >= threshold)
- {
- max_level = (float)j / HISTOGRAM_SLOTS * FLOAT_RANGE + HIST_MIN_INPUT;
- break;
- }
- }
-
-// Get slot below 99% of pixels
- total = 0;
- for(int j = HISTOGRAM_SLOTS - 1; j >= 0; j--)
- {
- total += accum[j];
- if(total >= threshold)
- {
- min_level = (float)j / HISTOGRAM_SLOTS * FLOAT_RANGE + HIST_MIN_INPUT;
- break;
- }
- }
-
-
- config.low_input[i] = min_level;
- config.high_input[i] = max_level;
- }
-}
-
-
-
-
-
-int HistogramMain::calculate_use_opengl()
-{
-// glHistogram doesn't work.
- int result = get_use_opengl() &&
- !config.automatic &&
- (!config.plot || !gui_open());
- return result;
-}
-
-
-int HistogramMain::process_buffer(VFrame *frame,
- int64_t start_position,
- double frame_rate)
-{
- int need_reconfigure = load_configuration();
-
-
-
- int use_opengl = calculate_use_opengl();
-
-//printf("%d\n", use_opengl);
- read_frame(frame,
- 0,
- start_position,
- frame_rate,
- use_opengl);
-
-// Apply histogram in hardware
- if(use_opengl) return run_opengl();
-
- if(!engine) engine = new HistogramEngine(this,
- get_project_smp() + 1,
- get_project_smp() + 1);
- this->input = frame;
- this->output = frame;
-// Always plot to set the curves if automatic
- if(config.plot || config.automatic) send_render_gui(frame);
-
-// Generate tables here. The same table is used by many packages to render
-// each horizontal stripe. Need to cover the entire output range in each
-// table to avoid green borders
-
-
- if(need_reconfigure ||
- !lookup[0] ||
- config.automatic)
- {
-// Calculate new curves
- if(config.automatic)
- {
- calculate_automatic(input);
- }
-
-
-// Generate transfer tables with value function for integer colormodels.
- for(int i = 0; i < 3; i++)
- tabulate_curve(i, 1);
- }
-
-// printf("HistogramMain::process_buffer %d %f %f %f %f %f %f %f %f %f\n",
-// __LINE__,
-// config.low_input[HISTOGRAM_RED],
-// config.gamma[HISTOGRAM_RED],
-// config.high_input[HISTOGRAM_RED],
-// config.low_input[HISTOGRAM_GREEN],
-// config.gamma[HISTOGRAM_GREEN],
-// config.high_input[HISTOGRAM_GREEN],
-// config.low_input[HISTOGRAM_BLUE],
-// config.gamma[HISTOGRAM_BLUE],
-// config.high_input[HISTOGRAM_BLUE]);
-
-
-
-// Apply histogram
- engine->process_packages(HistogramEngine::APPLY, input, 0);
-
-
- return 0;
-}
-
-void HistogramMain::tabulate_curve(int subscript, int use_value)
-{
- int i;
- if(!lookup[subscript])
- lookup[subscript] = new int[HISTOGRAM_SLOTS];
- if(!preview_lookup[subscript])
- preview_lookup[subscript] = new int[HISTOGRAM_SLOTS];
-
-//printf("HistogramMain::tabulate_curve %d input=%p\n", __LINE__, input);
-
-
-// Generate lookup tables for integer colormodels
- if(input)
- {
- switch(input->get_color_model())
- {
- case BC_RGB888:
- case BC_RGBA8888:
- for(i = 0; i < 0x100; i++)
- {
- lookup[subscript][i] =
- (int)(calculate_level((float)i / 0xff, subscript, use_value) *
- 0xff);
- CLAMP(lookup[subscript][i], 0, 0xff);
- }
- break;
-// All other integer colormodels are converted to 16 bit RGB
- default:
- for(i = 0; i < 0x10000; i++)
- {
- lookup[subscript][i] =
- (int)(calculate_level((float)i / 0xffff, subscript, use_value) *
- 0xffff);
- CLAMP(lookup[subscript][i], 0, 0xffff);
- }
-// for(i = 0; i < 0x100; i++)
-// {
-// if(subscript == HISTOGRAM_BLUE) printf("%d ", lookup[subscript][i * 0x100]);
-// }
-// if(subscript == HISTOGRAM_BLUE) printf("\n");
-
- break;
- }
- }
-
-// Lookup table for preview only used for GUI
- if(!use_value)
- {
- for(i = 0; i < 0x10000; i++)
- {
- preview_lookup[subscript][i] =
- (int)(calculate_level((float)i / 0xffff, subscript, use_value) *
- 0xffff);
- CLAMP(preview_lookup[subscript][i], 0, 0xffff);
- }
- }
-}
-
-int HistogramMain::handle_opengl()
-{
-#ifdef HAVE_GL
-// Functions to get pixel from either previous effect or texture
- static const char *histogram_get_pixel1 =
- "vec4 histogram_get_pixel()\n"
- "{\n"
- " return gl_FragColor;\n"
- "}\n";
-
- static const char *histogram_get_pixel2 =
- "uniform sampler2D tex;\n"
- "vec4 histogram_get_pixel()\n"
- "{\n"
- " return texture2D(tex, gl_TexCoord[0].st);\n"
- "}\n";
-
- static const char *head_frag =
- "uniform vec4 low_input;\n"
- "uniform vec4 high_input;\n"
- "uniform vec4 gamma;\n"
- "uniform vec4 low_output;\n"
- "uniform vec4 output_scale;\n"
- "void main()\n"
- "{\n"
- " float temp = 0.0;\n";
-
- static const char *get_rgb_frag =
- " vec4 pixel = histogram_get_pixel();\n";
-
- static const char *get_yuv_frag =
- " vec4 pixel = histogram_get_pixel();\n"
- YUV_TO_RGB_FRAG("pixel");
-
-#define APPLY_INPUT_CURVE(PIXEL, LOW_INPUT, HIGH_INPUT, GAMMA) \
- "// apply input curve\n" \
- " temp = (" PIXEL " - " LOW_INPUT ") / \n" \
- " (" HIGH_INPUT " - " LOW_INPUT ");\n" \
- " temp = max(temp, 0.0);\n" \
- " " PIXEL " = pow(temp, 1.0 / " GAMMA ");\n"
-
-
-
- static const char *apply_histogram_frag =
- APPLY_INPUT_CURVE("pixel.r", "low_input.r", "high_input.r", "gamma.r")
- APPLY_INPUT_CURVE("pixel.g", "low_input.g", "high_input.g", "gamma.g")
- APPLY_INPUT_CURVE("pixel.b", "low_input.b", "high_input.b", "gamma.b")
- "// apply output curve\n"
- " pixel.rgb *= output_scale.rgb;\n"
- " pixel.rgb += low_output.rgb;\n"
- APPLY_INPUT_CURVE("pixel.r", "low_input.a", "high_input.a", "gamma.a")
- APPLY_INPUT_CURVE("pixel.g", "low_input.a", "high_input.a", "gamma.a")
- APPLY_INPUT_CURVE("pixel.b", "low_input.a", "high_input.a", "gamma.a")
- "// apply output curve\n"
- " pixel.rgb *= vec3(output_scale.a, output_scale.a, output_scale.a);\n"
- " pixel.rgb += vec3(low_output.a, low_output.a, low_output.a);\n";
-
- static const char *put_rgb_frag =
- " gl_FragColor = pixel;\n"
- "}\n";
-
- static const char *put_yuv_frag =
- RGB_TO_YUV_FRAG("pixel")
- " gl_FragColor = pixel;\n"
- "}\n";
-
-
-
- get_output()->to_texture();
- get_output()->enable_opengl();
-
- const char *shader_stack[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
- int current_shader = 0;
- int aggregate_interpolation = 0;
- int aggregate_gamma = 0;
- int aggregate_colorbalance = 0;
-// All aggregation possibilities must be accounted for because unsupported
-// effects can get in between the aggregation members.
- if(!strcmp(get_output()->get_prev_effect(2), _("Interpolate Pixels")) &&
- !strcmp(get_output()->get_prev_effect(1), _("Gamma")) &&
- !strcmp(get_output()->get_prev_effect(0), _("Color Balance")))
- {
- aggregate_interpolation = 1;
- aggregate_gamma = 1;
- aggregate_colorbalance = 1;
- }
- else
- if(!strcmp(get_output()->get_prev_effect(1), _("Gamma")) &&
- !strcmp(get_output()->get_prev_effect(0), _("Color Balance")))
- {
- aggregate_gamma = 1;
- aggregate_colorbalance = 1;
- }
- else
- if(!strcmp(get_output()->get_prev_effect(1), _("Interpolate Pixels")) &&
- !strcmp(get_output()->get_prev_effect(0), _("Gamma")))
- {
- aggregate_interpolation = 1;
- aggregate_gamma = 1;
- }
- else
- if(!strcmp(get_output()->get_prev_effect(1), _("Interpolate Pixels")) &&
- !strcmp(get_output()->get_prev_effect(0), _("Color Balance")))
- {
- aggregate_interpolation = 1;
- aggregate_colorbalance = 1;
- }
- else
- if(!strcmp(get_output()->get_prev_effect(0), _("Interpolate Pixels")))
- aggregate_interpolation = 1;
- else
- if(!strcmp(get_output()->get_prev_effect(0), _("Gamma")))
- aggregate_gamma = 1;
- else
- if(!strcmp(get_output()->get_prev_effect(0), _("Color Balance")))
- aggregate_colorbalance = 1;
-
-
-// The order of processing is fixed by this sequence
- if(aggregate_interpolation)
- INTERPOLATE_COMPILE(shader_stack,
- current_shader)
-
- if(aggregate_gamma)
- GAMMA_COMPILE(shader_stack,
- current_shader,
- aggregate_interpolation)
-
- if(aggregate_colorbalance)
- COLORBALANCE_COMPILE(shader_stack,
- current_shader,
- aggregate_interpolation || aggregate_gamma)
-
-
- if(aggregate_interpolation || aggregate_gamma || aggregate_colorbalance)
- shader_stack[current_shader++] = histogram_get_pixel1;
- else
- shader_stack[current_shader++] = histogram_get_pixel2;
-
- unsigned int shader = 0;
- switch(get_output()->get_color_model())
- {
- case BC_YUV888:
- case BC_YUVA8888:
- shader_stack[current_shader++] = head_frag;
- shader_stack[current_shader++] = get_yuv_frag;
- shader_stack[current_shader++] = apply_histogram_frag;
- shader_stack[current_shader++] = put_yuv_frag;
- break;
- default:
- shader_stack[current_shader++] = head_frag;
- shader_stack[current_shader++] = get_rgb_frag;
- shader_stack[current_shader++] = apply_histogram_frag;
- shader_stack[current_shader++] = put_rgb_frag;
- break;
- }
-
- shader = VFrame::make_shader(0,
- shader_stack[0],
- shader_stack[1],
- shader_stack[2],
- shader_stack[3],
- shader_stack[4],
- shader_stack[5],
- shader_stack[6],
- shader_stack[7],
- shader_stack[8],
- shader_stack[9],
- shader_stack[10],
- shader_stack[11],
- shader_stack[12],
- shader_stack[13],
- shader_stack[14],
- shader_stack[15],
- 0);
-
-// printf("HistogramMain::handle_opengl %d %d %d %d shader=%d\n",
-// aggregate_interpolation,
-// aggregate_gamma,
-// aggregate_colorbalance,
-// current_shader,
-// shader);
-
- float low_input[4];
- float high_input[4];
- float gamma[4];
- float low_output[4];
- float output_scale[4];
-
-
-// printf("min x min y max x max y\n");
-// printf("%f %f %f %f\n", input_min_r[0], input_min_r[1], input_max_r[0], input_max_r[1]);
-// printf("%f %f %f %f\n", input_min_g[0], input_min_g[1], input_max_g[0], input_max_g[1]);
-// printf("%f %f %f %f\n", input_min_b[0], input_min_b[1], input_max_b[0], input_max_b[1]);
-// printf("%f %f %f %f\n", input_min_v[0], input_min_v[1], input_max_v[0], input_max_v[1]);
-
- for(int i = 0; i < HISTOGRAM_MODES; i++)
- {
- low_input[i] = config.low_input[i];
- high_input[i] = config.high_input[i];
- gamma[i] = config.gamma[i];
- low_output[i] = config.low_output[i];
- output_scale[i] = config.high_output[i] - config.low_output[i];
- }
-
- if(shader > 0)
- {
- glUseProgram(shader);
- glUniform1i(glGetUniformLocation(shader, "tex"), 0);
- if(aggregate_gamma) GAMMA_UNIFORMS(shader)
- if(aggregate_interpolation) INTERPOLATE_UNIFORMS(shader)
- if(aggregate_colorbalance) COLORBALANCE_UNIFORMS(shader)
- glUniform4fv(glGetUniformLocation(shader, "low_input"), 1, low_input);
- glUniform4fv(glGetUniformLocation(shader, "high_input"), 1, high_input);
- glUniform4fv(glGetUniformLocation(shader, "gamma"), 1, gamma);
- glUniform4fv(glGetUniformLocation(shader, "low_output"), 1, low_output);
- glUniform4fv(glGetUniformLocation(shader, "output_scale"), 1, output_scale);
- }
-
- get_output()->init_screen();
- get_output()->bind_texture(0);
-
- glDisable(GL_BLEND);
-
-// Draw the affected half
- if(config.split)
- {
- glBegin(GL_TRIANGLES);
- glNormal3f(0, 0, 1.0);
-
- glTexCoord2f(0.0 / get_output()->get_texture_w(),
- 0.0 / get_output()->get_texture_h());
- glVertex3f(0.0, -(float)get_output()->get_h(), 0);
-
-
- glTexCoord2f((float)get_output()->get_w() / get_output()->get_texture_w(),
- (float)get_output()->get_h() / get_output()->get_texture_h());
- glVertex3f((float)get_output()->get_w(), -0.0, 0);
-
- glTexCoord2f(0.0 / get_output()->get_texture_w(),
- (float)get_output()->get_h() / get_output()->get_texture_h());
- glVertex3f(0.0, -0.0, 0);
-
-
- glEnd();
- }
- else
- {
- get_output()->draw_texture();
- }
-
- glUseProgram(0);
-
-// Draw the unaffected half
- if(config.split)
- {
- glBegin(GL_TRIANGLES);
- glNormal3f(0, 0, 1.0);
-
-
- glTexCoord2f(0.0 / get_output()->get_texture_w(),
- 0.0 / get_output()->get_texture_h());
- glVertex3f(0.0, -(float)get_output()->get_h(), 0);
-
- glTexCoord2f((float)get_output()->get_w() / get_output()->get_texture_w(),
- 0.0 / get_output()->get_texture_h());
- glVertex3f((float)get_output()->get_w(),
- -(float)get_output()->get_h(), 0);
-
- glTexCoord2f((float)get_output()->get_w() / get_output()->get_texture_w(),
- (float)get_output()->get_h() / get_output()->get_texture_h());
- glVertex3f((float)get_output()->get_w(), -0.0, 0);
-
-
- glEnd();
- }
-
- get_output()->set_opengl_state(VFrame::SCREEN);
-#endif
- return 0;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-HistogramPackage::HistogramPackage()
- : LoadPackage()
-{
-}
-
-
-
-
-HistogramUnit::HistogramUnit(HistogramEngine *server,
- HistogramMain *plugin)
- : LoadClient(server)
-{
- this->plugin = plugin;
- this->server = server;
- for(int i = 0; i < HISTOGRAM_MODES; i++)
- accum[i] = new int[HISTOGRAM_SLOTS];
-}
-
-HistogramUnit::~HistogramUnit()
-{
- for(int i = 0; i < HISTOGRAM_MODES; i++)
- delete [] accum[i];
-}
-
-void HistogramUnit::process_package(LoadPackage *package)
-{
- HistogramPackage *pkg = (HistogramPackage*)package;
-
- if(server->operation == HistogramEngine::HISTOGRAM)
- {
- int do_value = server->do_value;
-
-
-#define HISTOGRAM_HEAD(type) \
-{ \
- for(int i = pkg->start; i < pkg->end; i++) \
- { \
- type *row = (type*)data->get_rows()[i]; \
- for(int j = 0; j < w; j++) \
- {
-
-#define HISTOGRAM_TAIL(components) \
-/* Value takes the maximum of the output RGB values */ \
- if(do_value) \
- { \
- CLAMP(r, 0, HISTOGRAM_SLOTS - 1); \
- CLAMP(g, 0, HISTOGRAM_SLOTS - 1); \
- CLAMP(b, 0, HISTOGRAM_SLOTS - 1); \
- r_out = lookup_r[r]; \
- g_out = lookup_g[g]; \
- b_out = lookup_b[b]; \
-/* v = (r * 76 + g * 150 + b * 29) >> 8; */ \
- v = MAX(r_out, g_out); \
- v = MAX(v, b_out); \
- v += -HISTOGRAM_MIN * 0xffff / 100; \
- CLAMP(v, 0, HISTOGRAM_SLOTS - 1); \
- accum_v[v]++; \
- } \
- \
- r += -HISTOGRAM_MIN * 0xffff / 100; \
- g += -HISTOGRAM_MIN * 0xffff / 100; \
- b += -HISTOGRAM_MIN * 0xffff / 100; \
- CLAMP(r, 0, HISTOGRAM_SLOTS - 1); \
- CLAMP(g, 0, HISTOGRAM_SLOTS - 1); \
- CLAMP(b, 0, HISTOGRAM_SLOTS - 1); \
- accum_r[r]++; \
- accum_g[g]++; \
- accum_b[b]++; \
- row += components; \
- } \
- } \
-}
-
-
-
-
- VFrame *data = server->data;
- int w = data->get_w();
- //int h = data->get_h();
- int *accum_r = accum[HISTOGRAM_RED];
- int *accum_g = accum[HISTOGRAM_GREEN];
- int *accum_b = accum[HISTOGRAM_BLUE];
- int *accum_v = accum[HISTOGRAM_VALUE];
- int32_t r, g, b, y, u, v;
- int r_out, g_out, b_out;
- int *lookup_r = plugin->preview_lookup[HISTOGRAM_RED];
- int *lookup_g = plugin->preview_lookup[HISTOGRAM_GREEN];
- int *lookup_b = plugin->preview_lookup[HISTOGRAM_BLUE];
-
- switch(data->get_color_model())
- {
- case BC_RGB888:
- HISTOGRAM_HEAD(unsigned char)
- r = (row[0] << 8) | row[0];
- g = (row[1] << 8) | row[1];
- b = (row[2] << 8) | row[2];
- HISTOGRAM_TAIL(3)
- break;
- case BC_RGB_FLOAT:
- HISTOGRAM_HEAD(float)
- r = (int)(row[0] * 0xffff);
- g = (int)(row[1] * 0xffff);
- b = (int)(row[2] * 0xffff);
- HISTOGRAM_TAIL(3)
- break;
- case BC_YUV888:
- HISTOGRAM_HEAD(unsigned char)
- y = (row[0] << 8) | row[0];
- u = (row[1] << 8) | row[1];
- v = (row[2] << 8) | row[2];
- plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
- HISTOGRAM_TAIL(3)
- break;
- case BC_RGBA8888:
- HISTOGRAM_HEAD(unsigned char)
- r = (row[0] << 8) | row[0];
- g = (row[1] << 8) | row[1];
- b = (row[2] << 8) | row[2];
- HISTOGRAM_TAIL(4)
- break;
- case BC_RGBA_FLOAT:
- HISTOGRAM_HEAD(float)
- r = (int)(row[0] * 0xffff);
- g = (int)(row[1] * 0xffff);
- b = (int)(row[2] * 0xffff);
- HISTOGRAM_TAIL(4)
- break;
- case BC_YUVA8888:
- HISTOGRAM_HEAD(unsigned char)
- y = (row[0] << 8) | row[0];
- u = (row[1] << 8) | row[1];
- v = (row[2] << 8) | row[2];
- plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
- HISTOGRAM_TAIL(4)
- break;
- case BC_RGB161616:
- HISTOGRAM_HEAD(uint16_t)
- r = row[0];
- g = row[1];
- b = row[2];
- HISTOGRAM_TAIL(3)
- break;
- case BC_YUV161616:
- HISTOGRAM_HEAD(uint16_t)
- y = row[0];
- u = row[1];
- v = row[2];
- plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
- HISTOGRAM_TAIL(3)
- break;
- case BC_RGBA16161616:
- HISTOGRAM_HEAD(uint16_t)
- r = row[0];
- g = row[1];
- b = row[2];
- HISTOGRAM_TAIL(3)
- break;
- case BC_YUVA16161616:
- HISTOGRAM_HEAD(uint16_t)
- y = row[0];
- u = row[1];
- v = row[2];
- plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
- HISTOGRAM_TAIL(4)
- break;
- }
- }
- else
- if(server->operation == HistogramEngine::APPLY)
- {
-
-
-
-#define PROCESS(type, components) \
-{ \
- for(int i = pkg->start; i < pkg->end; i++) \
- { \
- type *row = (type*)input->get_rows()[i]; \
- for(int j = 0; j < w; j++) \
- { \
- if ( plugin->config.split && ((j + i * w / h) < w) ) \
- continue; \
- row[0] = lookup_r[row[0]]; \
- row[1] = lookup_g[row[1]]; \
- row[2] = lookup_b[row[2]]; \
- row += components; \
- } \
- } \
-}
-
-#define PROCESS_YUV(type, components, max) \
-{ \
- for(int i = pkg->start; i < pkg->end; i++) \
- { \
- type *row = (type*)input->get_rows()[i]; \
- for(int j = 0; j < w; j++) \
- { \
- if ( plugin->config.split && ((j + i * w / h) < w) ) \
- continue; \
-/* Convert to 16 bit RGB */ \
- if(max == 0xff) \
- { \
- y = (row[0] << 8) | row[0]; \
- u = (row[1] << 8) | row[1]; \
- v = (row[2] << 8) | row[2]; \
- } \
- else \
- { \
- y = row[0]; \
- u = row[1]; \
- v = row[2]; \
- } \
- \
- plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v); \
- \
-/* Look up in RGB domain */ \
- r = lookup_r[r]; \
- g = lookup_g[g]; \
- b = lookup_b[b]; \
- \
-/* Convert to 16 bit YUV */ \
- plugin->yuv.rgb_to_yuv_16(r, g, b, y, u, v); \
- \
- if(max == 0xff) \
- { \
- row[0] = y >> 8; \
- row[1] = u >> 8; \
- row[2] = v >> 8; \
- } \
- else \
- { \
- row[0] = y; \
- row[1] = u; \
- row[2] = v; \
- } \
- row += components; \
- } \
- } \
-}
-
-#define PROCESS_FLOAT(components) \
-{ \
- for(int i = pkg->start; i < pkg->end; i++) \
- { \
- float *row = (float*)input->get_rows()[i]; \
- for(int j = 0; j < w; j++) \
- { \
- if ( plugin->config.split && ((j + i * w / h) < w) ) \
- continue; \
- float r = row[0]; \
- float g = row[1]; \
- float b = row[2]; \
- \
- r = plugin->calculate_level(r, HISTOGRAM_RED, 1); \
- g = plugin->calculate_level(g, HISTOGRAM_GREEN, 1); \
- b = plugin->calculate_level(b, HISTOGRAM_BLUE, 1); \
- \
- row[0] = r; \
- row[1] = g; \
- row[2] = b; \
- \
- row += components; \
- } \
- } \
-}
-
-
- VFrame *input = plugin->input;
- //VFrame *output = plugin->output;
- int w = input->get_w();
- int h = input->get_h();
- int *lookup_r = plugin->lookup[0];
- int *lookup_g = plugin->lookup[1];
- int *lookup_b = plugin->lookup[2];
- int r, g, b, y, u, v;
- switch(input->get_color_model())
- {
- case BC_RGB888:
- PROCESS(unsigned char, 3)
- break;
- case BC_RGB_FLOAT:
- PROCESS_FLOAT(3);
- break;
- case BC_RGBA8888:
- PROCESS(unsigned char, 4)
- break;
- case BC_RGBA_FLOAT:
- PROCESS_FLOAT(4);
- break;
- case BC_RGB161616:
- PROCESS(uint16_t, 3)
- break;
- case BC_RGBA16161616:
- PROCESS(uint16_t, 4)
- break;
- case BC_YUV888:
- PROCESS_YUV(unsigned char, 3, 0xff)
- break;
- case BC_YUVA8888:
- PROCESS_YUV(unsigned char, 4, 0xff)
- break;
- case BC_YUV161616:
- PROCESS_YUV(uint16_t, 3, 0xffff)
- break;
- case BC_YUVA16161616:
- PROCESS_YUV(uint16_t, 4, 0xffff)
- break;
- }
- }
-}
-
-
-
-
-
-
-HistogramEngine::HistogramEngine(HistogramMain *plugin,
- int total_clients,
- int total_packages)
- : LoadServer(total_clients, total_packages)
-{
- this->plugin = plugin;
-}
-
-void HistogramEngine::init_packages()
-{
- switch(operation)
- {
- case HISTOGRAM:
- total_size = data->get_h();
- break;
- case APPLY:
- total_size = data->get_h();
- break;
- }
-
-
- //int package_size = (int)((float)total_size / get_total_packages() + 1);
- //int start = 0;
-
- for(int i = 0; i < get_total_packages(); i++)
- {
- HistogramPackage *package = (HistogramPackage*)get_package(i);
- package->start = total_size * i / get_total_packages();
- package->end = total_size * (i + 1) / get_total_packages();
- }
-
-// Initialize clients here in case some don't get run.
- for(int i = 0; i < get_total_clients(); i++)
- {
- HistogramUnit *unit = (HistogramUnit*)get_client(i);
- for(int i = 0; i < HISTOGRAM_MODES; i++)
- bzero(unit->accum[i], sizeof(int) * HISTOGRAM_SLOTS);
- }
-
-}
-
-LoadClient* HistogramEngine::new_client()
-{
- return new HistogramUnit(this, plugin);
-}
-
-LoadPackage* HistogramEngine::new_package()
-{
- return new HistogramPackage;
-}
-
-void HistogramEngine::process_packages(int operation, VFrame *data, int do_value)
-{
- this->data = data;
- this->operation = operation;
- this->do_value = do_value;
- LoadServer::process_packages();
-}
-
-