resourcethread redraw speedup/fixes, replace vectorscope graticule IQ
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / motion / motionscan.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2012 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "clip.h"
23 //#include "../downsample/downsampleengine.h"
24 //#include "motion.h"
25 #include "motionscan.h"
26 #include "mutex.h"
27 #include "vframe.h"
28
29 #include <math.h>
30
31 // The module which does the actual scanning
32
33 MotionScanPackage::MotionScanPackage()
34  : LoadPackage()
35 {
36         valid = 1;
37 }
38
39 MotionScanUnit::MotionScanUnit(MotionScan *server)
40  : LoadClient(server)
41 {
42         this->server = server;
43         cache_lock = new Mutex("MotionScanUnit::cache_lock");
44 }
45
46 MotionScanUnit::~MotionScanUnit()
47 {
48         delete cache_lock;
49 }
50
51 void MotionScanUnit::process_package(LoadPackage *package)
52 {
53         MotionScanPackage *pkg = (MotionScanPackage*)package;
54         //int w = server->current_frame->get_w();
55         //int h = server->current_frame->get_h();
56         int color_model = server->current_frame->get_color_model();
57         int pixel_size = BC_CModels::calculate_pixelsize(color_model);
58         int row_bytes = server->current_frame->get_bytes_per_line();
59
60 // Single pixel
61         if( !server->subpixel ) {
62 // Try cache
63                 pkg->difference1 = server->get_cache(pkg->search_x, pkg->search_y);
64                 if( pkg->difference1 < 0 ) {
65 //printf("MotionScanUnit::process_package 1 search_x=%d search_y=%d"
66 // " scan_x1=%d scan_y1=%d scan_x2=%d scan_y2=%d x_steps=%d y_steps=%d\n",
67 // pkg->search_x, pkg->search_y, pkg->scan_x1, pkg->scan_y1, pkg->scan_x2, pkg->scan_y2,
68 // server->x_steps, server->y_steps);
69 // Pointers to first pixel in each block
70                         unsigned char *prev_ptr =
71                             server->previous_frame->get_rows()[pkg->search_y] +
72                                 pkg->search_x * pixel_size;
73                         unsigned char *current_ptr =
74                             server->current_frame->get_rows()[pkg->block_y1] +
75                                 pkg->block_x1 * pixel_size;
76 // Scan block
77                         pkg->difference1 = MotionScan::abs_diff(prev_ptr, current_ptr, row_bytes,
78                                 pkg->block_x2 - pkg->block_x1, pkg->block_y2 - pkg->block_y1,
79                                 color_model);
80
81 // printf("MotionScanUnit::process_package %d search_x=%d search_y=%d diff=%lld\n",
82 // __LINE__, server->block_x1 - pkg->search_x, server->block_y1 - pkg->search_y, pkg->difference1);
83                         server->put_cache(pkg->search_x, pkg->search_y, pkg->difference1);
84                 }
85         }
86 // Sub pixel
87         else {
88                 unsigned char *prev_ptr =
89                     server->previous_frame->get_rows()[pkg->search_y] +
90                         pkg->search_x * pixel_size;
91                 unsigned char *current_ptr =
92                     server->current_frame->get_rows()[pkg->block_y1] +
93                         pkg->block_x1 * pixel_size;
94
95 // With subpixel, there are two ways to compare each position, one by shifting
96 // the previous frame and two by shifting the current frame.
97                 pkg->difference1 = MotionScan::abs_diff_sub(prev_ptr, current_ptr, row_bytes,
98                         pkg->block_x2 - pkg->block_x1, pkg->block_y2 - pkg->block_y1,
99                         color_model, pkg->sub_x, pkg->sub_y);
100                 pkg->difference2 =
101                     MotionScan::abs_diff_sub(current_ptr, prev_ptr, row_bytes,
102                         pkg->block_x2 - pkg->block_x1, pkg->block_y2 - pkg->block_y1,
103                         color_model, pkg->sub_x, pkg->sub_y);
104 //printf("MotionScanUnit::process_package sub_x=%d sub_y=%d search_x=%d search_y=%d diff1=%lld diff2=%lld\n",
105 // sub_x, sub_y, search_x, search_y, pkg->difference1, pkg->difference2);
106         }
107 }
108
109 int64_t MotionScanUnit::get_cache(int x, int y)
110 {
111         int64_t result = -1;
112         cache_lock->lock("MotionScanUnit::get_cache");
113         for( int i = 0; i < cache.total; i++ ) {
114                 MotionScanCache *ptr = cache.values[i];
115                 if( ptr->x == x && ptr->y == y ) {
116                         result = ptr->difference;
117                         break;
118                 }
119         }
120         cache_lock->unlock();
121         return result;
122 }
123
124 void MotionScanUnit::put_cache(int x, int y, int64_t difference)
125 {
126         MotionScanCache *ptr = new MotionScanCache(x, y, difference);
127         cache_lock->lock("MotionScanUnit::put_cache");
128         cache.append(ptr);
129         cache_lock->unlock();
130 }
131
132 MotionScan::MotionScan(int total_clients, int total_packages)
133  : LoadServer( //1, 1
134                 total_clients, total_packages)
135 {
136         test_match = 1;
137         cache_lock = new Mutex("MotionScan::cache_lock");
138         downsampled_previous = 0;
139         downsampled_current = 0;
140 //      downsample = 0;
141 }
142
143 MotionScan::~MotionScan()
144 {
145         delete cache_lock;
146         delete downsampled_previous;
147         delete downsampled_current;
148 //      delete downsample;
149 }
150
151 void MotionScan::init_packages()
152 {
153 // Set package coords
154 //printf("MotionScan::init_packages %d %d\n", __LINE__, get_total_packages());
155         for( int i = 0; i < get_total_packages(); i++ ) {
156                 MotionScanPackage *pkg = (MotionScanPackage*)get_package(i);
157
158                 pkg->block_x1 = block_x1; pkg->block_x2 = block_x2;
159                 pkg->block_y1 = block_y1; pkg->block_y2 = block_y2;
160                 pkg->scan_x1 = scan_x1;   pkg->scan_x2 = scan_x2;
161                 pkg->scan_y1 = scan_y1;   pkg->scan_y2 = scan_y2;
162                 pkg->difference1 = 0;     pkg->difference2 = 0;
163                 pkg->step = i;            pkg->valid = 1;
164                 pkg->dx = pkg->dy = 0;
165
166                 if( !subpixel ) {
167                         pkg->search_x = pkg->scan_x1 +
168                                 (pkg->step % x_steps) * (scan_x2 - scan_x1) / x_steps;
169                         pkg->search_y = pkg->scan_y1 +
170                                 (pkg->step / x_steps) * (scan_y2 - scan_y1) / y_steps;
171                         pkg->sub_x = pkg->sub_y = 0;
172                 }
173                 else {
174                         pkg->sub_x = pkg->step % (OVERSAMPLE * 2);
175                         pkg->sub_y = pkg->step / (OVERSAMPLE * 2);
176
177                         if( horizontal_only ) pkg->sub_y = 0;
178                         if( vertical_only ) pkg->sub_x = 0;
179
180                         pkg->search_x = pkg->scan_x1 + pkg->sub_x / OVERSAMPLE + 1;
181                         pkg->search_y = pkg->scan_y1 + pkg->sub_y / OVERSAMPLE + 1;
182                         pkg->sub_x %= OVERSAMPLE;
183                         pkg->sub_y %= OVERSAMPLE;
184
185 // printf("MotionScan::init_packages %d i=%d search_x=%d search_y=%d sub_x=%d sub_y=%d\n",
186 // __LINE__, i, pkg->search_x, pkg->search_y, pkg->sub_x, pkg->sub_y);
187                 }
188
189 // printf("MotionScan::init_packages %d %d,%d %d,%d %d,%d\n",
190 // __LINE__, scan_x1, scan_x2, scan_y1, scan_y2, pkg->search_x, pkg->search_y);
191         }
192 }
193
194 LoadClient* MotionScan::new_client()
195 {
196         return new MotionScanUnit(this);
197 }
198
199 LoadPackage* MotionScan::new_package()
200 {
201         return new MotionScanPackage;
202 }
203
204 void MotionScan::set_test_match(int value)
205 {
206         this->test_match = value;
207 }
208
209 void MotionScan::scan_frame(VFrame *previous_frame, VFrame *current_frame,
210                 int global_range_w, int global_range_h,
211                 int global_block_w, int global_block_h,
212                 double block_x, double block_y, int frame_type,
213                 int tracking_type, int action_type,
214                 int horizontal_only, int vertical_only,
215                 int source_position, int total_steps, int total_dx,
216                 int total_dy, int global_origin_x, int global_origin_y,
217                 int load_ok, int load_dx, int load_dy)
218 {
219         this->previous_frame_arg = previous_frame;
220         this->current_frame_arg = current_frame;
221         this->horizontal_only = horizontal_only;
222         this->vertical_only = vertical_only;
223         this->previous_frame = previous_frame_arg;
224         this->current_frame = current_frame_arg;
225         this->global_origin_x = global_origin_x;
226         this->global_origin_y = global_origin_y;
227         subpixel = 0;
228
229         cache.remove_all_objects();
230
231 // Single macroblock
232         int w = current_frame->get_w();
233         int h = current_frame->get_h();
234
235 // Initial search parameters
236         int scan_w = w * global_range_w / 100;
237         int scan_h = h * global_range_h / 100;
238         int block_w = w * global_block_w / 100;
239         int block_h = h * global_block_h / 100;
240
241 // Location of block in previous frame
242         block_x1 = (int)(w * block_x / 100 - block_w / 2);
243         block_y1 = (int)(h * block_y / 100 - block_h / 2);
244         block_x2 = (int)(w * block_x / 100 + block_w / 2);
245         block_y2 = (int)(h * block_y / 100 + block_h / 2);
246
247 // Offset to location of previous block.  This offset needn't be very accurate
248 // since it's the offset of the previous image and current image we want.
249         if( frame_type == MotionScan::TRACK_PREVIOUS ) {
250                 block_x1 += total_dx / OVERSAMPLE;
251                 block_y1 += total_dy / OVERSAMPLE;
252                 block_x2 += total_dx / OVERSAMPLE;
253                 block_y2 += total_dy / OVERSAMPLE;
254         }
255
256         skip = 0;
257
258         switch( tracking_type ) {
259 // Don't calculate
260         case MotionScan::NO_CALCULATE:
261                 dx_result = dy_result = 0;
262                 skip = 1;
263                 break;
264
265         case MotionScan::LOAD:
266         case MotionScan::SAVE:
267                 if( load_ok ) {
268                         dx_result = load_dx;
269                         dy_result = load_dy;
270                         skip = 1;
271                 }
272                 break;
273
274 // Scan from scratch
275         default:
276                 skip = 0;
277                 break;
278         }
279
280         if( !skip && test_match ) {
281                 if( previous_frame->data_matches(current_frame) ) {
282                         printf("MotionScan::scan_frame: data matches. skipping.\n");
283                         dx_result = dy_result = 0;
284                         skip = 1;
285                 }
286         }
287 // Perform scan
288         if( !skip ) {
289 //printf("MotionScan::scan_frame %d\n", __LINE__);
290 // Location of block in current frame
291                 int origin_offset_x = this->global_origin_x * w / 100;
292                 int origin_offset_y = this->global_origin_y * h / 100;
293                 int x_result = block_x1 + origin_offset_x;
294                 int y_result = block_y1 + origin_offset_y;
295
296 //printf("MotionScan::scan_frame 1 %d %d %d %d %d %d %d %d\n",
297 // block_x1 + block_w / 2, block_y1 + block_h / 2,
298 // block_w, block_h, block_x1, block_y1, block_x2, block_y2);
299
300                 while(1) {
301 // Cache needs to be cleared if downsampling is used because the sums of
302 // different downsamplings can't be compared.
303 // Subpixel never uses the cache.
304 //                      cache.remove_all_objects();
305                         scan_x1 = x_result - scan_w / 2;
306                         scan_y1 = y_result - scan_h / 2;
307                         scan_x2 = x_result + scan_w / 2;
308                         scan_y2 = y_result + scan_h / 2;
309
310 // Zero out requested values
311                         if( horizontal_only ) {
312                                 scan_y1 = block_y1;
313                                 scan_y2 = block_y1 + 1;
314                         }
315                         if( vertical_only ) {
316                                 scan_x1 = block_x1;
317                                 scan_x2 = block_x1 + 1;
318                         }
319 //printf("MotionScan::scan_frame 1 %d %d %d %d %d %d %d %d\n",
320 // block_x1, block_y1, block_x2, block_y2, scan_x1, scan_y1, scan_x2, scan_y2);
321 // Clamp the block coords before the scan so we get useful scan coords.
322                         clamp_scan(w, h, &block_x1, &block_y1, &block_x2,
323                                 &block_y2, &scan_x1, &scan_y1, &scan_x2,
324                                 &scan_y2, 0);
325 // printf("MotionScan::scan_frame 1 %d block_x1=%d block_y1=%d block_x2=%d block_y2=%d\n"
326 //  "    scan_x1=%d scan_y1=%d scan_x2=%d scan_y2=%d\n"
327 //  "    x_result=%d y_result=%d\n", __LINE__, block_x1, block_y1, block_x2, block_y2,
328 //      scan_x1, scan_y1, scan_x2, scan_y2, x_result, y_result);
329
330 // Give up if invalid coords.
331                         if (scan_y2 <= scan_y1 || scan_x2 <= scan_x1 ||
332                             block_x2 <= block_x1 || block_y2 <= block_y1 )
333                                 break;
334
335 // For subpixel, the top row and left column are skipped
336                         if( subpixel ) {
337
338 //printf("MotionScan::scan_frame %d %d %d\n", __LINE__, x_result, y_result);
339 // Scan every subpixel in a 2 pixel * 2 pixel square
340                                 total_pixels = (2 * OVERSAMPLE) * (2 * OVERSAMPLE);
341
342                                 this->total_steps = total_pixels;
343 // These aren't used in subpixel
344                                 this->x_steps = OVERSAMPLE * 2;
345                                 this->y_steps = OVERSAMPLE * 2;
346
347                                 set_package_count(this->total_steps);
348                                 process_packages();
349
350 // Get least difference
351                                 int64_t min_difference = -1;
352                                 for( int i = 0; i < get_total_packages(); i++ ) {
353                                         MotionScanPackage *pkg = (MotionScanPackage *)get_package(i);
354 //printf("MotionScan::scan_frame %d search_x=%d search_y=%d sub_x=%d sub_y=%d diff1=%lld diff2=%lld\n",
355 //__LINE__, pkg->search_x, pkg->search_y, pkg->sub_x, pkg->sub_y, pkg->difference1, pkg->difference2);
356                                         if( pkg->difference1 < min_difference ||
357                                             min_difference == -1 ) {
358                                                 min_difference = pkg->difference1;
359
360 // The sub coords are 1 pixel up & left of the block coords
361                                                 x_result = pkg->search_x * OVERSAMPLE + pkg->sub_x;
362                                                 y_result = pkg->search_y * OVERSAMPLE + pkg->sub_y;
363 // Fill in results
364                                                 dx_result = block_x1 * OVERSAMPLE - x_result;
365                                                 dy_result = block_y1 * OVERSAMPLE - y_result;
366 //printf("MotionScan::scan_frame %d dx_result=%d dy_result=%d diff=%lld\n",
367 //__LINE__, dx_result, dy_result, min_difference);
368                                         }
369
370                                         if( pkg->difference2 < min_difference ) {
371                                                 min_difference = pkg->difference2;
372
373                                                 x_result = pkg->search_x * OVERSAMPLE - pkg->sub_x;
374                                                 y_result = pkg->search_y * OVERSAMPLE - pkg->sub_y;
375
376                                                 dx_result = block_x1 * OVERSAMPLE - x_result;
377                                                 dy_result = block_y1 * OVERSAMPLE - y_result;
378 //printf("MotionScan::scan_frame %d dx_result=%d dy_result=%d diff=%lld\n",
379 //__LINE__, dx_result, dy_result, min_difference);
380                                         }
381                                 }
382
383                                 break;
384                         }
385 // Single pixel
386                         else {
387                                 total_pixels =
388                                     (scan_x2 - scan_x1) * (scan_y2 - scan_y1);
389                                 this->total_steps =
390                                     MIN(total_steps, total_pixels);
391
392                                 if( this->total_steps == total_pixels ) {
393                                         x_steps = scan_x2 - scan_x1;
394                                         y_steps = scan_y2 - scan_y1;
395                                 }
396                                 else {
397                                         x_steps = (int)sqrt(this->total_steps);
398                                         y_steps = (int)sqrt(this->total_steps);
399                                 }
400
401 // Use downsampled images
402 //                              if( scan_x2 - scan_x1 > x_steps * 4 ||
403 //                                      scan_y2 - scan_y1 > y_steps * 4 )
404 //                              {
405 // printf("MotionScan::scan_frame %d total_pixels=%d total_steps=%d x_steps=%d y_steps=%d x y steps=%d\n",
406 // __LINE__,
407 // total_pixels,
408 // total_steps,
409 // x_steps,
410 // y_steps,
411 // x_steps * y_steps);
412 //
413 //                                      if( !downsampled_previous ||
414 //                                              !downsampled_previous->equivalent(previous_frame_arg) )
415 //                                      {
416 //                                              delete downsampled_previous;
417 //                                              downsampled_previous = new VFrame(*previous_frame_arg);
418 //                                      }
419 //
420 //                                      if( !downsampled_current ||
421 //                                              !downsampled_current->equivalent(current_frame_arg) )
422 //                                      {
423 //                                              delete downsampled_current;
424 //                                              downsampled_current = new VFrame(*current_frame_arg);
425 //                                      }
426 //
427 //
428 //                                      if( !downsample )
429 //                                              downsample = new DownSampleServer(get_total_clients(),
430 //                                                      get_total_clients());
431 //                                      downsample->process_frame(downsampled_previous,
432 //                                              previous_frame_arg, 1, 1, 1, 1,
433 //                                              (scan_y2 - scan_y1) / y_steps,
434 //                                              (scan_x2 - scan_x1) / x_steps,
435 //                                              0, 0);
436 //                                      downsample->process_frame(downsampled_current,
437 //                                              current_frame_arg, 1, 1, 1, 1,
438 //                                              (scan_y2 - scan_y1) / y_steps,
439 //                                              (scan_x2 - scan_x1) / x_steps,
440 //                                              0, 0);
441 //                                      this->previous_frame = downsampled_previous;
442 //                                      this->current_frame = downsampled_current;
443 //                              }
444
445 // printf("MotionScan::scan_frame %d this->total_steps=%d\n",
446 // __LINE__, this->total_steps);
447
448                                 set_package_count(this->total_steps);
449                                 process_packages();
450
451 // Get least difference
452                                 int64_t min_difference = -1;
453                                 for( int i = 0; i < get_total_packages(); i++ ) {
454                                         MotionScanPackage *pkg = (MotionScanPackage *) get_package(i);
455 //printf("MotionScan::scan_frame %d search_x=%d search_y=%d sub_x=%d sub_y=%d diff1=%lld diff2=%lld\n",
456 // __LINE__, pkg->search_x, pkg->search_y, pkg->sub_x, pkg->sub_y, pkg->difference1, pkg->difference2);
457                                         if (pkg->difference1 < min_difference
458                                             || min_difference == -1) {
459                                                 min_difference = pkg->difference1;
460                                                 x_result = pkg->search_x;
461                                                 y_result = pkg->search_y;
462                                                 x_result *= OVERSAMPLE;
463                                                 y_result *= OVERSAMPLE;
464 //printf("MotionScan::scan_frame %d x_result=%d y_result=%d diff=%lld\n",
465 //__LINE__, block_x1 * OVERSAMPLE - x_result, block_y1 * OVERSAMPLE - y_result, pkg->difference1);
466                                         }
467                                 }
468
469 // If a new search is required, rescale results back to pixels.
470                                 if( this->total_steps >= total_pixels ) {
471 // Single pixel accuracy reached.  Now do exhaustive subpixel search.
472                                         if( action_type == MotionScan::STABILIZE ||
473                                                 action_type == MotionScan::TRACK ||
474                                                 action_type == MotionScan::NOTHING ) {
475 //printf("MotionScan::scan_frame %d %d %d\n", __LINE__, x_result, y_result);
476                                                 x_result /= OVERSAMPLE;
477                                                 y_result /= OVERSAMPLE;
478                                                 scan_w = scan_h = 2;
479                                                 subpixel = 1;
480                                         }
481 // Fill in results and quit
482                                         else {
483                                                 dx_result = block_x1 * OVERSAMPLE - x_result;
484                                                 dy_result = block_y1 * OVERSAMPLE - y_result;
485 //printf("MotionScan::scan_frame %d %d %d\n", __LINE__, dx_result, dy_result);
486                                                 break;
487                                         }
488                                 }
489 // Reduce scan area and try again
490                                 else {
491                                         scan_w = (scan_x2 - scan_x1) / 2;
492                                         scan_h = (scan_y2 - scan_y1) / 2;
493                                         x_result /= OVERSAMPLE;
494                                         y_result /= OVERSAMPLE;
495                                 }
496                         }
497                 }
498                 dx_result = -dx_result;
499                 dy_result = -dy_result;
500         }
501 //printf("MotionScan::scan_frame %d\n", __LINE__);
502
503         if( vertical_only ) dx_result = 0;
504         if( horizontal_only ) dy_result = 0;
505
506 //printf("MotionScan::scan_frame %d dx=%.2f dy=%.2f\n",
507 // __LINE__, (float)this->dx_result / OVERSAMPLE, (float)this->dy_result / OVERSAMPLE);
508 }
509
510 int64_t MotionScan::get_cache(int x, int y)
511 {
512         int64_t result = -1;
513         cache_lock->lock("MotionScan::get_cache");
514         for( int i = 0; i < cache.total; i++ ) {
515                 MotionScanCache *ptr = cache.values[i];
516                 if( ptr->x == x && ptr->y == y ) {
517                         result = ptr->difference;
518                         break;
519                 }
520         }
521         cache_lock->unlock();
522         return result;
523 }
524
525 void MotionScan::put_cache(int x, int y, int64_t difference)
526 {
527         MotionScanCache *ptr = new MotionScanCache(x, y, difference);
528         cache_lock->lock("MotionScan::put_cache");
529         cache.append(ptr);
530         cache_lock->unlock();
531 }
532
533 #define ABS_DIFF(model, type, temp_type, multiplier, components) case model: { \
534         temp_type result_temp = 0; \
535         for( int i = 0; i < h; i++ ) { \
536                 type *prev_row = (type*)prev_ptr; \
537                 type *current_row = (type*)current_ptr; \
538                 for( int j = 0; j < w; j++ ) { \
539                         for( int k = 0; k < 3; k++ ) { \
540                                 temp_type difference; \
541                                 difference = *prev_row++ - *current_row++; \
542                                 if( difference < 0 ) \
543                                         result_temp -= difference; \
544                                 else \
545                                         result_temp += difference; \
546                         } \
547                         if( components == 4 ) { \
548                                 prev_row++; \
549                                 current_row++; \
550                         } \
551                 } \
552                 prev_ptr += row_bytes; \
553                 current_ptr += row_bytes; \
554         } \
555         result = (int64_t)(result_temp * multiplier); \
556 } break
557
558 int64_t MotionScan::abs_diff(unsigned char *prev_ptr,
559                 unsigned char *current_ptr, int row_bytes, int w,
560                 int h, int color_model)
561 {
562         int64_t result = 0;
563         switch( color_model ) {
564         ABS_DIFF(BC_RGB888, unsigned char, int64_t, 1, 3);
565         ABS_DIFF(BC_RGBA8888, unsigned char, int64_t, 1, 4);
566         ABS_DIFF(BC_RGB_FLOAT, float, double, 0x10000, 3);
567         ABS_DIFF(BC_RGBA_FLOAT, float, double, 0x10000, 4);
568         ABS_DIFF(BC_YUV888, unsigned char, int64_t, 1, 3);
569         ABS_DIFF(BC_YUVA8888, unsigned char, int64_t, 1, 4);
570         ABS_DIFF(BC_YUV161616, uint16_t, int64_t, 1, 3);
571         ABS_DIFF(BC_YUVA16161616, uint16_t, int64_t, 1, 4);
572         }
573         return result;
574 }
575
576 #define ABS_DIFF_SUB(model, type, temp_type, multiplier, components) case model: { \
577         temp_type result_temp = 0; \
578         temp_type y2_fraction = sub_y * 0x100 / OVERSAMPLE; \
579         temp_type y1_fraction = 0x100 - y2_fraction; \
580         temp_type x2_fraction = sub_x * 0x100 / OVERSAMPLE; \
581         temp_type x1_fraction = 0x100 - x2_fraction; \
582         for( int i = 0; i < h_sub; i++ ) { \
583                 type *prev_row1 = (type*)prev_ptr; \
584                 type *prev_row2 = (type*)prev_ptr + components; \
585                 type *prev_row3 = (type*)(prev_ptr + row_bytes); \
586                 type *prev_row4 = (type*)(prev_ptr + row_bytes) + components; \
587                 type *current_row = (type*)current_ptr; \
588                 for( int j = 0; j < w_sub; j++ ) { \
589 /* Scan each component */ \
590                         for( int k = 0; k < 3; k++ ) { \
591                                 temp_type difference; \
592                                 temp_type prev_value = \
593                                         (*prev_row1++ * x1_fraction * y1_fraction + \
594                                         *prev_row2++ * x2_fraction * y1_fraction + \
595                                         *prev_row3++ * x1_fraction * y2_fraction + \
596                                         *prev_row4++ * x2_fraction * y2_fraction) / \
597                                         0x100 / 0x100; \
598                                 temp_type current_value = *current_row++; \
599                                 difference = prev_value - current_value; \
600                                 if( difference < 0 ) \
601                                         result_temp -= difference; \
602                                 else \
603                                         result_temp += difference; \
604                         } \
605  \
606 /* skip alpha */ \
607                         if( components == 4 ) { \
608                                 prev_row1++; \
609                                 prev_row2++; \
610                                 prev_row3++; \
611                                 prev_row4++; \
612                                 current_row++; \
613                         } \
614                 } \
615                 prev_ptr += row_bytes; \
616                 current_ptr += row_bytes; \
617         } \
618         result = (int64_t)(result_temp * multiplier); \
619 } break
620
621 int64_t MotionScan::abs_diff_sub(unsigned char *prev_ptr,
622                 unsigned char *current_ptr, int row_bytes,
623                 int w, int h, int color_model, int sub_x,
624                 int sub_y)
625 {
626         int h_sub = h - 1;
627         int w_sub = w - 1;
628         int64_t result = 0;
629
630         switch( color_model ) {
631         ABS_DIFF_SUB(BC_RGB888, unsigned char, int64_t, 1, 3);
632         ABS_DIFF_SUB(BC_RGBA8888, unsigned char, int64_t, 1, 4);
633         ABS_DIFF_SUB(BC_RGB_FLOAT, float, double, 0x10000, 3);
634         ABS_DIFF_SUB(BC_RGBA_FLOAT, float, double, 0x10000, 4);
635         ABS_DIFF_SUB(BC_YUV888, unsigned char, int64_t, 1, 3);
636         ABS_DIFF_SUB(BC_YUVA8888, unsigned char, int64_t, 1, 4);
637         ABS_DIFF_SUB(BC_YUV161616, uint16_t, int64_t, 1, 3);
638         ABS_DIFF_SUB(BC_YUVA16161616, uint16_t, int64_t, 1, 4);
639         }
640         return result;
641 }
642
643 MotionScanCache::MotionScanCache(int x, int y, int64_t difference)
644 {
645         this->x = x;
646         this->y = y;
647         this->difference = difference;
648 }
649
650 void MotionScan::clamp_scan(int w, int h,
651                 int *block_x1, int *block_y1, int *block_x2,
652                 int *block_y2, int *scan_x1, int *scan_y1,
653                 int *scan_x2, int *scan_y2, int use_absolute)
654 {
655 //printf("MotionMain::clamp_scan 1 w=%d h=%d block=%d %d %d %d scan=%d %d %d %d absolute=%d\n",
656 // w, h, *block_x1, *block_y1, *block_x2, *block_y2, *scan_x1, *scan_y1, *scan_x2, *scan_y2,
657 // use_absolute);
658
659         if( use_absolute ) {
660 // Limit size of scan area
661 // Used for drawing vectors
662 // scan is always out of range before block.
663                 if( *scan_x1 < 0 ) {
664 //                      int difference = -*scan_x1;
665 //                      *block_x1 += difference;
666                         *scan_x1 = 0;
667                 }
668
669                 if( *scan_y1 < 0 ) {
670 //                      int difference = -*scan_y1;
671 //                      *block_y1 += difference;
672                         *scan_y1 = 0;
673                 }
674
675                 if( *scan_x2 > w ) {
676                         int difference = *scan_x2 - w;
677 //                      *block_x2 -= difference;
678                         *scan_x2 -= difference;
679                 }
680
681                 if( *scan_y2 > h ) {
682                         int difference = *scan_y2 - h;
683 //                      *block_y2 -= difference;
684                         *scan_y2 -= difference;
685                 }
686
687                 CLAMP(*scan_x1, 0, w);
688                 CLAMP(*scan_y1, 0, h);
689                 CLAMP(*scan_x2, 0, w);
690                 CLAMP(*scan_y2, 0, h);
691         }
692         else {
693 // Limit range of upper left block coordinates
694 // Used for motion tracking
695                 if( *scan_x1 < 0 ) {
696                         int difference = -*scan_x1;
697 //                      *block_x1 += difference;
698                         *scan_x2 += difference;
699                         *scan_x1 = 0;
700                 }
701
702                 if( *scan_y1 < 0 ) {
703                         int difference = -*scan_y1;
704 //                      *block_y1 += difference;
705                         *scan_y2 += difference;
706                         *scan_y1 = 0;
707                 }
708
709                 if( *scan_x2 - *block_x1 + *block_x2 > w ) {
710                         int difference = *scan_x2 - *block_x1 + *block_x2 - w;
711                         *scan_x2 -= difference;
712 //                      *block_x2 -= difference;
713                 }
714
715                 if( *scan_y2 - *block_y1 + *block_y2 > h ) {
716                         int difference = *scan_y2 - *block_y1 + *block_y2 - h;
717                         *scan_y2 -= difference;
718 //                      *block_y2 -= difference;
719                 }
720 //              CLAMP(*scan_x1, 0, w - (*block_x2 - *block_x1));
721 //              CLAMP(*scan_y1, 0, h - (*block_y2 - *block_y1));
722 //              CLAMP(*scan_x2, 0, w - (*block_x2 - *block_x1));
723 //              CLAMP(*scan_y2, 0, h - (*block_y2 - *block_y1));
724         }
725
726 // Sanity checks which break the calculation but should never happen if the
727 // center of the block is inside the frame.
728         CLAMP(*block_x1, 0, w);
729         CLAMP(*block_x2, 0, w);
730         CLAMP(*block_y1, 0, h);
731         CLAMP(*block_y2, 0, h);
732
733 //printf("MotionMain::clamp_scan 2 w=%d h=%d block=%d %d %d %d scan=%d %d %d %d absolute=%d\n",
734 // w, h, *block_x1, *block_y1, *block_x2, *block_y2, *scan_x1, *scan_y1, *scan_x2, *scan_y2,
735 // use_absolute);
736 }