add xvid/flv formats, add motion plugin varients + save file, fix build bug
[goodguy/history.git] / cinelerra-5.1 / plugins / motion / motionscan.C
index 67e8460e8671de4cb464e721a22a2c6edd1511cb..b1a533ef850477a9c7412d39e92c45d5d60c2a09 100644 (file)
@@ -1,46 +1,38 @@
 
 /*
  * CINELERRA
- * Copyright (C) 2016 Adam Williams <broadcast at earthling dot net>
- *
+ * Copyright (C) 2012 Adam Williams <broadcast at earthling dot net>
+ * 
  * 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 "affine.h"
-#include "bcsignals.h"
 #include "clip.h"
+//#include "../downsample/downsampleengine.h"
+//#include "motion.h"
 #include "motionscan.h"
 #include "mutex.h"
 #include "vframe.h"
 
-
 #include <math.h>
-#include <stdlib.h>
-#include <string.h>
 
 // The module which does the actual scanning
 
-// starting level of detail
-#define STARTING_DOWNSAMPLE 16
-// minimum size in each level of detail
-#define MIN_DOWNSAMPLED_SIZE 16
-// minimum scan range
-#define MIN_DOWNSAMPLED_SCAN 4
-// scan range for subpixel mode
-#define SUBPIXEL_RANGE 4
+
+
+
 
 MotionScanPackage::MotionScanPackage()
  : LoadPackage()
@@ -57,124 +49,116 @@ MotionScanUnit::MotionScanUnit(MotionScan *server)
  : LoadClient(server)
 {
        this->server = server;
+       cache_lock = new Mutex("MotionScanUnit::cache_lock");
 }
 
 MotionScanUnit::~MotionScanUnit()
 {
+       delete cache_lock;
 }
 
 
-void MotionScanUnit::single_pixel(MotionScanPackage *pkg)
+
+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();
 
-// printf("MotionScanUnit::process_package %d 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",
-// __LINE__,
-// 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 = 0;
 
-       if(server->do_rotate)
-       {
-               current_ptr = server->rotated_current[pkg->angle_step]->get_rows()[
-                       pkg->block_y1] +
-                       pkg->block_x1 * pixel_size;
-       }
-       else
-       {
-               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 angle_step=%d diff=%d\n",
-// __LINE__,
-// pkg->angle_step,
-// pkg->difference1);
-// 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);
-}
 
-void MotionScanUnit::subpixel(MotionScanPackage *pkg)
-{
-//PRINT_TRACE
-       //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();
-       unsigned char *prev_ptr = server->previous_frame->get_rows()[
-               pkg->search_y] +
-               pkg->search_x * pixel_size;
-// neglect rotation
-       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",
-// pkg->sub_x,
-// pkg->sub_y,
-// pkg->search_x,
-// pkg->search_y,
-// pkg->difference1,
-// pkg->difference2);
-}
 
-void MotionScanUnit::process_package(LoadPackage *package)
-{
-       MotionScanPackage *pkg = (MotionScanPackage*)package;
+
+
+
 
 
 // Single pixel
        if(!server->subpixel)
        {
-               single_pixel(pkg);
+// 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
        {
-               subpixel(pkg);
+               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);
        }
 
 
@@ -191,6 +175,33 @@ void MotionScanUnit::process_package(LoadPackage *package)
 
 
 
+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();
+}
+
+
+
 
 
 
@@ -202,880 +213,135 @@ void MotionScanUnit::process_package(LoadPackage *package)
 MotionScan::MotionScan(int total_clients,
        int total_packages)
  : LoadServer(
-// DEBUG
-//1, 1
-total_clients, total_packages
+//1, 1 
+total_clients, total_packages 
 )
 {
        test_match = 1;
+       cache_lock = new Mutex("MotionScan::cache_lock");
        downsampled_previous = 0;
        downsampled_current = 0;
-       rotated_current = 0;
-       rotater = 0;
+//     downsample = 0;
 }
 
 MotionScan::~MotionScan()
 {
+       delete cache_lock;
        delete downsampled_previous;
        delete downsampled_current;
-       if(rotated_current)
-       {
-               for(int i = 0; i < total_rotated; i++)
-               {
-                       delete rotated_current[i];
-               }
-
-               delete [] rotated_current;
-       }
-       delete rotater;
+//     delete downsample;
 }
 
 
 void MotionScan::init_packages()
 {
 // Set package coords
-// Total range of positions to scan with downsampling
-       int downsampled_scan_x1 = scan_x1 / current_downsample;
-       //int downsampled_scan_x2 = scan_x2 / current_downsample;
-       int downsampled_scan_y1 = scan_y1 / current_downsample;
-       //int downsampled_scan_y2 = scan_y2 / current_downsample;
-       int downsampled_block_x1 = block_x1 / current_downsample;
-       int downsampled_block_x2 = block_x2 / current_downsample;
-       int downsampled_block_y1 = block_y1 / current_downsample;
-       int downsampled_block_y2 = block_y2 / current_downsample;
-
-
 //printf("MotionScan::init_packages %d %d\n", __LINE__, get_total_packages());
-// printf("MotionScan::init_packages %d current_downsample=%d scan_x1=%d scan_x2=%d block_x1=%d block_x2=%d\n",
-// __LINE__,
-// current_downsample,
-// downsampled_scan_x1,
-// downsampled_scan_x2,
-// downsampled_block_x1,
-// downsampled_block_x2);
-// if(current_downsample == 8 && downsampled_scan_x1 == 47)
-// {
-// downsampled_previous->write_png("/tmp/previous");
-// downsampled_current->write_png("/tmp/current");
-// }
-
        for(int i = 0; i < get_total_packages(); i++)
        {
                MotionScanPackage *pkg = (MotionScanPackage*)get_package(i);
 
-               pkg->block_x1 = downsampled_block_x1;
-               pkg->block_x2 = downsampled_block_x2;
-               pkg->block_y1 = downsampled_block_y1;
-               pkg->block_y2 = downsampled_block_y2;
+               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;
-               pkg->angle_step = 0;
-
+               
                if(!subpixel)
                {
-                       if(rotation_pass)
-                       {
-                               pkg->search_x = scan_x1 / current_downsample;
-                               pkg->search_y = scan_y1 / current_downsample;
-                               pkg->angle_step = i;
-                       }
-                       else
-                       {
-
-                               int current_x_step = (i % x_steps);
-                               int current_y_step = (i / x_steps);
-
-       //printf("MotionScan::init_packages %d i=%d x_step=%d y_step=%d angle_step=%d\n",
-       //__LINE__, i, current_x_step, current_y_step, current_angle_step);
-                               pkg->search_x = downsampled_scan_x1 + current_x_step *
-                                       (scan_x2 - scan_x1) / current_downsample / x_steps;
-                               pkg->search_y = downsampled_scan_y1 + current_y_step *
-                                       (scan_y2 - scan_y1) / current_downsample / y_steps;
-
-                               if(do_rotate)
-                               {
-                                       pkg->angle_step = angle_steps / 2;
-                               }
-                               else
-                               {
-                                       pkg->angle_step = 0;
-                               }
-                       }
-
+                       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 = i % (OVERSAMPLE * SUBPIXEL_RANGE);
-                       pkg->sub_y = i / (OVERSAMPLE * SUBPIXEL_RANGE);
-
-//                     if(horizontal_only)
-//                     {
-//                             pkg->sub_y = 0;
-//                     }
-//
-//                     if(vertical_only)
-//                     {
-//                             pkg->sub_x = 0;
-//                     }
-
-                       pkg->search_x = scan_x1 + pkg->sub_x / OVERSAMPLE + 1;
-                       pkg->search_y = 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;
-}
-
-
-
-
-#define DOWNSAMPLE(type, temp_type, components, max) \
-{ \
-       temp_type r; \
-       temp_type g; \
-       temp_type b; \
-       temp_type a; \
-       type **in_rows = (type**)src->get_rows(); \
-       type **out_rows = (type**)dst->get_rows(); \
- \
-       for(int i = 0; i < h; i += downsample) \
-       { \
-               int y1 = MAX(i, 0); \
-               int y2 = MIN(i + downsample, h); \
- \
- \
-               for(int j = 0; \
-                       j < w; \
-                       j += downsample) \
-               { \
-                       int x1 = MAX(j, 0); \
-                       int x2 = MIN(j + downsample, w); \
- \
-                       temp_type scale = (x2 - x1) * (y2 - y1); \
-                       if(x2 > x1 && y2 > y1) \
-                       { \
- \
-/* Read in values */ \
-                               r = 0; \
-                               g = 0; \
-                               b = 0; \
-                               if(components == 4) a = 0; \
- \
-                               for(int k = y1; k < y2; k++) \
-                               { \
-                                       type *row = in_rows[k] + x1 * components; \
-                                       for(int l = x1; l < x2; l++) \
-                                       { \
-                                               r += *row++; \
-                                               g += *row++; \
-                                               b += *row++; \
-                                               if(components == 4) a += *row++; \
-                                       } \
-                               } \
- \
-/* Write average */ \
-                               r /= scale; \
-                               g /= scale; \
-                               b /= scale; \
-                               if(components == 4) a /= scale; \
- \
-                               type *row = out_rows[y1 / downsample] + \
-                                       x1 / downsample * components; \
-                               *row++ = r; \
-                               *row++ = g; \
-                               *row++ = b; \
-                               if(components == 4) *row++ = a; \
-                       } \
-               } \
-/*printf("DOWNSAMPLE 3 %d\n", i);*/ \
-       } \
-}
-
-
-
-
-void MotionScan::downsample_frame(VFrame *dst,
-       VFrame *src,
-       int downsample)
-{
-       int h = src->get_h();
-       int w = src->get_w();
-
-//PRINT_TRACE
-//printf("downsample=%d w=%d h=%d dst=%d %d\n", downsample, w, h, dst->get_w(), dst->get_h());
-       switch(src->get_color_model())
-       {
-               case BC_RGB888:
-                       DOWNSAMPLE(uint8_t, int64_t, 3, 0xff)
-                       break;
-               case BC_RGB_FLOAT:
-                       DOWNSAMPLE(float, float, 3, 1.0)
-                       break;
-               case BC_RGBA8888:
-                       DOWNSAMPLE(uint8_t, int64_t, 4, 0xff)
-                       break;
-               case BC_RGBA_FLOAT:
-                       DOWNSAMPLE(float, float, 4, 1.0)
-                       break;
-               case BC_YUV888:
-                       DOWNSAMPLE(uint8_t, int64_t, 3, 0xff)
-                       break;
-               case BC_YUVA8888:
-                       DOWNSAMPLE(uint8_t, int64_t, 4, 0xff)
-                       break;
-       }
-//PRINT_TRACE
-}
+                       pkg->sub_x = pkg->step % (OVERSAMPLE * 2);
+                       pkg->sub_y = pkg->step / (OVERSAMPLE * 2);
 
