Fixed initialisation of tf in file_open(). Without setting the memory to 0,
[cinelerra_cv/mob.git] / plugins / threshold / threshold.C
blobb94d29f4b29eb821555ed47d8a0e9296b434474c
1 #include "clip.h"
2 #include "bchash.h"
3 #include "filexml.h"
4 #include "histogramengine.h"
5 #include "language.h"
6 #include "plugincolors.h"
7 #include "threshold.h"
8 #include "thresholdwindow.h"
9 #include "vframe.h"
11 #include <string.h>
14 ThresholdConfig::ThresholdConfig()
16         reset();
19 int ThresholdConfig::equivalent(ThresholdConfig &that)
21         return EQUIV(min, that.min) &&
22                 EQUIV(max, that.max) &&
23                 plot == that.plot;
26 void ThresholdConfig::copy_from(ThresholdConfig &that)
28         min = that.min;
29         max = that.max;
30         plot = that.plot;
33 void ThresholdConfig::interpolate(ThresholdConfig &prev,
34         ThresholdConfig &next,
35         int64_t prev_frame, 
36         int64_t next_frame, 
37         int64_t current_frame)
39         double next_scale = (double)(current_frame - prev_frame) / 
40                 (next_frame - prev_frame);
41         double prev_scale = (double)(next_frame - current_frame) / 
42                 (next_frame - prev_frame);
44         min = prev.min * prev_scale + next.min * next_scale;
45         max = prev.max * prev_scale + next.max * next_scale;
46         plot = prev.plot;
49 void ThresholdConfig::reset()
51         min = 0.0;
52         max = 1.0;
53         plot = 1;
56 void ThresholdConfig::boundaries()
58         CLAMP(min, HISTOGRAM_MIN, max);
59         CLAMP(max, min, HISTOGRAM_MAX);
69 REGISTER_PLUGIN(ThresholdMain)
71 ThresholdMain::ThresholdMain(PluginServer *server)
72  : PluginVClient(server)
74         PLUGIN_CONSTRUCTOR_MACRO
75         engine = 0;
76         threshold_engine = 0;
79 ThresholdMain::~ThresholdMain()
81         PLUGIN_DESTRUCTOR_MACRO
82         delete engine;
83         delete threshold_engine;
86 int ThresholdMain::is_realtime()
88         return 1;
91 char* ThresholdMain::plugin_title() 
92
93         return N_("Threshold"); 
97 #include "picon_png.h"
98 NEW_PICON_MACRO(ThresholdMain)
100 SHOW_GUI_MACRO(ThresholdMain, ThresholdThread)
102 SET_STRING_MACRO(ThresholdMain)
104 RAISE_WINDOW_MACRO(ThresholdMain)
106 LOAD_CONFIGURATION_MACRO(ThresholdMain, ThresholdConfig)
114 int ThresholdMain::process_buffer(VFrame *frame,
115         int64_t start_position,
116         double frame_rate)
118         load_configuration();
120         int use_opengl = get_use_opengl() &&
121                 (!config.plot || !gui_open());
123         read_frame(frame,
124                 0,
125                 get_source_position(),
126                 get_framerate(),
127                 use_opengl);
129         if(use_opengl) return run_opengl();
131         send_render_gui(frame);
133         if(!threshold_engine)
134                 threshold_engine = new ThresholdEngine(this);
135         threshold_engine->process_packages(frame);
136         
137         return 0;
140 int ThresholdMain::load_defaults()
142         char directory[BCTEXTLEN], string[BCTEXTLEN];
143         sprintf(directory, "%sthreshold.rc", BCASTDIR);
144         defaults = new BC_Hash(directory);
145         defaults->load();
146         config.min = defaults->get("MIN", config.min);
147         config.max = defaults->get("MAX", config.max);
148         config.plot = defaults->get("PLOT", config.plot);
149         config.boundaries();
150         return 0;
153 int ThresholdMain::save_defaults()
155         defaults->update("MIN", config.min);
156         defaults->update("MAX", config.max);
157         defaults->update("PLOT", config.plot);
158         defaults->save();
161 void ThresholdMain::save_data(KeyFrame *keyframe)
163         FileXML file;
164         file.set_shared_string(keyframe->data, MESSAGESIZE);
165         file.tag.set_title("THRESHOLD");
166         file.tag.set_property("MIN", config.min);
167         file.tag.set_property("MAX", config.max);
168         file.tag.set_property("PLOT", config.plot);
169         file.append_tag();
170         file.terminate_string();
173 void ThresholdMain::read_data(KeyFrame *keyframe)
175         FileXML file;
176         file.set_shared_string(keyframe->data, strlen(keyframe->data));
177         int result = 0;
178         while(!result)
179         {
180                 result = file.read_tag();
181                 if(!result)
182                 {
183                         config.min = file.tag.get_property("MIN", config.min);
184                         config.max = file.tag.get_property("MAX", config.max);
185                         config.plot = file.tag.get_property("PLOT", config.plot);
186                 }
187         }
188         config.boundaries();
191 void ThresholdMain::update_gui()
193         if(thread)
194         {
195                 thread->window->lock_window("ThresholdMain::update_gui");
196                 if(load_configuration())
197                 {
198                         thread->window->min->update(config.min);
199                         thread->window->max->update(config.max);
200                         thread->window->plot->update(config.plot);
201                 }
202                 thread->window->unlock_window();
203         }
206 void ThresholdMain::render_gui(void *data)
208         if(thread)
209         {
210                 calculate_histogram((VFrame*)data);
211                 thread->window->lock_window("ThresholdMain::render_gui");
212                 thread->window->canvas->draw();
213                 thread->window->unlock_window();
214         }
217 void ThresholdMain::calculate_histogram(VFrame *frame)
219         if(!engine) engine = new HistogramEngine(get_project_smp() + 1,
220                 get_project_smp() + 1);
221         engine->process_packages(frame);
224 int ThresholdMain::handle_opengl()
226 #ifdef HAVE_GL
227         static char *rgb_shader = 
228                 "uniform sampler2D tex;\n"
229                 "uniform float min;\n"
230                 "uniform float max;\n"
231                 "void main()\n"
232                 "{\n"
233                 "       vec4 pixel = texture2D(tex, gl_TexCoord[0].st);\n"
234                 "       float v = dot(pixel.rgb, vec3(0.299, 0.587, 0.114));\n"
235                 "       if(v >= min && v < max)\n"
236                 "               pixel.rgb = vec3(1.0, 1.0, 1.0);\n"
237                 "       else\n"
238                 "               pixel.rgb = vec3(0.0, 0.0, 0.0);\n"
239                 "       gl_FragColor = pixel;\n"
240                 "}\n";
242         static char *yuv_shader = 
243                 "uniform sampler2D tex;\n"
244                 "uniform float min;\n"
245                 "uniform float max;\n"
246                 "void main()\n"
247                 "{\n"
248                 "       vec4 pixel = texture2D(tex, gl_TexCoord[0].st);\n"
249                 "       if(pixel.r >= min && pixel.r < max)\n"
250                 "               pixel.rgb = vec3(1.0, 0.5, 0.5);\n"
251                 "       else\n"
252                 "               pixel.rgb = vec3(0.0, 0.5, 0.5);\n"
253                 "       gl_FragColor = pixel;\n"
254                 "}\n";
256         get_output()->to_texture();
257         get_output()->enable_opengl();
259         unsigned int shader = 0;
260         if(cmodel_is_yuv(get_output()->get_color_model()))
261                 shader = VFrame::make_shader(0, yuv_shader, 0);
262         else
263                 shader = VFrame::make_shader(0, rgb_shader, 0);
265         if(shader > 0)
266         {
267                 glUseProgram(shader);
268                 glUniform1i(glGetUniformLocation(shader, "tex"), 0);
269                 glUniform1f(glGetUniformLocation(shader, "min"), config.min);
270                 glUniform1f(glGetUniformLocation(shader, "max"), config.max);
271         }
273         get_output()->init_screen();
274         get_output()->bind_texture(0);
275         get_output()->draw_texture();
276         glUseProgram(0);
277         get_output()->set_opengl_state(VFrame::SCREEN);
278 #endif
303 ThresholdPackage::ThresholdPackage()
304  : LoadPackage()
306         start = end = 0;
319 ThresholdUnit::ThresholdUnit(ThresholdEngine *server)
320  : LoadClient(server)
322         this->server = server;
325 void ThresholdUnit::process_package(LoadPackage *package)
327         ThresholdPackage *pkg = (ThresholdPackage*)package;
328         VFrame *data = server->data;
329         int min = (int)(server->plugin->config.min * 0xffff);
330         int max = (int)(server->plugin->config.max * 0xffff);
331         int r, g, b, a, y, u, v;
332         int w = server->data->get_w();
333         int h = server->data->get_h();
335 #define THRESHOLD_HEAD(type) \
336 { \
337         for(int i = pkg->start; i < pkg->end; i++) \
338         { \
339                 type *in_row = (type*)data->get_rows()[i]; \
340                 type *out_row = in_row; \
341                 for(int j = 0; j < w; j++) \
342                 {
344 #define THRESHOLD_TAIL(components, r_on, g_on, b_on, a_on, r_off, g_off, b_off, a_off) \
345                         v = (r * 76 + g * 150 + b * 29) >> 8; \
346                         if(v >= min && v < max) \
347                         { \
348                                 *out_row++ = r_on; \
349                                 *out_row++ = g_on; \
350                                 *out_row++ = b_on; \
351                                 if(components == 4) *out_row++ = a_on; \
352                         } \
353                         else \
354                         { \
355                                 *out_row++ = r_off; \
356                                 *out_row++ = g_off; \
357                                 *out_row++ = b_off; \
358                                 if(components == 4) *out_row++ = a_off; \
359                         } \
360                         in_row += components; \
361                 } \
362         } \
366         switch(data->get_color_model())
367         {
368                 case BC_RGB888:
369                         THRESHOLD_HEAD(unsigned char)
370                         r = (in_row[0] << 8) | in_row[0];
371                         g = (in_row[1] << 8) | in_row[1];
372                         b = (in_row[2] << 8) | in_row[2];
373                         THRESHOLD_TAIL(3, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0);
374                         break;
375                 case BC_RGB_FLOAT:
376                         THRESHOLD_HEAD(float)
377                         r = (int)(in_row[0] * 0xffff);
378                         g = (int)(in_row[1] * 0xffff);
379                         b = (int)(in_row[2] * 0xffff);
380                         THRESHOLD_TAIL(3, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0);
381                         break;
382                 case BC_RGBA8888:
383                         THRESHOLD_HEAD(unsigned char)
384                         r = (in_row[0] << 8) | in_row[0];
385                         g = (in_row[1] << 8) | in_row[1];
386                         b = (in_row[2] << 8) | in_row[2];
387                         THRESHOLD_TAIL(4, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0);
388                         break;
389                 case BC_RGBA_FLOAT:
390                         THRESHOLD_HEAD(float)
391                         r = (int)(in_row[0] * 0xffff);
392                         g = (int)(in_row[1] * 0xffff);
393                         b = (int)(in_row[2] * 0xffff);
394                         THRESHOLD_TAIL(4, 1.0, 1.0, 1.0, 1.0, 0, 0, 0, 0);
395                         break;
396                 case BC_YUV888:
397                         THRESHOLD_HEAD(unsigned char)
398                         y = (in_row[0] << 8) | in_row[0];
399                         u = (in_row[1] << 8) | in_row[1];
400                         v = (in_row[2] << 8) | in_row[2];
401                         server->yuv->yuv_to_rgb_16(r, g, b, y, u, v);
402                         THRESHOLD_TAIL(3, 0xff, 0x80, 0x80, 0xff, 0x0, 0x80, 0x80, 0x0)
403                         break;
404                 case BC_YUVA8888:
405                         THRESHOLD_HEAD(unsigned char)
406                         y = (in_row[0] << 8) | in_row[0];
407                         u = (in_row[1] << 8) | in_row[1];
408                         v = (in_row[2] << 8) | in_row[2];
409                         server->yuv->yuv_to_rgb_16(r, g, b, y, u, v);
410                         THRESHOLD_TAIL(4, 0xff, 0x80, 0x80, 0xff, 0x0, 0x80, 0x80, 0x0)
411                         break;
412                 case BC_YUV161616:
413                         THRESHOLD_HEAD(uint16_t)
414                         y = in_row[0];
415                         u = in_row[1];
416                         v = in_row[2];
417                         server->yuv->yuv_to_rgb_16(r, g, b, y, u, v);
418                         THRESHOLD_TAIL(3, 0xffff, 0x8000, 0x8000, 0xffff, 0x0, 0x8000, 0x8000, 0x0)
419                         break;
420                 case BC_YUVA16161616:
421                         THRESHOLD_HEAD(uint16_t)
422                         y = in_row[0];
423                         u = in_row[1];
424                         v = in_row[2];
425                         server->yuv->yuv_to_rgb_16(r, g, b, y, u, v);
426                         THRESHOLD_TAIL(4, 0xffff, 0x8000, 0x8000, 0xffff, 0x0, 0x8000, 0x8000, 0x0)
427                         break;
428         }
441 ThresholdEngine::ThresholdEngine(ThresholdMain *plugin)
442  : LoadServer(plugin->get_project_smp() + 1,
443         plugin->get_project_smp() + 1)
445         this->plugin = plugin;
446         yuv = new YUV;
449 ThresholdEngine::~ThresholdEngine()
451         delete yuv;
454 void ThresholdEngine::process_packages(VFrame *data)
456         this->data = data;
457         LoadServer::process_packages();
460 void ThresholdEngine::init_packages()
462         for(int i = 0; i < get_total_packages(); i++)
463         {
464                 ThresholdPackage *package = (ThresholdPackage*)get_package(i);
465                 package->start = data->get_h() * i / get_total_packages();
466                 package->end = data->get_h() * (i + 1) / get_total_packages();
467         }
470 LoadClient* ThresholdEngine::new_client()
472         return (LoadClient*)new ThresholdUnit(this);
475 LoadPackage* ThresholdEngine::new_package()
477         return (LoadPackage*)new HistogramPackage;