00001 #include "bcdisplayinfo.h"
00002 #include "clip.h"
00003 #include "bchash.h"
00004 #include "filexml.h"
00005 #include "keyframe.h"
00006 #include "language.h"
00007 #include "unsharp.h"
00008 #include "unsharpwindow.h"
00009 #include "picon_png.h"
00010
00011
00012 #include <errno.h>
00013 #include <unistd.h>
00014
00015 REGISTER_PLUGIN(UnsharpMain)
00016
00017
00018
00019 UnsharpConfig::UnsharpConfig()
00020 {
00021 radius = 5;
00022 amount = 0.5;
00023 threshold = 0;
00024 }
00025
00026 int UnsharpConfig::equivalent(UnsharpConfig &that)
00027 {
00028 return EQUIV(radius, that.radius) &&
00029 EQUIV(amount, that.amount) &&
00030 threshold == that.threshold;
00031 }
00032
00033 void UnsharpConfig::copy_from(UnsharpConfig &that)
00034 {
00035 radius = that.radius;
00036 amount = that.amount;
00037 threshold = that.threshold;
00038 }
00039
00040 void UnsharpConfig::interpolate(UnsharpConfig &prev,
00041 UnsharpConfig &next,
00042 int64_t prev_frame,
00043 int64_t next_frame,
00044 int64_t current_frame)
00045 {
00046 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
00047 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
00048 this->radius = prev.radius * prev_scale + next.radius * next_scale;
00049 this->amount = prev.amount * prev_scale + next.amount * next_scale;
00050 this->threshold = (int)(prev.threshold * prev_scale + next.threshold * next_scale);
00051 }
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071 UnsharpMain::UnsharpMain(PluginServer *server)
00072 : PluginVClient(server)
00073 {
00074 PLUGIN_CONSTRUCTOR_MACRO
00075 engine = 0;
00076 }
00077
00078 UnsharpMain::~UnsharpMain()
00079 {
00080 PLUGIN_DESTRUCTOR_MACRO
00081 delete engine;
00082 }
00083
00084 char* UnsharpMain::plugin_title() { return N_("Unsharp"); }
00085 int UnsharpMain::is_realtime() { return 1; }
00086
00087 NEW_PICON_MACRO(UnsharpMain)
00088
00089 SHOW_GUI_MACRO(UnsharpMain, UnsharpThread)
00090
00091 SET_STRING_MACRO(UnsharpMain)
00092
00093 RAISE_WINDOW_MACRO(UnsharpMain)
00094
00095 LOAD_CONFIGURATION_MACRO(UnsharpMain, UnsharpConfig)
00096
00097
00098
00099 void UnsharpMain::update_gui()
00100 {
00101 if(thread)
00102 {
00103 if(load_configuration())
00104 {
00105 thread->window->lock_window("UnsharpMain::update_gui");
00106 thread->window->update();
00107 thread->window->unlock_window();
00108 }
00109 }
00110 }
00111
00112
00113 int UnsharpMain::load_defaults()
00114 {
00115 char directory[BCTEXTLEN], string[BCTEXTLEN];
00116
00117 sprintf(directory, "%sunsharp.rc", BCASTDIR);
00118
00119
00120 defaults = new BC_Hash(directory);
00121 defaults->load();
00122
00123 config.radius = defaults->get("RADIUS", config.radius);
00124 config.amount = defaults->get("AMOUNT", config.amount);
00125 config.threshold = defaults->get("THRESHOLD", config.threshold);
00126 return 0;
00127 }
00128
00129
00130 int UnsharpMain::save_defaults()
00131 {
00132 defaults->update("RADIUS", config.radius);
00133 defaults->update("AMOUNT", config.amount);
00134 defaults->update("THRESHOLD", config.threshold);
00135 defaults->save();
00136 return 0;
00137 }
00138
00139
00140
00141 void UnsharpMain::save_data(KeyFrame *keyframe)
00142 {
00143 FileXML output;
00144
00145
00146 output.set_shared_string(keyframe->data, MESSAGESIZE);
00147 output.tag.set_title("UNSHARP");
00148
00149 output.tag.set_property("RADIUS", config.radius);
00150 output.tag.set_property("AMOUNT", config.amount);
00151 output.tag.set_property("THRESHOLD", config.threshold);
00152 output.append_tag();
00153 output.tag.set_title("/UNSHARP");
00154 output.append_tag();
00155 output.terminate_string();
00156 }
00157
00158 void UnsharpMain::read_data(KeyFrame *keyframe)
00159 {
00160 FileXML input;
00161
00162 input.set_shared_string(keyframe->data, strlen(keyframe->data));
00163
00164 int result = 0;
00165
00166 while(!result)
00167 {
00168 result = input.read_tag();
00169
00170 if(!result)
00171 {
00172 if(input.tag.title_is("UNSHARP"))
00173 {
00174 config.radius = input.tag.get_property("RADIUS", config.radius);
00175 config.amount = input.tag.get_property("AMOUNT", config.amount);
00176 config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
00177 }
00178 }
00179 }
00180 }
00181
00182
00183
00184
00185
00186
00187
00188 int UnsharpMain::process_buffer(VFrame *frame,
00189 int64_t start_position,
00190 double frame_rate)
00191 {
00192 int need_reconfigure = load_configuration();
00193
00194 if(!engine) engine = new UnsharpEngine(this,
00195 get_project_smp() + 1,
00196 get_project_smp() + 1);
00197 read_frame(frame,
00198 0,
00199 get_source_position(),
00200 get_framerate());
00201 engine->do_unsharp(frame);
00202 return 0;
00203 }
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216 UnsharpPackage::UnsharpPackage()
00217 : LoadPackage()
00218 {
00219 }
00220
00221
00222
00223
00224
00225
00226 UnsharpUnit::UnsharpUnit(UnsharpEngine *server,
00227 UnsharpMain *plugin)
00228 : LoadClient(server)
00229 {
00230 this->plugin = plugin;
00231 this->server = server;
00232 temp = 0;
00233 }
00234
00235 UnsharpUnit::~UnsharpUnit()
00236 {
00237 delete temp;
00238 }
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250 static int calculate_convolution_matrix(double radius, double **cmatrix)
00251 {
00252 radius = fabs(radius) + 1.0;
00253 double std_dev = radius;
00254 radius = std_dev * 2;
00255 int matrix_length = (int)(2 * ceil(radius - 0.5) + 1);
00256 matrix_length = MAX(1, matrix_length);
00257 int matrix_midpoint = matrix_length / 2 + 1;
00258 (*cmatrix) = new double[matrix_length];
00259
00260
00261 for(int i = matrix_length / 2 + 1; i < matrix_length; i++)
00262 {
00263 double base_x = i - floor(matrix_length / 2) - 0.5;
00264 double sum = 0;
00265 for(int j = 1; j <= 50; j++)
00266 {
00267 if(base_x + 0.02 * j <= radius)
00268 {
00269 sum += exp(-(base_x + 0.02 * j) *
00270 (base_x + 0.02 * j) /
00271 (2 * std_dev * std_dev));
00272 }
00273 }
00274 (*cmatrix)[i] = sum / 50;
00275 }
00276
00277
00278 for(int i = 0; i < matrix_length / 2; i++)
00279 {
00280 (*cmatrix)[i] = (*cmatrix)[matrix_length - 1 - i];
00281 }
00282
00283
00284 double sum = 0;
00285 for(int j = 0; j <= 50; j++)
00286 {
00287 sum += exp(-(0.5 + 0.02 * j) *
00288 (0.5 + 0.02 * j) /
00289 (2 * std_dev * std_dev));
00290 }
00291 (*cmatrix)[matrix_length / 2] = sum / 51;
00292
00293
00294 sum = 0;
00295 for(int i = 0; i < matrix_length; i++)
00296 sum += (*cmatrix)[i];
00297 for(int i = 0; i < matrix_length; i++)
00298 (*cmatrix)[i] = (*cmatrix)[i] / sum;
00299
00300 return matrix_length;
00301 }
00302
00303 static double get_convolution(double *cmatrix,
00304 float input,
00305 int index)
00306 {
00307 return cmatrix[index] * input;
00308 }
00309
00310 static void blur_pixels(double *cmatrix,
00311 int cmatrix_length,
00312 float *input,
00313 float *output,
00314 int pixels,
00315 int components)
00316 {
00317 if(cmatrix_length > pixels)
00318 {
00319 for(int pixel = 0; pixel < pixels; pixel++)
00320 {
00321 double scale = 0;
00322 for(int j = 0; j < pixels; j++)
00323 {
00324 if((j + cmatrix_length / 2 - pixel >= 0) &&
00325 (j + cmatrix_length / 2 - pixel < cmatrix_length))
00326 {
00327 scale += cmatrix[j + cmatrix_length / 2 - pixel];
00328 }
00329 }
00330
00331 for(int i = 0; i < components; i++)
00332 {
00333 double sum = 0;
00334 for(int j = 0; j < pixels; j++)
00335 {
00336 if((j >= pixel - cmatrix_length / 2) &&
00337 (j <= pixel + cmatrix_length / 2))
00338 {
00339 sum += input[j * components + i] * cmatrix[i];
00340 }
00341 }
00342 output[pixel * components + i] = sum / scale;
00343 }
00344 }
00345 }
00346 else
00347 {
00348 int cmatrix_middle = cmatrix_length / 2;
00349 int pixel;
00350 for(pixel = 0; pixel < cmatrix_middle; pixel++)
00351 {
00352 double scale = 0;
00353 for(int j = cmatrix_middle - pixel; j < cmatrix_length;j++)
00354 {
00355 scale += cmatrix[j];
00356 }
00357
00358 for(int i = 0; i < components; i++)
00359 {
00360 double sum = 0;
00361 for(int j = cmatrix_middle - pixel; j < cmatrix_length; j++)
00362 {
00363 sum += input[(pixel + j - cmatrix_middle) * components + i] *
00364 cmatrix[j];
00365 }
00366 output[pixel * components + i] = sum / scale;
00367 }
00368 }
00369
00370 float *output_ptr = output + pixel * components;
00371 for( ; pixel < pixels - cmatrix_middle; pixel++)
00372 {
00373 float *input_ptr = input + (pixel - cmatrix_middle) * components;
00374 for(int i = 0; i < components; i++)
00375 {
00376 double sum = 0;
00377 float *input_ptr2 = input_ptr;
00378 for(int j = cmatrix_length; j > 0; j--)
00379 {
00380 sum += get_convolution(cmatrix,
00381 *input_ptr2,
00382 cmatrix_length - j);
00383 input_ptr2 += components;
00384 }
00385 input_ptr++;
00386 *output_ptr++ = sum;
00387 }
00388 }
00389
00390 for( ; pixel < pixels; pixel++)
00391 {
00392 double scale = 0;
00393 for(int j = 0; j < pixels - pixel + cmatrix_middle; j++)
00394 {
00395 scale += cmatrix[j];
00396 }
00397
00398 for(int i = 0; i < components; i++)
00399 {
00400 double sum = 0;
00401 for(int j = 0; j < pixels - pixel + cmatrix_middle; j++)
00402 {
00403 sum += input[(pixel + j - cmatrix_middle) * components + i] *
00404 cmatrix[j];
00405 }
00406 output[pixel * components + i] = sum / scale;
00407 }
00408 }
00409 }
00410 }
00411
00412 #define GET_ROW(type, components) \
00413 { \
00414 type *in_row = (type*)src->get_rows()[row]; \
00415 int pixels = src->get_w() * components; \
00416 for(int i = 0; i < pixels; i++) \
00417 { \
00418 dst[i] = in_row[i]; \
00419 } \
00420 }
00421
00422 static void get_row(float *dst, VFrame *src, int row)
00423 {
00424 switch(src->get_color_model())
00425 {
00426 case BC_RGB888:
00427 case BC_YUV888:
00428 GET_ROW(unsigned char, 3);
00429 break;
00430 case BC_RGB_FLOAT:
00431 GET_ROW(float, 3);
00432 break;
00433 case BC_RGBA8888:
00434 case BC_YUVA8888:
00435 GET_ROW(unsigned char, 4);
00436 break;
00437 case BC_RGBA_FLOAT:
00438 GET_ROW(float, 4);
00439 break;
00440 case BC_YUV161616:
00441 GET_ROW(uint16_t, 3);
00442 break;
00443 case BC_YUVA16161616:
00444 GET_ROW(uint16_t, 4);
00445 break;
00446 }
00447 }
00448
00449 static void get_column(float *dst, VFrame *src, int column)
00450 {
00451 int components = cmodel_components(src->get_color_model());
00452 for(int i = 0; i < src->get_h(); i++)
00453 {
00454 float *input_pixel = (float*)src->get_rows()[i] + column * components;
00455 memcpy(dst, input_pixel, sizeof(float) * components);
00456 dst += components;
00457 }
00458 }
00459
00460 static void put_column(float *src, VFrame *dst, int column)
00461 {
00462 int components = cmodel_components(dst->get_color_model());
00463 for(int i = 0; i < dst->get_h(); i++)
00464 {
00465 float *output_pixel = (float*)dst->get_rows()[i] + column * components;
00466 memcpy(output_pixel, src, sizeof(float) * components);
00467 src += components;
00468 }
00469 }
00470
00471 void UnsharpUnit::process_package(LoadPackage *package)
00472 {
00473 UnsharpPackage *pkg = (UnsharpPackage*)package;
00474 int w = server->src->get_w();
00475 int h = server->src->get_h();
00476 int color_model = server->src->get_color_model();
00477 int components = cmodel_components(color_model);
00478 double *cmatrix = 0;
00479 int cmatrix_length = 0;
00480 int padded_y1 = pkg->y1;
00481 int padded_y2 = pkg->y2;
00482
00483 cmatrix_length = calculate_convolution_matrix(
00484 plugin->config.radius,
00485 &cmatrix);
00486
00487
00488 if(padded_y2 < server->src->get_h())
00489 {
00490 padded_y2 += cmatrix_length / 2;
00491 padded_y2 = MIN(server->src->get_h(), padded_y2);
00492 }
00493 if(padded_y1 > 0)
00494 {
00495 padded_y1 -= cmatrix_length / 2;
00496 padded_y1 = MAX(0, padded_y1);
00497 }
00498
00499 int padded_rows = padded_y2 - padded_y1;
00500
00501 if(!temp || temp->get_h() != padded_rows)
00502 {
00503 delete temp;
00504 temp = 0;
00505 }
00506
00507 if(!temp)
00508 {
00509 temp = new VFrame(0,
00510 server->src->get_w(),
00511 padded_rows,
00512 components == 3 ? BC_RGB_FLOAT : BC_RGBA_FLOAT);
00513 }
00514
00515 float *temp_in = new float[MAX(temp->get_w(), padded_rows) * components];
00516 float *temp_out = new float[MAX(temp->get_w(), padded_rows) * components];
00517
00518
00519 for(int i = padded_y1; i < padded_y2; i++)
00520 {
00521 get_row(temp_in, server->src, i);
00522 blur_pixels(cmatrix,
00523 cmatrix_length,
00524 temp_in,
00525 temp_out,
00526 temp->get_w(),
00527 components);
00528 memcpy(temp->get_rows()[i - padded_y1],
00529 temp_out,
00530 temp->get_bytes_per_line());
00531 }
00532
00533
00534 for(int i = 0; i < temp->get_w(); i++)
00535 {
00536 get_column(temp_in, temp, i);
00537 blur_pixels(cmatrix,
00538 cmatrix_length,
00539 temp_in,
00540 temp_out,
00541 padded_rows,
00542 components);
00543 put_column(temp_out, temp, i);
00544 }
00545
00546
00547
00548
00549
00550 #define UNSHARPEN(type, components, max) \
00551 { \
00552 float threshold = (float)plugin->config.threshold * max / 0xff; \
00553 float amount = plugin->config.amount; \
00554 \
00555 for(int i = pkg->y1; i < pkg->y2; i++) \
00556 { \
00557 float *blurry_row = (float*)temp->get_rows()[i - padded_y1]; \
00558 type *orig_row = (type*)server->src->get_rows()[i]; \
00559 for(int j = 0; j < server->src->get_w(); j++) \
00560 { \
00561 for(int k = 0; k < components; k++) \
00562 { \
00563 float diff = *orig_row - *blurry_row; \
00564 if(fabsf(2 * diff) < threshold) \
00565 diff = 0; \
00566 float value = *orig_row + amount * diff; \
00567 if(sizeof(type) == 4) \
00568 *orig_row = (type)value; \
00569 else \
00570 *orig_row = (type)CLIP(value, 0, max); \
00571 blurry_row++; \
00572 orig_row++; \
00573 } \
00574 } \
00575 } \
00576 }
00577
00578
00579 float threshold;
00580 switch(color_model)
00581 {
00582 case BC_RGB888:
00583 case BC_YUV888:
00584 UNSHARPEN(unsigned char, 3, 0xff);
00585 break;
00586 case BC_RGBA8888:
00587 case BC_YUVA8888:
00588 UNSHARPEN(unsigned char, 4, 0xff);
00589 break;
00590 case BC_RGB_FLOAT:
00591 UNSHARPEN(float, 3, 1.0);
00592 break;
00593 case BC_RGBA_FLOAT:
00594 UNSHARPEN(float, 4, 1.0);
00595 break;
00596 case BC_YUV161616:
00597 UNSHARPEN(uint16_t, 3, 0xffff);
00598 break;
00599 case BC_YUVA16161616:
00600 UNSHARPEN(uint16_t, 4, 0xffff);
00601 break;
00602 }
00603
00604 delete [] temp_in;
00605 delete [] temp_out;
00606 delete [] cmatrix;
00607 }
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617 UnsharpEngine::UnsharpEngine(UnsharpMain *plugin,
00618 int total_clients,
00619 int total_packages)
00620 : LoadServer(
00621
00622 total_clients, total_packages
00623 )
00624 {
00625 this->plugin = plugin;
00626 }
00627
00628 UnsharpEngine::~UnsharpEngine()
00629 {
00630 }
00631
00632
00633 void UnsharpEngine::init_packages()
00634 {
00635 for(int i = 0; i < get_total_packages(); i++)
00636 {
00637 UnsharpPackage *pkg = (UnsharpPackage*)get_package(i);
00638 pkg->y1 = src->get_h() * i / get_total_packages();
00639 pkg->y2 = src->get_h() * (i + 1) / get_total_packages();
00640 }
00641 }
00642
00643 LoadClient* UnsharpEngine::new_client()
00644 {
00645 return new UnsharpUnit(this, plugin);
00646 }
00647
00648 LoadPackage* UnsharpEngine::new_package()
00649 {
00650 return new UnsharpPackage;
00651 }
00652
00653
00654 void UnsharpEngine::do_unsharp(VFrame *src)
00655 {
00656 this->src = src;
00657
00658 process_packages();
00659 }
00660
00661
00662
00663
00664
00665
00666
00667
00668