-double MotionScan::step_to_angle(int step, double center)
-{
-       if(step < angle_steps / 2)
-       {
-               return center - angle_step * (angle_steps / 2 - step);
-       }
-       else
-       if(step > angle_steps / 2)
-       {
-               return center + angle_step * (step - angle_steps / 2);
-       }
-       else
-       {
-               return center;
-       }
-}
-
-#ifdef STDDEV_TEST
-static int compare(const void *p1, const void *p2)
-{
-       double value1 = *(double*)p1;
-       double value2 = *(double*)p2;
-
-//printf("compare %d value1=%f value2=%f\n", __LINE__, value1, value2);
-       return value1 > value2;
-}
-#endif
-
-// reject vectors based on content.  It's the reason Goog can't stabilize timelapses.
-//#define STDDEV_TEST
-
-// pixel accurate motion search
-void MotionScan::pixel_search(int &x_result, int &y_result, double &r_result)
-{
-// reduce level of detail until enough steps
-       while(current_downsample > 1 &&
-               ((block_x2 - block_x1) / current_downsample < MIN_DOWNSAMPLED_SIZE ||
-               (block_y2 - block_y1) / current_downsample < MIN_DOWNSAMPLED_SIZE
-               ||
-                (scan_x2 - scan_x1) / current_downsample < MIN_DOWNSAMPLED_SCAN ||
-               (scan_y2 - scan_y1) / current_downsample < MIN_DOWNSAMPLED_SCAN
-               ))
-       {
-               current_downsample /= 2;
-       }
-
-
-
-// create downsampled images.
-// Need to keep entire frame to search for rotation.
-       int downsampled_prev_w = previous_frame_arg->get_w() / current_downsample;
-       int downsampled_prev_h = previous_frame_arg->get_h() / current_downsample;
-       int downsampled_current_w = current_frame_arg->get_w() / current_downsample;
-       int downsampled_current_h = current_frame_arg->get_h() / current_downsample;
-
-// printf("MotionScan::pixel_search %d current_downsample=%d current_frame_arg->get_w()=%d downsampled_current_w=%d\n",
-// __LINE__,
-// current_downsample,
-// current_frame_arg->get_w(),
-// downsampled_current_w);
-
-       x_steps = (scan_x2 - scan_x1) / current_downsample;
-       y_steps = (scan_y2 - scan_y1) / current_downsample;
-
-// in rads
-       double test_angle1 = atan2((double)downsampled_current_h / 2 - 1, (double)downsampled_current_w / 2);
-       double test_angle2 = atan2((double)downsampled_current_h / 2, (double)downsampled_current_w / 2 - 1);
-
-// in deg
-       angle_step = 360.0f * fabs(test_angle1 - test_angle2) / 2 / M_PI;
-
-// printf("MotionScan::pixel_search %d test_angle1=%f test_angle2=%f angle_step=%f\n",
-// __LINE__,
-// 360.0f * test_angle1 / 2 / M_PI,
-// 360.0f * test_angle2 / 2 / M_PI,
-// angle_step);
-
-
-       if(do_rotate && angle_step < rotation_range)
-       {
-               angle_steps = 1 + (int)((scan_angle2 - scan_angle1) / angle_step + 0.5);
-       }
-       else
-       {
-               angle_steps = 1;
-       }
-
-
-       if(current_downsample > 1)
-       {
-               if(!downsampled_previous ||
-                       downsampled_previous->get_w() != downsampled_prev_w ||
-                       downsampled_previous->get_h() != downsampled_prev_h)
-               {
-                       delete downsampled_previous;
-                       downsampled_previous = new VFrame();
-                       downsampled_previous->set_use_shm(0);
-                       downsampled_previous->reallocate(0,
-                               -1,
-                               0,
-                               0,
-                               0,
-                               downsampled_prev_w + 1,
-                               downsampled_prev_h + 1,
-                               previous_frame_arg->get_color_model(),
-                               -1);
-               }
-
-               if(!downsampled_current ||
-                       downsampled_current->get_w() != downsampled_current_w ||
-                       downsampled_current->get_h() != downsampled_current_h)
-               {
-                       delete downsampled_current;
-                       downsampled_current = new VFrame();
-                       downsampled_current->set_use_shm(0);
-                       downsampled_current->reallocate(0,
-                               -1,
-                               0,
-                               0,
-                               0,
-                               downsampled_current_w + 1,
-                               downsampled_current_h + 1,
-                               current_frame_arg->get_color_model(),
-                               -1);
-               }
-
-
-               downsample_frame(downsampled_previous,
-                       previous_frame_arg,
-                       current_downsample);
-               downsample_frame(downsampled_current,
-                       current_frame_arg,
-                       current_downsample);
-               previous_frame = downsampled_previous;
-               current_frame = downsampled_current;
-
-       }
-       else
-       {
-               previous_frame = previous_frame_arg;
-               current_frame = current_frame_arg;
-       }
-
-
-
-// printf("MotionScan::pixel_search %d x_steps=%d y_steps=%d angle_steps=%d total_steps=%d\n",
-// __LINE__,
-// x_steps,
-// y_steps,
-// angle_steps,
-// total_steps);
-
-
-
-// test variance of constant macroblock
-       int color_model = current_frame->get_color_model();
-       int pixel_size = BC_CModels::calculate_pixelsize(color_model);
-       int row_bytes = current_frame->get_bytes_per_line();
-       int block_w = block_x2 - block_x1;
-       int block_h = block_y2 - block_y1;
-
-       unsigned char *current_ptr =
-               current_frame->get_rows()[block_y1 / current_downsample] +
-               (block_x1 / current_downsample) * pixel_size;
-       unsigned char *previous_ptr =
-               previous_frame->get_rows()[scan_y1 / current_downsample] +
-               (scan_x1 / current_downsample) * pixel_size;
-
-
-
-// test detail in prev & current frame
-       double range1 = calculate_range(current_ptr,
-               row_bytes,
-               block_w / current_downsample,
-               block_h / current_downsample,
-               color_model);
-
-       if(range1 < 1)
-       {
-printf("MotionScan::pixel_search %d range fail range1=%f\n", __LINE__, range1);
-               failed = 1;
-               return;
-       }
-
-       double range2 = calculate_range(previous_ptr,
-               row_bytes,
-               block_w / current_downsample,
-               block_h / current_downsample,
-               color_model);
-
-       if(range2 < 1)
-       {
-printf("MotionScan::pixel_search %d range fail range2=%f\n", __LINE__, range2);
-               failed = 1;
-               return;
-       }
-
-
-// create rotated images
-       if(rotated_current &&
-               (total_rotated != angle_steps ||
-               rotated_current[0]->get_w() != downsampled_current_w ||
-               rotated_current[0]->get_h() != downsampled_current_h))
-       {
-               for(int i = 0; i < total_rotated; i++)
-               {
-                       delete rotated_current[i];
-               }
-
-               delete [] rotated_current;
-               rotated_current = 0;
-               total_rotated = 0;
-       }
-
-       if(do_rotate)
-       {
-               total_rotated = angle_steps;
-
-
-               if(!rotated_current)
-               {
-                       rotated_current = new VFrame*[total_rotated];
-                       bzero(rotated_current, sizeof(VFrame*) * total_rotated);
-               }
-
-// printf("MotionScan::pixel_search %d total_rotated=%d w=%d h=%d block_w=%d block_h=%d\n",
-// __LINE__,
-// total_rotated,
-// downsampled_current_w,
-// downsampled_current_h,
-// (block_x2 - block_x1) / current_downsample,
-// (block_y2 - block_y1) / current_downsample);
-               for(int i = 0; i < angle_steps; i++)
-               {
-
-// printf("MotionScan::pixel_search %d w=%d h=%d x=%d y=%d angle=%f\n",
-// __LINE__,
-// downsampled_current_w,
-// downsampled_current_h,
-// (block_x1 + block_x2) / 2 / current_downsample,
-// (block_y1 + block_y2) / 2 / current_downsample,
-// step_to_angle(i, r_result));
-
-// printf("MotionScan::pixel_search %d i=%d rotated_current[i]=%p\n",
-// __LINE__,
-// i,
-// rotated_current[i]);
-                       if(!rotated_current[i])
+                       if(horizontal_only)
                        {
-                               rotated_current[i] = new VFrame();
-                               rotated_current[i]->set_use_shm(0);
-                               rotated_current[i]->reallocate(0,
-                                       -1,
-                                       0,
-                                       0,
-                                       0,
-                                       downsampled_current_w + 1,
-                                       downsampled_current_h + 1,
-                                       current_frame_arg->get_color_model(),
-                                       -1);
-//printf("MotionScan::pixel_search %d\n", __LINE__);
+                               pkg->sub_y = 0;
                        }
 
-
-                       if(!rotater)
+                       if(vertical_only)
                        {
-                               rotater = new AffineEngine(get_total_clients(),
-                                       get_total_clients());
+                               pkg->sub_x = 0;
                        }
 
-// get smallest viewport size required for the angle
-                       double diag = hypot((block_x2 - block_x1) / current_downsample,
-                               (block_y2 - block_y1) / current_downsample);
-                       double angle1 = atan2(block_y2 - block_y1, block_x2 - block_x1) +
-                               TO_RAD(step_to_angle(i, r_result));
-                       double angle2 = -atan2(block_y2 - block_y1, block_x2 - block_x1) +
-                               TO_RAD(step_to_angle(i, r_result));
-                       double max_horiz = MAX(abs(diag * cos(angle1)), abs(diag * cos(angle2)));
-                       double max_vert = MAX(abs(diag * sin(angle1)), abs(diag * sin(angle2)));
-                       int center_x = (block_x1 + block_x2) / 2 / current_downsample;
-                       int center_y = (block_y1 + block_y2) / 2 / current_downsample;
-                       int x1 = center_x - max_horiz / 2;
-                       int y1 = center_y - max_vert / 2;
-                       int x2 = x1 + max_horiz;
-                       int y2 = y1 + max_vert;
-                       CLAMP(x1, 0, downsampled_current_w - 1);
-                       CLAMP(y1, 0, downsampled_current_h - 1);
-                       CLAMP(x2, 0, downsampled_current_w - 1);
-                       CLAMP(y2, 0, downsampled_current_h - 1);
-
-//printf("MotionScan::pixel_search %d %f %f %d %d\n",
-//__LINE__, TO_DEG(angle1), TO_DEG(angle2), (int)max_horiz, (int)max_vert);
-                       rotater->set_in_viewport(x1,
-                               y1,
-                               x2 - x1,
-                               y2 - y1);
-                       rotater->set_out_viewport(x1,
-                               y1,
-                               x2 - x1,
-                               y2 - y1);
-
-//                     rotater->set_in_viewport(0,
-//                             0,
-//                             downsampled_current_w,
-//                             downsampled_current_h);
-//                     rotater->set_out_viewport(0,
-//                             0,
-//                             downsampled_current_w,
-//                             downsampled_current_h);
-
-                       rotater->set_in_pivot(center_x, center_y);
-                       rotater->set_out_pivot(center_x, center_y);
-
-                       rotater->rotate(rotated_current[i],
-                               current_frame,
-                               step_to_angle(i, r_result));
-
-// rotated_current[i]->draw_rect(block_x1 / current_downsample,
-// block_y1 / current_downsample,
-// block_x2 / current_downsample,
-// block_y2 / current_downsample);
-// char string[BCTEXTLEN];
-// sprintf(string, "/tmp/rotated%d", i);
-// rotated_current[i]->write_png(string);
-//downsampled_previous->write_png("/tmp/previous");
-//printf("MotionScan::pixel_search %d\n", __LINE__);
-               }
-       }
-
-
-
-
-
-
-// printf("MotionScan::pixel_search %d block x=%d y=%d w=%d h=%d\n",
-// __LINE__,
-// block_x1 / current_downsample,
-// block_y1 / current_downsample,
-// block_w / current_downsample,
-// block_h / current_downsample);
-
-
-
-
-
-
-
-//exit(1);
-// Test only translation of the middle rotated frame
-       rotation_pass = 0;
-       total_steps = x_steps * y_steps;
-       set_package_count(total_steps);
-       process_packages();
-
-
-
-
-
-
-// Get least difference
-       int64_t min_difference = -1;
-#ifdef STDDEV_TEST
-       double stddev_table[get_total_packages()];
-#endif
-       for(int i = 0; i < get_total_packages(); i++)
-       {
-               MotionScanPackage *pkg = (MotionScanPackage*)get_package(i);
-
-#ifdef STDDEV_TEST
-               double stddev = sqrt(pkg->difference1) /
-                       (block_w / current_downsample) /
-                       (block_h / current_downsample) /
-                       3;
-// printf("MotionScan::pixel_search %d current_downsample=%d search_x=%d search_y=%d diff1=%f\n",
-// __LINE__,
-// current_downsample,
-// pkg->search_x,
-// pkg->search_y,
-// sqrt(pkg->difference1) / block_w / current_downsample / block_h / 3 /* / variance */);
-
-// printf("MotionScan::pixel_search %d range1=%f stddev=%f\n",
-// __LINE__,
-// range1,
-// stddev);
-
-               stddev_table[i] = stddev;
-#endif // STDDEV_TEST
-
-               if(pkg->difference1 < min_difference || i == 0)
-               {
-                       min_difference = pkg->difference1;
-                       x_result = pkg->search_x * current_downsample * OVERSAMPLE;
-                       y_result = pkg->search_y * current_downsample * OVERSAMPLE;
-
-// printf("MotionScan::pixel_search %d x_result=%d y_result=%d angle_step=%d diff=%lld\n",
-// __LINE__,
-// block_x1 * OVERSAMPLE - x_result,
-// block_y1 * OVERSAMPLE - y_result,
-// pkg->angle_step,
-// pkg->difference1);
-
-               }
-       }
-
-
-#ifdef STDDEV_TEST
-       qsort(stddev_table, get_total_packages(), sizeof(double), compare);
-
-
-// reject motion vector if not similar enough
-//     if(stddev_table[0] > 0.2)
-//     {
-// if(debug)
-// {
-// printf("MotionScan::pixel_search %d stddev fail min_stddev=%f\n",
-// __LINE__,
-// stddev_table[0]);
-// }
-//             failed = 1;
-//             return;
-//     }
-
-if(debug)
-{
-       printf("MotionScan::pixel_search %d\n", __LINE__);
-       for(int i = 0; i < get_total_packages(); i++)
-       {
-               printf("%f\n", stddev_table[i]);
-       }
-}
-
-// reject motion vector if not a sigmoid curve
-// TODO: use linear interpolation
-       int steps = 2;
-       int step = get_total_packages() / steps;
-       double curve[steps];
-       for(int i = 0; i < steps; i++)
-       {
-               int start = get_total_packages() * i / steps;
-               int end = get_total_packages() * (i + 1) / steps;
-               end = MIN(end, get_total_packages() - 1);
-               curve[i] = stddev_table[end] - stddev_table[start];
-       }
-
-
-//     if(curve[0] < (curve[1] * 1.01) ||
-//             curve[2] < (curve[1] * 1.01) ||
-//             curve[0] < (curve[2] * 0.75))
-//     if(curve[0] < curve[1])
-//     {
-// if(debug)
-// {
-// printf("MotionScan::pixel_search %d curve fail %f %f\n",
-// __LINE__,
-// curve[0],
-// curve[1]);
-// }
-//             failed = 1;
-//             return;
-//     }
-
-if(debug)
-{
-printf("MotionScan::pixel_search %d curve=%f %f ranges=%f %f min_stddev=%f\n",
-__LINE__,
-curve[0],
-curve[1],
-range1,
-range2,
-stddev_table[0]);
-}
-#endif // STDDEV_TEST
-
-
-
-
-
-       if(do_rotate)
-       {
-               rotation_pass = 1;;
-               total_steps = angle_steps;
-               scan_x1 = x_result / OVERSAMPLE;
-               scan_y1 = y_result / OVERSAMPLE;
-               set_package_count(total_steps);
-               process_packages();
-
+                       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;
 
 
-               min_difference = -1;
-               double prev_r_result = r_result;
-               for(int i = 0; i < get_total_packages(); i++)
-               {
-                       MotionScanPackage *pkg = (MotionScanPackage*)get_package(i);
 
-// printf("MotionScan::pixel_search %d search_x=%d search_y=%d angle_step=%d sub_x=%d sub_y=%d diff1=%lld diff2=%lld\n",
+// 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->search_angle_step,
 // pkg->sub_x,
-// pkg->sub_y,
-// pkg->difference1,
-// pkg->difference2);
-                       if(pkg->difference1 < min_difference || i == 0)
-                       {
-                               min_difference = pkg->difference1;
-                               r_result = step_to_angle(i, prev_r_result);
-
-       // printf("MotionScan::pixel_search %d x_result=%d y_result=%d angle_step=%d diff=%lld\n",
-       // __LINE__,
-       // block_x1 * OVERSAMPLE - x_result,
-       // block_y1 * OVERSAMPLE - y_result,
-       // pkg->angle_step,
-       // pkg->difference1);
-                       }
+// pkg->sub_y);
                }
-       }
 
-
-// printf("MotionScan::scan_frame %d current_downsample=%d x_result=%f y_result=%f r_result=%f\n",
+// printf("MotionScan::init_packages %d %d,%d %d,%d %d,%d\n",
 // __LINE__,
-// current_downsample,
-// (float)x_result / OVERSAMPLE,
-// (float)y_result / OVERSAMPLE,
-// r_result);
-
-}
-
-
-// subpixel motion search
-void MotionScan::subpixel_search(int &x_result, int &y_result)
-{
-       rotation_pass = 0;
-       previous_frame = previous_frame_arg;
-       current_frame = current_frame_arg;
-
-//printf("MotionScan::scan_frame %d %d %d\n", __LINE__, x_result, y_result);
-// Scan every subpixel in a SUBPIXEL_RANGE * SUBPIXEL_RANGE square
-       total_steps = (SUBPIXEL_RANGE * OVERSAMPLE) * (SUBPIXEL_RANGE * OVERSAMPLE);
-
-// These aren't used in subpixel
-       x_steps = OVERSAMPLE * SUBPIXEL_RANGE;
-       y_steps = OVERSAMPLE * SUBPIXEL_RANGE;
-       angle_steps = 1;
-
-       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;
-
+// scan_x1,
+// scan_x2,
+// scan_y1,
+// scan_y2,
+// pkg->search_x,
+// pkg->search_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);
-               }
+LoadClient* MotionScan::new_client()
+{
+       return new MotionScanUnit(this);
+}
 
