4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "bccmodels.h"
24 #include "condition.h"
28 #include "sharpenwindow.h"
33 REGISTER_PLUGIN(SharpenMain)
41 SharpenConfig::SharpenConfig()
46 void SharpenConfig::reset(int clear)
55 case RESET_SHARPEN_SLIDER : sharpness = 0;
57 case RESET_DEFAULT_SETTINGS :
67 void SharpenConfig::copy_from(SharpenConfig &that)
69 horizontal = that.horizontal;
70 interlace = that.interlace;
71 sharpness = that.sharpness;
72 luminance = that.luminance;
75 int SharpenConfig::equivalent(SharpenConfig &that)
77 return horizontal == that.horizontal &&
78 interlace == that.interlace &&
79 EQUIV(sharpness, that.sharpness) &&
80 luminance == that.luminance;
83 void SharpenConfig::interpolate(SharpenConfig &prev,
89 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
90 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
91 this->sharpness = prev.sharpness * prev_scale + next.sharpness * next_scale;
92 this->interlace = prev.interlace;
93 this->horizontal = prev.horizontal;
94 this->luminance = prev.luminance;
107 SharpenMain::SharpenMain(PluginServer *server)
108 : PluginVClient(server)
114 SharpenMain::~SharpenMain()
120 for(int i = 0; i < total_engines; i++)
128 NEW_WINDOW_MACRO(SharpenMain, SharpenWindow)
131 LOAD_CONFIGURATION_MACRO(SharpenMain, SharpenConfig)
133 const char* SharpenMain::plugin_title() { return N_("Sharpen"); }
134 int SharpenMain::is_realtime() { return 1; }
138 int SharpenMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
144 load_configuration();
148 total_engines = PluginClient::smp > 1 ? 2 : 1;
149 engine = new SharpenEngine*[total_engines];
150 for(int i = 0; i < total_engines; i++)
152 engine[i] = new SharpenEngine(this);
157 get_luts(pos_lut, neg_lut, input_ptr->get_color_model());
159 if(config.sharpness != 0)
162 row_step = (config.interlace /* || config.horizontal */) ? 2 : 1;
164 for(j = 0; j < row_step; j += total_engines)
166 for(k = 0; k < total_engines && k + j < row_step; k++)
168 engine[k]->start_process_frame(input_ptr, input_ptr, k + j);
170 for(k = 0; k < total_engines && k + j < row_step; k++)
172 engine[k]->wait_process_frame();
177 if(input_ptr->get_rows()[0] != output_ptr->get_rows()[0])
179 output_ptr->copy_from(input_ptr);
184 void SharpenMain::update_gui()
188 load_configuration();
189 thread->window->lock_window("SharpenMain::update_gui");
190 ((SharpenWindow*)thread->window)->sharpen_slider->update((int)config.sharpness);
191 ((SharpenWindow*)thread->window)->sharpen_interlace->update(config.interlace);
192 ((SharpenWindow*)thread->window)->sharpen_horizontal->update(config.horizontal);
193 ((SharpenWindow*)thread->window)->sharpen_luminance->update(config.luminance);
194 thread->window->unlock_window();
201 int SharpenMain::get_luts(int *pos_lut, int *neg_lut, int color_model)
203 int i, inv_sharpness, vmax;
205 vmax = BC_CModels::calculate_max(color_model);
207 inv_sharpness = (int)(100 - config.sharpness);
208 if(config.horizontal) inv_sharpness /= 2;
209 if(inv_sharpness < 1) inv_sharpness = 1;
211 for(i = 0; i < vmax + 1; i++)
213 pos_lut[i] = 800 * i / inv_sharpness;
214 neg_lut[i] = (4 + pos_lut[i] - (i << 3)) >> 3;
220 void SharpenMain::save_data(KeyFrame *keyframe)
224 // cause data to be stored directly in text
225 output.set_shared_output(keyframe->xbuf);
226 output.tag.set_title("SHARPNESS");
227 output.tag.set_property("VALUE", config.sharpness);
228 output.tag.set_property("INTERLACE", config.interlace);
229 output.tag.set_property("HORIZONTAL", config.horizontal);
230 output.tag.set_property("LUMINANCE", config.luminance);
232 output.tag.set_title("/SHARPNESS");
234 output.append_newline();
235 output.terminate_string();
238 void SharpenMain::read_data(KeyFrame *keyframe)
242 input.set_shared_input(keyframe->xbuf);
248 result = input.read_tag();
252 if(input.tag.title_is("SHARPNESS"))
254 config.sharpness = input.tag.get_property("VALUE", config.sharpness);
255 config.interlace = input.tag.get_property("INTERLACE", config.interlace);
256 config.horizontal = input.tag.get_property("HORIZONTAL", config.horizontal);
257 config.luminance = input.tag.get_property("LUMINANCE", config.luminance);
258 //printf("SharpenMain::read_data %f\n", sharpness);
263 if(config.sharpness > MAXSHARPNESS)
264 config.sharpness = MAXSHARPNESS;
266 if(config.sharpness < 0) config.sharpness = 0;
272 SharpenEngine::SharpenEngine(SharpenMain *plugin)
275 this->plugin = plugin;
276 input_lock = new Condition(0,"SharpenEngine::input_lock");
277 output_lock = new Condition(0, "SharpenEngine::output_lock");
279 for(int i = 0; i < 4; i++)
281 neg_rows[i] = new unsigned char[plugin->input->get_w() *
283 MAX(sizeof(float), sizeof(int))];
287 SharpenEngine::~SharpenEngine()
290 input_lock->unlock();
293 for(int i = 0; i < 4; i++)
295 delete [] neg_rows[i];
301 int SharpenEngine::start_process_frame(VFrame *output, VFrame *input, int field)
303 this->output = output;
307 // Get coefficient for floating point
308 sharpness_coef = 100 - plugin->config.sharpness;
309 if(plugin->config.horizontal) sharpness_coef /= 2;
310 if(sharpness_coef < 1) sharpness_coef = 1;
311 sharpness_coef = 800.0 / sharpness_coef;
313 input_lock->unlock();
317 int SharpenEngine::wait_process_frame()
319 output_lock->lock("SharpenEngine::wait_process_frame");
323 float SharpenEngine::calculate_pos(float value)
325 return sharpness_coef * value;
328 float SharpenEngine::calculate_neg(float value)
330 return (calculate_pos(value) - (value * 8)) / 8;
333 #define FILTER(components, vmax) \
335 int *pos_lut = plugin->pos_lut; \
336 const int wordsize = sizeof(*src); \
338 /* Skip first pixel in row */ \
339 memcpy(dst, src, components * wordsize); \
348 pixel = (long)pos_lut[src[0]] - \
349 (long)neg0[-components] - \
351 (long)neg0[components] - \
352 (long)neg1[-components] - \
353 (long)neg1[components] - \
354 (long)neg2[-components] - \
356 (long)neg2[components]; \
357 pixel = (pixel + 4) >> 3; \
358 if(pixel < 0) dst[0] = 0; \
360 if(pixel > vmax) dst[0] = vmax; \
364 pixel = (long)pos_lut[src[1]] - \
365 (long)neg0[-components + 1] - \
367 (long)neg0[components + 1] - \
368 (long)neg1[-components + 1] - \
369 (long)neg1[components + 1] - \
370 (long)neg2[-components + 1] - \
372 (long)neg2[components + 1]; \
373 pixel = (pixel + 4) >> 3; \
374 if(pixel < 0) dst[1] = 0; \
376 if(pixel > vmax) dst[1] = vmax; \
380 pixel = (long)pos_lut[src[2]] - \
381 (long)neg0[-components + 2] - \
383 (long)neg0[components + 2] - \
384 (long)neg1[-components + 2] - \
385 (long)neg1[components + 2] - \
386 (long)neg2[-components + 2] - \
388 (long)neg2[components + 2]; \
389 pixel = (pixel + 4) >> 3; \
390 if(pixel < 0) dst[2] = 0; \
392 if(pixel > vmax) dst[2] = vmax; \
399 neg0 += components; \
400 neg1 += components; \
401 neg2 += components; \
405 /* Skip last pixel in row */ \
406 memcpy(dst, src, components * wordsize); \
409 void SharpenEngine::filter(int components,
418 FILTER(components, vmax);
421 void SharpenEngine::filter(int components,
430 FILTER(components, vmax);
433 void SharpenEngine::filter(int components,
442 const int wordsize = sizeof(float);
443 // First pixel in row
444 memcpy(dst, src, components * wordsize);
452 pixel = calculate_pos(src[0]) -
464 pixel = calculate_pos(src[1]) -
465 neg0[-components + 1] -
467 neg0[components + 1] -
468 neg1[-components + 1] -
469 neg1[components + 1] -
470 neg2[-components + 1] -
472 neg2[components + 1];
476 pixel = calculate_pos(src[2]) -
477 neg0[-components + 2] -
479 neg0[components + 2] -
480 neg1[-components + 2] -
481 neg1[components + 2] -
482 neg2[-components + 2] -
484 neg2[components + 2];
497 memcpy(dst, src, components * wordsize);
506 #define SHARPEN(components, type, temp_type, vmax) \
509 int wordsize = sizeof(type); \
510 unsigned char **input_rows, **output_rows; \
511 int w = plugin->input->get_w(); \
512 int h = plugin->input->get_h(); \
514 input_rows = input->get_rows(); \
515 output_rows = output->get_rows(); \
516 src_rows[0] = input_rows[field]; \
517 src_rows[1] = input_rows[field]; \
518 src_rows[2] = input_rows[field]; \
519 src_rows[3] = input_rows[field]; \
521 for(int j = 0; j < w; j++) \
523 temp_type *neg = (temp_type*)neg_rows[0]; \
524 type *src = (type*)src_rows[0]; \
525 for(int k = 0; k < components; k++) \
529 neg[j * components + k] = \
530 (temp_type)calculate_neg(src[j * components + k]); \
534 neg[j * components + k] = \
535 (temp_type)plugin->neg_lut[(int)src[j * components + k]]; \
543 for(int i = field; i < h; i += plugin->row_step) \
545 if((i + plugin->row_step) < h) \
547 if(count >= 3) count--; \
549 src_rows[row] = input_rows[i + plugin->row_step]; \
550 /* Calculate neg rows */ \
551 type *src = (type*)src_rows[row]; \
552 temp_type *neg = (temp_type*)neg_rows[row]; \
553 for(int k = 0; k < w; k++) \
555 for(int j = 0; j < components; j++) \
559 neg[k * components + j] = \
560 (temp_type)calculate_neg(src[k * components + j]); \
564 neg[k * components + j] = \
565 plugin->neg_lut[(int)src[k * components + j]]; \
571 row = (row + 1) & 3; \
578 dst_row = output_rows[i]; \
581 /* Do the filter */ \
582 if(plugin->config.horizontal) \
586 (type*)src_rows[(row + 2) & 3], \
588 (temp_type*)neg_rows[(row + 2) & 3] + components, \
589 (temp_type*)neg_rows[(row + 2) & 3] + components, \
590 (temp_type*)neg_rows[(row + 2) & 3] + components); \
595 (type*)src_rows[(row + 2) & 3], \
597 (temp_type*)neg_rows[(row + 1) & 3] + components, \
598 (temp_type*)neg_rows[(row + 2) & 3] + components, \
599 (temp_type*)neg_rows[(row + 3) & 3] + components); \
605 memcpy(dst_row, src_rows[0], w * components * wordsize); \
607 memcpy(dst_row, src_rows[2], w * components * wordsize); \
614 void SharpenEngine::run()
618 input_lock->lock("SharpenEngine::run");
621 output_lock->unlock();
626 switch(input->get_color_model())
629 SHARPEN(3, float, float, 1);
634 SHARPEN(3, unsigned char, int, 0xff);
638 SHARPEN(4, float, float, 1);
643 SHARPEN(4, unsigned char, int, 0xff);
648 SHARPEN(3, u_int16_t, int, 0xffff);
651 case BC_RGBA16161616:
652 case BC_YUVA16161616:
653 SHARPEN(4, u_int16_t, int, 0xffff);
657 output_lock->unlock();