4 * Copyright (C) 2012 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 "../downsample/downsampleengine.h"
25 #include "motionscan.h"
31 // The module which does the actual scanning
33 MotionScanPackage::MotionScanPackage()
39 MotionScanUnit::MotionScanUnit(MotionScan *server)
42 this->server = server;
43 cache_lock = new Mutex("MotionScanUnit::cache_lock");
46 MotionScanUnit::~MotionScanUnit()
51 void MotionScanUnit::process_package(LoadPackage *package)
53 MotionScanPackage *pkg = (MotionScanPackage*)package;
54 //int w = server->current_frame->get_w();
55 //int h = server->current_frame->get_h();
56 int color_model = server->current_frame->get_color_model();
57 int pixel_size = BC_CModels::calculate_pixelsize(color_model);
58 int row_bytes = server->current_frame->get_bytes_per_line();
61 if( !server->subpixel ) {
63 pkg->difference1 = server->get_cache(pkg->search_x, pkg->search_y);
64 if( pkg->difference1 < 0 ) {
65 //printf("MotionScanUnit::process_package 1 search_x=%d search_y=%d"
66 // " scan_x1=%d scan_y1=%d scan_x2=%d scan_y2=%d x_steps=%d y_steps=%d\n",
67 // pkg->search_x, pkg->search_y, pkg->scan_x1, pkg->scan_y1, pkg->scan_x2, pkg->scan_y2,
68 // server->x_steps, server->y_steps);
69 // Pointers to first pixel in each block
70 unsigned char *prev_ptr =
71 server->previous_frame->get_rows()[pkg->search_y] +
72 pkg->search_x * pixel_size;
73 unsigned char *current_ptr =
74 server->current_frame->get_rows()[pkg->block_y1] +
75 pkg->block_x1 * pixel_size;
77 pkg->difference1 = MotionScan::abs_diff(prev_ptr, current_ptr, row_bytes,
78 pkg->block_x2 - pkg->block_x1, pkg->block_y2 - pkg->block_y1,
81 // printf("MotionScanUnit::process_package %d search_x=%d search_y=%d diff=%lld\n",
82 // __LINE__, server->block_x1 - pkg->search_x, server->block_y1 - pkg->search_y, pkg->difference1);
83 server->put_cache(pkg->search_x, pkg->search_y, pkg->difference1);
88 unsigned char *prev_ptr =
89 server->previous_frame->get_rows()[pkg->search_y] +
90 pkg->search_x * pixel_size;
91 unsigned char *current_ptr =
92 server->current_frame->get_rows()[pkg->block_y1] +
93 pkg->block_x1 * pixel_size;
95 // With subpixel, there are two ways to compare each position, one by shifting
96 // the previous frame and two by shifting the current frame.
97 pkg->difference1 = MotionScan::abs_diff_sub(prev_ptr, current_ptr, row_bytes,
98 pkg->block_x2 - pkg->block_x1, pkg->block_y2 - pkg->block_y1,
99 color_model, pkg->sub_x, pkg->sub_y);
101 MotionScan::abs_diff_sub(current_ptr, prev_ptr, row_bytes,
102 pkg->block_x2 - pkg->block_x1, pkg->block_y2 - pkg->block_y1,
103 color_model, pkg->sub_x, pkg->sub_y);
104 //printf("MotionScanUnit::process_package sub_x=%d sub_y=%d search_x=%d search_y=%d diff1=%lld diff2=%lld\n",
105 // sub_x, sub_y, search_x, search_y, pkg->difference1, pkg->difference2);
109 int64_t MotionScanUnit::get_cache(int x, int y)
112 cache_lock->lock("MotionScanUnit::get_cache");
113 for( int i = 0; i < cache.total; i++ ) {
114 MotionScanCache *ptr = cache.values[i];
115 if( ptr->x == x && ptr->y == y ) {
116 result = ptr->difference;
120 cache_lock->unlock();
124 void MotionScanUnit::put_cache(int x, int y, int64_t difference)
126 MotionScanCache *ptr = new MotionScanCache(x, y, difference);
127 cache_lock->lock("MotionScanUnit::put_cache");
129 cache_lock->unlock();
132 MotionScan::MotionScan(int total_clients, int total_packages)
134 total_clients, total_packages)
137 cache_lock = new Mutex("MotionScan::cache_lock");
138 downsampled_previous = 0;
139 downsampled_current = 0;
143 MotionScan::~MotionScan()
146 delete downsampled_previous;
147 delete downsampled_current;
148 // delete downsample;
151 void MotionScan::init_packages()
153 // Set package coords
154 //printf("MotionScan::init_packages %d %d\n", __LINE__, get_total_packages());
155 for( int i = 0; i < get_total_packages(); i++ ) {
156 MotionScanPackage *pkg = (MotionScanPackage*)get_package(i);
158 pkg->block_x1 = block_x1; pkg->block_x2 = block_x2;
159 pkg->block_y1 = block_y1; pkg->block_y2 = block_y2;
160 pkg->scan_x1 = scan_x1; pkg->scan_x2 = scan_x2;
161 pkg->scan_y1 = scan_y1; pkg->scan_y2 = scan_y2;
162 pkg->difference1 = 0; pkg->difference2 = 0;
163 pkg->step = i; pkg->valid = 1;
164 pkg->dx = pkg->dy = 0;
167 pkg->search_x = pkg->scan_x1 +
168 (pkg->step % x_steps) * (scan_x2 - scan_x1) / x_steps;
169 pkg->search_y = pkg->scan_y1 +
170 (pkg->step / x_steps) * (scan_y2 - scan_y1) / y_steps;
171 pkg->sub_x = pkg->sub_y = 0;
174 pkg->sub_x = pkg->step % (OVERSAMPLE * 2);
175 pkg->sub_y = pkg->step / (OVERSAMPLE * 2);
177 if( horizontal_only ) pkg->sub_y = 0;
178 if( vertical_only ) pkg->sub_x = 0;
180 pkg->search_x = pkg->scan_x1 + pkg->sub_x / OVERSAMPLE + 1;
181 pkg->search_y = pkg->scan_y1 + pkg->sub_y / OVERSAMPLE + 1;
182 pkg->sub_x %= OVERSAMPLE;
183 pkg->sub_y %= OVERSAMPLE;
185 // printf("MotionScan::init_packages %d i=%d search_x=%d search_y=%d sub_x=%d sub_y=%d\n",
186 // __LINE__, i, pkg->search_x, pkg->search_y, pkg->sub_x, pkg->sub_y);
189 // printf("MotionScan::init_packages %d %d,%d %d,%d %d,%d\n",
190 // __LINE__, scan_x1, scan_x2, scan_y1, scan_y2, pkg->search_x, pkg->search_y);
194 LoadClient* MotionScan::new_client()
196 return new MotionScanUnit(this);
199 LoadPackage* MotionScan::new_package()
201 return new MotionScanPackage;
204 void MotionScan::set_test_match(int value)
206 this->test_match = value;
209 void MotionScan::scan_frame(VFrame *previous_frame, VFrame *current_frame,
210 int global_range_w, int global_range_h,
211 int global_block_w, int global_block_h,
212 double block_x, double block_y, int frame_type,
213 int tracking_type, int action_type,
214 int horizontal_only, int vertical_only,
215 int source_position, int total_steps, int total_dx,
216 int total_dy, int global_origin_x, int global_origin_y,
217 int load_ok, int load_dx, int load_dy)
219 this->previous_frame_arg = previous_frame;
220 this->current_frame_arg = current_frame;
221 this->horizontal_only = horizontal_only;
222 this->vertical_only = vertical_only;
223 this->previous_frame = previous_frame_arg;
224 this->current_frame = current_frame_arg;
225 this->global_origin_x = global_origin_x;
226 this->global_origin_y = global_origin_y;
229 cache.remove_all_objects();
232 int w = current_frame->get_w();
233 int h = current_frame->get_h();
235 // Initial search parameters
236 int scan_w = w * global_range_w / 100;
237 int scan_h = h * global_range_h / 100;
238 int block_w = w * global_block_w / 100;
239 int block_h = h * global_block_h / 100;
241 // Location of block in previous frame
242 block_x1 = (int)(w * block_x / 100 - block_w / 2);
243 block_y1 = (int)(h * block_y / 100 - block_h / 2);
244 block_x2 = (int)(w * block_x / 100 + block_w / 2);
245 block_y2 = (int)(h * block_y / 100 + block_h / 2);
247 // Offset to location of previous block. This offset needn't be very accurate
248 // since it's the offset of the previous image and current image we want.
249 if( frame_type == MotionScan::TRACK_PREVIOUS ) {
250 block_x1 += total_dx / OVERSAMPLE;
251 block_y1 += total_dy / OVERSAMPLE;
252 block_x2 += total_dx / OVERSAMPLE;
253 block_y2 += total_dy / OVERSAMPLE;
258 switch( tracking_type ) {
260 case MotionScan::NO_CALCULATE:
261 dx_result = dy_result = 0;
265 case MotionScan::LOAD:
266 case MotionScan::SAVE:
280 if( !skip && test_match ) {
281 if( previous_frame->data_matches(current_frame) ) {
282 printf("MotionScan::scan_frame: data matches. skipping.\n");
283 dx_result = dy_result = 0;
289 //printf("MotionScan::scan_frame %d\n", __LINE__);
290 // Location of block in current frame
291 int origin_offset_x = this->global_origin_x * w / 100;
292 int origin_offset_y = this->global_origin_y * h / 100;
293 int x_result = block_x1 + origin_offset_x;
294 int y_result = block_y1 + origin_offset_y;
296 //printf("MotionScan::scan_frame 1 %d %d %d %d %d %d %d %d\n",
297 // block_x1 + block_w / 2, block_y1 + block_h / 2,
298 // block_w, block_h, block_x1, block_y1, block_x2, block_y2);
301 // Cache needs to be cleared if downsampling is used because the sums of
302 // different downsamplings can't be compared.
303 // Subpixel never uses the cache.
304 // cache.remove_all_objects();
305 scan_x1 = x_result - scan_w / 2;
306 scan_y1 = y_result - scan_h / 2;
307 scan_x2 = x_result + scan_w / 2;
308 scan_y2 = y_result + scan_h / 2;
310 // Zero out requested values
311 if( horizontal_only ) {
313 scan_y2 = block_y1 + 1;
315 if( vertical_only ) {
317 scan_x2 = block_x1 + 1;
319 //printf("MotionScan::scan_frame 1 %d %d %d %d %d %d %d %d\n",
320 // block_x1, block_y1, block_x2, block_y2, scan_x1, scan_y1, scan_x2, scan_y2);
321 // Clamp the block coords before the scan so we get useful scan coords.
322 clamp_scan(w, h, &block_x1, &block_y1, &block_x2,
323 &block_y2, &scan_x1, &scan_y1, &scan_x2,
325 // printf("MotionScan::scan_frame 1 %d block_x1=%d block_y1=%d block_x2=%d block_y2=%d\n"
326 // " scan_x1=%d scan_y1=%d scan_x2=%d scan_y2=%d\n"
327 // " x_result=%d y_result=%d\n", __LINE__, block_x1, block_y1, block_x2, block_y2,
328 // scan_x1, scan_y1, scan_x2, scan_y2, x_result, y_result);
330 // Give up if invalid coords.
331 if (scan_y2 <= scan_y1 || scan_x2 <= scan_x1 ||
332 block_x2 <= block_x1 || block_y2 <= block_y1 )
335 // For subpixel, the top row and left column are skipped
338 //printf("MotionScan::scan_frame %d %d %d\n", __LINE__, x_result, y_result);
339 // Scan every subpixel in a 2 pixel * 2 pixel square
340 total_pixels = (2 * OVERSAMPLE) * (2 * OVERSAMPLE);
342 this->total_steps = total_pixels;
343 // These aren't used in subpixel
344 this->x_steps = OVERSAMPLE * 2;
345 this->y_steps = OVERSAMPLE * 2;
347 set_package_count(this->total_steps);
350 // Get least difference
351 int64_t min_difference = -1;
352 for( int i = 0; i < get_total_packages(); i++ ) {
353 MotionScanPackage *pkg = (MotionScanPackage *)get_package(i);
354 //printf("MotionScan::scan_frame %d search_x=%d search_y=%d sub_x=%d sub_y=%d diff1=%lld diff2=%lld\n",
355 //__LINE__, pkg->search_x, pkg->search_y, pkg->sub_x, pkg->sub_y, pkg->difference1, pkg->difference2);
356 if( pkg->difference1 < min_difference ||
357 min_difference == -1 ) {
358 min_difference = pkg->difference1;
360 // The sub coords are 1 pixel up & left of the block coords
361 x_result = pkg->search_x * OVERSAMPLE + pkg->sub_x;
362 y_result = pkg->search_y * OVERSAMPLE + pkg->sub_y;
364 dx_result = block_x1 * OVERSAMPLE - x_result;
365 dy_result = block_y1 * OVERSAMPLE - y_result;
366 //printf("MotionScan::scan_frame %d dx_result=%d dy_result=%d diff=%lld\n",
367 //__LINE__, dx_result, dy_result, min_difference);
370 if( pkg->difference2 < min_difference ) {
371 min_difference = pkg->difference2;
373 x_result = pkg->search_x * OVERSAMPLE - pkg->sub_x;
374 y_result = pkg->search_y * OVERSAMPLE - pkg->sub_y;
376 dx_result = block_x1 * OVERSAMPLE - x_result;
377 dy_result = block_y1 * OVERSAMPLE - y_result;
378 //printf("MotionScan::scan_frame %d dx_result=%d dy_result=%d diff=%lld\n",
379 //__LINE__, dx_result, dy_result, min_difference);
388 (scan_x2 - scan_x1) * (scan_y2 - scan_y1);
390 MIN(total_steps, total_pixels);
392 if( this->total_steps == total_pixels ) {
393 x_steps = scan_x2 - scan_x1;
394 y_steps = scan_y2 - scan_y1;
397 x_steps = (int)sqrt(this->total_steps);
398 y_steps = (int)sqrt(this->total_steps);
401 // Use downsampled images
402 // if( scan_x2 - scan_x1 > x_steps * 4 ||
403 // scan_y2 - scan_y1 > y_steps * 4 )
405 // printf("MotionScan::scan_frame %d total_pixels=%d total_steps=%d x_steps=%d y_steps=%d x y steps=%d\n",
411 // x_steps * y_steps);
413 // if( !downsampled_previous ||
414 // !downsampled_previous->equivalent(previous_frame_arg) )
416 // delete downsampled_previous;
417 // downsampled_previous = new VFrame(*previous_frame_arg);
420 // if( !downsampled_current ||
421 // !downsampled_current->equivalent(current_frame_arg) )
423 // delete downsampled_current;
424 // downsampled_current = new VFrame(*current_frame_arg);
429 // downsample = new DownSampleServer(get_total_clients(),
430 // get_total_clients());
431 // downsample->process_frame(downsampled_previous,
432 // previous_frame_arg, 1, 1, 1, 1,
433 // (scan_y2 - scan_y1) / y_steps,
434 // (scan_x2 - scan_x1) / x_steps,
436 // downsample->process_frame(downsampled_current,
437 // current_frame_arg, 1, 1, 1, 1,
438 // (scan_y2 - scan_y1) / y_steps,
439 // (scan_x2 - scan_x1) / x_steps,
441 // this->previous_frame = downsampled_previous;
442 // this->current_frame = downsampled_current;
445 // printf("MotionScan::scan_frame %d this->total_steps=%d\n",
446 // __LINE__, this->total_steps);
448 set_package_count(this->total_steps);
451 // Get least difference
452 int64_t min_difference = -1;
453 for( int i = 0; i < get_total_packages(); i++ ) {
454 MotionScanPackage *pkg = (MotionScanPackage *) get_package(i);
455 //printf("MotionScan::scan_frame %d search_x=%d search_y=%d sub_x=%d sub_y=%d diff1=%lld diff2=%lld\n",
456 // __LINE__, pkg->search_x, pkg->search_y, pkg->sub_x, pkg->sub_y, pkg->difference1, pkg->difference2);
457 if (pkg->difference1 < min_difference
458 || min_difference == -1) {
459 min_difference = pkg->difference1;
460 x_result = pkg->search_x;
461 y_result = pkg->search_y;
462 x_result *= OVERSAMPLE;
463 y_result *= OVERSAMPLE;
464 //printf("MotionScan::scan_frame %d x_result=%d y_result=%d diff=%lld\n",
465 //__LINE__, block_x1 * OVERSAMPLE - x_result, block_y1 * OVERSAMPLE - y_result, pkg->difference1);
469 // If a new search is required, rescale results back to pixels.
470 if( this->total_steps >= total_pixels ) {
471 // Single pixel accuracy reached. Now do exhaustive subpixel search.
472 if( action_type == MotionScan::STABILIZE ||
473 action_type == MotionScan::TRACK ||
474 action_type == MotionScan::NOTHING ) {
475 //printf("MotionScan::scan_frame %d %d %d\n", __LINE__, x_result, y_result);
476 x_result /= OVERSAMPLE;
477 y_result /= OVERSAMPLE;
481 // Fill in results and quit
483 dx_result = block_x1 * OVERSAMPLE - x_result;
484 dy_result = block_y1 * OVERSAMPLE - y_result;
485 //printf("MotionScan::scan_frame %d %d %d\n", __LINE__, dx_result, dy_result);
489 // Reduce scan area and try again
491 scan_w = (scan_x2 - scan_x1) / 2;
492 scan_h = (scan_y2 - scan_y1) / 2;
493 x_result /= OVERSAMPLE;
494 y_result /= OVERSAMPLE;
498 dx_result = -dx_result;
499 dy_result = -dy_result;
501 //printf("MotionScan::scan_frame %d\n", __LINE__);
503 if( vertical_only ) dx_result = 0;
504 if( horizontal_only ) dy_result = 0;
506 //printf("MotionScan::scan_frame %d dx=%.2f dy=%.2f\n",
507 // __LINE__, (float)this->dx_result / OVERSAMPLE, (float)this->dy_result / OVERSAMPLE);
510 int64_t MotionScan::get_cache(int x, int y)
513 cache_lock->lock("MotionScan::get_cache");
514 for( int i = 0; i < cache.total; i++ ) {
515 MotionScanCache *ptr = cache.values[i];
516 if( ptr->x == x && ptr->y == y ) {
517 result = ptr->difference;
521 cache_lock->unlock();
525 void MotionScan::put_cache(int x, int y, int64_t difference)
527 MotionScanCache *ptr = new MotionScanCache(x, y, difference);
528 cache_lock->lock("MotionScan::put_cache");
530 cache_lock->unlock();
533 #define ABS_DIFF(model, type, temp_type, multiplier, components) case model: { \
534 temp_type result_temp = 0; \
535 for( int i = 0; i < h; i++ ) { \
536 type *prev_row = (type*)prev_ptr; \
537 type *current_row = (type*)current_ptr; \
538 for( int j = 0; j < w; j++ ) { \
539 for( int k = 0; k < 3; k++ ) { \
540 temp_type difference; \
541 difference = *prev_row++ - *current_row++; \
542 if( difference < 0 ) \
543 result_temp -= difference; \
545 result_temp += difference; \
547 if( components == 4 ) { \
552 prev_ptr += row_bytes; \
553 current_ptr += row_bytes; \
555 result = (int64_t)(result_temp * multiplier); \
558 int64_t MotionScan::abs_diff(unsigned char *prev_ptr,
559 unsigned char *current_ptr, int row_bytes, int w,
560 int h, int color_model)
563 switch( color_model ) {
564 ABS_DIFF(BC_RGB888, unsigned char, int64_t, 1, 3);
565 ABS_DIFF(BC_RGBA8888, unsigned char, int64_t, 1, 4);
566 ABS_DIFF(BC_RGB_FLOAT, float, double, 0x10000, 3);
567 ABS_DIFF(BC_RGBA_FLOAT, float, double, 0x10000, 4);
568 ABS_DIFF(BC_YUV888, unsigned char, int64_t, 1, 3);
569 ABS_DIFF(BC_YUVA8888, unsigned char, int64_t, 1, 4);
570 ABS_DIFF(BC_YUV161616, uint16_t, int64_t, 1, 3);
571 ABS_DIFF(BC_YUVA16161616, uint16_t, int64_t, 1, 4);
576 #define ABS_DIFF_SUB(model, type, temp_type, multiplier, components) case model: { \
577 temp_type result_temp = 0; \
578 temp_type y2_fraction = sub_y * 0x100 / OVERSAMPLE; \
579 temp_type y1_fraction = 0x100 - y2_fraction; \
580 temp_type x2_fraction = sub_x * 0x100 / OVERSAMPLE; \
581 temp_type x1_fraction = 0x100 - x2_fraction; \
582 for( int i = 0; i < h_sub; i++ ) { \
583 type *prev_row1 = (type*)prev_ptr; \
584 type *prev_row2 = (type*)prev_ptr + components; \
585 type *prev_row3 = (type*)(prev_ptr + row_bytes); \
586 type *prev_row4 = (type*)(prev_ptr + row_bytes) + components; \
587 type *current_row = (type*)current_ptr; \
588 for( int j = 0; j < w_sub; j++ ) { \
589 /* Scan each component */ \
590 for( int k = 0; k < 3; k++ ) { \
591 temp_type difference; \
592 temp_type prev_value = \
593 (*prev_row1++ * x1_fraction * y1_fraction + \
594 *prev_row2++ * x2_fraction * y1_fraction + \
595 *prev_row3++ * x1_fraction * y2_fraction + \
596 *prev_row4++ * x2_fraction * y2_fraction) / \
598 temp_type current_value = *current_row++; \
599 difference = prev_value - current_value; \
600 if( difference < 0 ) \
601 result_temp -= difference; \
603 result_temp += difference; \
607 if( components == 4 ) { \
615 prev_ptr += row_bytes; \
616 current_ptr += row_bytes; \
618 result = (int64_t)(result_temp * multiplier); \
621 int64_t MotionScan::abs_diff_sub(unsigned char *prev_ptr,
622 unsigned char *current_ptr, int row_bytes,
623 int w, int h, int color_model, int sub_x,
630 switch( color_model ) {
631 ABS_DIFF_SUB(BC_RGB888, unsigned char, int64_t, 1, 3);
632 ABS_DIFF_SUB(BC_RGBA8888, unsigned char, int64_t, 1, 4);
633 ABS_DIFF_SUB(BC_RGB_FLOAT, float, double, 0x10000, 3);
634 ABS_DIFF_SUB(BC_RGBA_FLOAT, float, double, 0x10000, 4);
635 ABS_DIFF_SUB(BC_YUV888, unsigned char, int64_t, 1, 3);
636 ABS_DIFF_SUB(BC_YUVA8888, unsigned char, int64_t, 1, 4);
637 ABS_DIFF_SUB(BC_YUV161616, uint16_t, int64_t, 1, 3);
638 ABS_DIFF_SUB(BC_YUVA16161616, uint16_t, int64_t, 1, 4);
643 MotionScanCache::MotionScanCache(int x, int y, int64_t difference)
647 this->difference = difference;
650 void MotionScan::clamp_scan(int w, int h,
651 int *block_x1, int *block_y1, int *block_x2,
652 int *block_y2, int *scan_x1, int *scan_y1,
653 int *scan_x2, int *scan_y2, int use_absolute)
655 //printf("MotionMain::clamp_scan 1 w=%d h=%d block=%d %d %d %d scan=%d %d %d %d absolute=%d\n",
656 // w, h, *block_x1, *block_y1, *block_x2, *block_y2, *scan_x1, *scan_y1, *scan_x2, *scan_y2,
660 // Limit size of scan area
661 // Used for drawing vectors
662 // scan is always out of range before block.
664 // int difference = -*scan_x1;
665 // *block_x1 += difference;
670 // int difference = -*scan_y1;
671 // *block_y1 += difference;
676 int difference = *scan_x2 - w;
677 // *block_x2 -= difference;
678 *scan_x2 -= difference;
682 int difference = *scan_y2 - h;
683 // *block_y2 -= difference;
684 *scan_y2 -= difference;
687 CLAMP(*scan_x1, 0, w);
688 CLAMP(*scan_y1, 0, h);
689 CLAMP(*scan_x2, 0, w);
690 CLAMP(*scan_y2, 0, h);
693 // Limit range of upper left block coordinates
694 // Used for motion tracking
696 int difference = -*scan_x1;
697 // *block_x1 += difference;
698 *scan_x2 += difference;
703 int difference = -*scan_y1;
704 // *block_y1 += difference;
705 *scan_y2 += difference;
709 if( *scan_x2 - *block_x1 + *block_x2 > w ) {
710 int difference = *scan_x2 - *block_x1 + *block_x2 - w;
711 *scan_x2 -= difference;
712 // *block_x2 -= difference;
715 if( *scan_y2 - *block_y1 + *block_y2 > h ) {
716 int difference = *scan_y2 - *block_y1 + *block_y2 - h;
717 *scan_y2 -= difference;
718 // *block_y2 -= difference;
720 // CLAMP(*scan_x1, 0, w - (*block_x2 - *block_x1));
721 // CLAMP(*scan_y1, 0, h - (*block_y2 - *block_y1));
722 // CLAMP(*scan_x2, 0, w - (*block_x2 - *block_x1));
723 // CLAMP(*scan_y2, 0, h - (*block_y2 - *block_y1));
726 // Sanity checks which break the calculation but should never happen if the
727 // center of the block is inside the frame.
728 CLAMP(*block_x1, 0, w);
729 CLAMP(*block_x2, 0, w);
730 CLAMP(*block_y1, 0, h);
731 CLAMP(*block_y2, 0, h);
733 //printf("MotionMain::clamp_scan 2 w=%d h=%d block=%d %d %d %d scan=%d %d %d %d absolute=%d\n",
734 // w, h, *block_x1, *block_y1, *block_x2, *block_y2, *scan_x1, *scan_y1, *scan_x2, *scan_y2,