-               if(pkg->difference2 < min_difference)
-               {
-                       min_difference = pkg->difference2;
+LoadPackage* MotionScan::new_package()
+{
+       return new MotionScanPackage;
+}
 
-                       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);
-               }
-       }
+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,
-       int block_x,
-       int block_y,
+       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,
-       int do_motion,
-       int do_rotate,
-       double rotation_center,
-       double rotation_range)
+       int global_origin_y)
 {
        this->previous_frame_arg = previous_frame;
        this->current_frame_arg = current_frame;
@@ -1085,51 +351,25 @@ void MotionScan::scan_frame(VFrame *previous_frame,
        this->current_frame = current_frame_arg;
        this->global_origin_x = global_origin_x;
        this->global_origin_y = global_origin_y;
-       this->action_type = action_type;
-       this->do_motion = do_motion;
-       this->do_rotate = do_rotate;
-       this->rotation_center = rotation_center;
-       this->rotation_range = rotation_range;
-
-//printf("MotionScan::scan_frame %d\n", __LINE__);
-       dx_result = 0;
-       dy_result = 0;
-       dr_result = 0;
-       failed = 0;
-
        subpixel = 0;
-// starting level of detail
-// TODO: base it on a table of resolutions
-       current_downsample = STARTING_DOWNSAMPLE;
-       angle_step = 0;
+
+       cache.remove_all_objects();
 
 // Single macroblock
        int w = current_frame->get_w();
        int h = current_frame->get_h();
 
 // Initial search parameters
-       scan_w = global_range_w;
-       scan_h = global_range_h;
-
-       int block_w = global_block_w;
-       int block_h = global_block_h;
-
-// printf("MotionScan::scan_frame %d %d %d %d %d %d %d %d %d\n",
-// __LINE__,
-// global_range_w,
-// global_range_h,
-// global_block_w,
-// global_block_h,
-// scan_w,
-// scan_h,
-// block_w,
-// block_h);
+       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)(block_x - block_w / 2);
-       block_y1 = (int)(block_y - block_h / 2);
-       block_x2 = (int)(block_x + block_w / 2);
-       block_y2 = (int)(block_y + block_h / 2);
+       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.
@@ -1149,7 +389,6 @@ void MotionScan::scan_frame(VFrame *previous_frame,
                case MotionScan::NO_CALCULATE:
                        dx_result = 0;
                        dy_result = 0;
-                       dr_result = rotation_center;
                        skip = 1;
                        break;
 
@@ -1157,55 +396,21 @@ void MotionScan::scan_frame(VFrame *previous_frame,
                {
 // Load result from disk
                        char string[BCTEXTLEN];
-
-                       skip = 1;
-                       if(do_motion)
-                       {
-                               sprintf(string, "%s%06d",
-                                       MOTION_FILE,
-                                       source_position);
+                       sprintf(string, "%s%06d", 
+                               MOTION_FILE, 
+                               source_position);
 //printf("MotionScan::scan_frame %d %s\n", __LINE__, string);
-                               FILE *input = fopen(string, "r");
-                               if(input)
-                               {
-                                       int temp = fscanf(input,
-                                               "%d %d",
-                                               &dx_result,
-                                               &dy_result);
-                                       if( temp != 2 )
-                                               printf("MotionScan::scan_frame %d %s\n", __LINE__, string);
+                       FILE *input = fopen(string, "r");
+                       if(input)
+                       {
+                               (void)fscanf(input, "%d %d", 
+                                       &dx_result, &dy_result);
 // HACK
 //dx_result *= 2;
 //dy_result *= 2;
 //printf("MotionScan::scan_frame %d %d %d\n", __LINE__, dx_result, dy_result);
-                                       fclose(input);
-                               }
-                               else
-                               {
-                                       skip = 0;
-                               }
-                       }
-
-                       if(do_rotate)
-                       {
-                               sprintf(string,
-                                       "%s%06d",
-                                       ROTATION_FILE,
-                                       source_position);
-                               FILE *input = fopen(string, "r");
-                               if(input)
-                               {
-                                       int temp = fscanf(input, "%f", &dr_result);
-                                       if( temp != 1 )
-                                               printf("MotionScan::scan_frame %d %s\n", __LINE__, string);
-// DEBUG
-//dr_result += 0.25;
-                                       fclose(input);
-                               }
-                               else
-                               {
-                                       skip = 0;
-                               }
+                               fclose(input);
+                               skip = 1;
                        }
                        break;
                }
@@ -1216,8 +421,6 @@ void MotionScan::scan_frame(VFrame *previous_frame,
                        break;
        }
 
-
-
        if(!skip && test_match)
        {
                if(previous_frame->data_matches(current_frame))
@@ -1225,21 +428,19 @@ void MotionScan::scan_frame(VFrame *previous_frame,
 printf("MotionScan::scan_frame: data matches. skipping.\n");
                        dx_result = 0;
                        dy_result = 0;
-                       dr_result = rotation_center;
                        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;
-               int origin_offset_y = this->global_origin_y;
+               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;
-               double r_result = rotation_center;
 
 // printf("MotionScan::scan_frame 1 %d %d %d %d %d %d %d %d\n",
 // block_x1 + block_w / 2,
@@ -1251,31 +452,32 @@ printf("MotionScan::scan_frame: data matches. skipping.\n");
 // block_x2,
 // block_y2);
 
-               while(!failed)
+               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;
-                       scan_angle1 = r_result - rotation_range;
-                       scan_angle2 = r_result + rotation_range;
 
 
 
 // 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 %d block_x1=%d block_y1=%d block_x2=%d block_y2=%d scan_x1=%d scan_y1=%d scan_x2=%d scan_y2=%d\n",
-// __LINE__,
+                       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,
@@ -1284,11 +486,9 @@ printf("MotionScan::scan_frame: data matches. skipping.\n");
 // scan_y1,
 // scan_x2,
 // scan_y2);
-
-
 // Clamp the block coords before the scan so we get useful scan coords.
-                       clamp_scan(w,
-                               h,
+                       clamp_scan(w, 
+                               h, 
                                &block_x1,
                                &block_y1,
                                &block_x2,
@@ -1298,21 +498,18 @@ printf("MotionScan::scan_frame: data matches. skipping.\n");
                                &scan_x2,
                                &scan_y2,
                                0);
-
-
-// printf("MotionScan::scan_frame %d block_x1=%d block_y1=%d block_x2=%d block_y2=%d scan_x1=%d scan_y1=%d scan_x2=%d scan_y2=%d x_result=%d y_result=%d\n",
+// 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,
+// scan_x1, 
+// scan_y1, 
+// scan_x2, 
+// scan_y2, 
+// x_result, 
 // y_result);
-//if(y_result == 88) exit(0);
 
 
 // Give up if invalid coords.
@@ -1320,49 +517,179 @@ printf("MotionScan::scan_frame: data matches. skipping.\n");
                                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)
                        {
 
-                               subpixel_search(x_result, y_result);
-// printf("MotionScan::scan_frame %d x_result=%d y_result=%d\n",
-// __LINE__,
-// x_result / OVERSAMPLE,
-// y_result / OVERSAMPLE);
+//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
                        {
-                               pixel_search(x_result, y_result, r_result);
-//printf("MotionScan::scan_frame %d x_result=%d y_result=%d\n", __LINE__, x_result / OVERSAMPLE, y_result / OVERSAMPLE);
+                               total_pixels = (scan_x2 - scan_x1) * (scan_y2 - scan_y1);
+                               this->total_steps = MIN(total_steps, total_pixels);
 
-                               if(failed)
+                               if(this->total_steps == total_pixels)
                                {
-                                       dr_result = 0;
-                                       dx_result = 0;
-                                       dy_result = 0;
+                                       x_steps = scan_x2 - scan_x1;
+                                       y_steps = scan_y2 - scan_y1;
                                }
                                else
-                               if(current_downsample <= 1)
                                {
-                       // Single pixel accuracy reached.  Now do exhaustive subpixel search.
+                                       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;
-//printf("MotionScan::scan_frame %d x_result=%d y_result=%d\n", __LINE__, x_result, y_result);
-                                               scan_w = SUBPIXEL_RANGE;
-                                               scan_h = SUBPIXEL_RANGE;
-// Final R result
-                                               dr_result = rotation_center - r_result;
+                                               scan_w = 2;
+                                               scan_h = 2;
                                                subpixel = 1;
                                        }
                                        else
@@ -1370,109 +697,59 @@ printf("MotionScan::scan_frame: data matches. skipping.\n");
 // Fill in results and quit
                                                dx_result = block_x1 * OVERSAMPLE - x_result;
                                                dy_result = block_y1 * OVERSAMPLE - y_result;
-                                               dr_result = rotation_center - r_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;
-// need slightly more than 2x downsampling factor
-
-                                       if(current_downsample * 3 < scan_w &&
-                                               current_downsample * 3 < scan_h)
-                                       {
-                                               scan_w = current_downsample * 3;
-                                               scan_h = current_downsample * 3;
-                                       }
-
-                                       if(angle_step * 1.5 < rotation_range)
-                                       {
-                                               rotation_range = angle_step * 1.5;
-                                       }
-//printf("MotionScan::scan_frame %d %f %f\n", __LINE__, angle_step, rotation_range);
-
-                                       current_downsample /= 2;
-
-// convert back to pixels
+                                       scan_w = (scan_x2 - scan_x1) / 2;
+                                       scan_h = (scan_y2 - scan_y1) / 2;
                                        x_result /= OVERSAMPLE;
                                        y_result /= OVERSAMPLE;
-// debug
-//exit(1);
                                }
-
                        }
                }
 
                dx_result *= -1;
                dy_result *= -1;
-               dr_result *= -1;
        }
-// printf("MotionScan::scan_frame %d dx=%f dy=%f dr=%f\n",
-// __LINE__,
-// (float)dx_result / OVERSAMPLE,
-// (float)dy_result / OVERSAMPLE,
-// dr_result);
+//printf("MotionScan::scan_frame %d\n", __LINE__);
 
 
+       if(vertical_only) dx_result = 0;
+       if(horizontal_only) dy_result = 0;
+
 
 
 // Write results
-       if(!skip && tracking_type == MotionScan::SAVE)
+       if(tracking_type == MotionScan::SAVE)
        {
                char string[BCTEXTLEN];
-
-
-               if(do_motion)
+               sprintf(string, 
+                       "%s%06d", 
+                       MOTION_FILE, 
+                       source_position);
+               FILE *output = fopen(string, "w");
+               if(output)
                {
-                       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 motion failed\n", __LINE__);
-                       }
+                       fprintf(output, 
+                               "%d %d\n",
+                               dx_result,
+                               dy_result);
+                       fclose(output);
                }
-
-               if(do_rotate)
+               else
                {
-                       sprintf(string,
-                               "%s%06d",
-                               ROTATION_FILE,
-                               source_position);
-                       FILE *output = fopen(string, "w");
-                       if(output)
-                       {
-                               fprintf(output, "%f\n", dr_result);
-                               fclose(output);
-                       }
-                       else
-                       {
-                               printf("MotionScan::scan_frame %d save rotation failed\n", __LINE__);
-                       }
+                       printf("MotionScan::scan_frame %d: save coordinate failed", __LINE__);
                }
        }
 
-
-       if(vertical_only) dx_result = 0;
-       if(horizontal_only) dy_result = 0;
-
-// printf("MotionScan::scan_frame %d dx=%d dy=%d\n",
+// printf("MotionScan::scan_frame %d dx=%.2f dy=%.2f\n", 
 // __LINE__,
-// this->dx_result,
-// this->dy_result);
+// (float)this->dx_result / OVERSAMPLE,
+// (float)this->dy_result / OVERSAMPLE);
 }
 
 
@@ -1491,6 +768,31 @@ printf("MotionScan::scan_frame: data matches. skipping.\n");
 
 
 
+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) \
@@ -1506,8 +808,10 @@ printf("MotionScan::scan_frame: data matches. skipping.\n");
                        { \
                                temp_type difference; \
                                difference = *prev_row++ - *current_row++; \
-                               difference *= difference; \
-                               result_temp += difference; \
+                               if(difference < 0) \
+                                       result_temp -= difference; \
+                               else \
+                                       result_temp += difference; \
                        } \
                        if(components == 4) \
                        { \
@@ -1549,6 +853,12 @@ int64_t MotionScan::abs_diff(unsigned char *prev_ptr,
                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;
 }
@@ -1583,8 +893,10 @@ int64_t MotionScan::abs_diff(unsigned char *prev_ptr,
                                        0x100 / 0x100; \
                                temp_type current_value = *current_row++; \
                                difference = prev_value - current_value; \
-                               difference *= difference; \
-                               result_temp += difference; \
+                               if(difference < 0) \
+                                       result_temp -= difference; \
+                               else \
+                                       result_temp += difference; \
                        } \
  \
 /* skip alpha */ \
@@ -1639,161 +951,31 @@ int64_t MotionScan::abs_diff_sub(unsigned char *prev_ptr,
                case BC_YUVA8888:
                        ABS_DIFF_SUB(unsigned char, int64_t, 1, 4)
                        break;
-       }
-       return result;
-}
-
-
-#if 0
-#define VARIANCE(type, temp_type, multiplier, components) \
-{ \
-       temp_type average[3] = { 0 }; \
-       temp_type variance[3] = { 0 }; \
- \
-       for(int i = 0; i < h; i++) \
-       { \
-               type *row = (type*)current_ptr + i * row_bytes; \
-               for(int j = 0; j < w; j++) \
-               { \
-                       for(int k = 0; k < 3; k++) \
-                       { \
-                               average[k] += row[k]; \
-                       } \
-                       row += components; \
-               } \
-       } \
-       for(int k = 0; k < 3; k++) \
-       { \
-               average[k] /= w * h; \
-       } \
- \
-       for(int i = 0; i < h; i++) \
-       { \
-               type *row = (type*)current_ptr + i * row_bytes; \
-               for(int j = 0; j < w; j++) \
-               { \
-                       for(int k = 0; k < 3; k++) \
-                       { \
-                               variance[k] += SQR(row[k] - average[k]); \
-                       } \
-                       row += components; \
-               } \
-       } \
-       result = (double)multiplier * \
-               sqrt((variance[0] + variance[1] + variance[2]) / w / h / 3); \
-}
-
-double MotionScan::calculate_variance(unsigned char *current_ptr,
-       int row_bytes,
-       int w,
-       int h,
-       int color_model)
-{
-       double result = 0;
-
-       switch(color_model)
-       {
-               case BC_RGB888:
-                       VARIANCE(unsigned char, int, 1, 3)
-                       break;
-               case BC_RGBA8888:
-                       VARIANCE(unsigned char, int, 1, 4)
-                       break;
-               case BC_RGB_FLOAT:
-                       VARIANCE(float, double, 255, 3)
-                       break;
-               case BC_RGBA_FLOAT:
-                       VARIANCE(float, double, 255, 4)
-                       break;
-               case BC_YUV888:
-                       VARIANCE(unsigned char, int, 1, 3)
+               case BC_YUV161616:
+                       ABS_DIFF_SUB(uint16_t, int64_t, 1, 3)
                        break;
-               case BC_YUVA8888:
-                       VARIANCE(unsigned char, int, 1, 4)
+               case BC_YUVA16161616:
+                       ABS_DIFF_SUB(uint16_t, int64_t, 1, 4)
                        break;
        }
-
-
        return result;
 }
-#endif // 0
 
 
 
 
-#define RANGE(type, temp_type, multiplier, components) \
-{ \
-       temp_type min[3]; \
-       temp_type max[3]; \
-       min[0] = 0x7fff; \
-       min[1] = 0x7fff; \
-       min[2] = 0x7fff; \
-       max[0] = 0; \
-       max[1] = 0; \
-       max[2] = 0; \
- \
-       for(int i = 0; i < h; i++) \
-       { \
-               type *row = (type*)current_ptr + i * row_bytes; \
-               for(int j = 0; j < w; j++) \
-               { \
-                       for(int k = 0; k < 3; k++) \
-                       { \
-                               if(row[k] > max[k]) max[k] = row[k]; \
-                               if(row[k] < min[k]) min[k] = row[k]; \
-                       } \
-                       row += components; \
-               } \
-       } \
- \
-       for(int k = 0; k < 3; k++) \
-       { \
-               /* printf("MotionScan::calculate_range %d k=%d max=%d min=%d\n", __LINE__, k, max[k], min[k]); */ \
-               if(max[k] - min[k] > result) result = max[k] - min[k]; \
-       } \
- \
-}
 
-double MotionScan::calculate_range(unsigned char *current_ptr,
-       int row_bytes,
-       int w,
-       int h,
-       int color_model)
+MotionScanCache::MotionScanCache(int x, int y, int64_t difference)
 {
-       double result = 0;
-
-       switch(color_model)
-       {
-               case BC_RGB888:
-                       RANGE(unsigned char, int, 1, 3)
-                       break;
-               case BC_RGBA8888:
-                       RANGE(unsigned char, int, 1, 4)
-                       break;
-               case BC_RGB_FLOAT:
-                       RANGE(float, float, 255, 3)
-                       break;
-               case BC_RGBA_FLOAT:
-                       RANGE(float, float, 255, 4)
-                       break;
-               case BC_YUV888:
-                       RANGE(unsigned char, int, 1, 3)
-                       break;
-               case BC_YUVA8888:
-                       RANGE(unsigned char, int, 1, 4)
-                       break;
-       }
-
-
-       return result;
+       this->x = x;
+       this->y = y;
+       this->difference = difference;
 }
 
 
-//#define CLAMP_BLOCK
 
-// this truncates the scan area but not the macroblock unless the macro is defined
-void MotionScan::clamp_scan(int w,
-       int h,
+void MotionScan::clamp_scan(int w, 
+       int h, 
        int *block_x1,
        int *block_y1,
        int *block_x2,
@@ -1824,37 +1006,29 @@ void MotionScan::clamp_scan(int w,
 // scan is always out of range before block.
                if(*scan_x1 < 0)
                {
-#ifdef CLAMP_BLOCK
-                       int difference = -*scan_x1;
-                       *block_x1 += difference;
-#endif
+//                     int difference = -*scan_x1;
+//                     *block_x1 += difference;
                        *scan_x1 = 0;
                }
 
                if(*scan_y1 < 0)
                {
-#ifdef CLAMP_BLOCK
-                       int difference = -*scan_y1;
-                       *block_y1 += difference;
-#endif
+//                     int difference = -*scan_y1;
+//                     *block_y1 += difference;
                        *scan_y1 = 0;
                }
 
                if(*scan_x2 > w)
                {
                        int difference = *scan_x2 - w;
-#ifdef CLAMP_BLOCK
-                       *block_x2 -= difference;
-#endif
+//                     *block_x2 -= difference;
                        *scan_x2 -= difference;
                }
 
                if(*scan_y2 > h)
                {
                        int difference = *scan_y2 - h;
-#ifdef CLAMP_BLOCK
-                       *block_y2 -= difference;
-#endif
+//                     *block_y2 -= difference;
                        *scan_y2 -= difference;
                }
 
@@ -1870,9 +1044,7 @@ void MotionScan::clamp_scan(int w,
                if(*scan_x1 < 0)
                {
                        int difference = -*scan_x1;
-#ifdef CLAMP_BLOCK
-                       *block_x1 += difference;
-#endif
+//                     *block_x1 += difference;
                        *scan_x2 += difference;
                        *scan_x1 = 0;
                }
@@ -1880,9 +1052,7 @@ void MotionScan::clamp_scan(int w,
                if(*scan_y1 < 0)
                {
                        int difference = -*scan_y1;
-#ifdef CLAMP_BLOCK
-                       *block_y1 += difference;
-#endif
+//                     *block_y1 += difference;
                        *scan_y2 += difference;
                        *scan_y1 = 0;
                }
@@ -1891,18 +1061,14 @@ void MotionScan::clamp_scan(int w,
                {
                        int difference = *scan_x2 - *block_x1 + *block_x2 - w;
                        *scan_x2 -= difference;
-#ifdef CLAMP_BLOCK
-                       *block_x2 -= difference;
-#endif
+//                     *block_x2 -= difference;
                }
 
                if(*scan_y2 - *block_y1 + *block_y2 > h)
                {
                        int difference = *scan_y2 - *block_y1 + *block_y2 - h;
                        *scan_y2 -= difference;
-#ifdef CLAMP_BLOCK
-                       *block_y2 -= difference;
-#endif
+//                     *block_y2 -= difference;
                }
 
 //             CLAMP(*scan_x1, 0, w - (*block_x2 - *block_x1));