00001 #include "affine.h"
00002 #include "bcdisplayinfo.h"
00003 #include "clip.h"
00004 #include "bchash.h"
00005 #include "filexml.h"
00006 #include "keyframe.h"
00007 #include "language.h"
00008 #include "motion.h"
00009 #include "motionwindow.h"
00010 #include "mutex.h"
00011 #include "overlayframe.h"
00012 #include "picon_png.h"
00013 #include "rotateframe.h"
00014 #include "transportque.h"
00015
00016
00017 #include <errno.h>
00018 #include <unistd.h>
00019
00020 REGISTER_PLUGIN(MotionMain)
00021
00022
00023
00024 #ifndef DEBUG
00025 #define DEBUG
00026 #endif
00027
00028 static void sort(int *array, int total)
00029 {
00030 int done = 0;
00031 while(!done)
00032 {
00033 done = 1;
00034 for(int i = 0; i < total - 1; i++)
00035 {
00036 if(array[i] > array[i + 1])
00037 {
00038 array[i] ^= array[i + 1];
00039 array[i + 1] ^= array[i];
00040 array[i] ^= array[i + 1];
00041 done = 0;
00042 }
00043 }
00044 }
00045 }
00046
00047
00048
00049 MotionConfig::MotionConfig()
00050 {
00051 global_range_w = 5;
00052 global_range_h = 5;
00053 rotation_range = 5;
00054 block_count = 1;
00055 global_block_w = MIN_BLOCK;
00056 global_block_h = MIN_BLOCK;
00057 rotation_block_w = MIN_BLOCK;
00058 rotation_block_h = MIN_BLOCK;
00059 block_x = 50;
00060 block_y = 50;
00061 global_positions = 256;
00062 rotate_positions = 4;
00063 magnitude = 100;
00064 return_speed = 0;
00065 mode1 = STABILIZE;
00066 global = 1;
00067 rotate = 1;
00068 addtrackedframeoffset = 0;
00069 mode2 = NO_CALCULATE;
00070 draw_vectors = 1;
00071 mode3 = MotionConfig::TRACK_SINGLE;
00072 track_frame = 0;
00073 bottom_is_master = 1;
00074 horizontal_only = 0;
00075 vertical_only = 0;
00076 }
00077
00078 void MotionConfig::boundaries()
00079 {
00080 CLAMP(global_range_w, MIN_RADIUS, MAX_RADIUS);
00081 CLAMP(global_range_h, MIN_RADIUS, MAX_RADIUS);
00082 CLAMP(rotation_range, MIN_ROTATION, MAX_ROTATION);
00083 CLAMP(block_count, MIN_BLOCKS, MAX_BLOCKS);
00084 CLAMP(global_block_w, MIN_BLOCK, MAX_BLOCK);
00085 CLAMP(global_block_h, MIN_BLOCK, MAX_BLOCK);
00086 CLAMP(rotation_block_w, MIN_BLOCK, MAX_BLOCK);
00087 CLAMP(rotation_block_h, MIN_BLOCK, MAX_BLOCK);
00088 }
00089
00090 int MotionConfig::equivalent(MotionConfig &that)
00091 {
00092 return global_range_w == that.global_range_w &&
00093 global_range_h == that.global_range_h &&
00094 rotation_range == that.rotation_range &&
00095 mode1 == that.mode1 &&
00096 global == that.global &&
00097 rotate == that.rotate &&
00098 addtrackedframeoffset == that.addtrackedframeoffset &&
00099 draw_vectors == that.draw_vectors &&
00100 block_count == that.block_count &&
00101 global_block_w == that.global_block_w &&
00102 global_block_h == that.global_block_h &&
00103 rotation_block_w == that.rotation_block_w &&
00104 rotation_block_h == that.rotation_block_h &&
00105 EQUIV(block_x, that.block_x) &&
00106 EQUIV(block_y, that.block_y) &&
00107 global_positions == that.global_positions &&
00108 rotate_positions == that.rotate_positions &&
00109 magnitude == that.magnitude &&
00110 return_speed == that.return_speed &&
00111 mode3 == that.mode3 &&
00112 track_frame == that.track_frame &&
00113 bottom_is_master == that.bottom_is_master &&
00114 horizontal_only == that.horizontal_only &&
00115 vertical_only == that.vertical_only;
00116 }
00117
00118 void MotionConfig::copy_from(MotionConfig &that)
00119 {
00120 global_range_w = that.global_range_w;
00121 global_range_h = that.global_range_h;
00122 rotation_range = that.rotation_range;
00123 mode1 = that.mode1;
00124 global = that.global;
00125 rotate = that.rotate;
00126 addtrackedframeoffset = that.addtrackedframeoffset;
00127 mode2 = that.mode2;
00128 draw_vectors = that.draw_vectors;
00129 block_count = that.block_count;
00130 block_x = that.block_x;
00131 block_y = that.block_y;
00132 global_positions = that.global_positions;
00133 rotate_positions = that.rotate_positions;
00134 global_block_w = that.global_block_w;
00135 global_block_h = that.global_block_h;
00136 rotation_block_w = that.rotation_block_w;
00137 rotation_block_h = that.rotation_block_h;
00138 magnitude = that.magnitude;
00139 return_speed = that.return_speed;
00140 mode3 = that.mode3;
00141 track_frame = that.track_frame;
00142 bottom_is_master = that.bottom_is_master;
00143 horizontal_only = that.horizontal_only;
00144 vertical_only = that.vertical_only;
00145 }
00146
00147 void MotionConfig::interpolate(MotionConfig &prev,
00148 MotionConfig &next,
00149 int64_t prev_frame,
00150 int64_t next_frame,
00151 int64_t current_frame)
00152 {
00153 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
00154 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
00155 this->block_x = prev.block_x;
00156 this->block_y = prev.block_y;
00157 global_range_w = prev.global_range_w;
00158 global_range_h = prev.global_range_h;
00159 rotation_range = prev.rotation_range;
00160 mode1 = prev.mode1;
00161 global = prev.global;
00162 rotate = prev.rotate;
00163 addtrackedframeoffset = prev.addtrackedframeoffset;
00164 mode2 = prev.mode2;
00165 draw_vectors = prev.draw_vectors;
00166 block_count = prev.block_count;
00167 global_positions = prev.global_positions;
00168 rotate_positions = prev.rotate_positions;
00169 global_block_w = prev.global_block_w;
00170 global_block_h = prev.global_block_h;
00171 rotation_block_w = prev.rotation_block_w;
00172 rotation_block_h = prev.rotation_block_h;
00173 magnitude = prev.magnitude;
00174 return_speed = prev.return_speed;
00175 mode3 = prev.mode3;
00176 track_frame = prev.track_frame;
00177 bottom_is_master = prev.bottom_is_master;
00178 horizontal_only = prev.horizontal_only;
00179 vertical_only = prev.vertical_only;
00180 }
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200 MotionMain::MotionMain(PluginServer *server)
00201 : PluginVClient(server)
00202 {
00203 PLUGIN_CONSTRUCTOR_MACRO
00204 engine = 0;
00205 rotate_engine = 0;
00206 motion_rotate = 0;
00207 total_dx = 0;
00208 total_dy = 0;
00209 total_angle = 0;
00210 overlayer = 0;
00211 search_area = 0;
00212 search_size = 0;
00213 temp_frame = 0;
00214 previous_frame_number = -1;
00215
00216 prev_global_ref = 0;
00217 current_global_ref = 0;
00218 global_target_src = 0;
00219 global_target_dst = 0;
00220
00221 prev_rotate_ref = 0;
00222 current_rotate_ref = 0;
00223 rotate_target_src = 0;
00224 rotate_target_dst = 0;
00225 }
00226
00227 MotionMain::~MotionMain()
00228 {
00229 PLUGIN_DESTRUCTOR_MACRO
00230 delete engine;
00231 delete overlayer;
00232 delete [] search_area;
00233 delete temp_frame;
00234 delete rotate_engine;
00235 delete motion_rotate;
00236
00237
00238 delete prev_global_ref;
00239 delete current_global_ref;
00240 delete global_target_src;
00241 delete global_target_dst;
00242
00243 delete prev_rotate_ref;
00244 delete current_rotate_ref;
00245 delete rotate_target_src;
00246 delete rotate_target_dst;
00247 }
00248
00249 char* MotionMain::plugin_title() { return N_("Motion"); }
00250 int MotionMain::is_realtime() { return 1; }
00251 int MotionMain::is_multichannel() { return 1; }
00252
00253 NEW_PICON_MACRO(MotionMain)
00254
00255 SHOW_GUI_MACRO(MotionMain, MotionThread)
00256
00257 SET_STRING_MACRO(MotionMain)
00258
00259 RAISE_WINDOW_MACRO(MotionMain)
00260
00261 LOAD_CONFIGURATION_MACRO(MotionMain, MotionConfig)
00262
00263
00264
00265 void MotionMain::update_gui()
00266 {
00267 if(thread)
00268 {
00269 if(load_configuration())
00270 {
00271 thread->window->lock_window("MotionMain::update_gui");
00272
00273 char string[BCTEXTLEN];
00274 sprintf(string, "%d", config.global_positions);
00275 thread->window->global_search_positions->set_text(string);
00276 sprintf(string, "%d", config.rotate_positions);
00277 thread->window->rotation_search_positions->set_text(string);
00278
00279 thread->window->global_block_w->update(config.global_block_w);
00280 thread->window->global_block_h->update(config.global_block_h);
00281 thread->window->rotation_block_w->update(config.rotation_block_w);
00282 thread->window->rotation_block_h->update(config.rotation_block_h);
00283 thread->window->block_x->update(config.block_x);
00284 thread->window->block_y->update(config.block_y);
00285 thread->window->block_x_text->update((float)config.block_x);
00286 thread->window->block_y_text->update((float)config.block_y);
00287 thread->window->magnitude->update(config.magnitude);
00288 thread->window->return_speed->update(config.return_speed);
00289
00290
00291 thread->window->track_single->update(config.mode3 == MotionConfig::TRACK_SINGLE);
00292 thread->window->track_frame_number->update(config.track_frame);
00293 thread->window->track_previous->update(config.mode3 == MotionConfig::TRACK_PREVIOUS);
00294 thread->window->previous_same->update(config.mode3 == MotionConfig::PREVIOUS_SAME_BLOCK);
00295 if(config.mode3 != MotionConfig::TRACK_SINGLE)
00296 thread->window->track_frame_number->disable();
00297 else
00298 thread->window->track_frame_number->enable();
00299
00300 thread->window->mode1->set_text(
00301 Mode1::to_text(config.mode1));
00302 thread->window->mode2->set_text(
00303 Mode2::to_text(config.mode2));
00304 thread->window->mode3->set_text(
00305 Mode3::to_text(config.horizontal_only, config.vertical_only));
00306 thread->window->master_layer->set_text(
00307 MasterLayer::to_text(config.bottom_is_master));
00308
00309
00310 thread->window->update_mode();
00311 thread->window->unlock_window();
00312 }
00313 }
00314 }
00315
00316
00317 int MotionMain::load_defaults()
00318 {
00319 char directory[BCTEXTLEN], string[BCTEXTLEN];
00320
00321 sprintf(directory, "%smotion.rc", BCASTDIR);
00322
00323
00324 defaults = new BC_Hash(directory);
00325 defaults->load();
00326
00327 config.block_count = defaults->get("BLOCK_COUNT", config.block_count);
00328 config.global_positions = defaults->get("GLOBAL_POSITIONS", config.global_positions);
00329 config.rotate_positions = defaults->get("ROTATE_POSITIONS", config.rotate_positions);
00330 config.global_block_w = defaults->get("GLOBAL_BLOCK_W", config.global_block_w);
00331 config.global_block_h = defaults->get("GLOBAL_BLOCK_H", config.global_block_h);
00332 config.rotation_block_w = defaults->get("ROTATION_BLOCK_W", config.rotation_block_w);
00333 config.rotation_block_h = defaults->get("ROTATION_BLOCK_H", config.rotation_block_h);
00334 config.block_x = defaults->get("BLOCK_X", config.block_x);
00335 config.block_y = defaults->get("BLOCK_Y", config.block_y);
00336 config.global_range_w = defaults->get("GLOBAL_RANGE_W", config.global_range_w);
00337 config.global_range_h = defaults->get("GLOBAL_RANGE_H", config.global_range_h);
00338 config.rotation_range = defaults->get("ROTATION_RANGE", config.rotation_range);
00339 config.magnitude = defaults->get("MAGNITUDE", config.magnitude);
00340 config.return_speed = defaults->get("RETURN_SPEED", config.return_speed);
00341 config.mode1 = defaults->get("MODE1", config.mode1);
00342 config.global = defaults->get("GLOBAL", config.global);
00343 config.rotate = defaults->get("ROTATE", config.rotate);
00344 config.mode2 = defaults->get("MODE2", config.mode2);
00345 config.draw_vectors = defaults->get("DRAW_VECTORS", config.draw_vectors);
00346 config.mode3 = defaults->get("MODE3", config.mode3);
00347 config.track_frame = defaults->get("TRACK_FRAME", config.track_frame);
00348 config.bottom_is_master = defaults->get("BOTTOM_IS_MASTER", config.bottom_is_master);
00349 config.horizontal_only = defaults->get("HORIZONTAL_ONLY", config.horizontal_only);
00350 config.vertical_only = defaults->get("VERTICAL_ONLY", config.vertical_only);
00351 config.boundaries();
00352 return 0;
00353 }
00354
00355
00356 int MotionMain::save_defaults()
00357 {
00358 defaults->update("BLOCK_COUNT", config.block_count);
00359 defaults->update("GLOBAL_POSITIONS", config.global_positions);
00360 defaults->update("ROTATE_POSITIONS", config.rotate_positions);
00361 defaults->update("GLOBAL_BLOCK_W", config.global_block_w);
00362 defaults->update("GLOBAL_BLOCK_H", config.global_block_h);
00363 defaults->update("ROTATION_BLOCK_W", config.rotation_block_w);
00364 defaults->update("ROTATION_BLOCK_H", config.rotation_block_h);
00365 defaults->update("BLOCK_X", config.block_x);
00366 defaults->update("BLOCK_Y", config.block_y);
00367 defaults->update("GLOBAL_RANGE_W", config.global_range_w);
00368 defaults->update("GLOBAL_RANGE_H", config.global_range_h);
00369 defaults->update("ROTATION_RANGE", config.rotation_range);
00370 defaults->update("MAGNITUDE", config.magnitude);
00371 defaults->update("RETURN_SPEED", config.return_speed);
00372 defaults->update("MODE1", config.mode1);
00373 defaults->update("GLOBAL", config.global);
00374 defaults->update("ROTATE", config.rotate);
00375 defaults->update("MODE2", config.mode2);
00376 defaults->update("DRAW_VECTORS", config.draw_vectors);
00377 defaults->update("MODE3", config.mode3);
00378 defaults->update("TRACK_FRAME", config.track_frame);
00379 defaults->update("BOTTOM_IS_MASTER", config.bottom_is_master);
00380 defaults->update("HORIZONTAL_ONLY", config.horizontal_only);
00381 defaults->update("VERTICAL_ONLY", config.vertical_only);
00382 defaults->save();
00383 return 0;
00384 }
00385
00386
00387
00388 void MotionMain::save_data(KeyFrame *keyframe)
00389 {
00390 FileXML output;
00391
00392
00393 output.set_shared_string(keyframe->data, MESSAGESIZE);
00394 output.tag.set_title("MOTION");
00395
00396 output.tag.set_property("BLOCK_COUNT", config.block_count);
00397 output.tag.set_property("GLOBAL_POSITIONS", config.global_positions);
00398 output.tag.set_property("ROTATE_POSITIONS", config.rotate_positions);
00399 output.tag.set_property("GLOBAL_BLOCK_W", config.global_block_w);
00400 output.tag.set_property("GLOBAL_BLOCK_H", config.global_block_h);
00401 output.tag.set_property("ROTATION_BLOCK_W", config.rotation_block_w);
00402 output.tag.set_property("ROTATION_BLOCK_H", config.rotation_block_h);
00403 output.tag.set_property("BLOCK_X", config.block_x);
00404 output.tag.set_property("BLOCK_Y", config.block_y);
00405 output.tag.set_property("GLOBAL_RANGE_W", config.global_range_w);
00406 output.tag.set_property("GLOBAL_RANGE_H", config.global_range_h);
00407 output.tag.set_property("ROTATION_RANGE", config.rotation_range);
00408 output.tag.set_property("MAGNITUDE", config.magnitude);
00409 output.tag.set_property("RETURN_SPEED", config.return_speed);
00410 output.tag.set_property("MODE1", config.mode1);
00411 output.tag.set_property("GLOBAL", config.global);
00412 output.tag.set_property("ROTATE", config.rotate);
00413 output.tag.set_property("ADDTRACKEDFRAMEOFFSET", config.addtrackedframeoffset);
00414 output.tag.set_property("MODE2", config.mode2);
00415 output.tag.set_property("DRAW_VECTORS", config.draw_vectors);
00416 output.tag.set_property("MODE3", config.mode3);
00417 output.tag.set_property("TRACK_FRAME", config.track_frame);
00418 output.tag.set_property("BOTTOM_IS_MASTER", config.bottom_is_master);
00419 output.tag.set_property("HORIZONTAL_ONLY", config.horizontal_only);
00420 output.tag.set_property("VERTICAL_ONLY", config.vertical_only);
00421 output.append_tag();
00422 output.tag.set_title("/MOTION");
00423 output.append_tag();
00424 output.terminate_string();
00425 }
00426
00427 void MotionMain::read_data(KeyFrame *keyframe)
00428 {
00429 FileXML input;
00430
00431 input.set_shared_string(keyframe->data, strlen(keyframe->data));
00432
00433 int result = 0;
00434
00435 while(!result)
00436 {
00437 result = input.read_tag();
00438
00439 if(!result)
00440 {
00441 if(input.tag.title_is("MOTION"))
00442 {
00443 config.block_count = input.tag.get_property("BLOCK_COUNT", config.block_count);
00444 config.global_positions = input.tag.get_property("GLOBAL_POSITIONS", config.global_positions);
00445 config.rotate_positions = input.tag.get_property("ROTATE_POSITIONS", config.rotate_positions);
00446 config.global_block_w = input.tag.get_property("GLOBAL_BLOCK_W", config.global_block_w);
00447 config.global_block_h = input.tag.get_property("GLOBAL_BLOCK_H", config.global_block_h);
00448 config.rotation_block_w = input.tag.get_property("ROTATION_BLOCK_W", config.rotation_block_w);
00449 config.rotation_block_h = input.tag.get_property("ROTATION_BLOCK_H", config.rotation_block_h);
00450 config.block_x = input.tag.get_property("BLOCK_X", config.block_x);
00451 config.block_y = input.tag.get_property("BLOCK_Y", config.block_y);
00452 config.global_range_w = input.tag.get_property("GLOBAL_RANGE_W", config.global_range_w);
00453 config.global_range_h = input.tag.get_property("GLOBAL_RANGE_H", config.global_range_h);
00454 config.rotation_range = input.tag.get_property("ROTATION_RANGE", config.rotation_range);
00455 config.magnitude = input.tag.get_property("MAGNITUDE", config.magnitude);
00456 config.return_speed = input.tag.get_property("RETURN_SPEED", config.return_speed);
00457 config.mode1 = input.tag.get_property("MODE1", config.mode1);
00458 config.global = input.tag.get_property("GLOBAL", config.global);
00459 config.rotate = input.tag.get_property("ROTATE", config.rotate);
00460 config.addtrackedframeoffset = input.tag.get_property("ADDTRACKEDFRAMEOFFSET", config.addtrackedframeoffset);
00461 config.mode2 = input.tag.get_property("MODE2", config.mode2);
00462 config.draw_vectors = input.tag.get_property("DRAW_VECTORS", config.draw_vectors);
00463 config.mode3 = input.tag.get_property("MODE3", config.mode3);
00464 config.track_frame = input.tag.get_property("TRACK_FRAME", config.track_frame);
00465 config.bottom_is_master = input.tag.get_property("BOTTOM_IS_MASTER", config.bottom_is_master);
00466 config.horizontal_only = input.tag.get_property("HORIZONTAL_ONLY", config.horizontal_only);
00467 config.vertical_only = input.tag.get_property("VERTICAL_ONLY", config.vertical_only);
00468 }
00469 }
00470 }
00471 config.boundaries();
00472 }
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482 void MotionMain::allocate_temp(int w, int h, int color_model)
00483 {
00484 if(temp_frame &&
00485 (temp_frame->get_w() != w ||
00486 temp_frame->get_h() != h))
00487 {
00488 delete temp_frame;
00489 temp_frame = 0;
00490 }
00491 if(!temp_frame)
00492 temp_frame = new VFrame(0, w, h, color_model);
00493 }
00494
00495
00496
00497 void MotionMain::process_global()
00498 {
00499 if(!engine) engine = new MotionScan(this,
00500 PluginClient::get_project_smp() + 1,
00501 PluginClient::get_project_smp() + 1);
00502
00503
00504 engine->scan_frame(current_global_ref, prev_global_ref);
00505 current_dx = engine->dx_result;
00506 current_dy = engine->dy_result;
00507
00508
00509 if(config.mode3 != MotionConfig::TRACK_SINGLE)
00510 {
00511
00512 total_dx = (int64_t)total_dx * (100 - config.return_speed) / 100;
00513 total_dy = (int64_t)total_dy * (100 - config.return_speed) / 100;
00514 total_dx += engine->dx_result;
00515 total_dy += engine->dy_result;
00516 }
00517 else
00518
00519 {
00520 total_dx = engine->dx_result;
00521 total_dy = engine->dy_result;
00522 }
00523
00524
00525 if(config.magnitude < 100)
00526 {
00527 int block_w = (int64_t)config.global_block_w *
00528 current_global_ref->get_w() / 100;
00529 int block_h = (int64_t)config.global_block_h *
00530 current_global_ref->get_h() / 100;
00531 int block_x_orig = (int64_t)(config.block_x *
00532 current_global_ref->get_w() /
00533 100);
00534 int block_y_orig = (int64_t)(config.block_y *
00535 current_global_ref->get_h() /
00536 100);
00537
00538 int max_block_x = (int64_t)(current_global_ref->get_w() - block_x_orig) *
00539 OVERSAMPLE *
00540 config.magnitude /
00541 100;
00542 int max_block_y = (int64_t)(current_global_ref->get_h() - block_y_orig) *
00543 OVERSAMPLE *
00544 config.magnitude /
00545 100;
00546 int min_block_x = (int64_t)-block_x_orig *
00547 OVERSAMPLE *
00548 config.magnitude /
00549 100;
00550 int min_block_y = (int64_t)-block_y_orig *
00551 OVERSAMPLE *
00552 config.magnitude /
00553 100;
00554
00555 CLAMP(total_dx, min_block_x, max_block_x);
00556 CLAMP(total_dy, min_block_y, max_block_y);
00557 }
00558
00559 #ifdef DEBUG
00560 printf("MotionMain::process_global 2 total_dx=%.02f total_dy=%.02f\n",
00561 (float)total_dx / OVERSAMPLE,
00562 (float)total_dy / OVERSAMPLE);
00563 #endif
00564
00565 if(config.mode3 != MotionConfig::TRACK_SINGLE && !config.rotate)
00566 {
00567
00568
00569 prev_global_ref->copy_from(current_global_ref);
00570 previous_frame_number = get_source_position();
00571 }
00572
00573
00574 int interpolation;
00575 float dx;
00576 float dy;
00577 switch(config.mode1)
00578 {
00579 case MotionConfig::NOTHING:
00580 global_target_dst->copy_from(global_target_src);
00581 break;
00582 case MotionConfig::TRACK_PIXEL:
00583 interpolation = NEAREST_NEIGHBOR;
00584 dx = (int)(total_dx / OVERSAMPLE);
00585 dy = (int)(total_dy / OVERSAMPLE);
00586 break;
00587 case MotionConfig::STABILIZE_PIXEL:
00588 interpolation = NEAREST_NEIGHBOR;
00589 dx = -(int)(total_dx / OVERSAMPLE);
00590 dy = -(int)(total_dy / OVERSAMPLE);
00591 break;
00592 break;
00593 case MotionConfig::TRACK:
00594 interpolation = CUBIC_LINEAR;
00595 dx = (float)total_dx / OVERSAMPLE;
00596 dy = (float)total_dy / OVERSAMPLE;
00597 break;
00598 case MotionConfig::STABILIZE:
00599 interpolation = CUBIC_LINEAR;
00600 dx = -(float)total_dx / OVERSAMPLE;
00601 dy = -(float)total_dy / OVERSAMPLE;
00602 break;
00603 }
00604
00605
00606 if(config.mode1 != MotionConfig::NOTHING)
00607 {
00608 if(!overlayer)
00609 overlayer = new OverlayFrame(PluginClient::get_project_smp() + 1);
00610 global_target_dst->clear_frame();
00611 overlayer->overlay(global_target_dst,
00612 global_target_src,
00613 0,
00614 0,
00615 global_target_src->get_w(),
00616 global_target_src->get_h(),
00617 dx,
00618 dy,
00619 (float)global_target_src->get_w() + dx,
00620 (float)global_target_src->get_h() + dy,
00621 1,
00622 TRANSFER_REPLACE,
00623 interpolation);
00624 }
00625 }
00626
00627
00628
00629 void MotionMain::process_rotation()
00630 {
00631 int block_x;
00632 int block_y;
00633
00634
00635
00636 if(config.global)
00637 {
00638 if(!overlayer)
00639 overlayer = new OverlayFrame(PluginClient::get_project_smp() + 1);
00640 float dx;
00641 float dy;
00642 if(config.mode3 == MotionConfig::TRACK_SINGLE)
00643 {
00644 dx = (float)total_dx / OVERSAMPLE;
00645 dy = (float)total_dy / OVERSAMPLE;
00646 }
00647 else
00648 {
00649 dx = (float)current_dx / OVERSAMPLE;
00650 dy = (float)current_dy / OVERSAMPLE;
00651 }
00652
00653 prev_rotate_ref->clear_frame();
00654 overlayer->overlay(prev_rotate_ref,
00655 prev_global_ref,
00656 0,
00657 0,
00658 prev_global_ref->get_w(),
00659 prev_global_ref->get_h(),
00660 dx,
00661 dy,
00662 (float)prev_global_ref->get_w() + dx,
00663 (float)prev_global_ref->get_h() + dy,
00664 1,
00665 TRANSFER_REPLACE,
00666 CUBIC_LINEAR);
00667
00668 block_x = (int)(prev_rotate_ref->get_w() *
00669 config.block_x /
00670 100 +
00671 (float)total_dx /
00672 OVERSAMPLE);
00673 block_y = (int)(prev_rotate_ref->get_h() *
00674 config.block_y /
00675 100 +
00676 (float)total_dy /
00677 OVERSAMPLE);
00678
00679 rotate_target_src->copy_from(global_target_dst);
00680
00681 if(config.mode3 != MotionConfig::TRACK_SINGLE)
00682 {
00683 prev_global_ref->copy_from(current_global_ref);
00684 previous_frame_number = get_source_position();
00685 }
00686 }
00687 else
00688 {
00689
00690 block_x = (int)(prev_rotate_ref->get_w() *
00691 config.block_x /
00692 100);
00693 block_y = (int)(prev_rotate_ref->get_h() *
00694 config.block_y /
00695 100);
00696 }
00697
00698
00699
00700
00701 if(!motion_rotate)
00702 motion_rotate = new RotateScan(this,
00703 get_project_smp() + 1,
00704 get_project_smp() + 1);
00705
00706 current_angle = motion_rotate->scan_frame(prev_rotate_ref,
00707 current_rotate_ref,
00708 block_x,
00709 block_y);
00710
00711
00712
00713
00714 if(config.mode3 != MotionConfig::TRACK_SINGLE)
00715 {
00716
00717 total_angle = total_angle * (100 - config.return_speed) / 100;
00718 total_angle += current_angle;
00719
00720 if(!config.global)
00721 {
00722
00723
00724 prev_rotate_ref->copy_from(current_rotate_ref);
00725 previous_frame_number = get_source_position();
00726 }
00727 }
00728 else
00729 {
00730 total_angle = current_angle;
00731 }
00732
00733 #ifdef DEBUG
00734 printf("MotionMain::process_rotation total_angle=%f\n", total_angle);
00735 #endif
00736
00737
00738
00739 float angle;
00740 switch(config.mode1)
00741 {
00742 case MotionConfig::NOTHING:
00743 rotate_target_dst->copy_from(rotate_target_src);
00744 break;
00745 case MotionConfig::TRACK:
00746 case MotionConfig::TRACK_PIXEL:
00747 angle = total_angle;
00748 break;
00749 case MotionConfig::STABILIZE:
00750 case MotionConfig::STABILIZE_PIXEL:
00751 angle = -total_angle;
00752 break;
00753 }
00754
00755
00756
00757 if(config.mode1 != MotionConfig::NOTHING)
00758 {
00759 if(!rotate_engine)
00760 rotate_engine = new AffineEngine(PluginClient::get_project_smp() + 1,
00761 PluginClient::get_project_smp() + 1);
00762
00763 rotate_target_dst->clear_frame();
00764
00765
00766 switch(config.mode1)
00767 {
00768 case MotionConfig::TRACK:
00769 case MotionConfig::TRACK_PIXEL:
00770
00771 rotate_engine->set_pivot(block_x, block_y);
00772 break;
00773
00774 case MotionConfig::STABILIZE:
00775 case MotionConfig::STABILIZE_PIXEL:
00776 if(config.global)
00777 {
00778
00779 rotate_engine->set_pivot((int)(rotate_target_dst->get_w() *
00780 config.block_x /
00781 100),
00782 (int)(rotate_target_dst->get_h() *
00783 config.block_y /
00784 100));
00785
00786 }
00787 else
00788 {
00789
00790 rotate_engine->set_pivot(block_x, block_y);
00791 }
00792 break;
00793 }
00794
00795
00796 rotate_engine->rotate(rotate_target_dst, rotate_target_src, angle);
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825 }
00826
00827
00828 }
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838 int MotionMain::process_buffer(VFrame **frame,
00839 int64_t start_position,
00840 double frame_rate)
00841 {
00842 int need_reconfigure = load_configuration();
00843 int color_model = frame[0]->get_color_model();
00844 w = frame[0]->get_w();
00845 h = frame[0]->get_h();
00846
00847
00848 #ifdef DEBUG
00849 printf("MotionMain::process_buffer 1 start_position=%lld\n", start_position);
00850 #endif
00851
00852
00853
00854
00855 reference_layer = config.bottom_is_master ?
00856 PluginClient::total_in_buffers - 1 :
00857 0;
00858
00859 target_layer = config.bottom_is_master ?
00860 0 :
00861 PluginClient::total_in_buffers - 1;
00862
00863
00864 output_frame = frame[target_layer];
00865
00866
00867
00868 int64_t actual_previous_number;
00869
00870 int skip_current = 0;
00871
00872
00873 if(config.mode3 == MotionConfig::TRACK_SINGLE)
00874 {
00875 actual_previous_number = config.track_frame;
00876 if(get_direction() == PLAY_REVERSE)
00877 actual_previous_number++;
00878 if(actual_previous_number == start_position)
00879 skip_current = 1;
00880 }
00881 else
00882 {
00883 actual_previous_number = start_position;
00884 if(get_direction() == PLAY_FORWARD)
00885 {
00886 actual_previous_number--;
00887 if(actual_previous_number < get_source_start())
00888 skip_current = 1;
00889 else
00890 {
00891 KeyFrame *keyframe = get_prev_keyframe(start_position, 1);
00892 if(keyframe->position > 0 &&
00893 actual_previous_number < keyframe->position)
00894 skip_current = 1;
00895 }
00896 }
00897 else
00898 {
00899 actual_previous_number++;
00900 if(actual_previous_number >= get_source_start() + get_total_len())
00901 skip_current = 1;
00902 else
00903 {
00904 KeyFrame *keyframe = get_next_keyframe(start_position, 1);
00905 if(keyframe->position > 0 &&
00906 actual_previous_number >= keyframe->position)
00907 skip_current = 1;
00908 }
00909 }
00910
00911
00912
00913
00914 }
00915
00916
00917 if(!config.global && !config.rotate) skip_current = 1;
00918
00919
00920
00921
00922
00923
00924
00925
00926
00927 int need_reload = !skip_current &&
00928 (previous_frame_number != actual_previous_number ||
00929 need_reconfigure);
00930 if(need_reload)
00931 {
00932 total_dx = 0;
00933 total_dy = 0;
00934 total_angle = 0;
00935 previous_frame_number = actual_previous_number;
00936 }
00937
00938
00939 if(skip_current)
00940 {
00941 total_dx = 0;
00942 total_dy = 0;
00943 current_dx = 0;
00944 current_dy = 0;
00945 total_angle = 0;
00946 current_angle = 0;
00947 }
00948
00949
00950
00951
00952
00953 if(config.global)
00954 {
00955
00956
00957
00958
00959 if(!prev_global_ref)
00960 prev_global_ref = new VFrame(0, w, h, color_model);
00961 if(!current_global_ref)
00962 current_global_ref = new VFrame(0, w, h, color_model);
00963
00964
00965
00966 if(!global_target_src)
00967 global_target_src = new VFrame(0, w, h, color_model);
00968 if(!global_target_dst)
00969 global_target_dst = new VFrame(0, w, h, color_model);
00970
00971
00972
00973 if(need_reload)
00974 {
00975 read_frame(prev_global_ref,
00976 reference_layer,
00977 previous_frame_number,
00978 frame_rate);
00979 }
00980
00981 read_frame(current_global_ref,
00982 reference_layer,
00983 start_position,
00984 frame_rate);
00985 read_frame(global_target_src,
00986 target_layer,
00987 start_position,
00988 frame_rate);
00989
00990
00991
00992
00993 if(config.rotate)
00994 {
00995
00996
00997
00998
00999 if(!prev_rotate_ref)
01000 prev_rotate_ref = new VFrame(0, w, h, color_model);
01001
01002 if(!current_rotate_ref)
01003 current_rotate_ref = new VFrame(0, w, h, color_model);
01004 current_rotate_ref->copy_from(current_global_ref);
01005
01006
01007
01008
01009
01010
01011 if(!rotate_target_src)
01012 rotate_target_src = new VFrame(0, w, h, color_model);
01013 if(!rotate_target_dst)
01014 rotate_target_dst = new VFrame(0, w,h , color_model);
01015 }
01016 }
01017 else
01018
01019 if(config.rotate)
01020 {
01021
01022
01023 if(!prev_rotate_ref)
01024 prev_rotate_ref = new VFrame(0, w, h, color_model);
01025 if(!current_rotate_ref)
01026 current_rotate_ref = new VFrame(0, w, h, color_model);
01027
01028
01029
01030 if(!rotate_target_src)
01031 rotate_target_src = new VFrame(0, w, h, color_model);
01032 if(!rotate_target_dst)
01033 rotate_target_dst = new VFrame(0, w,h , color_model);
01034
01035
01036
01037 if(need_reload)
01038 {
01039 read_frame(prev_rotate_ref,
01040 reference_layer,
01041 previous_frame_number,
01042 frame_rate);
01043 }
01044 read_frame(current_rotate_ref,
01045 reference_layer,
01046 start_position,
01047 frame_rate);
01048 read_frame(rotate_target_src,
01049 target_layer,
01050 start_position,
01051 frame_rate);
01052 }
01053
01054
01055
01056
01057
01058
01059
01060
01061
01062
01063 if(!skip_current)
01064 {
01065
01066 if(config.global) process_global();
01067
01068 if(config.rotate) process_rotation();
01069
01070
01071 }
01072
01073
01074
01075
01076
01077
01078
01079 if(!skip_current)
01080 {
01081 if(config.rotate)
01082 {
01083 frame[target_layer]->copy_from(rotate_target_dst);
01084 }
01085 else
01086 {
01087 frame[target_layer]->copy_from(global_target_dst);
01088 }
01089 }
01090 else
01091
01092 {
01093 read_frame(frame[target_layer],
01094 target_layer,
01095 start_position,
01096 frame_rate);
01097 }
01098
01099 if(config.draw_vectors)
01100 {
01101 draw_vectors(frame[target_layer]);
01102 }
01103
01104 #ifdef DEBUG
01105 printf("MotionMain::process_buffer 100\n");
01106 #endif
01107 return 0;
01108 }
01109
01110
01111 void MotionMain::clamp_scan(int w,
01112 int h,
01113 int *block_x1,
01114 int *block_y1,
01115 int *block_x2,
01116 int *block_y2,
01117 int *scan_x1,
01118 int *scan_y1,
01119 int *scan_x2,
01120 int *scan_y2,
01121 int use_absolute)
01122 {
01123
01124
01125
01126
01127
01128
01129
01130
01131
01132
01133
01134
01135
01136 if(use_absolute)
01137 {
01138
01139 if(*scan_x1 < 0)
01140 {
01141 int difference = -*scan_x1;
01142 *block_x1 += difference;
01143 *scan_x1 = 0;
01144 }
01145
01146 if(*scan_y1 < 0)
01147 {
01148 int difference = -*scan_y1;
01149 *block_y1 += difference;
01150 *scan_y1 = 0;
01151 }
01152
01153 if(*scan_x2 > w)
01154 {
01155 int difference = *scan_x2 - w;
01156 *block_x2 -= difference;
01157 *scan_x2 -= difference;
01158 }
01159
01160 if(*scan_y2 > h)
01161 {
01162 int difference = *scan_y2 - h;
01163 *block_y2 -= difference;
01164 *scan_y2 -= difference;
01165 }
01166
01167 CLAMP(*scan_x1, 0, w);
01168 CLAMP(*scan_y1, 0, h);
01169 CLAMP(*scan_x2, 0, w);
01170 CLAMP(*scan_y2, 0, h);
01171 }
01172 else
01173 {
01174 if(*scan_x1 < 0)
01175 {
01176 int difference = -*scan_x1;
01177 *block_x1 += difference;
01178 *scan_x2 += difference;
01179 *scan_x1 = 0;
01180 }
01181
01182 if(*scan_y1 < 0)
01183 {
01184 int difference = -*scan_y1;
01185 *block_y1 += difference;
01186 *scan_y2 += difference;
01187 *scan_y1 = 0;
01188 }
01189
01190 if(*scan_x2 - *block_x1 + *block_x2 > w)
01191 {
01192 int difference = *scan_x2 - *block_x1 + *block_x2 - w;
01193 *block_x2 -= difference;
01194 }
01195
01196 if(*scan_y2 - *block_y1 + *block_y2 > h)
01197 {
01198 int difference = *scan_y2 - *block_y1 + *block_y2 - h;
01199 *block_y2 -= difference;
01200 }
01201
01202
01203
01204
01205
01206 }
01207
01208
01209
01210 CLAMP(*block_x1, 0, w);
01211 CLAMP(*block_x2, 0, w);
01212 CLAMP(*block_y1, 0, h);
01213 CLAMP(*block_y2, 0, h);
01214
01215
01216
01217
01218
01219
01220
01221
01222
01223
01224
01225
01226
01227 }
01228
01229
01230
01231 void MotionMain::draw_vectors(VFrame *frame)
01232 {
01233 int w = frame->get_w();
01234 int h = frame->get_h();
01235 int global_x1, global_y1;
01236 int global_x2, global_y2;
01237 int block_x, block_y;
01238 int block_w, block_h;
01239 int block_x1, block_y1;
01240 int block_x2, block_y2;
01241 int block_x3, block_y3;
01242 int block_x4, block_y4;
01243 int search_w, search_h;
01244 int search_x1, search_y1;
01245 int search_x2, search_y2;
01246 int search_x3, search_y3;
01247 int search_x4, search_y4;
01248
01249 if(config.global)
01250 {
01251
01252
01253
01254 if(config.mode3 == MotionConfig::TRACK_SINGLE)
01255 {
01256 global_x1 = (int64_t)(config.block_x *
01257 w /
01258 100);
01259 global_y1 = (int64_t)(config.block_y *
01260 h /
01261 100);
01262 global_x2 = global_x1 + total_dx / OVERSAMPLE;
01263 global_y2 = global_y1 + total_dy / OVERSAMPLE;
01264
01265 }
01266 else
01267
01268
01269 if(config.mode3 == MotionConfig::PREVIOUS_SAME_BLOCK)
01270 {
01271 global_x1 = (int64_t)(config.block_x *
01272 w /
01273 100);
01274 global_y1 = (int64_t)(config.block_y *
01275 h /
01276 100);
01277 global_x2 = global_x1 + current_dx / OVERSAMPLE;
01278 global_y2 = global_y1 + current_dy / OVERSAMPLE;
01279 }
01280 else
01281 {
01282 global_x1 = (int64_t)(config.block_x *
01283 w /
01284 100 +
01285 (total_dx - current_dx) /
01286 OVERSAMPLE);
01287 global_y1 = (int64_t)(config.block_y *
01288 h /
01289 100 +
01290 (total_dy - current_dy) /
01291 OVERSAMPLE);
01292 global_x2 = (int64_t)(config.block_x *
01293 w /
01294 100 +
01295 total_dx /
01296 OVERSAMPLE);
01297 global_y2 = (int64_t)(config.block_y *
01298 h /
01299 100 +
01300 total_dy /
01301 OVERSAMPLE);
01302 }
01303
01304 block_x = global_x1;
01305 block_y = global_y1;
01306 block_w = config.global_block_w * w / 100;
01307 block_h = config.global_block_h * h / 100;
01308 block_x1 = block_x - block_w / 2;
01309 block_y1 = block_y - block_h / 2;
01310 block_x2 = block_x + block_w / 2;
01311 block_y2 = block_y + block_h / 2;
01312 search_w = config.global_range_w * w / 100;
01313 search_h = config.global_range_h * h / 100;
01314 search_x1 = block_x1 - search_w / 2;
01315 search_y1 = block_y1 - search_h / 2;
01316 search_x2 = block_x2 + search_w / 2;
01317 search_y2 = block_y2 + search_h / 2;
01318
01319
01320
01321
01322
01323
01324
01325
01326
01327
01328
01329
01330
01331
01332
01333 clamp_scan(w,
01334 h,
01335 &block_x1,
01336 &block_y1,
01337 &block_x2,
01338 &block_y2,
01339 &search_x1,
01340 &search_y1,
01341 &search_x2,
01342 &search_y2,
01343 1);
01344
01345
01346 draw_arrow(frame, global_x1, global_y1, global_x2, global_y2);
01347
01348
01349 draw_line(frame, block_x1, block_y1, block_x2, block_y1);
01350 draw_line(frame, block_x2, block_y1, block_x2, block_y2);
01351 draw_line(frame, block_x2, block_y2, block_x1, block_y2);
01352 draw_line(frame, block_x1, block_y2, block_x1, block_y1);
01353
01354
01355
01356 draw_line(frame, search_x1, search_y1, search_x2, search_y1);
01357 draw_line(frame, search_x2, search_y1, search_x2, search_y2);
01358 draw_line(frame, search_x2, search_y2, search_x1, search_y2);
01359 draw_line(frame, search_x1, search_y2, search_x1, search_y1);
01360
01361
01362 if(config.rotate)
01363 {
01364 block_x = global_x2;
01365 block_y = global_y2;
01366 }
01367 }
01368 else
01369 {
01370 block_x = (int64_t)(config.block_x * w / 100);
01371 block_y = (int64_t)(config.block_y * h / 100);
01372 }
01373
01374 block_w = config.rotation_block_w * w / 100;
01375 block_h = config.rotation_block_h * h / 100;
01376 if(config.rotate)
01377 {
01378 float angle = total_angle * 2 * M_PI / 360;
01379 double base_angle1 = atan((float)block_h / block_w);
01380 double base_angle2 = atan((float)block_w / block_h);
01381 double target_angle1 = base_angle1 + angle;
01382 double target_angle2 = base_angle2 + angle;
01383 double radius = sqrt(block_w * block_w + block_h * block_h) / 2;
01384 block_x1 = (int)(block_x - cos(target_angle1) * radius);
01385 block_y1 = (int)(block_y - sin(target_angle1) * radius);
01386 block_x2 = (int)(block_x + sin(target_angle2) * radius);
01387 block_y2 = (int)(block_y - cos(target_angle2) * radius);
01388 block_x3 = (int)(block_x - sin(target_angle2) * radius);
01389 block_y3 = (int)(block_y + cos(target_angle2) * radius);
01390 block_x4 = (int)(block_x + cos(target_angle1) * radius);
01391 block_y4 = (int)(block_y + sin(target_angle1) * radius);
01392
01393 draw_line(frame, block_x1, block_y1, block_x2, block_y2);
01394 draw_line(frame, block_x2, block_y2, block_x4, block_y4);
01395 draw_line(frame, block_x4, block_y4, block_x3, block_y3);
01396 draw_line(frame, block_x3, block_y3, block_x1, block_y1);
01397
01398
01399
01400 if(!config.global)
01401 {
01402 draw_line(frame, block_x, block_y - 5, block_x, block_y + 6);
01403 draw_line(frame, block_x - 5, block_y, block_x + 6, block_y);
01404 }
01405 }
01406 }
01407
01408
01409
01410 void MotionMain::draw_pixel(VFrame *frame, int x, int y)
01411 {
01412 if(!(x >= 0 && y >= 0 && x < frame->get_w() && y < frame->get_h())) return;
01413
01414 #define DRAW_PIXEL(x, y, components, do_yuv, max, type) \
01415 { \
01416 type **rows = (type**)frame->get_rows(); \
01417 rows[y][x * components] = max - rows[y][x * components]; \
01418 if(!do_yuv) \
01419 { \
01420 rows[y][x * components + 1] = max - rows[y][x * components + 1]; \
01421 rows[y][x * components + 2] = max - rows[y][x * components + 2]; \
01422 } \
01423 else \
01424 { \
01425 rows[y][x * components + 1] = (max / 2 + 1) - rows[y][x * components + 1]; \
01426 rows[y][x * components + 2] = (max / 2 + 1) - rows[y][x * components + 2]; \
01427 } \
01428 if(components == 4) \
01429 rows[y][x * components + 3] = max; \
01430 }
01431
01432
01433 switch(frame->get_color_model())
01434 {
01435 case BC_RGB888:
01436 DRAW_PIXEL(x, y, 3, 0, 0xff, unsigned char);
01437 break;
01438 case BC_RGBA8888:
01439 DRAW_PIXEL(x, y, 4, 0, 0xff, unsigned char);
01440 break;
01441 case BC_RGB_FLOAT:
01442 DRAW_PIXEL(x, y, 3, 0, 1.0, float);
01443 break;
01444 case BC_RGBA_FLOAT:
01445 DRAW_PIXEL(x, y, 4, 0, 1.0, float);
01446 break;
01447 case BC_YUV888:
01448 DRAW_PIXEL(x, y, 3, 1, 0xff, unsigned char);
01449 break;
01450 case BC_YUVA8888:
01451 DRAW_PIXEL(x, y, 4, 1, 0xff, unsigned char);
01452 break;
01453 case BC_RGB161616:
01454 DRAW_PIXEL(x, y, 3, 0, 0xffff, uint16_t);
01455 break;
01456 case BC_YUV161616:
01457 DRAW_PIXEL(x, y, 3, 1, 0xffff, uint16_t);
01458 break;
01459 case BC_RGBA16161616:
01460 DRAW_PIXEL(x, y, 4, 0, 0xffff, uint16_t);
01461 break;
01462 case BC_YUVA16161616:
01463 DRAW_PIXEL(x, y, 4, 1, 0xffff, uint16_t);
01464 break;
01465 }
01466 }
01467
01468
01469 void MotionMain::draw_line(VFrame *frame, int x1, int y1, int x2, int y2)
01470 {
01471 int w = labs(x2 - x1);
01472 int h = labs(y2 - y1);
01473
01474
01475 if(!w && !h)
01476 {
01477 draw_pixel(frame, x1, y1);
01478 }
01479 else
01480 if(w > h)
01481 {
01482
01483 if(x2 < x1)
01484 {
01485 y2 ^= y1;
01486 y1 ^= y2;
01487 y2 ^= y1;
01488 x1 ^= x2;
01489 x2 ^= x1;
01490 x1 ^= x2;
01491 }
01492 int numerator = y2 - y1;
01493 int denominator = x2 - x1;
01494 for(int i = x1; i < x2; i++)
01495 {
01496 int y = y1 + (int64_t)(i - x1) * (int64_t)numerator / (int64_t)denominator;
01497 draw_pixel(frame, i, y);
01498 }
01499 }
01500 else
01501 {
01502
01503 if(y2 < y1)
01504 {
01505 y2 ^= y1;
01506 y1 ^= y2;
01507 y2 ^= y1;
01508 x1 ^= x2;
01509 x2 ^= x1;
01510 x1 ^= x2;
01511 }
01512 int numerator = x2 - x1;
01513 int denominator = y2 - y1;
01514 for(int i = y1; i < y2; i++)
01515 {
01516 int x = x1 + (int64_t)(i - y1) * (int64_t)numerator / (int64_t)denominator;
01517 draw_pixel(frame, x, i);
01518 }
01519 }
01520
01521 }
01522
01523 #define ARROW_SIZE 10
01524 void MotionMain::draw_arrow(VFrame *frame, int x1, int y1, int x2, int y2)
01525 {
01526 double angle = atan((float)(y2 - y1) / (float)(x2 - x1));
01527 double angle1 = angle + (float)145 / 360 * 2 * 3.14159265;
01528 double angle2 = angle - (float)145 / 360 * 2 * 3.14159265;
01529 int x3;
01530 int y3;
01531 int x4;
01532 int y4;
01533 if(x2 < x1)
01534 {
01535 x3 = x2 - (int)(ARROW_SIZE * cos(angle1));
01536 y3 = y2 - (int)(ARROW_SIZE * sin(angle1));
01537 x4 = x2 - (int)(ARROW_SIZE * cos(angle2));
01538 y4 = y2 - (int)(ARROW_SIZE * sin(angle2));
01539 }
01540 else
01541 {
01542 x3 = x2 + (int)(ARROW_SIZE * cos(angle1));
01543 y3 = y2 + (int)(ARROW_SIZE * sin(angle1));
01544 x4 = x2 + (int)(ARROW_SIZE * cos(angle2));
01545 y4 = y2 + (int)(ARROW_SIZE * sin(angle2));
01546 }
01547
01548
01549 draw_line(frame, x1, y1, x2, y2);
01550
01551
01552
01553 if(abs(y2 - y1) || abs(x2 - x1)) draw_line(frame, x2, y2, x3, y3);
01554
01555
01556 if(abs(y2 - y1) || abs(x2 - x1)) draw_line(frame, x2, y2, x4, y4);
01557
01558 }
01559
01560
01561
01562
01563 #define ABS_DIFF(type, temp_type, multiplier, components) \
01564 { \
01565 temp_type result_temp = 0; \
01566 for(int i = 0; i < h; i++) \
01567 { \
01568 type *prev_row = (type*)prev_ptr; \
01569 type *current_row = (type*)current_ptr; \
01570 for(int j = 0; j < w; j++) \
01571 { \
01572 for(int k = 0; k < 3; k++) \
01573 { \
01574 temp_type difference; \
01575 difference = *prev_row++ - *current_row++; \
01576 if(difference < 0) \
01577 result_temp -= difference; \
01578 else \
01579 result_temp += difference; \
01580 } \
01581 if(components == 4) \
01582 { \
01583 prev_row++; \
01584 current_row++; \
01585 } \
01586 } \
01587 prev_ptr += row_bytes; \
01588 current_ptr += row_bytes; \
01589 } \
01590 result = (int64_t)(result_temp * multiplier); \
01591 }
01592
01593 int64_t MotionMain::abs_diff(unsigned char *prev_ptr,
01594 unsigned char *current_ptr,
01595 int row_bytes,
01596 int w,
01597 int h,
01598 int color_model)
01599 {
01600 int64_t result = 0;
01601 switch(color_model)
01602 {
01603 case BC_RGB888:
01604 ABS_DIFF(unsigned char, int64_t, 1, 3)
01605 break;
01606 case BC_RGBA8888:
01607 ABS_DIFF(unsigned char, int64_t, 1, 4)
01608 break;
01609 case BC_RGB_FLOAT:
01610 ABS_DIFF(float, double, 0x10000, 3)
01611 break;
01612 case BC_RGBA_FLOAT:
01613 ABS_DIFF(float, double, 0x10000, 4)
01614 break;
01615 case BC_YUV888:
01616 ABS_DIFF(unsigned char, int64_t, 1, 3)
01617 break;
01618 case BC_YUVA8888:
01619 ABS_DIFF(unsigned char, int64_t, 1, 4)
01620 break;
01621 case BC_YUV161616:
01622 ABS_DIFF(uint16_t, int64_t, 1, 3)
01623 break;
01624 case BC_YUVA16161616:
01625 ABS_DIFF(uint16_t, int64_t, 1, 4)
01626 break;
01627 }
01628 return result;
01629 }
01630
01631
01632
01633 #define ABS_DIFF_SUB(type, temp_type, multiplier, components) \
01634 { \
01635 temp_type result_temp = 0; \
01636 temp_type y2_fraction = sub_y * 0x100 / OVERSAMPLE; \
01637 temp_type y1_fraction = 0x100 - y2_fraction; \
01638 temp_type x2_fraction = sub_x * 0x100 / OVERSAMPLE; \
01639 temp_type x1_fraction = 0x100 - x2_fraction; \
01640 for(int i = 0; i < h_sub; i++) \
01641 { \
01642 type *prev_row1 = (type*)prev_ptr; \
01643 type *prev_row2 = (type*)prev_ptr + components; \
01644 type *prev_row3 = (type*)(prev_ptr + row_bytes); \
01645 type *prev_row4 = (type*)(prev_ptr + row_bytes) + components; \
01646 type *current_row = (type*)current_ptr; \
01647 for(int j = 0; j < w_sub; j++) \
01648 { \
01649 for(int k = 0; k < 3; k++) \
01650 { \
01651 temp_type difference; \
01652 temp_type prev_value = \
01653 (*prev_row1++ * x1_fraction * y1_fraction + \
01654 *prev_row2++ * x2_fraction * y1_fraction + \
01655 *prev_row3++ * x1_fraction * y2_fraction + \
01656 *prev_row4++ * x2_fraction * y2_fraction) / \
01657 0x100 / 0x100; \
01658 temp_type current_value = *current_row++; \
01659 difference = prev_value - current_value; \
01660 if(difference < 0) \
01661 result_temp -= difference; \
01662 else \
01663 result_temp += difference; \
01664 } \
01665 \
01666 if(components == 4) \
01667 { \
01668 prev_row1++; \
01669 prev_row2++; \
01670 prev_row3++; \
01671 prev_row4++; \
01672 current_row++; \
01673 } \
01674 } \
01675 prev_ptr += row_bytes; \
01676 current_ptr += row_bytes; \
01677 } \
01678 result = (int64_t)(result_temp * multiplier); \
01679 }
01680
01681
01682
01683
01684 int64_t MotionMain::abs_diff_sub(unsigned char *prev_ptr,
01685 unsigned char *current_ptr,
01686 int row_bytes,
01687 int w,
01688 int h,
01689 int color_model,
01690 int sub_x,
01691 int sub_y)
01692 {
01693 int h_sub = h - 1;
01694 int w_sub = w - 1;
01695 int64_t result = 0;
01696
01697 switch(color_model)
01698 {
01699 case BC_RGB888:
01700 ABS_DIFF_SUB(unsigned char, int64_t, 1, 3)
01701 break;
01702 case BC_RGBA8888:
01703 ABS_DIFF_SUB(unsigned char, int64_t, 1, 4)
01704 break;
01705 case BC_RGB_FLOAT:
01706 ABS_DIFF_SUB(float, double, 0x10000, 3)
01707 break;
01708 case BC_RGBA_FLOAT:
01709 ABS_DIFF_SUB(float, double, 0x10000, 4)
01710 break;
01711 case BC_YUV888:
01712 ABS_DIFF_SUB(unsigned char, int64_t, 1, 3)
01713 break;
01714 case BC_YUVA8888:
01715 ABS_DIFF_SUB(unsigned char, int64_t, 1, 4)
01716 break;
01717 case BC_YUV161616:
01718 ABS_DIFF_SUB(uint16_t, int64_t, 1, 3)
01719 break;
01720 case BC_YUVA16161616:
01721 ABS_DIFF_SUB(uint16_t, int64_t, 1, 4)
01722 break;
01723 }
01724 return result;
01725 }
01726
01727
01728
01729
01730
01731 MotionScanPackage::MotionScanPackage()
01732 : LoadPackage()
01733 {
01734 valid = 1;
01735 }
01736
01737
01738
01739
01740
01741
01742 MotionScanUnit::MotionScanUnit(MotionScan *server,
01743 MotionMain *plugin)
01744 : LoadClient(server)
01745 {
01746 this->plugin = plugin;
01747 this->server = server;
01748 cache_lock = new Mutex("MotionScanUnit::cache_lock");
01749 }
01750
01751 MotionScanUnit::~MotionScanUnit()
01752 {
01753 delete cache_lock;
01754 }
01755
01756
01757
01758 void MotionScanUnit::process_package(LoadPackage *package)
01759 {
01760 MotionScanPackage *pkg = (MotionScanPackage*)package;
01761 int w = server->current_frame->get_w();
01762 int h = server->current_frame->get_h();
01763 int color_model = server->current_frame->get_color_model();
01764 int pixel_size = cmodel_calculate_pixelsize(color_model);
01765 int row_bytes = server->current_frame->get_bytes_per_line();
01766
01767
01768
01769
01770
01771
01772
01773
01774
01775
01776
01777
01778
01779 if(!server->subpixel)
01780 {
01781 int search_x = pkg->scan_x1 + (pkg->pixel % (pkg->scan_x2 - pkg->scan_x1));
01782 int search_y = pkg->scan_y1 + (pkg->pixel / (pkg->scan_x2 - pkg->scan_x1));
01783
01784
01785 pkg->difference1 = server->get_cache(search_x, search_y);
01786 if(pkg->difference1 < 0)
01787 {
01788
01789
01790
01791 unsigned char *prev_ptr = server->previous_frame->get_rows()[
01792 search_y] +
01793 search_x * pixel_size;
01794 unsigned char *current_ptr = server->current_frame->get_rows()[
01795 pkg->block_y1] +
01796 pkg->block_x1 * pixel_size;
01797
01798 pkg->difference1 = plugin->abs_diff(prev_ptr,
01799 current_ptr,
01800 row_bytes,
01801 pkg->block_x2 - pkg->block_x1,
01802 pkg->block_y2 - pkg->block_y1,
01803 color_model);
01804
01805 server->put_cache(search_x, search_y, pkg->difference1);
01806 }
01807 }
01808
01809
01810
01811
01812
01813
01814
01815 else
01816
01817
01818
01819
01820
01821
01822
01823
01824
01825 {
01826 int sub_x = pkg->pixel % (OVERSAMPLE * 2 - 1) + 1;
01827 int sub_y = pkg->pixel / (OVERSAMPLE * 2 - 1) + 1;
01828
01829 if(plugin->config.horizontal_only)
01830 {
01831 sub_y = 0;
01832 }
01833
01834 if(plugin->config.vertical_only)
01835 {
01836 sub_x = 0;
01837 }
01838
01839 int search_x = pkg->scan_x1 + sub_x / OVERSAMPLE;
01840 int search_y = pkg->scan_y1 + sub_y / OVERSAMPLE;
01841 sub_x %= OVERSAMPLE;
01842 sub_y %= OVERSAMPLE;
01843
01844
01845 unsigned char *prev_ptr = server->previous_frame->get_rows()[
01846 search_y] +
01847 search_x * pixel_size;
01848 unsigned char *current_ptr = server->current_frame->get_rows()[
01849 pkg->block_y1] +
01850 pkg->block_x1 * pixel_size;
01851
01852
01853
01854 pkg->difference1 = plugin->abs_diff_sub(prev_ptr,
01855 current_ptr,
01856 row_bytes,
01857 pkg->block_x2 - pkg->block_x1,
01858 pkg->block_y2 - pkg->block_y1,
01859 color_model,
01860 sub_x,
01861 sub_y);
01862 pkg->difference2 = plugin->abs_diff_sub(current_ptr,
01863 prev_ptr,
01864 row_bytes,
01865 pkg->block_x2 - pkg->block_x1,
01866 pkg->block_y2 - pkg->block_y1,
01867 color_model,
01868 sub_x,
01869 sub_y);
01870
01871
01872
01873
01874
01875
01876
01877 }
01878
01879
01880
01881
01882 }
01883
01884
01885
01886
01887
01888
01889
01890
01891
01892
01893 int64_t MotionScanUnit::get_cache(int x, int y)
01894 {
01895 int64_t result = -1;
01896 cache_lock->lock("MotionScanUnit::get_cache");
01897 for(int i = 0; i < cache.total; i++)
01898 {
01899 MotionScanCache *ptr = cache.values[i];
01900 if(ptr->x == x && ptr->y == y)
01901 {
01902 result = ptr->difference;
01903 break;
01904 }
01905 }
01906 cache_lock->unlock();
01907 return result;
01908 }
01909
01910 void MotionScanUnit::put_cache(int x, int y, int64_t difference)
01911 {
01912 MotionScanCache *ptr = new MotionScanCache(x, y, difference);
01913 cache_lock->lock("MotionScanUnit::put_cache");
01914 cache.append(ptr);
01915 cache_lock->unlock();
01916 }
01917
01918
01919
01920
01921
01922
01923
01924
01925
01926
01927
01928 MotionScan::MotionScan(MotionMain *plugin,
01929 int total_clients,
01930 int total_packages)
01931 : LoadServer(
01932
01933 total_clients, total_packages
01934 )
01935 {
01936 this->plugin = plugin;
01937 cache_lock = new Mutex("MotionScan::cache_lock");
01938 }
01939
01940 MotionScan::~MotionScan()
01941 {
01942 delete cache_lock;
01943 }
01944
01945
01946 void MotionScan::init_packages()
01947 {
01948
01949 for(int i = 0; i < get_total_packages(); i++)
01950 {
01951 MotionScanPackage *pkg = (MotionScanPackage*)get_package(i);
01952
01953 pkg->block_x1 = block_x1;
01954 pkg->block_x2 = block_x2;
01955 pkg->block_y1 = block_y1;
01956 pkg->block_y2 = block_y2;
01957 pkg->scan_x1 = scan_x1;
01958 pkg->scan_x2 = scan_x2;
01959 pkg->scan_y1 = scan_y1;
01960 pkg->scan_y2 = scan_y2;
01961 pkg->pixel = (int64_t)i * (int64_t)total_pixels / (int64_t)total_steps;
01962 pkg->difference1 = 0;
01963 pkg->difference2 = 0;
01964 pkg->dx = 0;
01965 pkg->dy = 0;
01966 pkg->valid = 1;
01967 }
01968 }
01969
01970 LoadClient* MotionScan::new_client()
01971 {
01972 return new MotionScanUnit(this, plugin);
01973 }
01974
01975 LoadPackage* MotionScan::new_package()
01976 {
01977 return new MotionScanPackage;
01978 }
01979
01980
01981 void MotionScan::scan_frame(VFrame *previous_frame,
01982 VFrame *current_frame)
01983 {
01984 this->previous_frame = previous_frame;
01985 this->current_frame = current_frame;
01986 subpixel = 0;
01987
01988 cache.remove_all_objects();
01989
01990
01991
01992 int w = current_frame->get_w();
01993 int h = current_frame->get_h();
01994
01995
01996 int scan_w = w * plugin->config.global_range_w / 100;
01997 int scan_h = h * plugin->config.global_range_h / 100;
01998 int block_w = w * plugin->config.global_block_w / 100;
01999 int block_h = h * plugin->config.global_block_h / 100;
02000
02001
02002 block_x1 = (int)(w * plugin->config.block_x / 100 - block_w / 2);
02003 block_y1 = (int)(h * plugin->config.block_y / 100 - block_h / 2);
02004 block_x2 = (int)(w * plugin->config.block_x / 100 + block_w / 2);
02005 block_y2 = (int)(h * plugin->config.block_y / 100 + block_h / 2);
02006
02007
02008
02009 if(plugin->config.mode3 == MotionConfig::TRACK_PREVIOUS)
02010 {
02011 block_x1 += plugin->total_dx / OVERSAMPLE;
02012 block_y1 += plugin->total_dy / OVERSAMPLE;
02013 block_x2 += plugin->total_dx / OVERSAMPLE;
02014 block_y2 += plugin->total_dy / OVERSAMPLE;
02015 }
02016
02017 skip = 0;
02018
02019 switch(plugin->config.mode2)
02020 {
02021
02022 case MotionConfig::NO_CALCULATE:
02023 dx_result = 0;
02024 dy_result = 0;
02025 skip = 1;
02026 break;
02027
02028 case MotionConfig::LOAD:
02029 {
02030
02031 char string[BCTEXTLEN];
02032 sprintf(string, "%s%06d", MOTION_FILE, plugin->get_source_position());
02033 FILE *input = fopen(string, "r");
02034 if(input)
02035 {
02036 fscanf(input,
02037 "%d %d",
02038 &dx_result,
02039 &dy_result);
02040 fclose(input);
02041 skip = 1;
02042 }
02043 break;
02044 }
02045
02046
02047 default:
02048 skip = 0;
02049 break;
02050 }
02051
02052
02053 if(!skip)
02054 {
02055
02056 int x_result = block_x1;
02057 int y_result = block_y1;
02058
02059
02060
02061
02062
02063
02064
02065
02066
02067
02068
02069 while(1)
02070 {
02071 scan_x1 = x_result - scan_w / 2;
02072 scan_y1 = y_result - scan_h / 2;
02073 scan_x2 = x_result + scan_w / 2;
02074 scan_y2 = y_result + scan_h / 2;
02075
02076
02077
02078
02079 if(plugin->config.horizontal_only)
02080 {
02081 scan_y1 = block_y1;
02082 scan_y2 = block_y1 + 1;
02083 }
02084 if(plugin->config.vertical_only)
02085 {
02086 scan_x1 = block_x1;
02087 scan_x2 = block_x1 + 1;
02088 }
02089
02090
02091
02092
02093
02094
02095
02096
02097
02098
02099
02100 MotionMain::clamp_scan(w,
02101 h,
02102 &block_x1,
02103 &block_y1,
02104 &block_x2,
02105 &block_y2,
02106 &scan_x1,
02107 &scan_y1,
02108 &scan_x2,
02109 &scan_y2,
02110 0);
02111
02112
02113
02114
02115
02116
02117
02118
02119
02120
02121
02122
02123
02124
02125 if(scan_y2 <= scan_y1 ||
02126 scan_x2 <= scan_x1 ||
02127 block_x2 <= block_x1 ||
02128 block_y2 <= block_y1)
02129 break;
02130
02131
02132 if(subpixel)
02133 {
02134 if(plugin->config.horizontal_only ||
02135 plugin->config.vertical_only)
02136 {
02137 total_pixels = 4 * OVERSAMPLE * OVERSAMPLE - 4 * OVERSAMPLE;
02138 }
02139 else
02140 {
02141 total_pixels = 4 * OVERSAMPLE;
02142 }
02143
02144 total_steps = total_pixels;
02145
02146 set_package_count(total_steps);
02147 process_packages();
02148
02149
02150 int64_t min_difference = -1;
02151 for(int i = 0; i < get_total_packages(); i++)
02152 {
02153 MotionScanPackage *pkg = (MotionScanPackage*)get_package(i);
02154 if(pkg->difference1 < min_difference || min_difference == -1)
02155 {
02156 min_difference = pkg->difference1;
02157
02158 if(plugin->config.vertical_only)
02159 x_result = scan_x1 * OVERSAMPLE;
02160 else
02161 x_result = scan_x1 * OVERSAMPLE +
02162 (pkg->pixel % (OVERSAMPLE * 2 - 1)) + 1;
02163
02164 if(plugin->config.horizontal_only)
02165 y_result = scan_y1 * OVERSAMPLE;
02166 else
02167 y_result = scan_y1 * OVERSAMPLE +
02168 (pkg->pixel / (OVERSAMPLE * 2 - 1)) + 1;
02169
02170
02171
02172 dx_result = block_x1 * OVERSAMPLE - x_result;
02173 dy_result = block_y1 * OVERSAMPLE - y_result;
02174 }
02175
02176 if(pkg->difference2 < min_difference)
02177 {
02178 min_difference = pkg->difference2;
02179
02180 if(plugin->config.vertical_only)
02181 x_result = scan_x1 * OVERSAMPLE;
02182 else
02183 x_result = scan_x2 * OVERSAMPLE -
02184 ((pkg->pixel % (OVERSAMPLE * 2 - 1)) + 1);
02185
02186 if(plugin->config.horizontal_only)
02187 y_result = scan_y1 * OVERSAMPLE;
02188 else
02189 y_result = scan_y2 * OVERSAMPLE -
02190 ((pkg->pixel / (OVERSAMPLE * 2 - 1)) + 1);
02191
02192 dx_result = block_x1 * OVERSAMPLE - x_result;
02193 dy_result = block_y1 * OVERSAMPLE - y_result;
02194 }
02195 }
02196
02197
02198 break;
02199 }
02200 else
02201 {
02202 total_pixels = (scan_x2 - scan_x1) * (scan_y2 - scan_y1);
02203 total_steps = MIN(plugin->config.global_positions, total_pixels);
02204
02205 set_package_count(total_steps);
02206 process_packages();
02207
02208
02209 int64_t min_difference = -1;
02210 for(int i = 0; i < get_total_packages(); i++)
02211 {
02212 MotionScanPackage *pkg = (MotionScanPackage*)get_package(i);
02213 if(pkg->difference1 < min_difference || min_difference == -1)
02214 {
02215 min_difference = pkg->difference1;
02216 x_result = scan_x1 + (pkg->pixel % (scan_x2 - scan_x1));
02217 y_result = scan_y1 + (pkg->pixel / (scan_x2 - scan_x1));
02218 x_result *= OVERSAMPLE;
02219 y_result *= OVERSAMPLE;
02220 }
02221 }
02222
02223
02224
02225
02226
02227
02228
02229
02230
02231
02232
02233
02234
02235
02236
02237
02238
02239
02240
02241
02242
02243
02244
02245
02246 if(total_steps >= total_pixels)
02247 {
02248
02249 if(plugin->config.mode1 == MotionConfig::STABILIZE ||
02250 plugin->config.mode1 == MotionConfig::TRACK ||
02251 plugin->config.mode1 == MotionConfig::NOTHING)
02252 {
02253 x_result /= OVERSAMPLE;
02254 y_result /= OVERSAMPLE;
02255 scan_w = 2;
02256 scan_h = 2;
02257 subpixel = 1;
02258 }
02259 else
02260 {
02261
02262 dx_result = block_x1 * OVERSAMPLE - x_result;
02263 dy_result = block_y1 * OVERSAMPLE - y_result;
02264 break;
02265 }
02266 }
02267 else
02268
02269 {
02270 scan_w = (scan_x2 - scan_x1) / 2;
02271 scan_h = (scan_y2 - scan_y1) / 2;
02272 x_result /= OVERSAMPLE;
02273 y_result /= OVERSAMPLE;
02274 }
02275 }
02276 }
02277
02278 dx_result *= -1;
02279 dy_result *= -1;
02280
02281
02282 if (plugin->config.addtrackedframeoffset) {
02283 int tf_dx_result, tf_dy_result;
02284 char string[BCTEXTLEN];
02285 sprintf(string, "%s%06d", MOTION_FILE, plugin->config.track_frame);
02286 FILE *input = fopen(string, "r");
02287 if(input)
02288 {
02289 fscanf(input,
02290 "%d %d",
02291 &tf_dx_result,
02292 &tf_dy_result);
02293 dx_result += tf_dx_result;
02294 dy_result += tf_dy_result;
02295 fclose(input);
02296 }
02297 }
02298
02299 }
02300
02301
02302
02303
02304
02305
02306
02307 if(plugin->config.mode2 == MotionConfig::SAVE)
02308 {
02309 char string[BCTEXTLEN];
02310 sprintf(string,
02311 "%s%06d",
02312 MOTION_FILE,
02313 plugin->get_source_position());
02314 FILE *output = fopen(string, "w");
02315 if(output)
02316 {
02317 fprintf(output,
02318 "%d %d\n",
02319 dx_result,
02320 dy_result);
02321 fclose(output);
02322 }
02323 else
02324 {
02325 perror("MotionScan::scan_frame SAVE 1");
02326 }
02327 }
02328
02329 #ifdef DEBUG
02330 printf("MotionScan::scan_frame 10 dx=%.2f dy=%.2f\n",
02331 (float)this->dx_result / OVERSAMPLE,
02332 (float)this->dy_result / OVERSAMPLE);
02333 #endif
02334 }
02335
02336
02337
02338
02339
02340
02341
02342
02343
02344
02345
02346
02347
02348
02349
02350
02351
02352 int64_t MotionScan::get_cache(int x, int y)
02353 {
02354 int64_t result = -1;
02355 cache_lock->lock("MotionScan::get_cache");
02356 for(int i = 0; i < cache.total; i++)
02357 {
02358 MotionScanCache *ptr = cache.values[i];
02359 if(ptr->x == x && ptr->y == y)
02360 {
02361 result = ptr->difference;
02362 break;
02363 }
02364 }
02365 cache_lock->unlock();
02366 return result;
02367 }
02368
02369 void MotionScan::put_cache(int x, int y, int64_t difference)
02370 {
02371 MotionScanCache *ptr = new MotionScanCache(x, y, difference);
02372 cache_lock->lock("MotionScan::put_cache");
02373 cache.append(ptr);
02374 cache_lock->unlock();
02375 }
02376
02377
02378
02379
02380
02381 MotionScanCache::MotionScanCache(int x, int y, int64_t difference)
02382 {
02383 this->x = x;
02384 this->y = y;
02385 this->difference = difference;
02386 }
02387
02388
02389
02390
02391
02392
02393
02394
02395
02396
02397
02398
02399
02400
02401 RotateScanPackage::RotateScanPackage()
02402 {
02403 }
02404
02405
02406 RotateScanUnit::RotateScanUnit(RotateScan *server, MotionMain *plugin)
02407 : LoadClient(server)
02408 {
02409 this->server = server;
02410 this->plugin = plugin;
02411 rotater = 0;
02412 temp = 0;
02413 }
02414
02415 RotateScanUnit::~RotateScanUnit()
02416 {
02417 delete rotater;
02418 delete temp;
02419 }
02420
02421 void RotateScanUnit::process_package(LoadPackage *package)
02422 {
02423 if(server->skip) return;
02424 RotateScanPackage *pkg = (RotateScanPackage*)package;
02425
02426 if((pkg->difference = server->get_cache(pkg->angle)) < 0)
02427 {
02428
02429 int color_model = server->previous_frame->get_color_model();
02430 int pixel_size = cmodel_calculate_pixelsize(color_model);
02431 int row_bytes = server->previous_frame->get_bytes_per_line();
02432
02433 if(!rotater)
02434 rotater = new AffineEngine(1, 1);
02435 if(!temp) temp = new VFrame(0,
02436 server->previous_frame->get_w(),
02437 server->previous_frame->get_h(),
02438 color_model);
02439
02440
02441
02442 rotater->set_viewport(server->block_x1,
02443 server->block_y1,
02444 server->block_x2 - server->block_x1,
02445 server->block_y2 - server->block_y1);
02446 rotater->set_pivot(server->block_x, server->block_y);
02447
02448 rotater->rotate(temp,
02449 server->previous_frame,
02450 pkg->angle);
02451
02452
02453
02454
02455 pkg->difference = plugin->abs_diff(
02456 temp->get_rows()[server->scan_y] + server->scan_x * pixel_size,
02457 server->current_frame->get_rows()[server->scan_y] + server->scan_x * pixel_size,
02458 row_bytes,
02459 server->scan_w,
02460 server->scan_h,
02461 color_model);
02462 server->put_cache(pkg->angle, pkg->difference);
02463
02464
02465
02466
02467
02468
02469
02470
02471
02472
02473
02474
02475 }
02476 }
02477
02478
02479
02480
02481
02482
02483
02484
02485
02486
02487
02488
02489
02490
02491
02492
02493
02494
02495
02496
02497
02498
02499 RotateScan::RotateScan(MotionMain *plugin,
02500 int total_clients,
02501 int total_packages)
02502 : LoadServer(
02503
02504 total_clients, total_packages
02505 )
02506 {
02507 this->plugin = plugin;
02508 cache_lock = new Mutex("RotateScan::cache_lock");
02509 }
02510
02511
02512 RotateScan::~RotateScan()
02513 {
02514 delete cache_lock;
02515 }
02516
02517 void RotateScan::init_packages()
02518 {
02519 for(int i = 0; i < get_total_packages(); i++)
02520 {
02521 RotateScanPackage *pkg = (RotateScanPackage*)get_package(i);
02522 pkg->angle = i *
02523 (scan_angle2 - scan_angle1) /
02524 (total_steps - 1) +
02525 scan_angle1;
02526 }
02527 }
02528
02529 LoadClient* RotateScan::new_client()
02530 {
02531 return new RotateScanUnit(this, plugin);
02532 }
02533
02534 LoadPackage* RotateScan::new_package()
02535 {
02536 return new RotateScanPackage;
02537 }
02538
02539
02540 float RotateScan::scan_frame(VFrame *previous_frame,
02541 VFrame *current_frame,
02542 int block_x,
02543 int block_y)
02544 {
02545 skip = 0;
02546 this->block_x = block_x;
02547 this->block_y = block_y;
02548
02549 switch(plugin->config.mode2)
02550 {
02551 case MotionConfig::NO_CALCULATE:
02552 result = 0;
02553 skip = 1;
02554 break;
02555
02556 case MotionConfig::LOAD:
02557 {
02558 char string[BCTEXTLEN];
02559 sprintf(string, "%s%06d", ROTATION_FILE, plugin->get_source_position());
02560 FILE *input = fopen(string, "r");
02561 if(input)
02562 {
02563 fscanf(input, "%f", &result);
02564 fclose(input);
02565 skip = 1;
02566 }
02567 else
02568 {
02569 perror("RotateScan::scan_frame LOAD");
02570 }
02571 break;
02572 }
02573 }
02574
02575
02576
02577
02578
02579
02580
02581
02582 this->previous_frame = previous_frame;
02583 this->current_frame = current_frame;
02584 int w = current_frame->get_w();
02585 int h = current_frame->get_h();
02586 int block_w = w * plugin->config.rotation_block_w / 100;
02587 int block_h = h * plugin->config.rotation_block_h / 100;
02588
02589 if(this->block_x - block_w / 2 < 0) block_w = this->block_x * 2;
02590 if(this->block_y - block_h / 2 < 0) block_h = this->block_y * 2;
02591 if(this->block_x + block_w / 2 > w) block_w = (w - this->block_x) * 2;
02592 if(this->block_y + block_h / 2 > h) block_h = (h - this->block_y) * 2;
02593
02594 block_x1 = this->block_x - block_w / 2;
02595 block_x2 = this->block_x + block_w / 2;
02596 block_y1 = this->block_y - block_h / 2;
02597 block_y2 = this->block_y + block_h / 2;
02598
02599
02600
02601
02602
02603 double center_x = this->block_x;
02604 double center_y = this->block_y;
02605 double max_angle = plugin->config.rotation_range;
02606 double base_angle1 = atan((float)block_h / block_w);
02607 double base_angle2 = atan((float)block_w / block_h);
02608 double target_angle1 = base_angle1 + max_angle * 2 * M_PI / 360;
02609 double target_angle2 = base_angle2 + max_angle * 2 * M_PI / 360;
02610 double radius = sqrt(block_w * block_w + block_h * block_h) / 2;
02611 double x1 = center_x - cos(target_angle1) * radius;
02612 double y1 = center_y - sin(target_angle1) * radius;
02613 double x2 = center_x + sin(target_angle2) * radius;
02614 double y2 = center_y - cos(target_angle2) * radius;
02615 double x3 = center_x - sin(target_angle2) * radius;
02616 double y3 = center_y + cos(target_angle2) * radius;
02617
02618
02619 double max_area1 = 0;
02620 double max_x1 = 0;
02621 double max_y1 = 0;
02622 for(double x = x1; x < x2; x++)
02623 {
02624 double y = y1 + (y2 - y1) * (x - x1) / (x2 - x1);
02625 if(x >= center_x && x < block_x2 && y >= block_y1 && y < center_y)
02626 {
02627 double area = fabs(x - center_x) * fabs(y - center_y);
02628 if(area > max_area1)
02629 {
02630 max_area1 = area;
02631 max_x1 = x;
02632 max_y1 = y;
02633 }
02634 }
02635 }
02636
02637
02638 double max_area2 = 0;
02639 double max_x2 = 0;
02640 double max_y2 = 0;
02641 for(double y = y1; y < y3; y++)
02642 {
02643 double x = x1 + (x3 - x1) * (y - y1) / (y3 - y1);
02644 if(x >= block_x1 && x < center_x && y >= block_y1 && y < center_y)
02645 {
02646 double area = fabs(x - center_x) * fabs(y - center_y);
02647 if(area > max_area2)
02648 {
02649 max_area2 = area;
02650 max_x2 = x;
02651 max_y2 = y;
02652 }
02653 }
02654 }
02655
02656 double max_x, max_y;
02657 max_x = max_x2;
02658 max_y = max_y1;
02659
02660
02661 scan_w = (int)(fabs(max_x - center_x) * 2);
02662 scan_h = (int)(fabs(max_y - center_y) * 2);
02663 scan_x = (int)(center_x - scan_w / 2);
02664 scan_y = (int)(center_y - scan_h / 2);
02665
02666
02667
02668
02669
02670 double angle1 = atan((double)block_h / block_w);
02671 double angle2 = atan((double)(block_h - 1) / (block_w + 1));
02672 double min_angle = fabs(angle2 - angle1) / OVERSAMPLE;
02673 min_angle = MAX(min_angle, MIN_ANGLE);
02674
02675 #ifdef DEBUG
02676 printf("RotateScan::scan_frame min_angle=%f\n", min_angle * 360 / 2 / M_PI);
02677 #endif
02678
02679 cache.remove_all_objects();
02680 if(!skip)
02681 {
02682
02683 float angle_range = (float)plugin->config.rotation_range;
02684 result = 0;
02685 total_steps = plugin->config.rotate_positions;
02686
02687
02688 while(angle_range >= min_angle * total_steps)
02689 {
02690 scan_angle1 = result - angle_range;
02691 scan_angle2 = result + angle_range;
02692
02693
02694 set_package_count(total_steps);
02695
02696 process_packages();
02697
02698 int64_t min_difference = -1;
02699 for(int i = 0; i < get_total_packages(); i++)
02700 {
02701 RotateScanPackage *pkg = (RotateScanPackage*)get_package(i);
02702 if(pkg->difference < min_difference || min_difference == -1)
02703 {
02704 min_difference = pkg->difference;
02705 result = pkg->angle;
02706 }
02707
02708 }
02709
02710 angle_range /= 2;
02711
02712
02713 }
02714 }
02715
02716
02717 if(!skip && plugin->config.mode2 == MotionConfig::SAVE)
02718 {
02719 char string[BCTEXTLEN];
02720 sprintf(string,
02721 "%s%06d",
02722 ROTATION_FILE,
02723 plugin->get_source_position());
02724 FILE *output = fopen(string, "w");
02725 if(output)
02726 {
02727 fprintf(output, "%f\n", result);
02728 fclose(output);
02729 }
02730 else
02731 {
02732 perror("RotateScan::scan_frame SAVE");
02733 }
02734 }
02735
02736 #ifdef DEBUG
02737 printf("RotateScan::scan_frame 10 angle=%f\n", result);
02738 #endif
02739
02740
02741
02742 return result;
02743 }
02744
02745 int64_t RotateScan::get_cache(float angle)
02746 {
02747 int64_t result = -1;
02748 cache_lock->lock("RotateScan::get_cache");
02749 for(int i = 0; i < cache.total; i++)
02750 {
02751 RotateScanCache *ptr = cache.values[i];
02752 if(fabs(ptr->angle - angle) <= MIN_ANGLE)
02753 {
02754 result = ptr->difference;
02755 break;
02756 }
02757 }
02758 cache_lock->unlock();
02759 return result;
02760 }
02761
02762 void RotateScan::put_cache(float angle, int64_t difference)
02763 {
02764 RotateScanCache *ptr = new RotateScanCache(angle, difference);
02765 cache_lock->lock("RotateScan::put_cache");
02766 cache.append(ptr);
02767 cache_lock->unlock();
02768 }
02769
02770
02771
02772
02773
02774
02775
02776
02777
02778 RotateScanCache::RotateScanCache(float angle, int64_t difference)
02779 {
02780 this->angle = angle;
02781 this->difference = difference;
02782 }
02783
02784
02785