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()
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 N_("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 = BC_CModels::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);
210 output.tag.set_property("INTERLACE", config.interlace);
211 output.tag.set_property("HORIZONTAL", config.horizontal);
212 output.tag.set_property("LUMINANCE", config.luminance);
214 output.tag.set_title("/SHARPNESS");
216 output.append_newline();
217 output.terminate_string();
220 void SharpenMain::read_data(KeyFrame *keyframe)
224 input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
230 result = input.read_tag();
234 if(input.tag.title_is("SHARPNESS"))
236 config.sharpness = input.tag.get_property("VALUE", config.sharpness);
237 config.interlace = input.tag.get_property("INTERLACE", config.interlace);
238 config.horizontal = input.tag.get_property("HORIZONTAL", config.horizontal);
239 config.luminance = input.tag.get_property("LUMINANCE", config.luminance);
240 //printf("SharpenMain::read_data %f\n", sharpness);
245 if(config.sharpness > MAXSHARPNESS)
246 config.sharpness = MAXSHARPNESS;
248 if(config.sharpness < 0) config.sharpness = 0;
254 SharpenEngine::SharpenEngine(SharpenMain *plugin)
257 this->plugin = plugin;
258 input_lock = new Condition(0,"SharpenEngine::input_lock");
259 output_lock = new Condition(0, "SharpenEngine::output_lock");
261 for(int i = 0; i < 4; i++)
263 neg_rows[i] = new unsigned char[plugin->input->get_w() *
265 MAX(sizeof(float), sizeof(int))];
269 SharpenEngine::~SharpenEngine()
272 input_lock->unlock();
275 for(int i = 0; i < 4; i++)
277 delete [] neg_rows[i];
283 int SharpenEngine::start_process_frame(VFrame *output, VFrame *input, int field)
285 this->output = output;
289 // Get coefficient for floating point
290 sharpness_coef = 100 - plugin->config.sharpness;
291 if(plugin->config.horizontal) sharpness_coef /= 2;
292 if(sharpness_coef < 1) sharpness_coef = 1;
293 sharpness_coef = 800.0 / sharpness_coef;
295 input_lock->unlock();
299 int SharpenEngine::wait_process_frame()
301 output_lock->lock("SharpenEngine::wait_process_frame");
305 float SharpenEngine::calculate_pos(float value)
307 return sharpness_coef * value;
310 float SharpenEngine::calculate_neg(float value)
312 return (calculate_pos(value) - (value * 8)) / 8;
315 #define FILTER(components, vmax) \
317 int *pos_lut = plugin->pos_lut; \
318 const int wordsize = sizeof(*src); \
320 /* Skip first pixel in row */ \
321 memcpy(dst, src, components * wordsize); \
330 pixel = (long)pos_lut[src[0]] - \
331 (long)neg0[-components] - \
333 (long)neg0[components] - \
334 (long)neg1[-components] - \
335 (long)neg1[components] - \
336 (long)neg2[-components] - \
338 (long)neg2[components]; \
339 pixel = (pixel + 4) >> 3; \
340 if(pixel < 0) dst[0] = 0; \
342 if(pixel > vmax) dst[0] = vmax; \
346 pixel = (long)pos_lut[src[1]] - \
347 (long)neg0[-components + 1] - \
349 (long)neg0[components + 1] - \
350 (long)neg1[-components + 1] - \
351 (long)neg1[components + 1] - \
352 (long)neg2[-components + 1] - \
354 (long)neg2[components + 1]; \
355 pixel = (pixel + 4) >> 3; \
356 if(pixel < 0) dst[1] = 0; \
358 if(pixel > vmax) dst[1] = vmax; \
362 pixel = (long)pos_lut[src[2]] - \
363 (long)neg0[-components + 2] - \
365 (long)neg0[components + 2] - \
366 (long)neg1[-components + 2] - \
367 (long)neg1[components + 2] - \
368 (long)neg2[-components + 2] - \
370 (long)neg2[components + 2]; \
371 pixel = (pixel + 4) >> 3; \
372 if(pixel < 0) dst[2] = 0; \
374 if(pixel > vmax) dst[2] = vmax; \
381 neg0 += components; \
382 neg1 += components; \
383 neg2 += components; \
387 /* Skip last pixel in row */ \
388 memcpy(dst, src, components * wordsize); \
391 void SharpenEngine::filter(int components,
400 FILTER(components, vmax);
403 void SharpenEngine::filter(int components,
412 FILTER(components, vmax);
415 void SharpenEngine::filter(int components,
424 const int wordsize = sizeof(float);
425 // First pixel in row
426 memcpy(dst, src, components * wordsize);
434 pixel = calculate_pos(src[0]) -
446 pixel = calculate_pos(src[1]) -
447 neg0[-components + 1] -
449 neg0[components + 1] -
450 neg1[-components + 1] -
451 neg1[components + 1] -
452 neg2[-components + 1] -
454 neg2[components + 1];
458 pixel = calculate_pos(src[2]) -
459 neg0[-components + 2] -
461 neg0[components + 2] -
462 neg1[-components + 2] -
463 neg1[components + 2] -
464 neg2[-components + 2] -
466 neg2[components + 2];
479 memcpy(dst, src, components * wordsize);
488 #define SHARPEN(components, type, temp_type, vmax) \
491 int wordsize = sizeof(type); \
492 unsigned char **input_rows, **output_rows; \
493 int w = plugin->input->get_w(); \
494 int h = plugin->input->get_h(); \
496 input_rows = input->get_rows(); \
497 output_rows = output->get_rows(); \
498 src_rows[0] = input_rows[field]; \
499 src_rows[1] = input_rows[field]; \
500 src_rows[2] = input_rows[field]; \
501 src_rows[3] = input_rows[field]; \
503 for(int j = 0; j < w; j++) \
505 temp_type *neg = (temp_type*)neg_rows[0]; \
506 type *src = (type*)src_rows[0]; \
507 for(int k = 0; k < components; k++) \
511 neg[j * components + k] = \
512 (temp_type)calculate_neg(src[j * components + k]); \
516 neg[j * components + k] = \
517 (temp_type)plugin->neg_lut[(int)src[j * components + k]]; \
525 for(int i = field; i < h; i += plugin->row_step) \
527 if((i + plugin->row_step) < h) \
529 if(count >= 3) count--; \
531 src_rows[row] = input_rows[i + plugin->row_step]; \
532 /* Calculate neg rows */ \
533 type *src = (type*)src_rows[row]; \
534 temp_type *neg = (temp_type*)neg_rows[row]; \
535 for(int k = 0; k < w; k++) \
537 for(int j = 0; j < components; j++) \
541 neg[k * components + j] = \
542 (temp_type)calculate_neg(src[k * components + j]); \
546 neg[k * components + j] = \
547 plugin->neg_lut[(int)src[k * components + j]]; \
553 row = (row + 1) & 3; \
560 dst_row = output_rows[i]; \
563 /* Do the filter */ \
564 if(plugin->config.horizontal) \
568 (type*)src_rows[(row + 2) & 3], \
570 (temp_type*)neg_rows[(row + 2) & 3] + components, \
571 (temp_type*)neg_rows[(row + 2) & 3] + components, \
572 (temp_type*)neg_rows[(row + 2) & 3] + components); \
577 (type*)src_rows[(row + 2) & 3], \
579 (temp_type*)neg_rows[(row + 1) & 3] + components, \
580 (temp_type*)neg_rows[(row + 2) & 3] + components, \
581 (temp_type*)neg_rows[(row + 3) & 3] + components); \
587 memcpy(dst_row, src_rows[0], w * components * wordsize); \
589 memcpy(dst_row, src_rows[2], w * components * wordsize); \
596 void SharpenEngine::run()
600 input_lock->lock("SharpenEngine::run");
603 output_lock->unlock();
608 switch(input->get_color_model())
611 SHARPEN(3, float, float, 1);
616 SHARPEN(3, unsigned char, int, 0xff);
620 SHARPEN(4, float, float, 1);
625 SHARPEN(4, unsigned char, int, 0xff);
630 SHARPEN(3, u_int16_t, int, 0xffff);
633 case BC_RGBA16161616:
634 case BC_YUVA16161616:
635 SHARPEN(4, u_int16_t, int, 0xffff);
639 output_lock->unlock();