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