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()
54 void SharpenConfig::copy_from(SharpenConfig &that)
56 horizontal = that.horizontal;
57 interlace = that.interlace;
58 sharpness = that.sharpness;
59 luminance = that.luminance;
62 int SharpenConfig::equivalent(SharpenConfig &that)
64 return horizontal == that.horizontal &&
65 interlace == that.interlace &&
66 EQUIV(sharpness, that.sharpness) &&
67 luminance == that.luminance;
70 void SharpenConfig::interpolate(SharpenConfig &prev,
76 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
77 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
78 this->sharpness = prev.sharpness * prev_scale + next.sharpness * next_scale;
79 this->interlace = prev.interlace;
80 this->horizontal = prev.horizontal;
81 this->luminance = prev.luminance;
94 SharpenMain::SharpenMain(PluginServer *server)
95 : PluginVClient(server)
101 SharpenMain::~SharpenMain()
107 for(int i = 0; i < total_engines; i++)
115 NEW_WINDOW_MACRO(SharpenMain, SharpenWindow)
118 LOAD_CONFIGURATION_MACRO(SharpenMain, SharpenConfig)
120 const char* SharpenMain::plugin_title() { return N_("Sharpen"); }
121 int SharpenMain::is_realtime() { return 1; }
125 int SharpenMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
131 load_configuration();
135 total_engines = PluginClient::smp > 1 ? 2 : 1;
136 engine = new SharpenEngine*[total_engines];
137 for(int i = 0; i < total_engines; i++)
139 engine[i] = new SharpenEngine(this);
144 get_luts(pos_lut, neg_lut, input_ptr->get_color_model());
146 if(config.sharpness != 0)
149 row_step = (config.interlace /* || config.horizontal */) ? 2 : 1;
151 for(j = 0; j < row_step; j += total_engines)
153 for(k = 0; k < total_engines && k + j < row_step; k++)
155 engine[k]->start_process_frame(input_ptr, input_ptr, k + j);
157 for(k = 0; k < total_engines && k + j < row_step; k++)
159 engine[k]->wait_process_frame();
164 if(input_ptr->get_rows()[0] != output_ptr->get_rows()[0])
166 output_ptr->copy_from(input_ptr);
171 void SharpenMain::update_gui()
175 load_configuration();
176 thread->window->lock_window("SharpenMain::update_gui");
177 ((SharpenWindow*)thread->window)->sharpen_slider->update((int)config.sharpness);
178 ((SharpenWindow*)thread->window)->sharpen_interlace->update(config.interlace);
179 ((SharpenWindow*)thread->window)->sharpen_horizontal->update(config.horizontal);
180 ((SharpenWindow*)thread->window)->sharpen_luminance->update(config.luminance);
181 thread->window->unlock_window();
188 int SharpenMain::get_luts(int *pos_lut, int *neg_lut, int color_model)
190 int i, inv_sharpness, vmax;
192 vmax = BC_CModels::calculate_max(color_model);
194 inv_sharpness = (int)(100 - config.sharpness);
195 if(config.horizontal) inv_sharpness /= 2;
196 if(inv_sharpness < 1) inv_sharpness = 1;
198 for(i = 0; i < vmax + 1; i++)
200 pos_lut[i] = 800 * i / inv_sharpness;
201 neg_lut[i] = (4 + pos_lut[i] - (i << 3)) >> 3;
207 void SharpenMain::save_data(KeyFrame *keyframe)
211 // cause data to be stored directly in text
212 output.set_shared_output(keyframe->xbuf);
213 output.tag.set_title("SHARPNESS");
214 output.tag.set_property("VALUE", config.sharpness);
215 output.tag.set_property("INTERLACE", config.interlace);
216 output.tag.set_property("HORIZONTAL", config.horizontal);
217 output.tag.set_property("LUMINANCE", config.luminance);
219 output.tag.set_title("/SHARPNESS");
221 output.append_newline();
222 output.terminate_string();
225 void SharpenMain::read_data(KeyFrame *keyframe)
229 input.set_shared_input(keyframe->xbuf);
235 result = input.read_tag();
239 if(input.tag.title_is("SHARPNESS"))
241 config.sharpness = input.tag.get_property("VALUE", config.sharpness);
242 config.interlace = input.tag.get_property("INTERLACE", config.interlace);
243 config.horizontal = input.tag.get_property("HORIZONTAL", config.horizontal);
244 config.luminance = input.tag.get_property("LUMINANCE", config.luminance);
245 //printf("SharpenMain::read_data %f\n", sharpness);
250 if(config.sharpness > MAXSHARPNESS)
251 config.sharpness = MAXSHARPNESS;
253 if(config.sharpness < 0) config.sharpness = 0;
259 SharpenEngine::SharpenEngine(SharpenMain *plugin)
262 this->plugin = plugin;
263 input_lock = new Condition(0,"SharpenEngine::input_lock");
264 output_lock = new Condition(0, "SharpenEngine::output_lock");
266 for(int i = 0; i < 4; i++)
268 neg_rows[i] = new unsigned char[plugin->input->get_w() *
270 MAX(sizeof(float), sizeof(int))];
274 SharpenEngine::~SharpenEngine()
277 input_lock->unlock();
280 for(int i = 0; i < 4; i++)
282 delete [] neg_rows[i];
288 int SharpenEngine::start_process_frame(VFrame *output, VFrame *input, int field)
290 this->output = output;
294 // Get coefficient for floating point
295 sharpness_coef = 100 - plugin->config.sharpness;
296 if(plugin->config.horizontal) sharpness_coef /= 2;
297 if(sharpness_coef < 1) sharpness_coef = 1;
298 sharpness_coef = 800.0 / sharpness_coef;
300 input_lock->unlock();
304 int SharpenEngine::wait_process_frame()
306 output_lock->lock("SharpenEngine::wait_process_frame");
310 float SharpenEngine::calculate_pos(float value)
312 return sharpness_coef * value;
315 float SharpenEngine::calculate_neg(float value)
317 return (calculate_pos(value) - (value * 8)) / 8;
320 #define FILTER(components, vmax) \
322 int *pos_lut = plugin->pos_lut; \
323 const int wordsize = sizeof(*src); \
325 /* Skip first pixel in row */ \
326 memcpy(dst, src, components * wordsize); \
335 pixel = (long)pos_lut[src[0]] - \
336 (long)neg0[-components] - \
338 (long)neg0[components] - \
339 (long)neg1[-components] - \
340 (long)neg1[components] - \
341 (long)neg2[-components] - \
343 (long)neg2[components]; \
344 pixel = (pixel + 4) >> 3; \
345 if(pixel < 0) dst[0] = 0; \
347 if(pixel > vmax) dst[0] = vmax; \
351 pixel = (long)pos_lut[src[1]] - \
352 (long)neg0[-components + 1] - \
354 (long)neg0[components + 1] - \
355 (long)neg1[-components + 1] - \
356 (long)neg1[components + 1] - \
357 (long)neg2[-components + 1] - \
359 (long)neg2[components + 1]; \
360 pixel = (pixel + 4) >> 3; \
361 if(pixel < 0) dst[1] = 0; \
363 if(pixel > vmax) dst[1] = vmax; \
367 pixel = (long)pos_lut[src[2]] - \
368 (long)neg0[-components + 2] - \
370 (long)neg0[components + 2] - \
371 (long)neg1[-components + 2] - \
372 (long)neg1[components + 2] - \
373 (long)neg2[-components + 2] - \
375 (long)neg2[components + 2]; \
376 pixel = (pixel + 4) >> 3; \
377 if(pixel < 0) dst[2] = 0; \
379 if(pixel > vmax) dst[2] = vmax; \
386 neg0 += components; \
387 neg1 += components; \
388 neg2 += components; \
392 /* Skip last pixel in row */ \
393 memcpy(dst, src, components * wordsize); \
396 void SharpenEngine::filter(int components,
405 FILTER(components, vmax);
408 void SharpenEngine::filter(int components,
417 FILTER(components, vmax);
420 void SharpenEngine::filter(int components,
429 const int wordsize = sizeof(float);
430 // First pixel in row
431 memcpy(dst, src, components * wordsize);
439 pixel = calculate_pos(src[0]) -
451 pixel = calculate_pos(src[1]) -
452 neg0[-components + 1] -
454 neg0[components + 1] -
455 neg1[-components + 1] -
456 neg1[components + 1] -
457 neg2[-components + 1] -
459 neg2[components + 1];
463 pixel = calculate_pos(src[2]) -
464 neg0[-components + 2] -
466 neg0[components + 2] -
467 neg1[-components + 2] -
468 neg1[components + 2] -
469 neg2[-components + 2] -
471 neg2[components + 2];
484 memcpy(dst, src, components * wordsize);
493 #define SHARPEN(components, type, temp_type, vmax) \
496 int wordsize = sizeof(type); \
497 unsigned char **input_rows, **output_rows; \
498 int w = plugin->input->get_w(); \
499 int h = plugin->input->get_h(); \
501 input_rows = input->get_rows(); \
502 output_rows = output->get_rows(); \
503 src_rows[0] = input_rows[field]; \
504 src_rows[1] = input_rows[field]; \
505 src_rows[2] = input_rows[field]; \
506 src_rows[3] = input_rows[field]; \
508 for(int j = 0; j < w; j++) \
510 temp_type *neg = (temp_type*)neg_rows[0]; \
511 type *src = (type*)src_rows[0]; \
512 for(int k = 0; k < components; k++) \
516 neg[j * components + k] = \
517 (temp_type)calculate_neg(src[j * components + k]); \
521 neg[j * components + k] = \
522 (temp_type)plugin->neg_lut[(int)src[j * components + k]]; \
530 for(int i = field; i < h; i += plugin->row_step) \
532 if((i + plugin->row_step) < h) \
534 if(count >= 3) count--; \
536 src_rows[row] = input_rows[i + plugin->row_step]; \
537 /* Calculate neg rows */ \
538 type *src = (type*)src_rows[row]; \
539 temp_type *neg = (temp_type*)neg_rows[row]; \
540 for(int k = 0; k < w; k++) \
542 for(int j = 0; j < components; j++) \
546 neg[k * components + j] = \
547 (temp_type)calculate_neg(src[k * components + j]); \
551 neg[k * components + j] = \
552 plugin->neg_lut[(int)src[k * components + j]]; \
558 row = (row + 1) & 3; \
565 dst_row = output_rows[i]; \
568 /* Do the filter */ \
569 if(plugin->config.horizontal) \
573 (type*)src_rows[(row + 2) & 3], \
575 (temp_type*)neg_rows[(row + 2) & 3] + components, \
576 (temp_type*)neg_rows[(row + 2) & 3] + components, \
577 (temp_type*)neg_rows[(row + 2) & 3] + components); \
582 (type*)src_rows[(row + 2) & 3], \
584 (temp_type*)neg_rows[(row + 1) & 3] + components, \
585 (temp_type*)neg_rows[(row + 2) & 3] + components, \
586 (temp_type*)neg_rows[(row + 3) & 3] + components); \
592 memcpy(dst_row, src_rows[0], w * components * wordsize); \
594 memcpy(dst_row, src_rows[2], w * components * wordsize); \
601 void SharpenEngine::run()
605 input_lock->lock("SharpenEngine::run");
608 output_lock->unlock();
613 switch(input->get_color_model())
616 SHARPEN(3, float, float, 1);
621 SHARPEN(3, unsigned char, int, 0xff);
625 SHARPEN(4, float, float, 1);
630 SHARPEN(4, unsigned char, int, 0xff);
635 SHARPEN(3, u_int16_t, int, 0xffff);
638 case BC_RGBA16161616:
639 case BC_YUVA16161616:
640 SHARPEN(4, u_int16_t, int, 0xffff);
644 output_lock->unlock();