/* * CINELERRA * Copyright (C) 2008 Adam Williams * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "clip.h" //#include "../downsample/downsampleengine.h" //#include "motion.h" #include "motionscan.h" #include "mutex.h" #include "vframe.h" #include // The module which does the actual scanning MotionScanPackage::MotionScanPackage() : LoadPackage() { valid = 1; } MotionScanUnit::MotionScanUnit(MotionScan *server) : LoadClient(server) { this->server = server; cache_lock = new Mutex("MotionScanUnit::cache_lock"); } MotionScanUnit::~MotionScanUnit() { delete cache_lock; } void MotionScanUnit::process_package(LoadPackage *package) { MotionScanPackage *pkg = (MotionScanPackage*)package; int w = server->current_frame->get_w(); int h = server->current_frame->get_h(); int color_model = server->current_frame->get_color_model(); int pixel_size = BC_CModels::calculate_pixelsize(color_model); int row_bytes = server->current_frame->get_bytes_per_line(); // Single pixel if(!server->subpixel) { // Try cache pkg->difference1 = server->get_cache(pkg->search_x, pkg->search_y); if(pkg->difference1 < 0) { //printf("MotionScanUnit::process_package 1 search_x=%d search_y=%d scan_x1=%d scan_y1=%d scan_x2=%d scan_y2=%d x_steps=%d y_steps=%d\n", //pkg->search_x, pkg->search_y, pkg->scan_x1, pkg->scan_y1, pkg->scan_x2, pkg->scan_y2, server->x_steps, server->y_steps); // Pointers to first pixel in each block unsigned char *prev_ptr = server->previous_frame->get_rows()[ pkg->search_y] + pkg->search_x * pixel_size; unsigned char *current_ptr = server->current_frame->get_rows()[ pkg->block_y1] + pkg->block_x1 * pixel_size; // Scan block pkg->difference1 = MotionScan::abs_diff(prev_ptr, current_ptr, row_bytes, pkg->block_x2 - pkg->block_x1, pkg->block_y2 - pkg->block_y1, color_model); // printf("MotionScanUnit::process_package %d search_x=%d search_y=%d diff=%lld\n", // __LINE__, server->block_x1 - pkg->search_x, server->block_y1 - pkg->search_y, pkg->difference1); server->put_cache(pkg->search_x, pkg->search_y, pkg->difference1); } } else // Sub pixel { unsigned char *prev_ptr = server->previous_frame->get_rows()[ pkg->search_y] + pkg->search_x * pixel_size; unsigned char *current_ptr = server->current_frame->get_rows()[ pkg->block_y1] + pkg->block_x1 * pixel_size; // With subpixel, there are two ways to compare each position, one by shifting // the previous frame and two by shifting the current frame. pkg->difference1 = MotionScan::abs_diff_sub(prev_ptr, current_ptr, row_bytes, pkg->block_x2 - pkg->block_x1, pkg->block_y2 - pkg->block_y1, color_model, pkg->sub_x, pkg->sub_y); pkg->difference2 = MotionScan::abs_diff_sub(current_ptr, prev_ptr, row_bytes, pkg->block_x2 - pkg->block_x1, pkg->block_y2 - pkg->block_y1, color_model, pkg->sub_x, pkg->sub_y); // printf("MotionScanUnit::process_package sub_x=%d sub_y=%d search_x=%d search_y=%d diff1=%lld diff2=%lld\n", // sub_x, // sub_y, // search_x, // search_y, // pkg->difference1, // pkg->difference2); } } int64_t MotionScanUnit::get_cache(int x, int y) { int64_t result = -1; cache_lock->lock("MotionScanUnit::get_cache"); for(int i = 0; i < cache.total; i++) { MotionScanCache *ptr = cache.values[i]; if(ptr->x == x && ptr->y == y) { result = ptr->difference; break; } } cache_lock->unlock(); return result; } void MotionScanUnit::put_cache(int x, int y, int64_t difference) { MotionScanCache *ptr = new MotionScanCache(x, y, difference); cache_lock->lock("MotionScanUnit::put_cache"); cache.append(ptr); cache_lock->unlock(); } MotionScan::MotionScan(int total_clients, int total_packages) : LoadServer( //1, 1 total_clients, total_packages ) { test_match = 1; cache_lock = new Mutex("MotionScan::cache_lock"); downsampled_previous = 0; downsampled_current = 0; // downsample = 0; } MotionScan::~MotionScan() { delete cache_lock; delete downsampled_previous; delete downsampled_current; // delete downsample; } void MotionScan::init_packages() { // Set package coords //printf("MotionScan::init_packages %d %d\n", __LINE__, get_total_packages()); for(int i = 0; i < get_total_packages(); i++) { MotionScanPackage *pkg = (MotionScanPackage*)get_package(i); pkg->block_x1 = block_x1; pkg->block_x2 = block_x2; pkg->block_y1 = block_y1; pkg->block_y2 = block_y2; pkg->scan_x1 = scan_x1; pkg->scan_x2 = scan_x2; pkg->scan_y1 = scan_y1; pkg->scan_y2 = scan_y2; pkg->step = i; pkg->difference1 = 0; pkg->difference2 = 0; pkg->dx = 0; pkg->dy = 0; pkg->valid = 1; if(!subpixel) { pkg->search_x = pkg->scan_x1 + (pkg->step % x_steps) * (scan_x2 - scan_x1) / x_steps; pkg->search_y = pkg->scan_y1 + (pkg->step / x_steps) * (scan_y2 - scan_y1) / y_steps; pkg->sub_x = 0; pkg->sub_y = 0; } else { pkg->sub_x = pkg->step % (OVERSAMPLE * 2); pkg->sub_y = pkg->step / (OVERSAMPLE * 2); if(horizontal_only) { pkg->sub_y = 0; } if(vertical_only) { pkg->sub_x = 0; } pkg->search_x = pkg->scan_x1 + pkg->sub_x / OVERSAMPLE + 1; pkg->search_y = pkg->scan_y1 + pkg->sub_y / OVERSAMPLE + 1; pkg->sub_x %= OVERSAMPLE; pkg->sub_y %= OVERSAMPLE; // printf("MotionScan::init_packages %d i=%d search_x=%d search_y=%d sub_x=%d sub_y=%d\n", // __LINE__, // i, // pkg->search_x, // pkg->search_y, // pkg->sub_x, // pkg->sub_y); } // printf("MotionScan::init_packages %d %d,%d %d,%d %d,%d\n", // __LINE__, // scan_x1, // scan_x2, // scan_y1, // scan_y2, // pkg->search_x, // pkg->search_y); } } LoadClient* MotionScan::new_client() { return new MotionScanUnit(this); } LoadPackage* MotionScan::new_package() { return new MotionScanPackage; } void MotionScan::set_test_match(int value) { this->test_match = value; } void MotionScan::scan_frame(VFrame *previous_frame, VFrame *current_frame, int global_range_w, int global_range_h, int global_block_w, int global_block_h, double block_x, double block_y, int frame_type, int tracking_type, int action_type, int horizontal_only, int vertical_only, int source_position, int total_steps, int total_dx, int total_dy, int global_origin_x, int global_origin_y) { this->previous_frame_arg = previous_frame; this->current_frame_arg = current_frame; this->horizontal_only = horizontal_only; this->vertical_only = vertical_only; this->previous_frame = previous_frame_arg; this->current_frame = current_frame_arg; this->global_origin_x = global_origin_x; this->global_origin_y = global_origin_y; subpixel = 0; cache.remove_all_objects(); // Single macroblock int w = current_frame->get_w(); int h = current_frame->get_h(); // Initial search parameters int scan_w = w * global_range_w / 100; int scan_h = h * global_range_h / 100; int block_w = w * global_block_w / 100; int block_h = h * global_block_h / 100; // Location of block in previous frame block_x1 = (int)(w * block_x / 100 - block_w / 2); block_y1 = (int)(h * block_y / 100 - block_h / 2); block_x2 = (int)(w * block_x / 100 + block_w / 2); block_y2 = (int)(h * block_y / 100 + block_h / 2); // Offset to location of previous block. This offset needn't be very accurate // since it's the offset of the previous image and current image we want. if(frame_type == MotionScan::TRACK_PREVIOUS) { block_x1 += total_dx / OVERSAMPLE; block_y1 += total_dy / OVERSAMPLE; block_x2 += total_dx / OVERSAMPLE; block_y2 += total_dy / OVERSAMPLE; } skip = 0; switch(tracking_type) { // Don't calculate case MotionScan::NO_CALCULATE: dx_result = 0; dy_result = 0; skip = 1; break; case MotionScan::LOAD: { //printf("MotionScan::scan_frame %d\n", __LINE__); // Load result from disk char string[BCTEXTLEN]; sprintf(string, "%s%06d", MOTION_FILE, source_position); FILE *input = fopen(string, "r"); if(input) { fscanf(input, "%d %d", &dx_result, &dy_result); fclose(input); skip = 1; } break; } // Scan from scratch default: skip = 0; break; } if(!skip && test_match) { if(previous_frame->data_matches(current_frame)) { printf("MotionScan::scan_frame: data matches. skipping.\n"); dx_result = 0; dy_result = 0; skip = 1; } } // Perform scan if(!skip) { //printf("MotionScan::scan_frame %d\n", __LINE__); // Location of block in current frame int origin_offset_x = this->global_origin_x * w / 100; int origin_offset_y = this->global_origin_y * h / 100; int x_result = block_x1 + origin_offset_x; int y_result = block_y1 + origin_offset_y; // printf("MotionScan::scan_frame 1 %d %d %d %d %d %d %d %d\n", // block_x1 + block_w / 2, // block_y1 + block_h / 2, // block_w, // block_h, // block_x1, // block_y1, // block_x2, // block_y2); while(1) { // Cache needs to be cleared if downsampling is used because the sums of // different downsamplings can't be compared. // Subpixel never uses the cache. // cache.remove_all_objects(); scan_x1 = x_result - scan_w / 2; scan_y1 = y_result - scan_h / 2; scan_x2 = x_result + scan_w / 2; scan_y2 = y_result + scan_h / 2; // Zero out requested values if(horizontal_only) { scan_y1 = block_y1; scan_y2 = block_y1 + 1; } if(vertical_only) { scan_x1 = block_x1; scan_x2 = block_x1 + 1; } // printf("MotionScan::scan_frame 1 %d %d %d %d %d %d %d %d\n", // block_x1, // block_y1, // block_x2, // block_y2, // scan_x1, // scan_y1, // scan_x2, // scan_y2); // Clamp the block coords before the scan so we get useful scan coords. clamp_scan(w, h, &block_x1, &block_y1, &block_x2, &block_y2, &scan_x1, &scan_y1, &scan_x2, &scan_y2, 0); // printf("MotionScan::scan_frame 1 %d 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", // __LINE__, // block_x1, // block_y1, // block_x2, // block_y2, // scan_x1, // scan_y1, // scan_x2, // scan_y2, // x_result, // y_result); // Give up if invalid coords. if(scan_y2 <= scan_y1 || scan_x2 <= scan_x1 || block_x2 <= block_x1 || block_y2 <= block_y1) break; // For subpixel, the top row and left column are skipped if(subpixel) { //printf("MotionScan::scan_frame %d %d %d\n", __LINE__, x_result, y_result); // Scan every subpixel in a 2 pixel * 2 pixel square total_pixels = (2 * OVERSAMPLE) * (2 * OVERSAMPLE); this->total_steps = total_pixels; // These aren't used in subpixel this->x_steps = OVERSAMPLE * 2; this->y_steps = OVERSAMPLE * 2; set_package_count(this->total_steps); process_packages(); // Get least difference int64_t min_difference = -1; for(int i = 0; i < get_total_packages(); i++) { MotionScanPackage *pkg = (MotionScanPackage*)get_package(i); //printf("MotionScan::scan_frame %d search_x=%d search_y=%d sub_x=%d sub_y=%d diff1=%lld diff2=%lld\n", //__LINE__, pkg->search_x, pkg->search_y, pkg->sub_x, pkg->sub_y, pkg->difference1, pkg->difference2); if(pkg->difference1 < min_difference || min_difference == -1) { min_difference = pkg->difference1; // The sub coords are 1 pixel up & left of the block coords x_result = pkg->search_x * OVERSAMPLE + pkg->sub_x; y_result = pkg->search_y * OVERSAMPLE + pkg->sub_y; // Fill in results dx_result = block_x1 * OVERSAMPLE - x_result; dy_result = block_y1 * OVERSAMPLE - y_result; //printf("MotionScan::scan_frame %d dx_result=%d dy_result=%d diff=%lld\n", //__LINE__, dx_result, dy_result, min_difference); } if(pkg->difference2 < min_difference) { min_difference = pkg->difference2; x_result = pkg->search_x * OVERSAMPLE - pkg->sub_x; y_result = pkg->search_y * OVERSAMPLE - pkg->sub_y; dx_result = block_x1 * OVERSAMPLE - x_result; dy_result = block_y1 * OVERSAMPLE - y_result; //printf("MotionScan::scan_frame %d dx_result=%d dy_result=%d diff=%lld\n", //__LINE__, dx_result, dy_result, min_difference); } } break; } else // Single pixel { total_pixels = (scan_x2 - scan_x1) * (scan_y2 - scan_y1); this->total_steps = MIN(total_steps, total_pixels); if(this->total_steps == total_pixels) { x_steps = scan_x2 - scan_x1; y_steps = scan_y2 - scan_y1; } else { x_steps = (int)sqrt(this->total_steps); y_steps = (int)sqrt(this->total_steps); } // Use downsampled images // if(scan_x2 - scan_x1 > x_steps * 4 || // scan_y2 - scan_y1 > y_steps * 4) // { // printf("MotionScan::scan_frame %d total_pixels=%d total_steps=%d x_steps=%d y_steps=%d x y steps=%d\n", // __LINE__, // total_pixels, // total_steps, // x_steps, // y_steps, // x_steps * y_steps); // // if(!downsampled_previous || // !downsampled_previous->equivalent(previous_frame_arg)) // { // delete downsampled_previous; // downsampled_previous = new VFrame(*previous_frame_arg); // } // // if(!downsampled_current || // !downsampled_current->equivalent(current_frame_arg)) // { // delete downsampled_current; // downsampled_current = new VFrame(*current_frame_arg); // } // // // if(!downsample) // downsample = new DownSampleServer(get_total_clients(), // get_total_clients()); // downsample->process_frame(downsampled_previous, // previous_frame_arg, // 1, // 1, // 1, // 1, // (scan_y2 - scan_y1) / y_steps, // (scan_x2 - scan_x1) / x_steps, // 0, // 0); // downsample->process_frame(downsampled_current, // current_frame_arg, // 1, // 1, // 1, // 1, // (scan_y2 - scan_y1) / y_steps, // (scan_x2 - scan_x1) / x_steps, // 0, // 0); // this->previous_frame = downsampled_previous; // this->current_frame = downsampled_current; // } // printf("MotionScan::scan_frame %d this->total_steps=%d\n", // __LINE__, // this->total_steps); set_package_count(this->total_steps); process_packages(); // Get least difference int64_t min_difference = -1; for(int i = 0; i < get_total_packages(); i++) { MotionScanPackage *pkg = (MotionScanPackage*)get_package(i); //printf("MotionScan::scan_frame %d search_x=%d search_y=%d sub_x=%d sub_y=%d diff1=%lld diff2=%lld\n", //__LINE__, pkg->search_x, pkg->search_y, pkg->sub_x, pkg->sub_y, pkg->difference1, pkg->difference2); if(pkg->difference1 < min_difference || min_difference == -1) { min_difference = pkg->difference1; x_result = pkg->search_x; y_result = pkg->search_y; x_result *= OVERSAMPLE; y_result *= OVERSAMPLE; //printf("MotionScan::scan_frame %d x_result=%d y_result=%d diff=%lld\n", //__LINE__, block_x1 * OVERSAMPLE - x_result, block_y1 * OVERSAMPLE - y_result, pkg->difference1); } } // If a new search is required, rescale results back to pixels. if(this->total_steps >= total_pixels) { // Single pixel accuracy reached. Now do exhaustive subpixel search. if(action_type == MotionScan::STABILIZE || action_type == MotionScan::TRACK || action_type == MotionScan::NOTHING) { //printf("MotionScan::scan_frame %d %d %d\n", __LINE__, x_result, y_result); x_result /= OVERSAMPLE; y_result /= OVERSAMPLE; scan_w = 2; scan_h = 2; subpixel = 1; } else { // Fill in results and quit dx_result = block_x1 * OVERSAMPLE - x_result; dy_result = block_y1 * OVERSAMPLE - y_result; //printf("MotionScan::scan_frame %d %d %d\n", __LINE__, dx_result, dy_result); break; } } else // Reduce scan area and try again { scan_w = (scan_x2 - scan_x1) / 2; scan_h = (scan_y2 - scan_y1) / 2; x_result /= OVERSAMPLE; y_result /= OVERSAMPLE; } } } dx_result *= -1; dy_result *= -1; } //printf("MotionScan::scan_frame %d\n", __LINE__); if(vertical_only) dx_result = 0; if(horizontal_only) dy_result = 0; // Write results if(tracking_type == MotionScan::SAVE) { char string[BCTEXTLEN]; sprintf(string, "%s%06d", MOTION_FILE, source_position); FILE *output = fopen(string, "w"); if(output) { fprintf(output, "%d %d\n", dx_result, dy_result); fclose(output); } else { printf("MotionScan::scan_frame %d: save coordinate failed", __LINE__); } } // printf("MotionScan::scan_frame %d dx=%.2f dy=%.2f\n", // __LINE__, // (float)this->dx_result / OVERSAMPLE, // (float)this->dy_result / OVERSAMPLE); } int64_t MotionScan::get_cache(int x, int y) { int64_t result = -1; cache_lock->lock("MotionScan::get_cache"); for(int i = 0; i < cache.total; i++) { MotionScanCache *ptr = cache.values[i]; if(ptr->x == x && ptr->y == y) { result = ptr->difference; break; } } cache_lock->unlock(); return result; } void MotionScan::put_cache(int x, int y, int64_t difference) { MotionScanCache *ptr = new MotionScanCache(x, y, difference); cache_lock->lock("MotionScan::put_cache"); cache.append(ptr); cache_lock->unlock(); } #define ABS_DIFF(type, temp_type, multiplier, components) \ { \ temp_type result_temp = 0; \ for(int i = 0; i < h; i++) \ { \ type *prev_row = (type*)prev_ptr; \ type *current_row = (type*)current_ptr; \ for(int j = 0; j < w; j++) \ { \ for(int k = 0; k < 3; k++) \ { \ temp_type difference; \ difference = *prev_row++ - *current_row++; \ if(difference < 0) \ result_temp -= difference; \ else \ result_temp += difference; \ } \ if(components == 4) \ { \ prev_row++; \ current_row++; \ } \ } \ prev_ptr += row_bytes; \ current_ptr += row_bytes; \ } \ result = (int64_t)(result_temp * multiplier); \ } int64_t MotionScan::abs_diff(unsigned char *prev_ptr, unsigned char *current_ptr, int row_bytes, int w, int h, int color_model) { int64_t result = 0; switch(color_model) { case BC_RGB888: ABS_DIFF(unsigned char, int64_t, 1, 3) break; case BC_RGBA8888: ABS_DIFF(unsigned char, int64_t, 1, 4) break; case BC_RGB_FLOAT: ABS_DIFF(float, double, 0x10000, 3) break; case BC_RGBA_FLOAT: ABS_DIFF(float, double, 0x10000, 4) break; case BC_YUV888: ABS_DIFF(unsigned char, int64_t, 1, 3) break; case BC_YUVA8888: ABS_DIFF(unsigned char, int64_t, 1, 4) break; case BC_YUV161616: ABS_DIFF(uint16_t, int64_t, 1, 3) break; case BC_YUVA16161616: ABS_DIFF(uint16_t, int64_t, 1, 4) break; } return result; } #define ABS_DIFF_SUB(type, temp_type, multiplier, components) \ { \ temp_type result_temp = 0; \ temp_type y2_fraction = sub_y * 0x100 / OVERSAMPLE; \ temp_type y1_fraction = 0x100 - y2_fraction; \ temp_type x2_fraction = sub_x * 0x100 / OVERSAMPLE; \ temp_type x1_fraction = 0x100 - x2_fraction; \ for(int i = 0; i < h_sub; i++) \ { \ type *prev_row1 = (type*)prev_ptr; \ type *prev_row2 = (type*)prev_ptr + components; \ type *prev_row3 = (type*)(prev_ptr + row_bytes); \ type *prev_row4 = (type*)(prev_ptr + row_bytes) + components; \ type *current_row = (type*)current_ptr; \ for(int j = 0; j < w_sub; j++) \ { \ /* Scan each component */ \ for(int k = 0; k < 3; k++) \ { \ temp_type difference; \ temp_type prev_value = \ (*prev_row1++ * x1_fraction * y1_fraction + \ *prev_row2++ * x2_fraction * y1_fraction + \ *prev_row3++ * x1_fraction * y2_fraction + \ *prev_row4++ * x2_fraction * y2_fraction) / \ 0x100 / 0x100; \ temp_type current_value = *current_row++; \ difference = prev_value - current_value; \ if(difference < 0) \ result_temp -= difference; \ else \ result_temp += difference; \ } \ \ /* skip alpha */ \ if(components == 4) \ { \ prev_row1++; \ prev_row2++; \ prev_row3++; \ prev_row4++; \ current_row++; \ } \ } \ prev_ptr += row_bytes; \ current_ptr += row_bytes; \ } \ result = (int64_t)(result_temp * multiplier); \ } int64_t MotionScan::abs_diff_sub(unsigned char *prev_ptr, unsigned char *current_ptr, int row_bytes, int w, int h, int color_model, int sub_x, int sub_y) { int h_sub = h - 1; int w_sub = w - 1; int64_t result = 0; switch(color_model) { case BC_RGB888: ABS_DIFF_SUB(unsigned char, int64_t, 1, 3) break; case BC_RGBA8888: ABS_DIFF_SUB(unsigned char, int64_t, 1, 4) break; case BC_RGB_FLOAT: ABS_DIFF_SUB(float, double, 0x10000, 3) break; case BC_RGBA_FLOAT: ABS_DIFF_SUB(float, double, 0x10000, 4) break; case BC_YUV888: ABS_DIFF_SUB(unsigned char, int64_t, 1, 3) break; case BC_YUVA8888: ABS_DIFF_SUB(unsigned char, int64_t, 1, 4) break; case BC_YUV161616: ABS_DIFF_SUB(uint16_t, int64_t, 1, 3) break; case BC_YUVA16161616: ABS_DIFF_SUB(uint16_t, int64_t, 1, 4) break; } return result; } MotionScanCache::MotionScanCache(int x, int y, int64_t difference) { this->x = x; this->y = y; this->difference = difference; } void MotionScan::clamp_scan(int w, int h, int *block_x1, int *block_y1, int *block_x2, int *block_y2, int *scan_x1, int *scan_y1, int *scan_x2, int *scan_y2, int use_absolute) { // printf("MotionMain::clamp_scan 1 w=%d h=%d block=%d %d %d %d scan=%d %d %d %d absolute=%d\n", // w, // h, // *block_x1, // *block_y1, // *block_x2, // *block_y2, // *scan_x1, // *scan_y1, // *scan_x2, // *scan_y2, // use_absolute); if(use_absolute) { // scan is always out of range before block. if(*scan_x1 < 0) { int difference = -*scan_x1; *block_x1 += difference; *scan_x1 = 0; } if(*scan_y1 < 0) { int difference = -*scan_y1; *block_y1 += difference; *scan_y1 = 0; } if(*scan_x2 > w) { int difference = *scan_x2 - w; *block_x2 -= difference; *scan_x2 -= difference; } if(*scan_y2 > h) { int difference = *scan_y2 - h; *block_y2 -= difference; *scan_y2 -= difference; } CLAMP(*scan_x1, 0, w); CLAMP(*scan_y1, 0, h); CLAMP(*scan_x2, 0, w); CLAMP(*scan_y2, 0, h); } else { if(*scan_x1 < 0) { int difference = -*scan_x1; *block_x1 += difference; *scan_x2 += difference; *scan_x1 = 0; } if(*scan_y1 < 0) { int difference = -*scan_y1; *block_y1 += difference; *scan_y2 += difference; *scan_y1 = 0; } if(*scan_x2 - *block_x1 + *block_x2 > w) { int difference = *scan_x2 - *block_x1 + *block_x2 - w; *block_x2 -= difference; } if(*scan_y2 - *block_y1 + *block_y2 > h) { int difference = *scan_y2 - *block_y1 + *block_y2 - h; *block_y2 -= difference; } // CLAMP(*scan_x1, 0, w - (*block_x2 - *block_x1)); // CLAMP(*scan_y1, 0, h - (*block_y2 - *block_y1)); // CLAMP(*scan_x2, 0, w - (*block_x2 - *block_x1)); // CLAMP(*scan_y2, 0, h - (*block_y2 - *block_y1)); } // Sanity checks which break the calculation but should never happen if the // center of the block is inside the frame. CLAMP(*block_x1, 0, w); CLAMP(*block_x2, 0, w); CLAMP(*block_y1, 0, h); CLAMP(*block_y2, 0, h); // printf("MotionMain::clamp_scan 2 w=%d h=%d block=%d %d %d %d scan=%d %d %d %d absolute=%d\n", // w, // h, // *block_x1, // *block_y1, // *block_x2, // *block_y2, // *scan_x1, // *scan_y1, // *scan_x2, // *scan_y2, // use_absolute); }