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 "colormodels.h"
24 #include "condition.h"
28 #include "sharpenwindow.h"
33 REGISTER_PLUGIN(SharpenMain)
41 SharpenConfig::SharpenConfig()
49 void SharpenConfig::copy_from(SharpenConfig &that)
51 horizontal = that.horizontal;
52 interlace = that.interlace;
53 sharpness = that.sharpness;
54 luminance = that.luminance;
57 int SharpenConfig::equivalent(SharpenConfig &that)
59 return horizontal == that.horizontal &&
60 interlace == that.interlace &&
61 EQUIV(sharpness, that.sharpness) &&
62 luminance == that.luminance;
65 void SharpenConfig::interpolate(SharpenConfig &prev,
71 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
72 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
73 this->sharpness = prev.sharpness * prev_scale + next.sharpness * next_scale;
74 this->interlace = prev.interlace;
75 this->horizontal = prev.horizontal;
76 this->luminance = prev.luminance;
89 SharpenMain::SharpenMain(PluginServer *server)
90 : PluginVClient(server)
96 SharpenMain::~SharpenMain()
102 for(int i = 0; i < total_engines; i++)
110 NEW_WINDOW_MACRO(SharpenMain, SharpenWindow)
113 LOAD_CONFIGURATION_MACRO(SharpenMain, SharpenConfig)
115 const char* SharpenMain::plugin_title() { return _("Sharpen"); }
116 int SharpenMain::is_realtime() { return 1; }
120 int SharpenMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
126 load_configuration();
130 total_engines = PluginClient::smp > 1 ? 2 : 1;
131 engine = new SharpenEngine*[total_engines];
132 for(int i = 0; i < total_engines; i++)
134 engine[i] = new SharpenEngine(this);
139 get_luts(pos_lut, neg_lut, input_ptr->get_color_model());
141 if(config.sharpness != 0)
144 row_step = (config.interlace /* || config.horizontal */) ? 2 : 1;
146 for(j = 0; j < row_step; j += total_engines)
148 for(k = 0; k < total_engines && k + j < row_step; k++)
150 engine[k]->start_process_frame(input_ptr, input_ptr, k + j);
152 for(k = 0; k < total_engines && k + j < row_step; k++)
154 engine[k]->wait_process_frame();
159 if(input_ptr->get_rows()[0] != output_ptr->get_rows()[0])
161 output_ptr->copy_from(input_ptr);
166 void SharpenMain::update_gui()
170 load_configuration();
171 thread->window->lock_window("SharpenMain::update_gui");
172 ((SharpenWindow*)thread->window)->sharpen_slider->update((int)config.sharpness);
173 ((SharpenWindow*)thread->window)->sharpen_interlace->update(config.interlace);
174 ((SharpenWindow*)thread->window)->sharpen_horizontal->update(config.horizontal);
175 ((SharpenWindow*)thread->window)->sharpen_luminance->update(config.luminance);
176 thread->window->unlock_window();
183 int SharpenMain::get_luts(int *pos_lut, int *neg_lut, int color_model)
185 int i, inv_sharpness, vmax;
187 vmax = cmodel_calculate_max(color_model);
189 inv_sharpness = (int)(100 - config.sharpness);
190 if(config.horizontal) inv_sharpness /= 2;
191 if(inv_sharpness < 1) inv_sharpness = 1;
193 for(i = 0; i < vmax + 1; i++)
195 pos_lut[i] = 800 * i / inv_sharpness;
196 neg_lut[i] = (4 + pos_lut[i] - (i << 3)) >> 3;
202 void SharpenMain::save_data(KeyFrame *keyframe)
206 // cause data to be stored directly in text
207 output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
208 output.tag.set_title("SHARPNESS");
209 output.tag.set_property("VALUE", config.sharpness);
214 output.tag.set_title("INTERLACE");
218 if(config.horizontal)
220 output.tag.set_title("HORIZONTAL");
226 output.tag.set_title("LUMINANCE");
229 output.terminate_string();
232 void SharpenMain::read_data(KeyFrame *keyframe)
236 input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
239 int new_interlace = 0;
240 int new_horizontal = 0;
241 int new_luminance = 0;
245 result = input.read_tag();
249 if(input.tag.title_is("SHARPNESS"))
251 config.sharpness = input.tag.get_property("VALUE", config.sharpness);
252 //printf("SharpenMain::read_data %f\n", sharpness);
255 if(input.tag.title_is("INTERLACE"))
260 if(input.tag.title_is("HORIZONTAL"))
265 if(input.tag.title_is("LUMINANCE"))
272 config.interlace = new_interlace;
273 config.horizontal = new_horizontal;
274 config.luminance = new_luminance;
276 if(config.sharpness > MAXSHARPNESS)
277 config.sharpness = MAXSHARPNESS;
279 if(config.sharpness < 0) config.sharpness = 0;
285 SharpenEngine::SharpenEngine(SharpenMain *plugin)
288 this->plugin = plugin;
289 input_lock = new Condition(0,"SharpenEngine::input_lock");
290 output_lock = new Condition(0, "SharpenEngine::output_lock");
292 for(int i = 0; i < 4; i++)
294 neg_rows[i] = new unsigned char[plugin->input->get_w() *
296 MAX(sizeof(float), sizeof(int))];
300 SharpenEngine::~SharpenEngine()
303 input_lock->unlock();
306 for(int i = 0; i < 4; i++)
308 delete [] neg_rows[i];
314 int SharpenEngine::start_process_frame(VFrame *output, VFrame *input, int field)
316 this->output = output;
320 // Get coefficient for floating point
321 sharpness_coef = 100 - plugin->config.sharpness;
322 if(plugin->config.horizontal) sharpness_coef /= 2;
323 if(sharpness_coef < 1) sharpness_coef = 1;
324 sharpness_coef = 800.0 / sharpness_coef;
326 input_lock->unlock();
330 int SharpenEngine::wait_process_frame()
332 output_lock->lock("SharpenEngine::wait_process_frame");
336 float SharpenEngine::calculate_pos(float value)
338 return sharpness_coef * value;
341 float SharpenEngine::calculate_neg(float value)
343 return (calculate_pos(value) - (value * 8)) / 8;
346 #define FILTER(components, vmax) \
348 int *pos_lut = plugin->pos_lut; \
349 const int wordsize = sizeof(*src); \
351 /* Skip first pixel in row */ \
352 memcpy(dst, src, components * wordsize); \
361 pixel = (long)pos_lut[src[0]] - \
362 (long)neg0[-components] - \
364 (long)neg0[components] - \
365 (long)neg1[-components] - \
366 (long)neg1[components] - \
367 (long)neg2[-components] - \
369 (long)neg2[components]; \
370 pixel = (pixel + 4) >> 3; \
371 if(pixel < 0) dst[0] = 0; \
373 if(pixel > vmax) dst[0] = vmax; \
377 pixel = (long)pos_lut[src[1]] - \
378 (long)neg0[-components + 1] - \
380 (long)neg0[components + 1] - \
381 (long)neg1[-components + 1] - \
382 (long)neg1[components + 1] - \
383 (long)neg2[-components + 1] - \
385 (long)neg2[components + 1]; \
386 pixel = (pixel + 4) >> 3; \
387 if(pixel < 0) dst[1] = 0; \
389 if(pixel > vmax) dst[1] = vmax; \
393 pixel = (long)pos_lut[src[2]] - \
394 (long)neg0[-components + 2] - \
396 (long)neg0[components + 2] - \
397 (long)neg1[-components + 2] - \
398 (long)neg1[components + 2] - \
399 (long)neg2[-components + 2] - \
401 (long)neg2[components + 2]; \
402 pixel = (pixel + 4) >> 3; \
403 if(pixel < 0) dst[2] = 0; \
405 if(pixel > vmax) dst[2] = vmax; \
412 neg0 += components; \
413 neg1 += components; \
414 neg2 += components; \
418 /* Skip last pixel in row */ \
419 memcpy(dst, src, components * wordsize); \
422 void SharpenEngine::filter(int components,
431 FILTER(components, vmax);
434 void SharpenEngine::filter(int components,
443 FILTER(components, vmax);
446 void SharpenEngine::filter(int components,
455 const int wordsize = sizeof(float);
456 // First pixel in row
457 memcpy(dst, src, components * wordsize);
465 pixel = calculate_pos(src[0]) -
477 pixel = calculate_pos(src[1]) -
478 neg0[-components + 1] -
480 neg0[components + 1] -
481 neg1[-components + 1] -
482 neg1[components + 1] -
483 neg2[-components + 1] -
485 neg2[components + 1];
489 pixel = calculate_pos(src[2]) -
490 neg0[-components + 2] -
492 neg0[components + 2] -
493 neg1[-components + 2] -
494 neg1[components + 2] -
495 neg2[-components + 2] -
497 neg2[components + 2];
510 memcpy(dst, src, components * wordsize);
519 #define SHARPEN(components, type, temp_type, vmax) \
522 int wordsize = sizeof(type); \
523 unsigned char **input_rows, **output_rows; \
524 int w = plugin->input->get_w(); \
525 int h = plugin->input->get_h(); \
527 input_rows = input->get_rows(); \
528 output_rows = output->get_rows(); \
529 src_rows[0] = input_rows[field]; \
530 src_rows[1] = input_rows[field]; \
531 src_rows[2] = input_rows[field]; \
532 src_rows[3] = input_rows[field]; \
534 for(int j = 0; j < w; j++) \
536 temp_type *neg = (temp_type*)neg_rows[0]; \
537 type *src = (type*)src_rows[0]; \
538 for(int k = 0; k < components; k++) \
542 neg[j * components + k] = \
543 (temp_type)calculate_neg(src[j * components + k]); \
547 neg[j * components + k] = \
548 (temp_type)plugin->neg_lut[(int)src[j * components + k]]; \
556 for(int i = field; i < h; i += plugin->row_step) \
558 if((i + plugin->row_step) < h) \
560 if(count >= 3) count--; \
562 src_rows[row] = input_rows[i + plugin->row_step]; \
563 /* Calculate neg rows */ \
564 type *src = (type*)src_rows[row]; \
565 temp_type *neg = (temp_type*)neg_rows[row]; \
566 for(int k = 0; k < w; k++) \
568 for(int j = 0; j < components; j++) \
572 neg[k * components + j] = \
573 (temp_type)calculate_neg(src[k * components + j]); \
577 neg[k * components + j] = \
578 plugin->neg_lut[(int)src[k * components + j]]; \
584 row = (row + 1) & 3; \
591 dst_row = output_rows[i]; \
594 /* Do the filter */ \
595 if(plugin->config.horizontal) \
599 (type*)src_rows[(row + 2) & 3], \
601 (temp_type*)neg_rows[(row + 2) & 3] + components, \
602 (temp_type*)neg_rows[(row + 2) & 3] + components, \
603 (temp_type*)neg_rows[(row + 2) & 3] + components); \
608 (type*)src_rows[(row + 2) & 3], \
610 (temp_type*)neg_rows[(row + 1) & 3] + components, \
611 (temp_type*)neg_rows[(row + 2) & 3] + components, \
612 (temp_type*)neg_rows[(row + 3) & 3] + components); \
618 memcpy(dst_row, src_rows[0], w * components * wordsize); \
620 memcpy(dst_row, src_rows[2], w * components * wordsize); \
627 void SharpenEngine::run()
631 input_lock->lock("SharpenEngine::run");
634 output_lock->unlock();
639 switch(input->get_color_model())
642 SHARPEN(3, float, float, 1);
647 SHARPEN(3, unsigned char, int, 0xff);
651 SHARPEN(4, float, float, 1);
656 SHARPEN(4, unsigned char, int, 0xff);
661 SHARPEN(3, u_int16_t, int, 0xffff);
664 case BC_RGBA16161616:
665 case BC_YUVA16161616:
666 SHARPEN(4, u_int16_t, int, 0xffff);
670 output_lock->unlock();