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