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