b1a533ef850477a9c7412d39e92c45d5d60c2a09
[goodguy/history.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
34
35
36
37 MotionScanPackage::MotionScanPackage()
38  : LoadPackage()
39 {
40         valid = 1;
41 }
42
43
44
45
46
47
48 MotionScanUnit::MotionScanUnit(MotionScan *server)
49  : LoadClient(server)
50 {
51         this->server = server;
52         cache_lock = new Mutex("MotionScanUnit::cache_lock");
53 }
54
55 MotionScanUnit::~MotionScanUnit()
56 {
57         delete cache_lock;
58 }
59
60
61
62 void MotionScanUnit::process_package(LoadPackage *package)
63 {
64         MotionScanPackage *pkg = (MotionScanPackage*)package;
65         //int w = server->current_frame->get_w();
66         //int h = server->current_frame->get_h();
67         int color_model = server->current_frame->get_color_model();
68         int pixel_size = BC_CModels::calculate_pixelsize(color_model);
69         int row_bytes = server->current_frame->get_bytes_per_line();
70
71
72
73
74
75
76
77
78
79
80
81
82 // Single pixel
83         if(!server->subpixel)
84         {
85 // Try cache
86                 pkg->difference1 = server->get_cache(pkg->search_x, pkg->search_y);
87                 if(pkg->difference1 < 0)
88                 {
89 //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", 
90 //pkg->search_x, pkg->search_y, pkg->scan_x1, pkg->scan_y1, pkg->scan_x2, pkg->scan_y2, server->x_steps, server->y_steps);
91 // Pointers to first pixel in each block
92                         unsigned char *prev_ptr = server->previous_frame->get_rows()[
93                                 pkg->search_y] +        
94                                 pkg->search_x * pixel_size;
95                         unsigned char *current_ptr = server->current_frame->get_rows()[
96                                 pkg->block_y1] +
97                                 pkg->block_x1 * pixel_size;
98
99 // Scan block
100                         pkg->difference1 = MotionScan::abs_diff(prev_ptr,
101                                 current_ptr,
102                                 row_bytes,
103                                 pkg->block_x2 - pkg->block_x1,
104                                 pkg->block_y2 - pkg->block_y1,
105                                 color_model);
106
107 // printf("MotionScanUnit::process_package %d search_x=%d search_y=%d diff=%lld\n",
108 // __LINE__, server->block_x1 - pkg->search_x, server->block_y1 - pkg->search_y, pkg->difference1);
109                         server->put_cache(pkg->search_x, pkg->search_y, pkg->difference1);
110                 }
111         }
112
113
114
115
116
117
118
119         else
120
121
122
123
124
125
126
127
128 // Sub pixel
129         {
130                 unsigned char *prev_ptr = server->previous_frame->get_rows()[
131                         pkg->search_y] +
132                         pkg->search_x * pixel_size;
133                 unsigned char *current_ptr = server->current_frame->get_rows()[
134                         pkg->block_y1] +
135                         pkg->block_x1 * pixel_size;
136
137 // With subpixel, there are two ways to compare each position, one by shifting
138 // the previous frame and two by shifting the current frame.
139                 pkg->difference1 = MotionScan::abs_diff_sub(prev_ptr,
140                         current_ptr,
141                         row_bytes,
142                         pkg->block_x2 - pkg->block_x1,
143                         pkg->block_y2 - pkg->block_y1,
144                         color_model,
145                         pkg->sub_x,
146                         pkg->sub_y);
147                 pkg->difference2 = MotionScan::abs_diff_sub(current_ptr,
148                         prev_ptr,
149                         row_bytes,
150                         pkg->block_x2 - pkg->block_x1,
151                         pkg->block_y2 - pkg->block_y1,
152                         color_model,
153                         pkg->sub_x,
154                         pkg->sub_y);
155 // printf("MotionScanUnit::process_package sub_x=%d sub_y=%d search_x=%d search_y=%d diff1=%lld diff2=%lld\n",
156 // sub_x,
157 // sub_y,
158 // search_x,
159 // search_y,
160 // pkg->difference1,
161 // pkg->difference2);
162         }
163
164
165
166
167 }
168
169
170
171
172
173
174
175
176
177
178 int64_t MotionScanUnit::get_cache(int x, int y)
179 {
180         int64_t result = -1;
181         cache_lock->lock("MotionScanUnit::get_cache");
182         for(int i = 0; i < cache.total; i++)
183         {
184                 MotionScanCache *ptr = cache.values[i];
185                 if(ptr->x == x && ptr->y == y)
186                 {
187                         result = ptr->difference;
188                         break;
189                 }
190         }
191         cache_lock->unlock();
192         return result;
193 }
194
195 void MotionScanUnit::put_cache(int x, int y, int64_t difference)
196 {
197         MotionScanCache *ptr = new MotionScanCache(x, y, difference);
198         cache_lock->lock("MotionScanUnit::put_cache");
199         cache.append(ptr);
200         cache_lock->unlock();
201 }
202
203
204
205
206
207
208
209
210
211
212
213 MotionScan::MotionScan(int total_clients,
214         int total_packages)
215  : LoadServer(
216 //1, 1 
217 total_clients, total_packages 
218 )
219 {
220         test_match = 1;
221         cache_lock = new Mutex("MotionScan::cache_lock");
222         downsampled_previous = 0;
223         downsampled_current = 0;
224 //      downsample = 0;
225 }
226
227 MotionScan::~MotionScan()
228 {
229         delete cache_lock;
230         delete downsampled_previous;
231         delete downsampled_current;
232 //      delete downsample;
233 }
234
235
236 void MotionScan::init_packages()
237 {
238 // Set package coords
239 //printf("MotionScan::init_packages %d %d\n", __LINE__, get_total_packages());
240         for(int i = 0; i < get_total_packages(); i++)
241         {
242                 MotionScanPackage *pkg = (MotionScanPackage*)get_package(i);
243
244                 pkg->block_x1 = block_x1;
245                 pkg->block_x2 = block_x2;
246                 pkg->block_y1 = block_y1;
247                 pkg->block_y2 = block_y2;
248                 pkg->scan_x1 = scan_x1;
249                 pkg->scan_x2 = scan_x2;
250                 pkg->scan_y1 = scan_y1;
251                 pkg->scan_y2 = scan_y2;
252                 pkg->step = i;
253                 pkg->difference1 = 0;
254                 pkg->difference2 = 0;
255                 pkg->dx = 0;
256                 pkg->dy = 0;
257                 pkg->valid = 1;
258                 
259                 if(!subpixel)
260                 {
261                         pkg->search_x = pkg->scan_x1 + (pkg->step % x_steps) *
262                                 (scan_x2 - scan_x1) / x_steps;
263                         pkg->search_y = pkg->scan_y1 + (pkg->step / x_steps) *
264                                 (scan_y2 - scan_y1) / y_steps;
265                         pkg->sub_x = 0;
266                         pkg->sub_y = 0;
267                 }
268                 else
269                 {
270                         pkg->sub_x = pkg->step % (OVERSAMPLE * 2);
271                         pkg->sub_y = pkg->step / (OVERSAMPLE * 2);
272
273                         if(horizontal_only)
274                         {
275                                 pkg->sub_y = 0;
276                         }
277
278                         if(vertical_only)
279                         {
280                                 pkg->sub_x = 0;
281                         }
282
283                         pkg->search_x = pkg->scan_x1 + pkg->sub_x / OVERSAMPLE + 1;
284                         pkg->search_y = pkg->scan_y1 + pkg->sub_y / OVERSAMPLE + 1;
285                         pkg->sub_x %= OVERSAMPLE;
286                         pkg->sub_y %= OVERSAMPLE;
287
288
289
290 // printf("MotionScan::init_packages %d i=%d search_x=%d search_y=%d sub_x=%d sub_y=%d\n", 
291 // __LINE__,
292 // i,
293 // pkg->search_x,
294 // pkg->search_y,
295 // pkg->sub_x,
296 // pkg->sub_y);
297                 }
298
299 // printf("MotionScan::init_packages %d %d,%d %d,%d %d,%d\n",
300 // __LINE__,
301 // scan_x1,
302 // scan_x2,
303 // scan_y1,
304 // scan_y2,
305 // pkg->search_x,
306 // pkg->search_y);
307         }
308 }
309
310 LoadClient* MotionScan::new_client()
311 {
312         return new MotionScanUnit(this);
313 }
314
315 LoadPackage* MotionScan::new_package()
316 {
317         return new MotionScanPackage;
318 }
319
320
321 void MotionScan::set_test_match(int value)
322 {
323         this->test_match = value;
324 }
325
326 void MotionScan::scan_frame(VFrame *previous_frame,
327         VFrame *current_frame,
328         int global_range_w,
329         int global_range_h,
330         int global_block_w,
331         int global_block_h,
332         double block_x,
333         double block_y,
334         int frame_type,
335         int tracking_type,
336         int action_type,
337         int horizontal_only,
338         int vertical_only,
339         int source_position,
340         int total_steps,
341         int total_dx,
342         int total_dy,
343         int global_origin_x,
344         int global_origin_y)
345 {
346         this->previous_frame_arg = previous_frame;
347         this->current_frame_arg = current_frame;
348         this->horizontal_only = horizontal_only;
349         this->vertical_only = vertical_only;
350         this->previous_frame = previous_frame_arg;
351         this->current_frame = current_frame_arg;
352         this->global_origin_x = global_origin_x;
353         this->global_origin_y = global_origin_y;
354         subpixel = 0;
355
356         cache.remove_all_objects();
357
358 // Single macroblock
359         int w = current_frame->get_w();
360         int h = current_frame->get_h();
361
362 // Initial search parameters
363         int scan_w = w * global_range_w / 100;
364         int scan_h = h * global_range_h / 100;
365         int block_w = w * global_block_w / 100;
366         int block_h = h * global_block_h / 100;
367
368 // Location of block in previous frame
369         block_x1 = (int)(w * block_x / 100 - block_w / 2);
370         block_y1 = (int)(h * block_y / 100 - block_h / 2);
371         block_x2 = (int)(w * block_x / 100 + block_w / 2);
372         block_y2 = (int)(h * block_y / 100 + block_h / 2);
373
374 // Offset to location of previous block.  This offset needn't be very accurate
375 // since it's the offset of the previous image and current image we want.
376         if(frame_type == MotionScan::TRACK_PREVIOUS)
377         {
378                 block_x1 += total_dx / OVERSAMPLE;
379                 block_y1 += total_dy / OVERSAMPLE;
380                 block_x2 += total_dx / OVERSAMPLE;
381                 block_y2 += total_dy / OVERSAMPLE;
382         }
383
384         skip = 0;
385
386         switch(tracking_type)
387         {
388 // Don't calculate
389                 case MotionScan::NO_CALCULATE:
390                         dx_result = 0;
391                         dy_result = 0;
392                         skip = 1;
393                         break;
394
395                 case MotionScan::LOAD:
396                 {
397 // Load result from disk
398                         char string[BCTEXTLEN];
399                         sprintf(string, "%s%06d", 
400                                 MOTION_FILE, 
401                                 source_position);
402 //printf("MotionScan::scan_frame %d %s\n", __LINE__, string);
403                         FILE *input = fopen(string, "r");
404                         if(input)
405                         {
406                                 (void)fscanf(input, "%d %d", 
407                                         &dx_result, &dy_result);
408 // HACK
409 //dx_result *= 2;
410 //dy_result *= 2;
411 //printf("MotionScan::scan_frame %d %d %d\n", __LINE__, dx_result, dy_result);
412                                 fclose(input);
413                                 skip = 1;
414                         }
415                         break;
416                 }
417
418 // Scan from scratch
419                 default:
420                         skip = 0;
421                         break;
422         }
423
424         if(!skip && test_match)
425         {
426                 if(previous_frame->data_matches(current_frame))
427                 {
428 printf("MotionScan::scan_frame: data matches. skipping.\n");
429                         dx_result = 0;
430                         dy_result = 0;
431                         skip = 1;
432                 }
433         }
434
435 // Perform scan
436         if(!skip)
437         {
438 //printf("MotionScan::scan_frame %d\n", __LINE__);
439 // Location of block in current frame
440                 int origin_offset_x = this->global_origin_x * w / 100;
441                 int origin_offset_y = this->global_origin_y * h / 100;
442                 int x_result = block_x1 + origin_offset_x;
443                 int y_result = block_y1 + origin_offset_y;
444
445 // printf("MotionScan::scan_frame 1 %d %d %d %d %d %d %d %d\n",
446 // block_x1 + block_w / 2,
447 // block_y1 + block_h / 2,
448 // block_w,
449 // block_h,
450 // block_x1,
451 // block_y1,
452 // block_x2,
453 // block_y2);
454
455                 while(1)
456                 {
457 // Cache needs to be cleared if downsampling is used because the sums of 
458 // different downsamplings can't be compared.
459 // Subpixel never uses the cache.
460 //                      cache.remove_all_objects();
461                         scan_x1 = x_result - scan_w / 2;
462                         scan_y1 = y_result - scan_h / 2;
463                         scan_x2 = x_result + scan_w / 2;
464                         scan_y2 = y_result + scan_h / 2;
465
466
467
468 // Zero out requested values
469                         if(horizontal_only)
470                         {
471                                 scan_y1 = block_y1;
472                                 scan_y2 = block_y1 + 1;
473                         }
474                         if(vertical_only)
475                         {
476                                 scan_x1 = block_x1;
477                                 scan_x2 = block_x1 + 1;
478                         }
479
480 // printf("MotionScan::scan_frame 1 %d %d %d %d %d %d %d %d\n",
481 // block_x1,
482 // block_y1,
483 // block_x2,
484 // block_y2,
485 // scan_x1,
486 // scan_y1,
487 // scan_x2,
488 // scan_y2);
489 // Clamp the block coords before the scan so we get useful scan coords.
490                         clamp_scan(w, 
491                                 h, 
492                                 &block_x1,
493                                 &block_y1,
494                                 &block_x2,
495                                 &block_y2,
496                                 &scan_x1,
497                                 &scan_y1,
498                                 &scan_x2,
499                                 &scan_y2,
500                                 0);
501 // 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", 
502 // __LINE__,
503 // block_x1,
504 // block_y1,
505 // block_x2,
506 // block_y2,
507 // scan_x1, 
508 // scan_y1, 
509 // scan_x2, 
510 // scan_y2, 
511 // x_result, 
512 // y_result);
513
514
515 // Give up if invalid coords.
516                         if(scan_y2 <= scan_y1 ||
517                                 scan_x2 <= scan_x1 ||
518                                 block_x2 <= block_x1 ||
519                                 block_y2 <= block_y1)
520                                 break;
521
522 // For subpixel, the top row and left column are skipped
523                         if(subpixel)
524                         {
525
526 //printf("MotionScan::scan_frame %d %d %d\n", __LINE__, x_result, y_result);
527 // Scan every subpixel in a 2 pixel * 2 pixel square
528                                 total_pixels = (2 * OVERSAMPLE) * (2 * OVERSAMPLE);
529
530                                 this->total_steps = total_pixels;
531 // These aren't used in subpixel
532                                 this->x_steps = OVERSAMPLE * 2;
533                                 this->y_steps = OVERSAMPLE * 2;
534
535                                 set_package_count(this->total_steps);
536                                 process_packages();
537
538 // Get least difference
539                                 int64_t min_difference = -1;
540                                 for(int i = 0; i < get_total_packages(); i++)
541                                 {
542                                         MotionScanPackage *pkg = (MotionScanPackage*)get_package(i);
543 //printf("MotionScan::scan_frame %d search_x=%d search_y=%d sub_x=%d sub_y=%d diff1=%lld diff2=%lld\n", 
544 //__LINE__, pkg->search_x, pkg->search_y, pkg->sub_x, pkg->sub_y, pkg->difference1, pkg->difference2);
545                                         if(pkg->difference1 < min_difference || min_difference == -1)
546                                         {
547                                                 min_difference = pkg->difference1;
548
549 // The sub coords are 1 pixel up & left of the block coords
550                                                 x_result = pkg->search_x * OVERSAMPLE + pkg->sub_x;
551                                                 y_result = pkg->search_y * OVERSAMPLE + pkg->sub_y;
552
553
554 // Fill in results
555                                                 dx_result = block_x1 * OVERSAMPLE - x_result;
556                                                 dy_result = block_y1 * OVERSAMPLE - y_result;
557 //printf("MotionScan::scan_frame %d dx_result=%d dy_result=%d diff=%lld\n", 
558 //__LINE__, dx_result, dy_result, min_difference);
559                                         }
560
561                                         if(pkg->difference2 < min_difference)
562                                         {
563                                                 min_difference = pkg->difference2;
564
565                                                 x_result = pkg->search_x * OVERSAMPLE - pkg->sub_x;
566                                                 y_result = pkg->search_y * OVERSAMPLE - pkg->sub_y;
567
568                                                 dx_result = block_x1 * OVERSAMPLE - x_result;
569                                                 dy_result = block_y1 * OVERSAMPLE - y_result;
570 //printf("MotionScan::scan_frame %d dx_result=%d dy_result=%d diff=%lld\n", 
571 //__LINE__, dx_result, dy_result, min_difference);
572                                         }
573                                 }
574
575                                 break;
576                         }
577                         else
578 // Single pixel
579                         {
580                                 total_pixels = (scan_x2 - scan_x1) * (scan_y2 - scan_y1);
581                                 this->total_steps = MIN(total_steps, total_pixels);
582
583                                 if(this->total_steps == total_pixels)
584                                 {
585                                         x_steps = scan_x2 - scan_x1;
586                                         y_steps = scan_y2 - scan_y1;
587                                 }
588                                 else
589                                 {
590                                         x_steps = (int)sqrt(this->total_steps);
591                                         y_steps = (int)sqrt(this->total_steps);
592                                 }
593
594 // Use downsampled images
595 //                              if(scan_x2 - scan_x1 > x_steps * 4 ||
596 //                                      scan_y2 - scan_y1 > y_steps * 4)
597 //                              {
598 // printf("MotionScan::scan_frame %d total_pixels=%d total_steps=%d x_steps=%d y_steps=%d x y steps=%d\n",
599 // __LINE__,
600 // total_pixels,
601 // total_steps,
602 // x_steps,
603 // y_steps,
604 // x_steps * y_steps);
605 // 
606 //                                      if(!downsampled_previous ||
607 //                                              !downsampled_previous->equivalent(previous_frame_arg))
608 //                                      {
609 //                                              delete downsampled_previous;
610 //                                              downsampled_previous = new VFrame(*previous_frame_arg);
611 //                                      }
612 // 
613 //                                      if(!downsampled_current ||
614 //                                              !downsampled_current->equivalent(current_frame_arg))
615 //                                      {
616 //                                              delete downsampled_current;
617 //                                              downsampled_current = new VFrame(*current_frame_arg);
618 //                                      }
619 // 
620 // 
621 //                                      if(!downsample)
622 //                                              downsample = new DownSampleServer(get_total_clients(), 
623 //                                                      get_total_clients());
624 //                                      downsample->process_frame(downsampled_previous, 
625 //                                              previous_frame_arg, 
626 //                                              1, 
627 //                                              1, 
628 //                                              1, 
629 //                                              1,
630 //                                              (scan_y2 - scan_y1) / y_steps,
631 //                                              (scan_x2 - scan_x1) / x_steps,
632 //                                              0,
633 //                                              0);
634 //                                      downsample->process_frame(downsampled_current, 
635 //                                              current_frame_arg, 
636 //                                              1, 
637 //                                              1, 
638 //                                              1, 
639 //                                              1,
640 //                                              (scan_y2 - scan_y1) / y_steps,
641 //                                              (scan_x2 - scan_x1) / x_steps,
642 //                                              0,
643 //                                              0);
644 //                                      this->previous_frame = downsampled_previous;
645 //                                      this->current_frame = downsampled_current;
646 //                              }
647
648
649
650
651
652 // printf("MotionScan::scan_frame %d this->total_steps=%d\n", 
653 // __LINE__, 
654 // this->total_steps);
655
656
657                                 set_package_count(this->total_steps);
658                                 process_packages();
659
660 // Get least difference
661                                 int64_t min_difference = -1;
662                                 for(int i = 0; i < get_total_packages(); i++)
663                                 {
664                                         MotionScanPackage *pkg = (MotionScanPackage*)get_package(i);
665 //printf("MotionScan::scan_frame %d search_x=%d search_y=%d sub_x=%d sub_y=%d diff1=%lld diff2=%lld\n", 
666 //__LINE__, pkg->search_x, pkg->search_y, pkg->sub_x, pkg->sub_y, pkg->difference1, pkg->difference2);
667                                         if(pkg->difference1 < min_difference || min_difference == -1)
668                                         {
669                                                 min_difference = pkg->difference1;
670                                                 x_result = pkg->search_x;
671                                                 y_result = pkg->search_y;
672                                                 x_result *= OVERSAMPLE;
673                                                 y_result *= OVERSAMPLE;
674 //printf("MotionScan::scan_frame %d x_result=%d y_result=%d diff=%lld\n", 
675 //__LINE__, block_x1 * OVERSAMPLE - x_result, block_y1 * OVERSAMPLE - y_result, pkg->difference1);
676                                         }
677                                 }
678
679
680 // If a new search is required, rescale results back to pixels.
681                                 if(this->total_steps >= total_pixels)
682                                 {
683 // Single pixel accuracy reached.  Now do exhaustive subpixel search.
684                                         if(action_type == MotionScan::STABILIZE ||
685                                                 action_type == MotionScan::TRACK ||
686                                                 action_type == MotionScan::NOTHING)
687                                         {
688 //printf("MotionScan::scan_frame %d %d %d\n", __LINE__, x_result, y_result);
689                                                 x_result /= OVERSAMPLE;
690                                                 y_result /= OVERSAMPLE;
691                                                 scan_w = 2;
692                                                 scan_h = 2;
693                                                 subpixel = 1;
694                                         }
695                                         else
696                                         {
697 // Fill in results and quit
698                                                 dx_result = block_x1 * OVERSAMPLE - x_result;
699                                                 dy_result = block_y1 * OVERSAMPLE - y_result;
700 //printf("MotionScan::scan_frame %d %d %d\n", __LINE__, dx_result, dy_result);
701                                                 break;
702                                         }
703                                 }
704                                 else
705 // Reduce scan area and try again
706                                 {
707                                         scan_w = (scan_x2 - scan_x1) / 2;
708                                         scan_h = (scan_y2 - scan_y1) / 2;
709                                         x_result /= OVERSAMPLE;
710                                         y_result /= OVERSAMPLE;
711                                 }
712                         }
713                 }
714
715                 dx_result *= -1;
716                 dy_result *= -1;
717         }
718 //printf("MotionScan::scan_frame %d\n", __LINE__);
719
720
721         if(vertical_only) dx_result = 0;
722         if(horizontal_only) dy_result = 0;
723
724
725
726 // Write results
727         if(tracking_type == MotionScan::SAVE)
728         {
729                 char string[BCTEXTLEN];
730                 sprintf(string, 
731                         "%s%06d", 
732                         MOTION_FILE, 
733                         source_position);
734                 FILE *output = fopen(string, "w");
735                 if(output)
736                 {
737                         fprintf(output, 
738                                 "%d %d\n",
739                                 dx_result,
740                                 dy_result);
741                         fclose(output);
742                 }
743                 else
744                 {
745                         printf("MotionScan::scan_frame %d: save coordinate failed", __LINE__);
746                 }
747         }
748
749 // printf("MotionScan::scan_frame %d dx=%.2f dy=%.2f\n", 
750 // __LINE__,
751 // (float)this->dx_result / OVERSAMPLE,
752 // (float)this->dy_result / OVERSAMPLE);
753 }
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771 int64_t MotionScan::get_cache(int x, int y)
772 {
773         int64_t result = -1;
774         cache_lock->lock("MotionScan::get_cache");
775         for(int i = 0; i < cache.total; i++)
776         {
777                 MotionScanCache *ptr = cache.values[i];
778                 if(ptr->x == x && ptr->y == y)
779                 {
780                         result = ptr->difference;
781                         break;
782                 }
783         }
784         cache_lock->unlock();
785         return result;
786 }
787
788 void MotionScan::put_cache(int x, int y, int64_t difference)
789 {
790         MotionScanCache *ptr = new MotionScanCache(x, y, difference);
791         cache_lock->lock("MotionScan::put_cache");
792         cache.append(ptr);
793         cache_lock->unlock();
794 }
795
796
797
798 #define ABS_DIFF(type, temp_type, multiplier, components) \
799 { \
800         temp_type result_temp = 0; \
801         for(int i = 0; i < h; i++) \
802         { \
803                 type *prev_row = (type*)prev_ptr; \
804                 type *current_row = (type*)current_ptr; \
805                 for(int j = 0; j < w; j++) \
806                 { \
807                         for(int k = 0; k < 3; k++) \
808                         { \
809                                 temp_type difference; \
810                                 difference = *prev_row++ - *current_row++; \
811                                 if(difference < 0) \
812                                         result_temp -= difference; \
813                                 else \
814                                         result_temp += difference; \
815                         } \
816                         if(components == 4) \
817                         { \
818                                 prev_row++; \
819                                 current_row++; \
820                         } \
821                 } \
822                 prev_ptr += row_bytes; \
823                 current_ptr += row_bytes; \
824         } \
825         result = (int64_t)(result_temp * multiplier); \
826 }
827
828 int64_t MotionScan::abs_diff(unsigned char *prev_ptr,
829         unsigned char *current_ptr,
830         int row_bytes,
831         int w,
832         int h,
833         int color_model)
834 {
835         int64_t result = 0;
836         switch(color_model)
837         {
838                 case BC_RGB888:
839                         ABS_DIFF(unsigned char, int64_t, 1, 3)
840                         break;
841                 case BC_RGBA8888:
842                         ABS_DIFF(unsigned char, int64_t, 1, 4)
843                         break;
844                 case BC_RGB_FLOAT:
845                         ABS_DIFF(float, double, 0x10000, 3)
846                         break;
847                 case BC_RGBA_FLOAT:
848                         ABS_DIFF(float, double, 0x10000, 4)
849                         break;
850                 case BC_YUV888:
851                         ABS_DIFF(unsigned char, int64_t, 1, 3)
852                         break;
853                 case BC_YUVA8888:
854                         ABS_DIFF(unsigned char, int64_t, 1, 4)
855                         break;
856                 case BC_YUV161616:
857                         ABS_DIFF(uint16_t, int64_t, 1, 3)
858                         break;
859                 case BC_YUVA16161616:
860                         ABS_DIFF(uint16_t, int64_t, 1, 4)
861                         break;
862         }
863         return result;
864 }
865
866
867
868 #define ABS_DIFF_SUB(type, temp_type, multiplier, components) \
869 { \
870         temp_type result_temp = 0; \
871         temp_type y2_fraction = sub_y * 0x100 / OVERSAMPLE; \
872         temp_type y1_fraction = 0x100 - y2_fraction; \
873         temp_type x2_fraction = sub_x * 0x100 / OVERSAMPLE; \
874         temp_type x1_fraction = 0x100 - x2_fraction; \
875         for(int i = 0; i < h_sub; i++) \
876         { \
877                 type *prev_row1 = (type*)prev_ptr; \
878                 type *prev_row2 = (type*)prev_ptr + components; \
879                 type *prev_row3 = (type*)(prev_ptr + row_bytes); \
880                 type *prev_row4 = (type*)(prev_ptr + row_bytes) + components; \
881                 type *current_row = (type*)current_ptr; \
882                 for(int j = 0; j < w_sub; j++) \
883                 { \
884 /* Scan each component */ \
885                         for(int k = 0; k < 3; k++) \
886                         { \
887                                 temp_type difference; \
888                                 temp_type prev_value = \
889                                         (*prev_row1++ * x1_fraction * y1_fraction + \
890                                         *prev_row2++ * x2_fraction * y1_fraction + \
891                                         *prev_row3++ * x1_fraction * y2_fraction + \
892                                         *prev_row4++ * x2_fraction * y2_fraction) / \
893                                         0x100 / 0x100; \
894                                 temp_type current_value = *current_row++; \
895                                 difference = prev_value - current_value; \
896                                 if(difference < 0) \
897                                         result_temp -= difference; \
898                                 else \
899                                         result_temp += difference; \
900                         } \
901  \
902 /* skip alpha */ \
903                         if(components == 4) \
904                         { \
905                                 prev_row1++; \
906                                 prev_row2++; \
907                                 prev_row3++; \
908                                 prev_row4++; \
909                                 current_row++; \
910                         } \
911                 } \
912                 prev_ptr += row_bytes; \
913                 current_ptr += row_bytes; \
914         } \
915         result = (int64_t)(result_temp * multiplier); \
916 }
917
918
919
920
921 int64_t MotionScan::abs_diff_sub(unsigned char *prev_ptr,
922         unsigned char *current_ptr,
923         int row_bytes,
924         int w,
925         int h,
926         int color_model,
927         int sub_x,
928         int sub_y)
929 {
930         int h_sub = h - 1;
931         int w_sub = w - 1;
932         int64_t result = 0;
933
934         switch(color_model)
935         {
936                 case BC_RGB888:
937                         ABS_DIFF_SUB(unsigned char, int64_t, 1, 3)
938                         break;
939                 case BC_RGBA8888:
940                         ABS_DIFF_SUB(unsigned char, int64_t, 1, 4)
941                         break;
942                 case BC_RGB_FLOAT:
943                         ABS_DIFF_SUB(float, double, 0x10000, 3)
944                         break;
945                 case BC_RGBA_FLOAT:
946                         ABS_DIFF_SUB(float, double, 0x10000, 4)
947                         break;
948                 case BC_YUV888:
949                         ABS_DIFF_SUB(unsigned char, int64_t, 1, 3)
950                         break;
951                 case BC_YUVA8888:
952                         ABS_DIFF_SUB(unsigned char, int64_t, 1, 4)
953                         break;
954                 case BC_YUV161616:
955                         ABS_DIFF_SUB(uint16_t, int64_t, 1, 3)
956                         break;
957                 case BC_YUVA16161616:
958                         ABS_DIFF_SUB(uint16_t, int64_t, 1, 4)
959                         break;
960         }
961         return result;
962 }
963
964
965
966
967
968 MotionScanCache::MotionScanCache(int x, int y, int64_t difference)
969 {
970         this->x = x;
971         this->y = y;
972         this->difference = difference;
973 }
974
975
976
977 void MotionScan::clamp_scan(int w, 
978         int h, 
979         int *block_x1,
980         int *block_y1,
981         int *block_x2,
982         int *block_y2,
983         int *scan_x1,
984         int *scan_y1,
985         int *scan_x2,
986         int *scan_y2,
987         int use_absolute)
988 {
989 // printf("MotionMain::clamp_scan 1 w=%d h=%d block=%d %d %d %d scan=%d %d %d %d absolute=%d\n",
990 // w,
991 // h,
992 // *block_x1,
993 // *block_y1,
994 // *block_x2,
995 // *block_y2,
996 // *scan_x1,
997 // *scan_y1,
998 // *scan_x2,
999 // *scan_y2,
1000 // use_absolute);
1001
1002         if(use_absolute)
1003         {
1004 // Limit size of scan area
1005 // Used for drawing vectors
1006 // scan is always out of range before block.
1007                 if(*scan_x1 < 0)
1008                 {
1009 //                      int difference = -*scan_x1;
1010 //                      *block_x1 += difference;
1011                         *scan_x1 = 0;
1012                 }
1013
1014                 if(*scan_y1 < 0)
1015                 {
1016 //                      int difference = -*scan_y1;
1017 //                      *block_y1 += difference;
1018                         *scan_y1 = 0;
1019                 }
1020
1021                 if(*scan_x2 > w)
1022                 {
1023                         int difference = *scan_x2 - w;
1024 //                      *block_x2 -= difference;
1025                         *scan_x2 -= difference;
1026                 }
1027
1028                 if(*scan_y2 > h)
1029                 {
1030                         int difference = *scan_y2 - h;
1031 //                      *block_y2 -= difference;
1032                         *scan_y2 -= difference;
1033                 }
1034
1035                 CLAMP(*scan_x1, 0, w);
1036                 CLAMP(*scan_y1, 0, h);
1037                 CLAMP(*scan_x2, 0, w);
1038                 CLAMP(*scan_y2, 0, h);
1039         }
1040         else
1041         {
1042 // Limit range of upper left block coordinates
1043 // Used for motion tracking
1044                 if(*scan_x1 < 0)
1045                 {
1046                         int difference = -*scan_x1;
1047 //                      *block_x1 += difference;
1048                         *scan_x2 += difference;
1049                         *scan_x1 = 0;
1050                 }
1051
1052                 if(*scan_y1 < 0)
1053                 {
1054                         int difference = -*scan_y1;
1055 //                      *block_y1 += difference;
1056                         *scan_y2 += difference;
1057                         *scan_y1 = 0;
1058                 }
1059
1060                 if(*scan_x2 - *block_x1 + *block_x2 > w)
1061                 {
1062                         int difference = *scan_x2 - *block_x1 + *block_x2 - w;
1063                         *scan_x2 -= difference;
1064 //                      *block_x2 -= difference;
1065                 }
1066
1067                 if(*scan_y2 - *block_y1 + *block_y2 > h)
1068                 {
1069                         int difference = *scan_y2 - *block_y1 + *block_y2 - h;
1070                         *scan_y2 -= difference;
1071 //                      *block_y2 -= difference;
1072                 }
1073
1074 //              CLAMP(*scan_x1, 0, w - (*block_x2 - *block_x1));
1075 //              CLAMP(*scan_y1, 0, h - (*block_y2 - *block_y1));
1076 //              CLAMP(*scan_x2, 0, w - (*block_x2 - *block_x1));
1077 //              CLAMP(*scan_y2, 0, h - (*block_y2 - *block_y1));
1078         }
1079
1080 // Sanity checks which break the calculation but should never happen if the
1081 // center of the block is inside the frame.
1082         CLAMP(*block_x1, 0, w);
1083         CLAMP(*block_x2, 0, w);
1084         CLAMP(*block_y1, 0, h);
1085         CLAMP(*block_y2, 0, h);
1086
1087 // printf("MotionMain::clamp_scan 2 w=%d h=%d block=%d %d %d %d scan=%d %d %d %d absolute=%d\n",
1088 // w,
1089 // h,
1090 // *block_x1,
1091 // *block_y1,
1092 // *block_x2,
1093 // *block_y2,
1094 // *scan_x1,
1095 // *scan_y1,
1096 // *scan_x2,
1097 // *scan_y2,
1098 // use_absolute);
1099 }
1100
1101
1102