2 #include "colormodels.h"
8 #include "sharpenwindow.h"
13 REGISTER_PLUGIN(SharpenMain)
21 SharpenConfig::SharpenConfig()
29 void SharpenConfig::copy_from(SharpenConfig &that)
31 horizontal = that.horizontal;
32 interlace = that.interlace;
33 sharpness = that.sharpness;
34 luminance = that.luminance;
37 int SharpenConfig::equivalent(SharpenConfig &that)
39 return horizontal == that.horizontal &&
40 interlace == that.interlace &&
41 EQUIV(sharpness, that.sharpness) &&
42 luminance == that.luminance;
45 void SharpenConfig::interpolate(SharpenConfig &prev,
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);
53 this->sharpness = prev.sharpness * prev_scale + next.sharpness * next_scale;
54 this->interlace = prev.interlace;
55 this->horizontal = prev.horizontal;
56 this->luminance = prev.luminance;
69 SharpenMain::SharpenMain(PluginServer *server)
70 : PluginVClient(server)
72 PLUGIN_CONSTRUCTOR_MACRO
76 SharpenMain::~SharpenMain()
78 PLUGIN_DESTRUCTOR_MACRO
82 for(int i = 0; i < total_engines; i++)
90 SHOW_GUI_MACRO(SharpenMain, SharpenThread)
92 SET_STRING_MACRO(SharpenMain)
94 RAISE_WINDOW_MACRO(SharpenMain)
96 NEW_PICON_MACRO(SharpenMain)
98 LOAD_CONFIGURATION_MACRO(SharpenMain, SharpenConfig)
100 char* SharpenMain::plugin_title() { return N_("Sharpen"); }
101 int SharpenMain::is_realtime() { return 1; }
105 int SharpenMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
111 load_configuration();
115 total_engines = PluginClient::smp > 1 ? 2 : 1;
116 engine = new SharpenEngine*[total_engines];
117 for(int i = 0; i < total_engines; i++)
119 engine[i] = new SharpenEngine(this);
124 get_luts(pos_lut, neg_lut, input_ptr->get_color_model());
126 if(config.sharpness != 0)
129 row_step = (config.interlace /* || config.horizontal */) ? 2 : 1;
131 for(j = 0; j < row_step; j += total_engines)
133 for(k = 0; k < total_engines && k + j < row_step; k++)
135 engine[k]->start_process_frame(input_ptr, input_ptr, k + j);
137 for(k = 0; k < total_engines && k + j < row_step; k++)
139 engine[k]->wait_process_frame();
144 if(input_ptr->get_rows()[0] != output_ptr->get_rows()[0])
146 output_ptr->copy_from(input_ptr);
151 void SharpenMain::update_gui()
155 load_configuration();
156 thread->window->lock_window();
157 thread->window->sharpen_slider->update((int)config.sharpness);
158 thread->window->sharpen_interlace->update(config.interlace);
159 thread->window->sharpen_horizontal->update(config.horizontal);
160 thread->window->sharpen_luminance->update(config.luminance);
161 thread->window->unlock_window();
165 int SharpenMain::load_defaults()
167 char directory[1024], string[1024];
168 // set the default directory
169 sprintf(directory, "%ssharpen.rc", BCASTDIR);
172 defaults = new BC_Hash(directory);
175 config.sharpness = defaults->get("SHARPNESS", config.sharpness);
176 config.interlace = defaults->get("INTERLACE", config.interlace);
177 config.horizontal = defaults->get("HORIZONTAL", config.horizontal);
178 config.luminance = defaults->get("LUMINANCE", config.luminance);
179 //printf("SharpenMain::load_defaults 1 %f %d %d %d\n", sharpness, interlace, horizontal, luminance);
183 int SharpenMain::save_defaults()
185 //printf("SharpenMain::save_defaults 1 %f %d %d %d\n", sharpness, interlace, horizontal, luminance);
186 defaults->update("SHARPNESS", config.sharpness);
187 defaults->update("INTERLACE", config.interlace);
188 defaults->update("HORIZONTAL", config.horizontal);
189 defaults->update("LUMINANCE", config.luminance);
197 int SharpenMain::get_luts(int *pos_lut, int *neg_lut, int color_model)
199 int i, inv_sharpness, vmax;
201 vmax = cmodel_calculate_max(color_model);
203 inv_sharpness = (int)(100 - config.sharpness);
204 if(config.horizontal) inv_sharpness /= 2;
205 if(inv_sharpness < 1) inv_sharpness = 1;
207 for(i = 0; i < vmax + 1; i++)
209 pos_lut[i] = 800 * i / inv_sharpness;
210 neg_lut[i] = (4 + pos_lut[i] - (i << 3)) >> 3;
216 void SharpenMain::save_data(KeyFrame *keyframe)
220 // cause data to be stored directly in text
221 output.set_shared_string(keyframe->data, MESSAGESIZE);
222 output.tag.set_title("SHARPNESS");
223 output.tag.set_property("VALUE", config.sharpness);
228 output.tag.set_title("INTERLACE");
232 if(config.horizontal)
234 output.tag.set_title("HORIZONTAL");
240 output.tag.set_title("LUMINANCE");
243 output.terminate_string();
246 void SharpenMain::read_data(KeyFrame *keyframe)
250 input.set_shared_string(keyframe->data, strlen(keyframe->data));
253 int new_interlace = 0;
254 int new_horizontal = 0;
255 int new_luminance = 0;
259 result = input.read_tag();
263 if(input.tag.title_is("SHARPNESS"))
265 config.sharpness = input.tag.get_property("VALUE", config.sharpness);
266 //printf("SharpenMain::read_data %f\n", sharpness);
269 if(input.tag.title_is("INTERLACE"))
274 if(input.tag.title_is("HORIZONTAL"))
279 if(input.tag.title_is("LUMINANCE"))
286 config.interlace = new_interlace;
287 config.horizontal = new_horizontal;
288 config.luminance = new_luminance;
290 if(config.sharpness > MAXSHARPNESS)
291 config.sharpness = MAXSHARPNESS;
293 if(config.sharpness < 0) config.sharpness = 0;
299 SharpenEngine::SharpenEngine(SharpenMain *plugin)
302 this->plugin = plugin;
303 input_lock = new Condition(0,"SharpenEngine::input_lock");
304 output_lock = new Condition(0, "SharpenEngine::output_lock");
306 for(int i = 0; i < 4; i++)
308 neg_rows[i] = new unsigned char[plugin->input->get_w() *
310 MAX(sizeof(float), sizeof(int))];
314 SharpenEngine::~SharpenEngine()
317 input_lock->unlock();
320 for(int i = 0; i < 4; i++)
322 delete [] neg_rows[i];
328 int SharpenEngine::start_process_frame(VFrame *output, VFrame *input, int field)
330 this->output = output;
334 // Get coefficient for floating point
335 sharpness_coef = 100 - plugin->config.sharpness;
336 if(plugin->config.horizontal) sharpness_coef /= 2;
337 if(sharpness_coef < 1) sharpness_coef = 1;
338 sharpness_coef = 800.0 / sharpness_coef;
340 input_lock->unlock();
344 int SharpenEngine::wait_process_frame()
346 output_lock->lock("SharpenEngine::wait_process_frame");
350 float SharpenEngine::calculate_pos(float value)
352 return sharpness_coef * value;
355 float SharpenEngine::calculate_neg(float value)
357 return (calculate_pos(value) - (value * 8)) / 8;
360 #define FILTER(components, vmax) \
362 int *pos_lut = plugin->pos_lut; \
363 const int wordsize = sizeof(*src); \
365 /* Skip first pixel in row */ \
366 memcpy(dst, src, components * wordsize); \
375 pixel = (long)pos_lut[src[0]] - \
376 (long)neg0[-components] - \
378 (long)neg0[components] - \
379 (long)neg1[-components] - \
380 (long)neg1[components] - \
381 (long)neg2[-components] - \
383 (long)neg2[components]; \
384 pixel = (pixel + 4) >> 3; \
385 if(pixel < 0) dst[0] = 0; \
387 if(pixel > vmax) dst[0] = vmax; \
391 pixel = (long)pos_lut[src[1]] - \
392 (long)neg0[-components + 1] - \
394 (long)neg0[components + 1] - \
395 (long)neg1[-components + 1] - \
396 (long)neg1[components + 1] - \
397 (long)neg2[-components + 1] - \
399 (long)neg2[components + 1]; \
400 pixel = (pixel + 4) >> 3; \
401 if(pixel < 0) dst[1] = 0; \
403 if(pixel > vmax) dst[1] = vmax; \
407 pixel = (long)pos_lut[src[2]] - \
408 (long)neg0[-components + 2] - \
410 (long)neg0[components + 2] - \
411 (long)neg1[-components + 2] - \
412 (long)neg1[components + 2] - \
413 (long)neg2[-components + 2] - \
415 (long)neg2[components + 2]; \
416 pixel = (pixel + 4) >> 3; \
417 if(pixel < 0) dst[2] = 0; \
419 if(pixel > vmax) dst[2] = vmax; \
426 neg0 += components; \
427 neg1 += components; \
428 neg2 += components; \
432 /* Skip last pixel in row */ \
433 memcpy(dst, src, components * wordsize); \
436 void SharpenEngine::filter(int components,
445 FILTER(components, vmax);
448 void SharpenEngine::filter(int components,
457 FILTER(components, vmax);
460 void SharpenEngine::filter(int components,
469 const int wordsize = sizeof(float);
470 // First pixel in row
471 memcpy(dst, src, components * wordsize);
479 pixel = calculate_pos(src[0]) -
491 pixel = calculate_pos(src[1]) -
492 neg0[-components + 1] -
494 neg0[components + 1] -
495 neg1[-components + 1] -
496 neg1[components + 1] -
497 neg2[-components + 1] -
499 neg2[components + 1];
503 pixel = calculate_pos(src[2]) -
504 neg0[-components + 2] -
506 neg0[components + 2] -
507 neg1[-components + 2] -
508 neg1[components + 2] -
509 neg2[-components + 2] -
511 neg2[components + 2];
524 memcpy(dst, src, components * wordsize);
533 #define SHARPEN(components, type, temp_type, vmax) \
536 int wordsize = sizeof(type); \
537 unsigned char **input_rows, **output_rows; \
538 int w = plugin->input->get_w(); \
539 int h = plugin->input->get_h(); \
541 input_rows = input->get_rows(); \
542 output_rows = output->get_rows(); \
543 src_rows[0] = input_rows[field]; \
544 src_rows[1] = input_rows[field]; \
545 src_rows[2] = input_rows[field]; \
546 src_rows[3] = input_rows[field]; \
548 for(int j = 0; j < w; j++) \
550 temp_type *neg = (temp_type*)neg_rows[0]; \
551 type *src = (type*)src_rows[0]; \
552 for(int k = 0; k < components; k++) \
556 neg[j * components + k] = \
557 (temp_type)calculate_neg(src[j * components + k]); \
561 neg[j * components + k] = \
562 (temp_type)plugin->neg_lut[(int)src[j * components + k]]; \
570 for(int i = field; i < h; i += plugin->row_step) \
572 if((i + plugin->row_step) < h) \
574 if(count >= 3) count--; \
576 src_rows[row] = input_rows[i + plugin->row_step]; \
577 /* Calculate neg rows */ \
578 type *src = (type*)src_rows[row]; \
579 temp_type *neg = (temp_type*)neg_rows[row]; \
580 for(int k = 0; k < w; k++) \
582 for(int j = 0; j < components; j++) \
586 neg[k * components + j] = \
587 (temp_type)calculate_neg(src[k * components + j]); \
591 neg[k * components + j] = \
592 plugin->neg_lut[(int)src[k * components + j]]; \
598 row = (row + 1) & 3; \
605 dst_row = output_rows[i]; \
608 /* Do the filter */ \
609 if(plugin->config.horizontal) \
613 (type*)src_rows[(row + 2) & 3], \
615 (temp_type*)neg_rows[(row + 2) & 3] + components, \
616 (temp_type*)neg_rows[(row + 2) & 3] + components, \
617 (temp_type*)neg_rows[(row + 2) & 3] + components); \
622 (type*)src_rows[(row + 2) & 3], \
624 (temp_type*)neg_rows[(row + 1) & 3] + components, \
625 (temp_type*)neg_rows[(row + 2) & 3] + components, \
626 (temp_type*)neg_rows[(row + 3) & 3] + components); \
632 memcpy(dst_row, src_rows[0], w * components * wordsize); \
634 memcpy(dst_row, src_rows[2], w * components * wordsize); \
641 void SharpenEngine::run()
645 input_lock->lock("SharpenEngine::run");
648 output_lock->unlock();
653 switch(input->get_color_model())
656 SHARPEN(3, float, float, 1);
661 SHARPEN(3, unsigned char, int, 0xff);
665 SHARPEN(4, float, float, 1);
670 SHARPEN(4, unsigned char, int, 0xff);
675 SHARPEN(3, u_int16_t, int, 0xffff);
678 case BC_RGBA16161616:
679 case BC_YUVA16161616:
680 SHARPEN(4, u_int16_t, int, 0xffff);
684 output_lock->unlock();