X-Git-Url: http://git.cinelerra-gg.org/git/?a=blobdiff_plain;f=cinelerra-5.1%2Fplugins%2Fmotion.new%2Fmotionscan.C;fp=cinelerra-5.1%2Fplugins%2Fmotion.new%2Fmotionscan.C;h=4fd451cd7625318b97eb0942bab9e3138308b3aa;hb=30bdb85eb33a8ee7ba675038a86c6be59c43d7bd;hp=0000000000000000000000000000000000000000;hpb=52fcc46226f9df46f9ce9d0566dc568455a7db0b;p=goodguy%2Fhistory.git diff --git a/cinelerra-5.1/plugins/motion.new/motionscan.C b/cinelerra-5.1/plugins/motion.new/motionscan.C new file mode 100644 index 00000000..4fd451cd --- /dev/null +++ b/cinelerra-5.1/plugins/motion.new/motionscan.C @@ -0,0 +1,1090 @@ + +/* + * 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); +} + + +