00001 #include "clip.h"
00002 #include "colormodels.h"
00003 #include "condition.h"
00004 #include "filexml.h"
00005 #include "language.h"
00006 #include "picon_png.h"
00007 #include "sharpen.h"
00008 #include "sharpenwindow.h"
00009
00010 #include <stdio.h>
00011 #include <string.h>
00012
00013 REGISTER_PLUGIN(SharpenMain)
00014
00015
00016
00017
00018
00019
00020
00021 SharpenConfig::SharpenConfig()
00022 {
00023 horizontal = 0;
00024 interlace = 0;
00025 sharpness = 50;
00026 luminance = 0;
00027 }
00028
00029 void SharpenConfig::copy_from(SharpenConfig &that)
00030 {
00031 horizontal = that.horizontal;
00032 interlace = that.interlace;
00033 sharpness = that.sharpness;
00034 luminance = that.luminance;
00035 }
00036
00037 int SharpenConfig::equivalent(SharpenConfig &that)
00038 {
00039 return horizontal == that.horizontal &&
00040 interlace == that.interlace &&
00041 EQUIV(sharpness, that.sharpness) &&
00042 luminance == that.luminance;
00043 }
00044
00045 void SharpenConfig::interpolate(SharpenConfig &prev,
00046 SharpenConfig &next,
00047 long prev_frame,
00048 long next_frame,
00049 long current_frame)
00050 {
00051 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
00052 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
00053 this->sharpness = prev.sharpness * prev_scale + next.sharpness * next_scale;
00054 this->interlace = prev.interlace;
00055 this->horizontal = prev.horizontal;
00056 this->luminance = prev.luminance;
00057 }
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069 SharpenMain::SharpenMain(PluginServer *server)
00070 : PluginVClient(server)
00071 {
00072 PLUGIN_CONSTRUCTOR_MACRO
00073 engine = 0;
00074 }
00075
00076 SharpenMain::~SharpenMain()
00077 {
00078 PLUGIN_DESTRUCTOR_MACRO
00079
00080 if(engine)
00081 {
00082 for(int i = 0; i < total_engines; i++)
00083 {
00084 delete engine[i];
00085 }
00086 delete engine;
00087 }
00088 }
00089
00090 SHOW_GUI_MACRO(SharpenMain, SharpenThread)
00091
00092 SET_STRING_MACRO(SharpenMain)
00093
00094 RAISE_WINDOW_MACRO(SharpenMain)
00095
00096 NEW_PICON_MACRO(SharpenMain)
00097
00098 LOAD_CONFIGURATION_MACRO(SharpenMain, SharpenConfig)
00099
00100 char* SharpenMain::plugin_title() { return N_("Sharpen"); }
00101 int SharpenMain::is_realtime() { return 1; }
00102
00103
00104
00105 int SharpenMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
00106 {
00107 int i, j, k;
00108 output = output_ptr;
00109 input = input_ptr;
00110
00111 load_configuration();
00112 if(!engine)
00113 {
00114
00115 total_engines = PluginClient::smp > 1 ? 2 : 1;
00116 engine = new SharpenEngine*[total_engines];
00117 for(int i = 0; i < total_engines; i++)
00118 {
00119 engine[i] = new SharpenEngine(this);
00120 engine[i]->start();
00121 }
00122 }
00123
00124 get_luts(pos_lut, neg_lut, input_ptr->get_color_model());
00125
00126 if(config.sharpness != 0)
00127 {
00128
00129 row_step = (config.interlace ) ? 2 : 1;
00130
00131 for(j = 0; j < row_step; j += total_engines)
00132 {
00133 for(k = 0; k < total_engines && k + j < row_step; k++)
00134 {
00135 engine[k]->start_process_frame(input_ptr, input_ptr, k + j);
00136 }
00137 for(k = 0; k < total_engines && k + j < row_step; k++)
00138 {
00139 engine[k]->wait_process_frame();
00140 }
00141 }
00142 }
00143 else
00144 if(input_ptr->get_rows()[0] != output_ptr->get_rows()[0])
00145 {
00146 output_ptr->copy_from(input_ptr);
00147 }
00148 return 0;
00149 }
00150
00151 void SharpenMain::update_gui()
00152 {
00153 if(thread)
00154 {
00155 load_configuration();
00156 thread->window->lock_window();
00157 thread->window->sharpen_slider->update((int)config.sharpness);
00158 thread->window->sharpen_interlace->update(config.interlace);
00159 thread->window->sharpen_horizontal->update(config.horizontal);
00160 thread->window->sharpen_luminance->update(config.luminance);
00161 thread->window->unlock_window();
00162 }
00163 }
00164
00165 int SharpenMain::load_defaults()
00166 {
00167 char directory[1024], string[1024];
00168
00169 sprintf(directory, "%ssharpen.rc", BCASTDIR);
00170
00171
00172 defaults = new BC_Hash(directory);
00173 defaults->load();
00174
00175 config.sharpness = defaults->get("SHARPNESS", config.sharpness);
00176 config.interlace = defaults->get("INTERLACE", config.interlace);
00177 config.horizontal = defaults->get("HORIZONTAL", config.horizontal);
00178 config.luminance = defaults->get("LUMINANCE", config.luminance);
00179
00180 return 0;
00181 }
00182
00183 int SharpenMain::save_defaults()
00184 {
00185
00186 defaults->update("SHARPNESS", config.sharpness);
00187 defaults->update("INTERLACE", config.interlace);
00188 defaults->update("HORIZONTAL", config.horizontal);
00189 defaults->update("LUMINANCE", config.luminance);
00190 defaults->save();
00191 return 0;
00192 }
00193
00194
00195
00196
00197 int SharpenMain::get_luts(int *pos_lut, int *neg_lut, int color_model)
00198 {
00199 int i, inv_sharpness, vmax;
00200
00201 vmax = cmodel_calculate_max(color_model);
00202
00203 inv_sharpness = (int)(100 - config.sharpness);
00204 if(config.horizontal) inv_sharpness /= 2;
00205 if(inv_sharpness < 1) inv_sharpness = 1;
00206
00207 for(i = 0; i < vmax + 1; i++)
00208 {
00209 pos_lut[i] = 800 * i / inv_sharpness;
00210 neg_lut[i] = (4 + pos_lut[i] - (i << 3)) >> 3;
00211 }
00212
00213 return 0;
00214 }
00215
00216 void SharpenMain::save_data(KeyFrame *keyframe)
00217 {
00218 FileXML output;
00219
00220
00221 output.set_shared_string(keyframe->data, MESSAGESIZE);
00222 output.tag.set_title("SHARPNESS");
00223 output.tag.set_property("VALUE", config.sharpness);
00224 output.append_tag();
00225
00226 if(config.interlace)
00227 {
00228 output.tag.set_title("INTERLACE");
00229 output.append_tag();
00230 output.tag.set_title("/INTERLACE");
00231 output.append_tag();
00232 }
00233
00234 if(config.horizontal)
00235 {
00236 output.tag.set_title("HORIZONTAL");
00237 output.append_tag();
00238 output.tag.set_title("/HORIZONTAL");
00239 output.append_tag();
00240 }
00241
00242 if(config.luminance)
00243 {
00244 output.tag.set_title("LUMINANCE");
00245 output.append_tag();
00246 output.tag.set_title("/LUMINANCE");
00247 output.append_tag();
00248 }
00249 output.tag.set_title("/SHARPNESS");
00250 output.append_tag();
00251 output.terminate_string();
00252 }
00253
00254 void SharpenMain::read_data(KeyFrame *keyframe)
00255 {
00256 FileXML input;
00257
00258 input.set_shared_string(keyframe->data, strlen(keyframe->data));
00259
00260 int result = 0;
00261 int new_interlace = 0;
00262 int new_horizontal = 0;
00263 int new_luminance = 0;
00264
00265 while(!result)
00266 {
00267 result = input.read_tag();
00268
00269 if(!result)
00270 {
00271 if(input.tag.title_is("SHARPNESS"))
00272 {
00273 config.sharpness = input.tag.get_property("VALUE", config.sharpness);
00274
00275 }
00276 else
00277 if(input.tag.title_is("INTERLACE"))
00278 {
00279 new_interlace = 1;
00280 }
00281 else
00282 if(input.tag.title_is("HORIZONTAL"))
00283 {
00284 new_horizontal = 1;
00285 }
00286 else
00287 if(input.tag.title_is("LUMINANCE"))
00288 {
00289 new_luminance = 1;
00290 }
00291 }
00292 }
00293
00294 config.interlace = new_interlace;
00295 config.horizontal = new_horizontal;
00296 config.luminance = new_luminance;
00297
00298 if(config.sharpness > MAXSHARPNESS)
00299 config.sharpness = MAXSHARPNESS;
00300 else
00301 if(config.sharpness < 0) config.sharpness = 0;
00302 }
00303
00304
00305
00306
00307 SharpenEngine::SharpenEngine(SharpenMain *plugin)
00308 : Thread(1, 0, 0)
00309 {
00310 this->plugin = plugin;
00311 input_lock = new Condition(0,"SharpenEngine::input_lock");
00312 output_lock = new Condition(0, "SharpenEngine::output_lock");
00313 last_frame = 0;
00314 for(int i = 0; i < 4; i++)
00315 {
00316 neg_rows[i] = new unsigned char[plugin->input->get_w() *
00317 4 *
00318 MAX(sizeof(float), sizeof(int))];
00319 }
00320 }
00321
00322 SharpenEngine::~SharpenEngine()
00323 {
00324 last_frame = 1;
00325 input_lock->unlock();
00326 Thread::join();
00327
00328 for(int i = 0; i < 4; i++)
00329 {
00330 delete [] neg_rows[i];
00331 }
00332 delete input_lock;
00333 delete output_lock;
00334 }
00335
00336 int SharpenEngine::start_process_frame(VFrame *output, VFrame *input, int field)
00337 {
00338 this->output = output;
00339 this->input = input;
00340 this->field = field;
00341
00342
00343 sharpness_coef = 100 - plugin->config.sharpness;
00344 if(plugin->config.horizontal) sharpness_coef /= 2;
00345 if(sharpness_coef < 1) sharpness_coef = 1;
00346 sharpness_coef = 800.0 / sharpness_coef;
00347
00348 input_lock->unlock();
00349 return 0;
00350 }
00351
00352 int SharpenEngine::wait_process_frame()
00353 {
00354 output_lock->lock("SharpenEngine::wait_process_frame");
00355 return 0;
00356 }
00357
00358 float SharpenEngine::calculate_pos(float value)
00359 {
00360 return sharpness_coef * value;
00361 }
00362
00363 float SharpenEngine::calculate_neg(float value)
00364 {
00365 return (calculate_pos(value) - (value * 8)) / 8;
00366 }
00367
00368 #define FILTER(components, vmax) \
00369 { \
00370 int *pos_lut = plugin->pos_lut; \
00371 const int wordsize = sizeof(*src); \
00372 \
00373 \
00374 memcpy(dst, src, components * wordsize); \
00375 dst += components; \
00376 src += components; \
00377 \
00378 w -= 2; \
00379 \
00380 while(w > 0) \
00381 { \
00382 long pixel; \
00383 pixel = (long)pos_lut[src[0]] - \
00384 (long)neg0[-components] - \
00385 (long)neg0[0] - \
00386 (long)neg0[components] - \
00387 (long)neg1[-components] - \
00388 (long)neg1[components] - \
00389 (long)neg2[-components] - \
00390 (long)neg2[0] - \
00391 (long)neg2[components]; \
00392 pixel = (pixel + 4) >> 3; \
00393 if(pixel < 0) dst[0] = 0; \
00394 else \
00395 if(pixel > vmax) dst[0] = vmax; \
00396 else \
00397 dst[0] = pixel; \
00398 \
00399 pixel = (long)pos_lut[src[1]] - \
00400 (long)neg0[-components + 1] - \
00401 (long)neg0[1] - \
00402 (long)neg0[components + 1] - \
00403 (long)neg1[-components + 1] - \
00404 (long)neg1[components + 1] - \
00405 (long)neg2[-components + 1] - \
00406 (long)neg2[1] - \
00407 (long)neg2[components + 1]; \
00408 pixel = (pixel + 4) >> 3; \
00409 if(pixel < 0) dst[1] = 0; \
00410 else \
00411 if(pixel > vmax) dst[1] = vmax; \
00412 else \
00413 dst[1] = pixel; \
00414 \
00415 pixel = (long)pos_lut[src[2]] - \
00416 (long)neg0[-components + 2] - \
00417 (long)neg0[2] - \
00418 (long)neg0[components + 2] - \
00419 (long)neg1[-components + 2] - \
00420 (long)neg1[components + 2] - \
00421 (long)neg2[-components + 2] - \
00422 (long)neg2[2] - \
00423 (long)neg2[components + 2]; \
00424 pixel = (pixel + 4) >> 3; \
00425 if(pixel < 0) dst[2] = 0; \
00426 else \
00427 if(pixel > vmax) dst[2] = vmax; \
00428 else \
00429 dst[2] = pixel; \
00430 \
00431 src += components; \
00432 dst += components; \
00433 \
00434 neg0 += components; \
00435 neg1 += components; \
00436 neg2 += components; \
00437 w--; \
00438 } \
00439 \
00440 \
00441 memcpy(dst, src, components * wordsize); \
00442 }
00443
00444 void SharpenEngine::filter(int components,
00445 int vmax,
00446 int w,
00447 u_int16_t *src,
00448 u_int16_t *dst,
00449 int *neg0,
00450 int *neg1,
00451 int *neg2)
00452 {
00453 FILTER(components, vmax);
00454 }
00455
00456 void SharpenEngine::filter(int components,
00457 int vmax,
00458 int w,
00459 unsigned char *src,
00460 unsigned char *dst,
00461 int *neg0,
00462 int *neg1,
00463 int *neg2)
00464 {
00465 FILTER(components, vmax);
00466 }
00467
00468 void SharpenEngine::filter(int components,
00469 int vmax,
00470 int w,
00471 float *src,
00472 float *dst,
00473 float *neg0,
00474 float *neg1,
00475 float *neg2)
00476 {
00477 const int wordsize = sizeof(float);
00478
00479 memcpy(dst, src, components * wordsize);
00480 dst += components;
00481 src += components;
00482
00483 w -= 2;
00484 while(w > 0)
00485 {
00486 float pixel;
00487 pixel = calculate_pos(src[0]) -
00488 neg0[-components] -
00489 neg0[0] -
00490 neg0[components] -
00491 neg1[-components] -
00492 neg1[components] -
00493 neg2[-components] -
00494 neg2[0] -
00495 neg2[components];
00496 pixel /= 8;
00497 dst[0] = pixel;
00498
00499 pixel = calculate_pos(src[1]) -
00500 neg0[-components + 1] -
00501 neg0[1] -
00502 neg0[components + 1] -
00503 neg1[-components + 1] -
00504 neg1[components + 1] -
00505 neg2[-components + 1] -
00506 neg2[1] -
00507 neg2[components + 1];
00508 pixel /= 8;
00509 dst[1] = pixel;
00510
00511 pixel = calculate_pos(src[2]) -
00512 neg0[-components + 2] -
00513 neg0[2] -
00514 neg0[components + 2] -
00515 neg1[-components + 2] -
00516 neg1[components + 2] -
00517 neg2[-components + 2] -
00518 neg2[2] -
00519 neg2[components + 2];
00520 pixel /= 8;
00521 dst[2] = pixel;
00522
00523 src += components;
00524 dst += components;
00525 neg0 += components;
00526 neg1 += components;
00527 neg2 += components;
00528 w--;
00529 }
00530
00531
00532 memcpy(dst, src, components * wordsize);
00533 }
00534
00535
00536
00537
00538
00539
00540
00541 #define SHARPEN(components, type, temp_type, vmax) \
00542 { \
00543 int count, row; \
00544 int wordsize = sizeof(type); \
00545 unsigned char **input_rows, **output_rows; \
00546 int w = plugin->input->get_w(); \
00547 int h = plugin->input->get_h(); \
00548 \
00549 input_rows = input->get_rows(); \
00550 output_rows = output->get_rows(); \
00551 src_rows[0] = input_rows[field]; \
00552 src_rows[1] = input_rows[field]; \
00553 src_rows[2] = input_rows[field]; \
00554 src_rows[3] = input_rows[field]; \
00555 \
00556 for(int j = 0; j < w; j++) \
00557 { \
00558 temp_type *neg = (temp_type*)neg_rows[0]; \
00559 type *src = (type*)src_rows[0]; \
00560 for(int k = 0; k < components; k++) \
00561 { \
00562 if(wordsize == 4) \
00563 { \
00564 neg[j * components + k] = \
00565 (temp_type)calculate_neg(src[j * components + k]); \
00566 } \
00567 else \
00568 { \
00569 neg[j * components + k] = \
00570 (temp_type)plugin->neg_lut[(int)src[j * components + k]]; \
00571 } \
00572 } \
00573 } \
00574 \
00575 row = 1; \
00576 count = 1; \
00577 \
00578 for(int i = field; i < h; i += plugin->row_step) \
00579 { \
00580 if((i + plugin->row_step) < h) \
00581 { \
00582 if(count >= 3) count--; \
00583 \
00584 src_rows[row] = input_rows[i + plugin->row_step]; \
00585 \
00586 type *src = (type*)src_rows[row]; \
00587 temp_type *neg = (temp_type*)neg_rows[row]; \
00588 for(int k = 0; k < w; k++) \
00589 { \
00590 for(int j = 0; j < components; j++) \
00591 { \
00592 if(wordsize == 4) \
00593 { \
00594 neg[k * components + j] = \
00595 (temp_type)calculate_neg(src[k * components + j]); \
00596 } \
00597 else \
00598 { \
00599 neg[k * components + j] = \
00600 plugin->neg_lut[(int)src[k * components + j]]; \
00601 } \
00602 } \
00603 } \
00604 \
00605 count++; \
00606 row = (row + 1) & 3; \
00607 } \
00608 else \
00609 { \
00610 count--; \
00611 } \
00612 \
00613 dst_row = output_rows[i]; \
00614 if(count == 3) \
00615 { \
00616 \
00617 if(plugin->config.horizontal) \
00618 filter(components, \
00619 vmax, \
00620 w, \
00621 (type*)src_rows[(row + 2) & 3], \
00622 (type*)dst_row, \
00623 (temp_type*)neg_rows[(row + 2) & 3] + components, \
00624 (temp_type*)neg_rows[(row + 2) & 3] + components, \
00625 (temp_type*)neg_rows[(row + 2) & 3] + components); \
00626 else \
00627 filter(components, \
00628 vmax, \
00629 w, \
00630 (type*)src_rows[(row + 2) & 3], \
00631 (type*)dst_row, \
00632 (temp_type*)neg_rows[(row + 1) & 3] + components, \
00633 (temp_type*)neg_rows[(row + 2) & 3] + components, \
00634 (temp_type*)neg_rows[(row + 3) & 3] + components); \
00635 } \
00636 else \
00637 if(count == 2) \
00638 { \
00639 if(i == 0) \
00640 memcpy(dst_row, src_rows[0], w * components * wordsize); \
00641 else \
00642 memcpy(dst_row, src_rows[2], w * components * wordsize); \
00643 } \
00644 } \
00645 }
00646
00647
00648
00649 void SharpenEngine::run()
00650 {
00651 while(1)
00652 {
00653 input_lock->lock("SharpenEngine::run");
00654 if(last_frame)
00655 {
00656 output_lock->unlock();
00657 return;
00658 }
00659
00660
00661 switch(input->get_color_model())
00662 {
00663 case BC_RGB_FLOAT:
00664 SHARPEN(3, float, float, 1);
00665 break;
00666
00667 case BC_RGB888:
00668 case BC_YUV888:
00669 SHARPEN(3, unsigned char, int, 0xff);
00670 break;
00671
00672 case BC_RGBA_FLOAT:
00673 SHARPEN(4, float, float, 1);
00674 break;
00675
00676 case BC_RGBA8888:
00677 case BC_YUVA8888:
00678 SHARPEN(4, unsigned char, int, 0xff);
00679 break;
00680
00681 case BC_RGB161616:
00682 case BC_YUV161616:
00683 SHARPEN(3, u_int16_t, int, 0xffff);
00684 break;
00685
00686 case BC_RGBA16161616:
00687 case BC_YUVA16161616:
00688 SHARPEN(4, u_int16_t, int, 0xffff);
00689 break;
00690 }
00691
00692 output_lock->unlock();
00693 }
00694 }
00695