4 * Copyright (C) 2016 Adam Williams <broadcast at earthling dot net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "../motion-hv/motionscan-hv.h"
24 #include "bcdisplayinfo.h"
25 #include "bcsignals.h"
32 #include "motionwindow.h"
34 #include "overlayframe.h"
35 #include "rotateframe.h"
36 #include "transportque.h"
42 REGISTER_PLUGIN(MotionMain2)
51 MotionConfig::MotionConfig()
53 for(int i = 0; i < TOTAL_POINTS; i++)
56 global_range_w[i] = 5;
57 global_range_h[i] = 5;
58 global_origin_x[i] = 0;
59 global_origin_y[i] = 0;
60 global_block_w[i] = MIN_BLOCK;
61 global_block_h[i] = MIN_BLOCK;
67 global_positions = 256;
70 action = MotionScan::STABILIZE;
71 calculation = MotionScan::NO_CALCULATE;
72 tracking_object = MotionScan::TRACK_SINGLE;
79 void MotionConfig::boundaries()
81 for(int i = 0; i < TOTAL_POINTS; i++)
83 CLAMP(global_range_w[i], MIN_RADIUS, MAX_RADIUS);
84 CLAMP(global_range_h[i], MIN_RADIUS, MAX_RADIUS);
85 CLAMP(global_origin_x[i], MIN_ORIGIN, MAX_ORIGIN);
86 CLAMP(global_origin_y[i], MIN_ORIGIN, MAX_ORIGIN);
87 CLAMP(global_block_w[i], MIN_BLOCK, MAX_BLOCK);
88 CLAMP(global_block_h[i], MIN_BLOCK, MAX_BLOCK);
93 int MotionConfig::equivalent(MotionConfig &that)
96 for(int i = 0; i < TOTAL_POINTS; i++)
98 if(global[i] != that.global[i] ||
99 global_range_w[i] != that.global_range_w[i] ||
100 global_range_h[i] != that.global_range_h[i] ||
101 draw_vectors[i] != that.draw_vectors[i] ||
102 global_block_w[i] != that.global_block_w[i] ||
103 global_block_h[i] != that.global_block_h[i] ||
104 global_origin_x[i] != that.global_origin_x[i] ||
105 global_origin_y[i] != that.global_origin_y[i] ||
106 !EQUIV(block_x[i], that.block_x[i]) ||
107 !EQUIV(block_y[i], that.block_y[i]))
111 if(magnitude != that.magnitude ||
112 return_speed != that.return_speed ||
113 action != that.action ||
114 calculation != that.calculation ||
115 tracking_object != that.tracking_object ||
116 track_frame != that.track_frame ||
117 bottom_is_master != that.bottom_is_master ||
118 horizontal_only != that.horizontal_only ||
119 vertical_only != that.vertical_only ||
120 global_positions != that.global_positions) result = 0;
125 void MotionConfig::copy_from(MotionConfig &that)
127 for(int i = 0; i < TOTAL_POINTS; i++)
129 global[i] = that.global[i];
130 global_range_w[i] = that.global_range_w[i];
131 global_range_h[i] = that.global_range_h[i];
132 global_origin_x[i] = that.global_origin_x[i];
133 global_origin_y[i] = that.global_origin_y[i];
134 draw_vectors[i] = that.draw_vectors[i];
135 block_x[i] = that.block_x[i];
136 block_y[i] = that.block_y[i];
137 global_block_w[i] = that.global_block_w[i];
138 global_block_h[i] = that.global_block_h[i];
141 global_positions = that.global_positions;
142 magnitude = that.magnitude;
143 return_speed = that.return_speed;
144 action = that.action;
145 calculation = that.calculation;
146 tracking_object = that.tracking_object;
147 track_frame = that.track_frame;
148 bottom_is_master = that.bottom_is_master;
149 horizontal_only = that.horizontal_only;
150 vertical_only = that.vertical_only;
153 void MotionConfig::interpolate(MotionConfig &prev,
157 int64_t current_frame)
159 //double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
160 //double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
162 for(int i = 0; i < TOTAL_POINTS; i++)
164 this->global[i] = prev.global[i];
165 this->block_x[i] = prev.block_x[i];
166 this->block_y[i] = prev.block_y[i];
167 this->global_range_w[i] = prev.global_range_w[i];
168 this->global_range_h[i] = prev.global_range_h[i];
169 this->global_origin_x[i] = prev.global_origin_x[i];
170 this->global_origin_y[i] = prev.global_origin_y[i];
171 this->draw_vectors[i] = prev.draw_vectors[i];
172 this->global_block_w[i] = prev.global_block_w[i];
173 this->global_block_h[i] = prev.global_block_h[i];
176 this->global_positions = prev.global_positions;
177 magnitude = prev.magnitude;
178 return_speed = prev.return_speed;
179 action = prev.action;
180 calculation = prev.calculation;
181 tracking_object = prev.tracking_object;
182 track_frame = prev.track_frame;
183 bottom_is_master = prev.bottom_is_master;
184 horizontal_only = prev.horizontal_only;
185 vertical_only = prev.vertical_only;
206 MotionMain2::MotionMain2(PluginServer *server)
207 : PluginVClient(server)
212 for(int i = 0; i < TOTAL_POINTS; i++)
221 previous_frame_number = -1;
224 current_global_ref = 0;
225 global_target_src = 0;
226 global_target_dst = 0;
229 MotionMain2::~MotionMain2()
235 delete [] search_area;
239 delete prev_global_ref;
240 delete current_global_ref;
241 delete global_target_src;
242 delete global_target_dst;
245 const char* MotionMain2::plugin_title() { return _("Motion 2 Point"); }
246 int MotionMain2::is_realtime() { return 1; }
247 int MotionMain2::is_multichannel() { return 1; }
250 NEW_WINDOW_MACRO(MotionMain2, MotionWindow)
252 LOAD_CONFIGURATION_MACRO(MotionMain2, MotionConfig)
256 void MotionMain2::update_gui()
260 if(load_configuration())
262 thread->window->lock_window("MotionMain2::update_gui");
264 char string[BCTEXTLEN];
266 for(int i = 0; i < TOTAL_POINTS; i++)
268 ((MotionWindow*)thread->window)->global[i]->update(config.global[i]);
270 ((MotionWindow*)thread->window)->global_block_w[i]->update(config.global_block_w[i]);
271 ((MotionWindow*)thread->window)->global_block_h[i]->update(config.global_block_h[i]);
272 ((MotionWindow*)thread->window)->global_origin_x[i]->update(config.global_origin_x[i]);
273 ((MotionWindow*)thread->window)->global_origin_y[i]->update(config.global_origin_y[i]);
274 ((MotionWindow*)thread->window)->block_x[i]->update(config.block_x[i]);
275 ((MotionWindow*)thread->window)->block_y[i]->update(config.block_y[i]);
276 ((MotionWindow*)thread->window)->block_x_text[i]->update((float)config.block_x[i]);
277 ((MotionWindow*)thread->window)->block_y_text[i]->update((float)config.block_y[i]);
278 ((MotionWindow*)thread->window)->vectors[i]->update(config.draw_vectors[i]);
281 sprintf(string, "%d", config.global_positions);
282 ((MotionWindow*)thread->window)->global_search_positions->set_text(string);
283 ((MotionWindow*)thread->window)->magnitude->update(config.magnitude);
284 ((MotionWindow*)thread->window)->return_speed->update(config.return_speed);
287 ((MotionWindow*)thread->window)->track_single->update(config.tracking_object == MotionScan::TRACK_SINGLE);
288 ((MotionWindow*)thread->window)->track_frame_number->update(config.track_frame);
289 ((MotionWindow*)thread->window)->track_previous->update(config.tracking_object == MotionScan::TRACK_PREVIOUS);
290 ((MotionWindow*)thread->window)->previous_same->update(config.tracking_object == MotionScan::PREVIOUS_SAME_BLOCK);
291 if(config.tracking_object != MotionScan::TRACK_SINGLE)
292 ((MotionWindow*)thread->window)->track_frame_number->disable();
294 ((MotionWindow*)thread->window)->track_frame_number->enable();
296 ((MotionWindow*)thread->window)->action->set_text(
297 Action::to_text(config.action));
298 ((MotionWindow*)thread->window)->calculation->set_text(
299 Calculation::to_text(config.calculation));
300 ((MotionWindow*)thread->window)->tracking_direction->set_text(
301 TrackingDirection::to_text(config.horizontal_only, config.vertical_only));
302 ((MotionWindow*)thread->window)->master_layer->set_text(
303 MasterLayer::to_text(config.bottom_is_master));
306 ((MotionWindow*)thread->window)->update_mode();
307 thread->window->unlock_window();
316 void MotionMain2::save_data(KeyFrame *keyframe)
320 // cause data to be stored directly in text
321 output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
322 output.tag.set_title("MOTION2");
324 char string[BCTEXTLEN];
325 for(int i = 0; i < TOTAL_POINTS; i++)
327 sprintf(string, "GLOBAL%d", i);
328 output.tag.set_property(string, config.global[i]);
329 sprintf(string, "GLOBAL_BLOCK_W%d", i);
330 output.tag.set_property(string, config.global_block_w[i]);
331 sprintf(string, "GLOBAL_BLOCK_H%d", i);
332 output.tag.set_property(string, config.global_block_h[i]);
333 sprintf(string, "BLOCK_X%d", i);
334 output.tag.set_property(string, config.block_x[i]);
335 sprintf(string, "BLOCK_Y%d", i);
336 output.tag.set_property(string, config.block_y[i]);
337 sprintf(string, "GLOBAL_RANGE_W%d", i);
338 output.tag.set_property(string, config.global_range_w[i]);
339 sprintf(string, "GLOBAL_RANGE_H%d", i);
340 output.tag.set_property(string, config.global_range_h[i]);
341 sprintf(string, "GLOBAL_ORIGIN_X%d", i);
342 output.tag.set_property(string, config.global_origin_x[i]);
343 sprintf(string, "GLOBAL_ORIGIN_Y%d", i);
344 output.tag.set_property(string, config.global_origin_y[i]);
345 sprintf(string, "DRAW_VECTORS%d", i);
346 output.tag.set_property(string, config.draw_vectors[i]);
349 output.tag.set_property("GLOBAL_POSITIONS", config.global_positions);
350 output.tag.set_property("MAGNITUDE", config.magnitude);
351 output.tag.set_property("RETURN_SPEED", config.return_speed);
352 output.tag.set_property("ACTION_TYPE", config.action);
353 output.tag.set_property("TRACKING_TYPE", config.calculation);
354 output.tag.set_property("TRACKING_OBJECT", config.tracking_object);
355 output.tag.set_property("TRACK_FRAME", config.track_frame);
356 output.tag.set_property("BOTTOM_IS_MASTER", config.bottom_is_master);
357 output.tag.set_property("HORIZONTAL_ONLY", config.horizontal_only);
358 output.tag.set_property("VERTICAL_ONLY", config.vertical_only);
360 output.tag.set_title("/MOTION2");
362 output.append_newline();
363 output.terminate_string();
366 void MotionMain2::read_data(KeyFrame *keyframe)
370 input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
376 result = input.read_tag();
380 if(input.tag.title_is("MOTION2"))
382 char string[BCTEXTLEN];
383 for(int i = 0; i < TOTAL_POINTS; i++)
385 sprintf(string, "GLOBAL%d", i);
386 config.global[i] = input.tag.get_property(string, config.global[i]);
387 sprintf(string, "GLOBAL_BLOCK_W%d", i);
388 config.global_block_w[i] = input.tag.get_property(string, config.global_block_w[i]);
389 sprintf(string, "GLOBAL_BLOCK_H%d", i);
390 config.global_block_h[i] = input.tag.get_property(string, config.global_block_h[i]);
391 sprintf(string, "BLOCK_X%d", i);
392 config.block_x[i] = input.tag.get_property(string, config.block_x[i]);
393 sprintf(string, "BLOCK_Y%d", i);
394 config.block_y[i] = input.tag.get_property(string, config.block_y[i]);
395 sprintf(string, "GLOBAL_RANGE_W%d", i);
396 config.global_range_w[i] = input.tag.get_property(string, config.global_range_w[i]);
397 sprintf(string, "GLOBAL_RANGE_H%d", i);
398 config.global_range_h[i] = input.tag.get_property(string, config.global_range_h[i]);
399 sprintf(string, "GLOBAL_ORIGIN_X%d", i);
400 config.global_origin_x[i] = input.tag.get_property(string, config.global_origin_x[i]);
401 sprintf(string, "GLOBAL_ORIGIN_Y%d", i);
402 config.global_origin_y[i] = input.tag.get_property(string, config.global_origin_y[i]);
403 sprintf(string, "DRAW_VECTORS%d", i);
404 config.draw_vectors[i] = input.tag.get_property(string, config.draw_vectors[i]);
407 config.global_positions = input.tag.get_property("GLOBAL_POSITIONS", config.global_positions);
408 config.magnitude = input.tag.get_property("MAGNITUDE", config.magnitude);
409 config.return_speed = input.tag.get_property("RETURN_SPEED", config.return_speed);
410 config.action = input.tag.get_property("ACTION_TYPE", config.action);
411 config.calculation = input.tag.get_property("TRACKING_TYPE", config.calculation);
412 config.tracking_object = input.tag.get_property("TRACKING_OBJECT", config.tracking_object);
413 config.track_frame = input.tag.get_property("TRACK_FRAME", config.track_frame);
414 config.bottom_is_master = input.tag.get_property("BOTTOM_IS_MASTER", config.bottom_is_master);
415 config.horizontal_only = input.tag.get_property("HORIZONTAL_ONLY", config.horizontal_only);
416 config.vertical_only = input.tag.get_property("VERTICAL_ONLY", config.vertical_only);
431 void MotionMain2::allocate_temp(int w, int h, int color_model)
434 (temp_frame->get_w() != w ||
435 temp_frame->get_h() != h))
441 temp_frame = new VFrame(w, h, color_model, 0);
446 void MotionMain2::scan_motion(int point)
448 int w = current_global_ref->get_w();
449 int h = current_global_ref->get_h();
452 if(!engine) engine = new MotionScan(PluginClient::get_project_smp() + 1,
453 PluginClient::get_project_smp() + 1);
455 // Get the current motion vector between the previous and current frame
456 engine->scan_frame(current_global_ref,
458 config.global_range_w[point] * w / 100,
459 config.global_range_h[point] * h / 100,
460 config.global_block_w[point] * w / 100,
461 config.global_block_h[point] * h / 100,
462 config.block_x[point] * w / 100,
463 config.block_y[point] * h / 100,
464 config.tracking_object,
467 config.horizontal_only,
468 config.vertical_only,
469 get_source_position(),
472 config.global_origin_x[point] * w / 100,
473 config.global_origin_y[point] * h / 100,
479 current_dx[point] = engine->dx_result;
480 current_dy[point] = engine->dy_result;
482 // Add current motion vector to accumulation vector.
483 if(config.tracking_object != MotionScan::TRACK_SINGLE)
486 total_dx[point] = (int64_t)total_dx[point] * (100 - config.return_speed) / 100;
487 total_dy[point] = (int64_t)total_dy[point] * (100 - config.return_speed) / 100;
488 total_dx[point] += engine->dx_result;
489 total_dy[point] += engine->dy_result;
492 // Make accumulation vector current
494 total_dx[point] = engine->dx_result;
495 total_dy[point] = engine->dy_result;
496 // printf("MotionMain2::scan_motion %d %d %d %d\n",
503 // Clamp accumulation vector
504 if(config.magnitude < 100)
506 //int block_w = (int64_t)config.global_block_w[point] *
507 // current_global_ref->get_w() / 100;
508 //int block_h = (int64_t)config.global_block_h[point] *
509 // current_global_ref->get_h() / 100;
510 int block_x_orig = (int64_t)(config.block_x[point] *
511 current_global_ref->get_w() /
513 int block_y_orig = (int64_t)(config.block_y[point] *
514 current_global_ref->get_h() /
517 int max_block_x = (int64_t)(current_global_ref->get_w() - block_x_orig) *
521 int max_block_y = (int64_t)(current_global_ref->get_h() - block_y_orig) *
525 int min_block_x = (int64_t)-block_x_orig *
529 int min_block_y = (int64_t)-block_y_orig *
534 CLAMP(total_dx[point], min_block_x, max_block_x);
535 CLAMP(total_dy[point], min_block_y, max_block_y);
538 // printf("MotionMain2::scan_motion %d %d %d %d\n",
550 void MotionMain2::apply_motion()
552 if(config.tracking_object != MotionScan::TRACK_SINGLE)
554 // Transfer current reference frame to previous reference frame and update
556 prev_global_ref->copy_from(current_global_ref);
557 previous_frame_number = get_source_position();
560 // Decide what to do with target based on requested operation
561 //int interpolation; // variable set but not used
562 float origin_x[TOTAL_POINTS];
563 float origin_y[TOTAL_POINTS];
564 float end_x[TOTAL_POINTS];
565 float end_y[TOTAL_POINTS];
566 for(int i = 0; i < TOTAL_POINTS; i++)
568 get_current_vector(&origin_x[i],
577 // Calculate rotation if 2 points
581 if(config.global[ROTATION_POINT])
583 if(origin_x[1] - origin_x[0])
584 angle0 = atan((double)(origin_y[0] - origin_y[1]) /
585 (double)(origin_x[0] - origin_x[1]));
586 if(end_x[1] - end_x[0])
587 angle = atan((double)(end_y[0] - end_y[1]) /
588 (double)(end_x[0] - end_x[1]));
589 // printf("MotionMain2::apply_motion %d angle0=%f angle=%f\n",
591 // angle0 * 360 / 2 / M_PI,
592 // angle * 360 / 2 / M_PI);
597 // zoom = DISTANCE(origin_x[1], origin_y[1], origin_x[0], origin_y[0]) /
598 // DISTANCE(end_x[1], end_y[1], end_x[0], end_y[0]);
602 printf("MotionMain2::apply_motion %d total_dx=%.02f total_dy=%.02f angle=%f zoom=%f\n",
604 (float)total_dx[TRANSLATION_POINT] / OVERSAMPLE,
605 (float)total_dy[TRANSLATION_POINT] / OVERSAMPLE,
606 angle * 360 / 2 / M_PI,
609 // Calculate translation
612 switch(config.action)
614 case MotionScan::NOTHING:
615 global_target_dst->copy_from(global_target_src);
617 case MotionScan::TRACK:
618 //interpolation = CUBIC_LINEAR;
619 dx = (float)total_dx[0] / OVERSAMPLE;
620 dy = (float)total_dy[0] / OVERSAMPLE;
622 case MotionScan::TRACK_PIXEL:
623 //interpolation = NEAREST_NEIGHBOR;
624 dx = (int)(total_dx[0] / OVERSAMPLE);
625 dy = (int)(total_dy[0] / OVERSAMPLE);
627 //interpolation = NEAREST_NEIGHBOR;
628 dx = -(int)(total_dx[0] / OVERSAMPLE);
629 dy = -(int)(total_dy[0] / OVERSAMPLE);
632 case MotionScan::STABILIZE:
633 //interpolation = CUBIC_LINEAR;
634 dx = -(float)total_dx[0] / OVERSAMPLE;
635 dy = -(float)total_dy[0] / OVERSAMPLE;
644 if(config.action != MotionScan::NOTHING)
646 double w = get_output()->get_w();
647 double h = get_output()->get_h();
648 double pivot_x = end_x[0];
649 double pivot_y = end_y[0];
650 double angle1 = atan((double)pivot_y / (double)pivot_x) + angle;
651 double angle2 = atan((double)(w - pivot_x) / (double)pivot_y) + angle;
652 double angle3 = atan((double)(h - pivot_y) / (double)(w - pivot_x)) + angle;
653 double angle4 = atan((double)pivot_x / (double)(h - pivot_y)) + angle;
654 double radius1 = DISTANCE(0, 0, pivot_x, pivot_y) * zoom;
655 double radius2 = DISTANCE(w, 0, pivot_x, pivot_y) * zoom;
656 double radius3 = DISTANCE(w, h, pivot_x, pivot_y) * zoom;
657 double radius4 = DISTANCE(0, h, pivot_x, pivot_y) * zoom;
660 float x1 = (dx + pivot_x - cos(angle1) * radius1) * 100 / w;
661 float y1 = (dy + pivot_y - sin(angle1) * radius1) * 100 / h;
662 float x2 = (dx + pivot_x + sin(angle2) * radius2) * 100 / w;
663 float y2 = (dy + pivot_y - cos(angle2) * radius2) * 100 / h;
664 float x3 = (dx + pivot_x + cos(angle3) * radius3) * 100 / w;
665 float y3 = (dy + pivot_y + sin(angle3) * radius3) * 100 / h;
666 float x4 = (dx + pivot_x - sin(angle4) * radius4) * 100 / w;
667 float y4 = (dy + pivot_y + cos(angle4) * radius4) * 100 / h;
671 affine = new AffineEngine(PluginClient::get_project_smp() + 1,
672 PluginClient::get_project_smp() + 1);
673 global_target_dst->clear_frame();
676 // printf("MotionMain2::apply_motion %d %.02f %.02f %.02f %.02f %.02f %.02f %.02f %.02f\n",
687 affine->process(global_target_dst,
690 AffineEngine::PERSPECTIVE,
708 int MotionMain2::process_buffer(VFrame **frame,
709 int64_t start_position,
712 int need_reconfigure = load_configuration();
713 int color_model = frame[0]->get_color_model();
714 w = frame[0]->get_w();
715 h = frame[0]->get_h();
719 printf("MotionMain2::process_buffer 1 start_position=%jd\n", start_position);
723 // Calculate the source and destination pointers for each of the operations.
724 // Get the layer to track motion in.
725 reference_layer = config.bottom_is_master ?
726 PluginClient::total_in_buffers - 1 :
728 // Get the layer to apply motion in.
729 target_layer = config.bottom_is_master ?
731 PluginClient::total_in_buffers - 1;
734 output_frame = frame[target_layer];
737 // Get the position of previous reference frame.
738 int64_t actual_previous_number;
739 // Skip if match frame not available
740 int skip_current = 0;
743 if(config.tracking_object == MotionScan::TRACK_SINGLE)
745 actual_previous_number = config.track_frame;
746 if(get_direction() == PLAY_REVERSE)
747 actual_previous_number++;
748 if(actual_previous_number == start_position)
753 actual_previous_number = start_position;
754 if(get_direction() == PLAY_FORWARD)
756 actual_previous_number--;
757 if(actual_previous_number < get_source_start())
761 KeyFrame *keyframe = get_prev_keyframe(start_position, 1);
762 if(keyframe->position > 0 &&
763 actual_previous_number < keyframe->position)
769 actual_previous_number++;
770 if(actual_previous_number >= get_source_start() + get_total_len())
774 KeyFrame *keyframe = get_next_keyframe(start_position, 1);
775 if(keyframe->position > 0 &&
776 actual_previous_number >= keyframe->position)
781 // Only count motion since last keyframe
787 // Point 0 must be tracked for any other points to be tracked
788 // Action and Calculation must be something
789 if( !config.global[0] || ( config.action == MotionScan::NOTHING &&
790 config.calculation == MotionScan::NO_CALCULATE) )
794 // printf("process_buffer %d %lld %lld %d\n",
796 // previous_frame_number,
797 // actual_previous_number,
798 // need_reconfigure);
799 // Load match frame and reset vectors
800 int need_reload = !skip_current &&
801 (previous_frame_number != actual_previous_number ||
805 for(int i = 0; i < TOTAL_POINTS; i++)
810 previous_frame_number = actual_previous_number;
816 for(int i = 0; i < TOTAL_POINTS; i++)
828 // Get the global pointers. Here we walk through the sequence of events.
831 // Global reads previous frame and compares
832 // with current frame to get the current translation.
833 // The center of the search area is fixed in compensate mode or
834 // the user value + the accumulation vector in track mode.
836 prev_global_ref = new VFrame(w, h, color_model, 0);
837 if(!current_global_ref)
838 current_global_ref = new VFrame(w, h, color_model, 0);
840 // Global loads the current target frame into the src and
841 // writes it to the dst frame with desired translation.
842 if(!global_target_src)
843 global_target_src = new VFrame(w, h, color_model, 0);
844 if(!global_target_dst)
845 global_target_dst = new VFrame(w, h, color_model, 0);
848 // Load the global frames
851 read_frame(prev_global_ref,
853 previous_frame_number,
858 read_frame(current_global_ref,
863 read_frame(global_target_src,
879 // Get position change from previous frame to current frame
882 for(int i = 0; i < TOTAL_POINTS; i++)
883 if(config.global[i]) scan_motion(i);
892 //printf("MotionMain2::process_buffer 90 %d\n", skip_current);
894 // Transfer the relevant target frame to the output
897 frame[target_layer]->copy_from(global_target_dst);
900 // Read the target destination directly
902 read_frame(frame[target_layer],
909 if(config.draw_vectors)
911 for(int i = 0; i < TOTAL_POINTS; i++)
912 draw_vectors(frame[target_layer], i);
916 printf("MotionMain2::process_buffer 100 skip_current=%d\n", skip_current);
925 void MotionMain2::clamp_scan(int w,
937 // printf("MotionMain2::clamp_scan 1 w=%d h=%d block=%d %d %d %d scan=%d %d %d %d absolute=%d\n",
952 // scan is always out of range before block.
955 int difference = -*scan_x1;
956 *block_x1 += difference;
962 int difference = -*scan_y1;
963 *block_y1 += difference;
969 int difference = *scan_x2 - w;
970 *block_x2 -= difference;
971 *scan_x2 -= difference;
976 int difference = *scan_y2 - h;
977 *block_y2 -= difference;
978 *scan_y2 -= difference;
981 CLAMP(*scan_x1, 0, w);
982 CLAMP(*scan_y1, 0, h);
983 CLAMP(*scan_x2, 0, w);
984 CLAMP(*scan_y2, 0, h);
990 int difference = -*scan_x1;
991 *block_x1 += difference;
992 *scan_x2 += difference;
998 int difference = -*scan_y1;
999 *block_y1 += difference;
1000 *scan_y2 += difference;
1004 if(*scan_x2 - *block_x1 + *block_x2 > w)
1006 int difference = *scan_x2 - *block_x1 + *block_x2 - w;
1007 *block_x2 -= difference;
1010 if(*scan_y2 - *block_y1 + *block_y2 > h)
1012 int difference = *scan_y2 - *block_y1 + *block_y2 - h;
1013 *block_y2 -= difference;
1016 // CLAMP(*scan_x1, 0, w - (*block_x2 - *block_x1));
1017 // CLAMP(*scan_y1, 0, h - (*block_y2 - *block_y1));
1018 // CLAMP(*scan_x2, 0, w - (*block_x2 - *block_x1));
1019 // CLAMP(*scan_y2, 0, h - (*block_y2 - *block_y1));
1022 // Sanity checks which break the calculation but should never happen if the
1023 // center of the block is inside the frame.
1024 CLAMP(*block_x1, 0, w);
1025 CLAMP(*block_x2, 0, w);
1026 CLAMP(*block_y1, 0, h);
1027 CLAMP(*block_y2, 0, h);
1029 // printf("MotionMain2::clamp_scan 2 w=%d h=%d block=%d %d %d %d scan=%d %d %d %d absolute=%d\n",
1046 void MotionMain2::get_current_vector(float *origin_x,
1054 int w = get_output()->get_w();
1055 int h = get_output()->get_h();
1062 if(!origin_x) origin_x = &temp1;
1063 if(!origin_y) origin_y = &temp2;
1064 if(!current_x1) current_x1 = &temp3;
1065 if(!current_y1) current_y1 = &temp4;
1066 if(!current_x2) current_x2 = &temp5;
1067 if(!current_y2) current_y2 = &temp6;
1077 if(config.global[point])
1080 // Start of vector is center of previous block.
1081 // End of vector is total accumulation.
1082 if(config.tracking_object == MotionScan::TRACK_SINGLE)
1084 (*origin_x) = (*current_x1) = ((float)config.block_x[point] *
1087 (*origin_y) = (*current_y1) = ((float)config.block_y[point] *
1090 (*current_x2) = (*current_x1) + (float)total_dx[point] / OVERSAMPLE;
1091 (*current_y2) = (*current_y1) + (float)total_dy[point] / OVERSAMPLE;
1094 // Start of vector is center of previous block.
1095 // End of vector is current change.
1096 if(config.tracking_object == MotionScan::PREVIOUS_SAME_BLOCK)
1098 (*origin_x) = (*current_x1) = ((float)config.block_x[point] *
1101 (*origin_y) = (*current_y1) = ((float)config.block_y[point] *
1104 (*current_x2) = (*origin_x) + (float)current_dx[point] / OVERSAMPLE;
1105 (*current_y2) = (*origin_y) + (float)current_dy[point] / OVERSAMPLE;
1109 (*origin_x) = (float)config.block_x[point] *
1112 (*origin_y) = (float)config.block_y[point] *
1115 (*current_x1) = ((*origin_x) +
1116 (float)(total_dx[point] - current_dx[point]) /
1118 (*current_y1) = ((*origin_y) +
1119 (float)(total_dy[point] - current_dy[point]) /
1121 (*current_x2) = ((*origin_x) +
1122 (float)total_dx[point] /
1124 (*current_y2) = ((*origin_y) +
1125 (float)total_dy[point] /
1132 void MotionMain2::draw_vectors(VFrame *frame, int point)
1134 int w = frame->get_w();
1135 int h = frame->get_h();
1136 float global_x1, global_y1;
1137 float global_x2, global_y2;
1138 int block_x, block_y;
1139 int block_w, block_h;
1140 int block_x1, block_y1;
1141 int block_x2, block_y2;
1142 int search_w, search_h;
1143 int search_x1, search_y1;
1144 int search_x2, search_y2;
1145 int origin_offset_x;
1146 int origin_offset_y;
1148 if(!config.draw_vectors[point]) return;
1151 if(config.global[point])
1154 get_current_vector(0,
1163 // Draw destination rectangle
1164 if(config.action == MotionScan::NOTHING ||
1165 config.action == MotionScan::TRACK)
1167 block_x = (int)global_x2;
1168 block_y = (int)global_y2;
1171 // Draw source rectangle
1173 block_x = (int)global_x1;
1174 block_y = (int)global_y1;
1176 block_w = config.global_block_w[point] * w / 100;
1177 block_h = config.global_block_h[point] * h / 100;
1178 origin_offset_x = config.global_origin_x[point] * w / 100;
1179 origin_offset_y = config.global_origin_y[point] * h / 100;
1180 block_x1 = block_x - block_w / 2;
1181 block_y1 = block_y - block_h / 2;
1182 block_x2 = block_x + block_w / 2;
1183 block_y2 = block_y + block_h / 2;
1184 search_w = config.global_range_w[point] * w / 100;
1185 search_h = config.global_range_h[point] * h / 100;
1186 search_x1 = block_x1 + origin_offset_x - search_w / 2;
1187 search_y1 = block_y1 + origin_offset_y - search_h / 2;
1188 search_x2 = block_x2 + origin_offset_x + search_w / 2;
1189 search_y2 = block_y2 + origin_offset_y + search_h / 2;
1191 // printf("MotionMain2::draw_vectors %d %d %d %d %d %d %d %d %d %d %d %d\n",
1205 MotionScan::clamp_scan(w,
1218 draw_arrow(frame, (int)global_x1, (int)global_y1, (int)global_x2, (int)global_y2);
1221 draw_line(frame, block_x1, block_y1, block_x2, block_y1);
1222 draw_line(frame, block_x2, block_y1, block_x2, block_y2);
1223 draw_line(frame, block_x2, block_y2, block_x1, block_y2);
1224 draw_line(frame, block_x1, block_y2, block_x1, block_y1);
1228 draw_line(frame, search_x1, search_y1, search_x2, search_y1);
1229 draw_line(frame, search_x2, search_y1, search_x2, search_y2);
1230 draw_line(frame, search_x2, search_y2, search_x1, search_y2);
1231 draw_line(frame, search_x1, search_y2, search_x1, search_y1);
1237 void MotionMain2::draw_pixel(VFrame *frame, int x, int y)
1239 if(!(x >= 0 && y >= 0 && x < frame->get_w() && y < frame->get_h())) return;
1241 #define DRAW_PIXEL(x, y, components, do_yuv, max, type) \
1243 type **rows = (type**)frame->get_rows(); \
1244 rows[y][x * components] = max - rows[y][x * components]; \
1247 rows[y][x * components + 1] = max - rows[y][x * components + 1]; \
1248 rows[y][x * components + 2] = max - rows[y][x * components + 2]; \
1252 rows[y][x * components + 1] = (max / 2 + 1) - rows[y][x * components + 1]; \
1253 rows[y][x * components + 2] = (max / 2 + 1) - rows[y][x * components + 2]; \
1255 if(components == 4) \
1256 rows[y][x * components + 3] = max; \
1260 switch(frame->get_color_model())
1263 DRAW_PIXEL(x, y, 3, 0, 0xff, unsigned char);
1266 DRAW_PIXEL(x, y, 4, 0, 0xff, unsigned char);
1269 DRAW_PIXEL(x, y, 3, 0, 1.0, float);
1272 DRAW_PIXEL(x, y, 4, 0, 1.0, float);
1275 DRAW_PIXEL(x, y, 3, 1, 0xff, unsigned char);
1278 DRAW_PIXEL(x, y, 4, 1, 0xff, unsigned char);
1281 DRAW_PIXEL(x, y, 3, 0, 0xffff, uint16_t);
1284 DRAW_PIXEL(x, y, 3, 1, 0xffff, uint16_t);
1286 case BC_RGBA16161616:
1287 DRAW_PIXEL(x, y, 4, 0, 0xffff, uint16_t);
1289 case BC_YUVA16161616:
1290 DRAW_PIXEL(x, y, 4, 1, 0xffff, uint16_t);
1296 void MotionMain2::draw_line(VFrame *frame, int x1, int y1, int x2, int y2)
1298 int w = labs(x2 - x1);
1299 int h = labs(y2 - y1);
1300 //printf("MotionMain2::draw_line 1 %d %d %d %d\n", x1, y1, x2, y2);
1304 draw_pixel(frame, x1, y1);
1309 // Flip coordinates so x1 < x2
1319 int numerator = y2 - y1;
1320 int denominator = x2 - x1;
1321 for(int i = x1; i < x2; i++)
1323 int y = y1 + (int64_t)(i - x1) * (int64_t)numerator / (int64_t)denominator;
1324 draw_pixel(frame, i, y);
1329 // Flip coordinates so y1 < y2
1339 int numerator = x2 - x1;
1340 int denominator = y2 - y1;
1341 for(int i = y1; i < y2; i++)
1343 int x = x1 + (int64_t)(i - y1) * (int64_t)numerator / (int64_t)denominator;
1344 draw_pixel(frame, x, i);
1347 //printf("MotionMain2::draw_line 2\n");
1350 #define ARROW_SIZE 10
1351 void MotionMain2::draw_arrow(VFrame *frame, int x1, int y1, int x2, int y2)
1353 double angle = atan((float)(y2 - y1) / (float)(x2 - x1));
1354 double angle1 = angle + (float)145 / 360 * 2 * 3.14159265;
1355 double angle2 = angle - (float)145 / 360 * 2 * 3.14159265;
1362 x3 = x2 - (int)(ARROW_SIZE * cos(angle1));
1363 y3 = y2 - (int)(ARROW_SIZE * sin(angle1));
1364 x4 = x2 - (int)(ARROW_SIZE * cos(angle2));
1365 y4 = y2 - (int)(ARROW_SIZE * sin(angle2));
1369 x3 = x2 + (int)(ARROW_SIZE * cos(angle1));
1370 y3 = y2 + (int)(ARROW_SIZE * sin(angle1));
1371 x4 = x2 + (int)(ARROW_SIZE * cos(angle2));
1372 y4 = y2 + (int)(ARROW_SIZE * sin(angle2));
1376 draw_line(frame, x1, y1, x2, y2);
1377 // draw_line(frame, x1, y1 + 1, x2, y2 + 1);
1380 if(abs(y2 - y1) || abs(x2 - x1)) draw_line(frame, x2, y2, x3, y3);
1381 // draw_line(frame, x2, y2 + 1, x3, y3 + 1);
1383 if(abs(y2 - y1) || abs(x2 - x1)) draw_line(frame, x2, y2, x4, y4);
1384 // draw_line(frame, x2, y2 + 1, x4, y4 + 1);
1400 #define ABS_DIFF(type, temp_type, multiplier, components) \
1402 temp_type result_temp = 0; \
1403 for(int i = 0; i < h; i++) \
1405 type *prev_row = (type*)prev_ptr; \
1406 type *current_row = (type*)current_ptr; \
1407 for(int j = 0; j < w; j++) \
1409 for(int k = 0; k < 3; k++) \
1411 temp_type difference; \
1412 difference = *prev_row++ - *current_row++; \
1413 if(difference < 0) \
1414 result_temp -= difference; \
1416 result_temp += difference; \
1418 if(components == 4) \
1424 prev_ptr += row_bytes; \
1425 current_ptr += row_bytes; \
1427 result = (int64_t)(result_temp * multiplier); \
1430 int64_t MotionMain2::abs_diff(unsigned char *prev_ptr,
1431 unsigned char *current_ptr,
1441 ABS_DIFF(unsigned char, int64_t, 1, 3)
1444 ABS_DIFF(unsigned char, int64_t, 1, 4)
1447 ABS_DIFF(float, double, 0x10000, 3)
1450 ABS_DIFF(float, double, 0x10000, 4)
1453 ABS_DIFF(unsigned char, int64_t, 1, 3)
1456 ABS_DIFF(unsigned char, int64_t, 1, 4)
1459 ABS_DIFF(uint16_t, int64_t, 1, 3)
1461 case BC_YUVA16161616:
1462 ABS_DIFF(uint16_t, int64_t, 1, 4)
1470 #define ABS_DIFF_SUB(type, temp_type, multiplier, components) \
1472 temp_type result_temp = 0; \
1473 temp_type y2_fraction = sub_y * 0x100 / OVERSAMPLE; \
1474 temp_type y1_fraction = 0x100 - y2_fraction; \
1475 temp_type x2_fraction = sub_x * 0x100 / OVERSAMPLE; \
1476 temp_type x1_fraction = 0x100 - x2_fraction; \
1477 for(int i = 0; i < h_sub; i++) \
1479 type *prev_row1 = (type*)prev_ptr; \
1480 type *prev_row2 = (type*)prev_ptr + components; \
1481 type *prev_row3 = (type*)(prev_ptr + row_bytes); \
1482 type *prev_row4 = (type*)(prev_ptr + row_bytes) + components; \
1483 type *current_row = (type*)current_ptr; \
1484 for(int j = 0; j < w_sub; j++) \
1486 for(int k = 0; k < 3; k++) \
1488 temp_type difference; \
1489 temp_type prev_value = \
1490 (*prev_row1++ * x1_fraction * y1_fraction + \
1491 *prev_row2++ * x2_fraction * y1_fraction + \
1492 *prev_row3++ * x1_fraction * y2_fraction + \
1493 *prev_row4++ * x2_fraction * y2_fraction) / \
1495 temp_type current_value = *current_row++; \
1496 difference = prev_value - current_value; \
1497 if(difference < 0) \
1498 result_temp -= difference; \
1500 result_temp += difference; \
1503 if(components == 4) \
1512 prev_ptr += row_bytes; \
1513 current_ptr += row_bytes; \
1515 result = (int64_t)(result_temp * multiplier); \
1521 int64_t MotionMain2::abs_diff_sub(unsigned char *prev_ptr,
1522 unsigned char *current_ptr,
1537 ABS_DIFF_SUB(unsigned char, int64_t, 1, 3)
1540 ABS_DIFF_SUB(unsigned char, int64_t, 1, 4)
1543 ABS_DIFF_SUB(float, double, 0x10000, 3)
1546 ABS_DIFF_SUB(float, double, 0x10000, 4)
1549 ABS_DIFF_SUB(unsigned char, int64_t, 1, 3)
1552 ABS_DIFF_SUB(unsigned char, int64_t, 1, 4)
1555 ABS_DIFF_SUB(uint16_t, int64_t, 1, 3)
1557 case BC_YUVA16161616:
1558 ABS_DIFF_SUB(uint16_t, int64_t, 1, 4)
1568 MotionScanPackage::MotionScanPackage()
1579 MotionScanUnit::MotionScanUnit(MotionScan *server,
1580 MotionMain2 *plugin)
1581 : LoadClient(server)
1583 this->plugin = plugin;
1584 this->server = server;
1585 cache_lock = new Mutex("MotionScanUnit::cache_lock");
1588 MotionScanUnit::~MotionScanUnit()
1595 void MotionScanUnit::process_package(LoadPackage *package)
1597 MotionScanPackage *pkg = (MotionScanPackage*)package;
1598 int w = server->current_frame->get_w();
1599 int h = server->current_frame->get_h();
1600 int color_model = server->current_frame->get_color_model();
1601 int pixel_size = cmodel_calculate_pixelsize(color_model);
1602 int row_bytes = server->current_frame->get_bytes_per_line();
1617 if(!server->subpixel)
1619 int search_x = pkg->scan_x1 + (pkg->pixel % (pkg->scan_x2 - pkg->scan_x1));
1620 int search_y = pkg->scan_y1 + (pkg->pixel / (pkg->scan_x2 - pkg->scan_x1));
1623 pkg->difference1 = server->get_cache(search_x, search_y);
1624 if(pkg->difference1 < 0)
1626 //printf("MotionScanUnit::process_package 1 %d %d\n",
1627 //search_x, search_y, pkg->block_x2 - pkg->block_x1, pkg->block_y2 - pkg->block_y1);
1628 // Pointers to first pixel in each block
1629 unsigned char *prev_ptr = server->previous_frame->get_rows()[
1631 search_x * pixel_size;
1632 unsigned char *current_ptr = server->current_frame->get_rows()[
1634 pkg->block_x1 * pixel_size;
1636 pkg->difference1 = plugin->abs_diff(prev_ptr,
1639 pkg->block_x2 - pkg->block_x1,
1640 pkg->block_y2 - pkg->block_y1,
1642 //printf("MotionScanUnit::process_package 2\n");
1643 server->put_cache(search_x, search_y, pkg->difference1);
1664 int sub_x = pkg->pixel % (OVERSAMPLE * 2 - 1) + 1;
1665 int sub_y = pkg->pixel / (OVERSAMPLE * 2 - 1) + 1;
1667 if(plugin->config.horizontal_only)
1672 if(plugin->config.vertical_only)
1677 int search_x = pkg->scan_x1 + sub_x / OVERSAMPLE;
1678 int search_y = pkg->scan_y1 + sub_y / OVERSAMPLE;
1679 sub_x %= OVERSAMPLE;
1680 sub_y %= OVERSAMPLE;
1683 unsigned char *prev_ptr = server->previous_frame->get_rows()[
1685 search_x * pixel_size;
1686 unsigned char *current_ptr = server->current_frame->get_rows()[
1688 pkg->block_x1 * pixel_size;
1690 // With subpixel, there are two ways to compare each position, one by shifting
1691 // the previous frame and two by shifting the current frame.
1692 pkg->difference1 = plugin->abs_diff_sub(prev_ptr,
1695 pkg->block_x2 - pkg->block_x1,
1696 pkg->block_y2 - pkg->block_y1,
1700 pkg->difference2 = plugin->abs_diff_sub(current_ptr,
1703 pkg->block_x2 - pkg->block_x1,
1704 pkg->block_y2 - pkg->block_y1,
1708 // printf("MotionScanUnit::process_package sub_x=%d sub_y=%d search_x=%d search_y=%d diff1=%lld diff2=%lld\n",
1713 // pkg->difference1,
1714 // pkg->difference2);
1732 int64_t MotionScanUnit::get_cache(int x, int y)
1734 int64_t result = -1;
1735 cache_lock->lock("MotionScanUnit::get_cache");
1736 for(int i = 0; i < cache.total; i++)
1738 MotionScanCache *ptr = cache.values[i];
1739 if(ptr->x == x && ptr->y == y)
1741 result = ptr->difference;
1745 cache_lock->unlock();
1749 void MotionScanUnit::put_cache(int x, int y, int64_t difference)
1751 MotionScanCache *ptr = new MotionScanCache(x, y, difference);
1752 cache_lock->lock("MotionScanUnit::put_cache");
1754 cache_lock->unlock();
1767 MotionScan::MotionScan(MotionMain2 *plugin,
1772 total_clients, total_packages
1775 this->plugin = plugin;
1776 cache_lock = new Mutex("MotionScan::cache_lock");
1779 MotionScan::~MotionScan()
1785 void MotionScan::init_packages()
1787 // Set package coords
1788 for(int i = 0; i < get_total_packages(); i++)
1790 MotionScanPackage *pkg = (MotionScanPackage*)get_package(i);
1792 pkg->block_x1 = block_x1;
1793 pkg->block_x2 = block_x2;
1794 pkg->block_y1 = block_y1;
1795 pkg->block_y2 = block_y2;
1796 pkg->scan_x1 = scan_x1;
1797 pkg->scan_x2 = scan_x2;
1798 pkg->scan_y1 = scan_y1;
1799 pkg->scan_y2 = scan_y2;
1800 pkg->pixel = (int64_t)i * (int64_t)total_pixels / (int64_t)total_steps;
1801 pkg->difference1 = 0;
1802 pkg->difference2 = 0;
1809 LoadClient* MotionScan::new_client()
1811 return new MotionScanUnit(this, plugin);
1814 LoadPackage* MotionScan::new_package()
1816 return new MotionScanPackage;
1820 void MotionScan::scan_frame(VFrame *previous_frame,
1821 VFrame *current_frame,
1824 this->previous_frame = previous_frame;
1825 this->current_frame = current_frame;
1826 this->point = point;
1829 cache.remove_all_objects();
1832 // Single macroblock
1833 int w = current_frame->get_w();
1834 int h = current_frame->get_h();
1836 // Initial search parameters
1837 int scan_w = w * plugin->config.global_range_w[point] / 100;
1838 int scan_h = h * plugin->config.global_range_h[point] / 100;
1839 int block_w = w * plugin->config.global_block_w[point] / 100;
1840 int block_h = h * plugin->config.global_block_h[point] / 100;
1842 // Location of block in previous frame
1843 block_x1 = (int)(w * plugin->config.block_x[point] / 100 - block_w / 2);
1844 block_y1 = (int)(h * plugin->config.block_y[point] / 100 - block_h / 2);
1845 block_x2 = (int)(w * plugin->config.block_x[point] / 100 + block_w / 2);
1846 block_y2 = (int)(h * plugin->config.block_y[point] / 100 + block_h / 2);
1848 // Offset to location of previous block. This offset needn't be very accurate
1849 // since it's the offset of the previous image and current image we want.
1850 if(plugin->config.tracking_object == MotionScan::TRACK_PREVIOUS)
1852 block_x1 += plugin->total_dx[point] / OVERSAMPLE;
1853 block_y1 += plugin->total_dy[point] / OVERSAMPLE;
1854 block_x2 += plugin->total_dx[point] / OVERSAMPLE;
1855 block_y2 += plugin->total_dy[point] / OVERSAMPLE;
1860 switch(plugin->config.calculation)
1863 case MotionScan::NO_CALCULATE:
1869 case MotionScan::LOAD:
1871 printf("MotionScan::scan_frame %d\n", __LINE__);
1872 // Load result from disk
1873 char string[BCTEXTLEN];
1874 sprintf(string, "%s%06d",
1876 plugin->get_source_position());
1878 input = fopen(string, "r");
1881 for(int i = 0; i <= point; i++)
1894 // Scan from scratch
1903 printf("MotionScan::scan_frame %d\n", __LINE__);
1904 // Calculate center of search area in current frame
1905 int origin_offset_x = plugin->config.global_origin_x[point] * w / 100;
1906 int origin_offset_y = plugin->config.global_origin_y[point] * h / 100;
1907 int x_result = block_x1 + origin_offset_x;
1908 int y_result = block_y1 + origin_offset_y;
1910 // printf("MotionScan::scan_frame 1 %d %d %d %d %d %d %d %d\n",
1911 // block_x1 + block_w / 2,
1912 // block_y1 + block_h / 2,
1922 scan_x1 = x_result - scan_w / 2;
1923 scan_y1 = y_result - scan_h / 2;
1924 scan_x2 = x_result + scan_w / 2;
1925 scan_y2 = y_result + scan_h / 2;
1929 // Zero out requested values
1930 if(plugin->config.horizontal_only)
1933 scan_y2 = block_y1 + 1;
1935 if(plugin->config.vertical_only)
1938 scan_x2 = block_x1 + 1;
1941 // printf("MotionScan::scan_frame 1 %d %d %d %d %d %d %d %d\n",
1950 // Clamp the block coords before the scan so we get useful scan coords.
1951 MotionScan::clamp_scan(w,
1962 // printf("MotionScan::scan_frame 1\n block_x1=%d block_y1=%d block_x2=%d block_y2=%d\n scan_x1=%d scan_y1=%d scan_x2=%d scan_y2=%d\n x_result=%d y_result=%d\n",
1975 // Give up if invalid coords.
1976 if(scan_y2 <= scan_y1 ||
1977 scan_x2 <= scan_x1 ||
1978 block_x2 <= block_x1 ||
1979 block_y2 <= block_y1)
1983 // For subpixel, the top row and left column are skipped
1987 if(plugin->config.horizontal_only ||
1988 plugin->config.vertical_only)
1990 total_pixels = 4 * OVERSAMPLE * OVERSAMPLE - 4 * OVERSAMPLE;
1994 total_pixels = 4 * OVERSAMPLE;
1997 total_steps = total_pixels;
1999 set_package_count(total_steps);
2002 // Get least difference
2003 int64_t min_difference = -1;
2004 for(int i = 0; i < get_total_packages(); i++)
2006 MotionScanPackage *pkg = (MotionScanPackage*)get_package(i);
2007 if(pkg->difference1 < min_difference || min_difference == -1)
2009 min_difference = pkg->difference1;
2011 if(plugin->config.vertical_only)
2012 x_result = scan_x1 * OVERSAMPLE;
2014 x_result = scan_x1 * OVERSAMPLE +
2015 (pkg->pixel % (OVERSAMPLE * 2 - 1)) + 1;
2017 if(plugin->config.horizontal_only)
2018 y_result = scan_y1 * OVERSAMPLE;
2020 y_result = scan_y1 * OVERSAMPLE +
2021 (pkg->pixel / (OVERSAMPLE * 2 - 1)) + 1;
2025 dx_result = block_x1 * OVERSAMPLE - x_result;
2026 dy_result = block_y1 * OVERSAMPLE - y_result;
2029 if(pkg->difference2 < min_difference)
2031 min_difference = pkg->difference2;
2033 if(plugin->config.vertical_only)
2034 x_result = scan_x1 * OVERSAMPLE;
2036 x_result = scan_x2 * OVERSAMPLE -
2037 ((pkg->pixel % (OVERSAMPLE * 2 - 1)) + 1);
2039 if(plugin->config.horizontal_only)
2040 y_result = scan_y1 * OVERSAMPLE;
2042 y_result = scan_y2 * OVERSAMPLE -
2043 ((pkg->pixel / (OVERSAMPLE * 2 - 1)) + 1);
2045 dx_result = block_x1 * OVERSAMPLE - x_result;
2046 dy_result = block_y1 * OVERSAMPLE - y_result;
2051 //printf("MotionScan::scan_frame 1 %d %d %d %d\n", block_x1, block_y1, x_result, y_result);
2057 total_pixels = (scan_x2 - scan_x1) * (scan_y2 - scan_y1);
2058 total_steps = MIN(plugin->config.global_positions, total_pixels);
2060 set_package_count(total_steps);
2063 // Get least difference
2064 int64_t min_difference = -1;
2065 for(int i = 0; i < get_total_packages(); i++)
2067 MotionScanPackage *pkg = (MotionScanPackage*)get_package(i);
2068 if(pkg->difference1 < min_difference || min_difference == -1)
2070 min_difference = pkg->difference1;
2071 x_result = scan_x1 + (pkg->pixel % (scan_x2 - scan_x1));
2072 y_result = scan_y1 + (pkg->pixel / (scan_x2 - scan_x1));
2073 x_result *= OVERSAMPLE;
2074 y_result *= OVERSAMPLE;
2080 // printf("MotionScan::scan_frame 10 total_steps=%d total_pixels=%d subpixel=%d\n",
2085 // printf(" scan w=%d h=%d scan x1=%d y1=%d x2=%d y2=%d\n",
2093 // printf("MotionScan::scan_frame 2 block x1=%d y1=%d x2=%d y2=%d result x=%.2f y=%.2f\n",
2098 // (float)x_result / 4,
2099 // (float)y_result / 4);
2102 // If a new search is required, rescale results back to pixels.
2103 if(total_steps >= total_pixels)
2105 // Single pixel accuracy reached. Now do exhaustive subpixel search.
2106 if(plugin->config.action == MotionScan::STABILIZE ||
2107 plugin->config.action == MotionScan::TRACK ||
2108 plugin->config.action == MotionScan::NOTHING)
2110 x_result /= OVERSAMPLE;
2111 y_result /= OVERSAMPLE;
2118 // Fill in results and quit
2119 dx_result = block_x1 * OVERSAMPLE - x_result;
2120 dy_result = block_y1 * OVERSAMPLE - y_result;
2125 // Reduce scan area and try again
2127 scan_w = (scan_x2 - scan_x1) / 2;
2128 scan_h = (scan_y2 - scan_y1) / 2;
2129 x_result /= OVERSAMPLE;
2130 y_result /= OVERSAMPLE;
2145 if(plugin->config.calculation == MotionScan::SAVE)
2147 char string[BCTEXTLEN];
2151 plugin->get_source_position());
2154 output = fopen(string, "w");
2156 output = fopen(string, "a");
2167 perror("MotionScan::scan_frame SAVE 1");
2172 printf("MotionScan::scan_frame 10 point=%d dx=%.2f dy=%.2f\n",
2174 (float)this->dx_result / OVERSAMPLE,
2175 (float)this->dy_result / OVERSAMPLE);
2195 int64_t MotionScan::get_cache(int x, int y)
2197 int64_t result = -1;
2198 cache_lock->lock("MotionScan::get_cache");
2199 for(int i = 0; i < cache.total; i++)
2201 MotionScanCache *ptr = cache.values[i];
2202 if(ptr->x == x && ptr->y == y)
2204 result = ptr->difference;
2208 cache_lock->unlock();
2212 void MotionScan::put_cache(int x, int y, int64_t difference)
2214 MotionScanCache *ptr = new MotionScanCache(x, y, difference);
2215 cache_lock->lock("MotionScan::put_cache");
2217 cache_lock->unlock();
2224 MotionScanCache::MotionScanCache(int x, int y, int64_t difference)
2228 this->difference = difference;