remove old openjpeg which was upgrade awhile back
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / motion2point / motion.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2016 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 "affine.h"
23 #include "../motion-hv/motionscan-hv.h"
24 #include "bcdisplayinfo.h"
25 #include "bcsignals.h"
26 #include "clip.h"
27 #include "bchash.h"
28 #include "filexml.h"
29 #include "keyframe.h"
30 #include "language.h"
31 #include "motion.h"
32 #include "motionwindow.h"
33 #include "mutex.h"
34 #include "overlayframe.h"
35 #include "rotateframe.h"
36 #include "transportque.h"
37
38
39 #include <errno.h>
40 #include <unistd.h>
41
42 REGISTER_PLUGIN(MotionMain2)
43
44 //#undef DEBUG
45
46 #ifndef DEBUG
47 #define DEBUG
48 #endif
49
50
51 MotionConfig::MotionConfig()
52 {
53         for(int i = 0; i < TOTAL_POINTS; i++)
54         {
55                 global[i] = 1;
56                 global_range_w[i] = 5;
57                 global_range_h[i] = 5;
58                 global_origin_x[i] = 0;
59                 global_origin_y[i] = 0;
60                 global_block_w[i] = MIN_BLOCK;
61                 global_block_h[i] = MIN_BLOCK;
62                 block_x[i] = 50;
63                 block_y[i] = 50;
64                 draw_vectors[i] = 1;
65         }
66
67         global_positions = 256;
68         magnitude = 100;
69         return_speed = 0;
70         action = MotionScan::STABILIZE;
71         calculation = MotionScan::NO_CALCULATE;
72         tracking_object = MotionScan::TRACK_SINGLE;
73         track_frame = 0;
74         bottom_is_master = 1;
75         horizontal_only = 0;
76         vertical_only = 0;
77 }
78
79 void MotionConfig::boundaries()
80 {
81         for(int i = 0; i < TOTAL_POINTS; i++)
82         {
83                 CLAMP(global_range_w[i], MIN_RADIUS, MAX_RADIUS);
84                 CLAMP(global_range_h[i], MIN_RADIUS, MAX_RADIUS);
85                 CLAMP(global_origin_x[i], MIN_ORIGIN, MAX_ORIGIN);
86                 CLAMP(global_origin_y[i], MIN_ORIGIN, MAX_ORIGIN);
87                 CLAMP(global_block_w[i], MIN_BLOCK, MAX_BLOCK);
88                 CLAMP(global_block_h[i], MIN_BLOCK, MAX_BLOCK);
89         }
90
91 }
92
93 int MotionConfig::equivalent(MotionConfig &that)
94 {
95         int result = 1;
96         for(int i = 0; i < TOTAL_POINTS; i++)
97         {
98                 if(global[i] != that.global[i] ||
99                    global_range_w[i] != that.global_range_w[i] ||
100                    global_range_h[i] != that.global_range_h[i] ||
101                    draw_vectors[i] != that.draw_vectors[i] ||
102                    global_block_w[i] != that.global_block_w[i] ||
103                    global_block_h[i] != that.global_block_h[i] ||
104                    global_origin_x[i] != that.global_origin_x[i] ||
105                    global_origin_y[i] != that.global_origin_y[i] ||
106                    !EQUIV(block_x[i], that.block_x[i]) ||
107                    !EQUIV(block_y[i], that.block_y[i]))
108                    result = 0;
109         }
110
111         if(magnitude != that.magnitude ||
112                 return_speed != that.return_speed ||
113                 action != that.action ||
114                 calculation != that.calculation ||
115                 tracking_object != that.tracking_object ||
116                 track_frame != that.track_frame ||
117                 bottom_is_master != that.bottom_is_master ||
118                 horizontal_only != that.horizontal_only ||
119                 vertical_only != that.vertical_only ||
120             global_positions != that.global_positions) result = 0;
121
122         return result;
123 }
124
125 void MotionConfig::copy_from(MotionConfig &that)
126 {
127         for(int i = 0; i < TOTAL_POINTS; i++)
128         {
129                 global[i] = that.global[i];
130                 global_range_w[i] = that.global_range_w[i];
131                 global_range_h[i] = that.global_range_h[i];
132                 global_origin_x[i] = that.global_origin_x[i];
133                 global_origin_y[i] = that.global_origin_y[i];
134                 draw_vectors[i] = that.draw_vectors[i];
135                 block_x[i] = that.block_x[i];
136                 block_y[i] = that.block_y[i];
137                 global_block_w[i] = that.global_block_w[i];
138                 global_block_h[i] = that.global_block_h[i];
139         }
140
141         global_positions = that.global_positions;
142         magnitude = that.magnitude;
143         return_speed = that.return_speed;
144         action = that.action;
145         calculation = that.calculation;
146         tracking_object = that.tracking_object;
147         track_frame = that.track_frame;
148         bottom_is_master = that.bottom_is_master;
149         horizontal_only = that.horizontal_only;
150         vertical_only = that.vertical_only;
151 }
152
153 void MotionConfig::interpolate(MotionConfig &prev,
154         MotionConfig &next,
155         int64_t prev_frame,
156         int64_t next_frame,
157         int64_t current_frame)
158 {
159         //double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
160         //double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
161
162         for(int i = 0; i < TOTAL_POINTS; i++)
163         {
164                 this->global[i] = prev.global[i];
165                 this->block_x[i] = prev.block_x[i];
166                 this->block_y[i] = prev.block_y[i];
167                 this->global_range_w[i] = prev.global_range_w[i];
168                 this->global_range_h[i] = prev.global_range_h[i];
169                 this->global_origin_x[i] = prev.global_origin_x[i];
170                 this->global_origin_y[i] = prev.global_origin_y[i];
171                 this->draw_vectors[i] = prev.draw_vectors[i];
172                 this->global_block_w[i] = prev.global_block_w[i];
173                 this->global_block_h[i] = prev.global_block_h[i];
174         }
175
176         this->global_positions = prev.global_positions;
177         magnitude = prev.magnitude;
178         return_speed = prev.return_speed;
179         action = prev.action;
180         calculation = prev.calculation;
181         tracking_object = prev.tracking_object;
182         track_frame = prev.track_frame;
183         bottom_is_master = prev.bottom_is_master;
184         horizontal_only = prev.horizontal_only;
185         vertical_only = prev.vertical_only;
186 }
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206 MotionMain2::MotionMain2(PluginServer *server)
207  : PluginVClient(server)
208 {
209
210         engine = 0;
211         affine = 0;
212         for(int i = 0; i < TOTAL_POINTS; i++)
213         {
214                 total_dx[i] = 0;
215                 total_dy[i] = 0;
216         }
217         overlayer = 0;
218         search_area = 0;
219         search_size = 0;
220         temp_frame = 0;
221         previous_frame_number = -1;
222
223         prev_global_ref = 0;
224         current_global_ref = 0;
225         global_target_src = 0;
226         global_target_dst = 0;
227 }
228
229 MotionMain2::~MotionMain2()
230 {
231
232         delete engine;
233         delete affine;
234         delete overlayer;
235         delete [] search_area;
236         delete temp_frame;
237
238
239         delete prev_global_ref;
240         delete current_global_ref;
241         delete global_target_src;
242         delete global_target_dst;
243 }
244
245 const char* MotionMain2::plugin_title() { return N_("Motion 2 Point"); }
246 int MotionMain2::is_realtime() { return 1; }
247 int MotionMain2::is_multichannel() { return 1; }
248
249
250 NEW_WINDOW_MACRO(MotionMain2, MotionWindow)
251
252 LOAD_CONFIGURATION_MACRO(MotionMain2, MotionConfig)
253
254
255
256 void MotionMain2::update_gui()
257 {
258         if(thread)
259         {
260                 if(load_configuration())
261                 {
262                         thread->window->lock_window("MotionMain2::update_gui");
263
264                         char string[BCTEXTLEN];
265
266                         for(int i = 0; i < TOTAL_POINTS; i++)
267                         {
268                                 ((MotionWindow*)thread->window)->global[i]->update(config.global[i]);
269
270                                 ((MotionWindow*)thread->window)->global_block_w[i]->update(config.global_block_w[i]);
271                                 ((MotionWindow*)thread->window)->global_block_h[i]->update(config.global_block_h[i]);
272                                 ((MotionWindow*)thread->window)->global_origin_x[i]->update(config.global_origin_x[i]);
273                                 ((MotionWindow*)thread->window)->global_origin_y[i]->update(config.global_origin_y[i]);
274                                 ((MotionWindow*)thread->window)->block_x[i]->update(config.block_x[i]);
275                                 ((MotionWindow*)thread->window)->block_y[i]->update(config.block_y[i]);
276                                 ((MotionWindow*)thread->window)->block_x_text[i]->update((float)config.block_x[i]);
277                                 ((MotionWindow*)thread->window)->block_y_text[i]->update((float)config.block_y[i]);
278                                 ((MotionWindow*)thread->window)->vectors[i]->update(config.draw_vectors[i]);
279                         }
280
281                         sprintf(string, "%d", config.global_positions);
282                         ((MotionWindow*)thread->window)->global_search_positions->set_text(string);
283                         ((MotionWindow*)thread->window)->magnitude->update(config.magnitude);
284                         ((MotionWindow*)thread->window)->return_speed->update(config.return_speed);
285
286
287                         ((MotionWindow*)thread->window)->track_single->update(config.tracking_object == MotionScan::TRACK_SINGLE);
288                         ((MotionWindow*)thread->window)->track_frame_number->update(config.track_frame);
289                         ((MotionWindow*)thread->window)->track_previous->update(config.tracking_object == MotionScan::TRACK_PREVIOUS);
290                         ((MotionWindow*)thread->window)->previous_same->update(config.tracking_object == MotionScan::PREVIOUS_SAME_BLOCK);
291                         if(config.tracking_object != MotionScan::TRACK_SINGLE)
292                                 ((MotionWindow*)thread->window)->track_frame_number->disable();
293                         else
294                                 ((MotionWindow*)thread->window)->track_frame_number->enable();
295
296                         ((MotionWindow*)thread->window)->action->set_text(
297                                 Action::to_text(config.action));
298                         ((MotionWindow*)thread->window)->calculation->set_text(
299                                 Calculation::to_text(config.calculation));
300                         ((MotionWindow*)thread->window)->tracking_direction->set_text(
301                                 TrackingDirection::to_text(config.horizontal_only, config.vertical_only));
302                         ((MotionWindow*)thread->window)->master_layer->set_text(
303                                 MasterLayer::to_text(config.bottom_is_master));
304
305
306                         ((MotionWindow*)thread->window)->update_mode();
307                         thread->window->unlock_window();
308                 }
309         }
310 }
311
312
313
314
315
316 void MotionMain2::save_data(KeyFrame *keyframe)
317 {
318         FileXML output;
319
320 // cause data to be stored directly in text
321         output.set_shared_output(keyframe->xbuf);
322         output.tag.set_title("MOTION2");
323
324         char string[BCTEXTLEN];
325         for(int i = 0; i < TOTAL_POINTS; i++)
326         {
327                 sprintf(string, "GLOBAL%d", i);
328                 output.tag.set_property(string, config.global[i]);
329                 sprintf(string, "GLOBAL_BLOCK_W%d", i);
330                 output.tag.set_property(string, config.global_block_w[i]);
331                 sprintf(string, "GLOBAL_BLOCK_H%d", i);
332                 output.tag.set_property(string, config.global_block_h[i]);
333                 sprintf(string, "BLOCK_X%d", i);
334                 output.tag.set_property(string, config.block_x[i]);
335                 sprintf(string, "BLOCK_Y%d", i);
336                 output.tag.set_property(string, config.block_y[i]);
337                 sprintf(string, "GLOBAL_RANGE_W%d", i);
338                 output.tag.set_property(string, config.global_range_w[i]);
339                 sprintf(string, "GLOBAL_RANGE_H%d", i);
340                 output.tag.set_property(string, config.global_range_h[i]);
341                 sprintf(string, "GLOBAL_ORIGIN_X%d", i);
342                 output.tag.set_property(string, config.global_origin_x[i]);
343                 sprintf(string, "GLOBAL_ORIGIN_Y%d", i);
344                 output.tag.set_property(string, config.global_origin_y[i]);
345                 sprintf(string, "DRAW_VECTORS%d", i);
346                 output.tag.set_property(string, config.draw_vectors[i]);
347         }
348
349         output.tag.set_property("GLOBAL_POSITIONS", config.global_positions);
350         output.tag.set_property("MAGNITUDE", config.magnitude);
351         output.tag.set_property("RETURN_SPEED", config.return_speed);
352         output.tag.set_property("ACTION_TYPE", config.action);
353         output.tag.set_property("TRACKING_TYPE", config.calculation);
354         output.tag.set_property("TRACKING_OBJECT", config.tracking_object);
355         output.tag.set_property("TRACK_FRAME", config.track_frame);
356         output.tag.set_property("BOTTOM_IS_MASTER", config.bottom_is_master);
357         output.tag.set_property("HORIZONTAL_ONLY", config.horizontal_only);
358         output.tag.set_property("VERTICAL_ONLY", config.vertical_only);
359         output.append_tag();
360         output.tag.set_title("/MOTION2");
361         output.append_tag();
362         output.append_newline();
363         output.terminate_string();
364 }
365
366 void MotionMain2::read_data(KeyFrame *keyframe)
367 {
368         FileXML input;
369
370         input.set_shared_input(keyframe->xbuf);
371
372         int result = 0;
373
374         while(!result)
375         {
376                 result = input.read_tag();
377
378                 if(!result)
379                 {
380                         if(input.tag.title_is("MOTION2"))
381                         {
382                                 char string[BCTEXTLEN];
383                                 for(int i = 0; i < TOTAL_POINTS; i++)
384                                 {
385                                         sprintf(string, "GLOBAL%d", i);
386                                         config.global[i] = input.tag.get_property(string, config.global[i]);
387                                         sprintf(string, "GLOBAL_BLOCK_W%d", i);
388                                         config.global_block_w[i] = input.tag.get_property(string, config.global_block_w[i]);
389                                         sprintf(string, "GLOBAL_BLOCK_H%d", i);
390                                         config.global_block_h[i] = input.tag.get_property(string, config.global_block_h[i]);
391                                         sprintf(string, "BLOCK_X%d", i);
392                                         config.block_x[i] = input.tag.get_property(string, config.block_x[i]);
393                                         sprintf(string, "BLOCK_Y%d", i);
394                                         config.block_y[i] = input.tag.get_property(string, config.block_y[i]);
395                                         sprintf(string, "GLOBAL_RANGE_W%d", i);
396                                         config.global_range_w[i] = input.tag.get_property(string, config.global_range_w[i]);
397                                         sprintf(string, "GLOBAL_RANGE_H%d", i);
398                                         config.global_range_h[i] = input.tag.get_property(string, config.global_range_h[i]);
399                                         sprintf(string, "GLOBAL_ORIGIN_X%d", i);
400                                         config.global_origin_x[i] = input.tag.get_property(string, config.global_origin_x[i]);
401                                         sprintf(string, "GLOBAL_ORIGIN_Y%d", i);
402                                         config.global_origin_y[i] = input.tag.get_property(string, config.global_origin_y[i]);
403                                         sprintf(string, "DRAW_VECTORS%d", i);
404                                         config.draw_vectors[i] = input.tag.get_property(string, config.draw_vectors[i]);
405                                 }
406
407                                 config.global_positions = input.tag.get_property("GLOBAL_POSITIONS", config.global_positions);
408                                 config.magnitude = input.tag.get_property("MAGNITUDE", config.magnitude);
409                                 config.return_speed = input.tag.get_property("RETURN_SPEED", config.return_speed);
410                                 config.action = input.tag.get_property("ACTION_TYPE", config.action);
411                                 config.calculation = input.tag.get_property("TRACKING_TYPE", config.calculation);
412                                 config.tracking_object = input.tag.get_property("TRACKING_OBJECT", config.tracking_object);
413                                 config.track_frame = input.tag.get_property("TRACK_FRAME", config.track_frame);
414                                 config.bottom_is_master = input.tag.get_property("BOTTOM_IS_MASTER", config.bottom_is_master);
415                                 config.horizontal_only = input.tag.get_property("HORIZONTAL_ONLY", config.horizontal_only);
416                                 config.vertical_only = input.tag.get_property("VERTICAL_ONLY", config.vertical_only);
417                         }
418                 }
419         }
420         config.boundaries();
421 }
422
423
424
425
426
427
428
429
430
431 void MotionMain2::allocate_temp(int w, int h, int color_model)
432 {
433         if(temp_frame &&
434                 (temp_frame->get_w() != w ||
435                 temp_frame->get_h() != h))
436         {
437                 delete temp_frame;
438                 temp_frame = 0;
439         }
440         if(!temp_frame)
441                 temp_frame = new VFrame(w, h, color_model, 0);
442 }
443
444
445
446 void MotionMain2::scan_motion(int point)
447 {
448         int w = current_global_ref->get_w();
449         int h = current_global_ref->get_h();
450
451
452         if(!engine) engine = new MotionScan(PluginClient::get_project_smp() + 1,
453                 PluginClient::get_project_smp() + 1);
454
455 // Get the current motion vector between the previous and current frame
456         engine->scan_frame(current_global_ref,
457                 prev_global_ref,
458                 config.global_range_w[point] * w / 100,
459                 config.global_range_h[point] * h / 100,
460                 config.global_block_w[point] * w / 100,
461                 config.global_block_h[point] * h / 100,
462                 config.block_x[point] * w / 100,
463                 config.block_y[point] * h / 100,
464                 config.tracking_object,
465                 config.calculation,
466                 config.action,
467                 config.horizontal_only,
468                 config.vertical_only,
469                 get_source_position(),
470                 total_dx[point],
471                 total_dy[point],
472                 config.global_origin_x[point] * w / 100,
473                 config.global_origin_y[point] * h / 100,
474                 1,
475                 0,
476                 0,
477                 0);
478
479         current_dx[point] = engine->dx_result;
480         current_dy[point] = engine->dy_result;
481
482 // Add current motion vector to accumulation vector.
483         if(config.tracking_object != MotionScan::TRACK_SINGLE)
484         {
485 // Retract over time
486                 total_dx[point] = (int64_t)total_dx[point] * (100 - config.return_speed) / 100;
487                 total_dy[point] = (int64_t)total_dy[point] * (100 - config.return_speed) / 100;
488                 total_dx[point] += engine->dx_result;
489                 total_dy[point] += engine->dy_result;
490         }
491         else
492 // Make accumulation vector current
493         {
494                 total_dx[point] = engine->dx_result;
495                 total_dy[point] = engine->dy_result;
496 // printf("MotionMain2::scan_motion %d %d %d %d\n",
497 // __LINE__,
498 // point,
499 // total_dx[point],
500 // total_dy[point]);
501         }
502
503 // Clamp accumulation vector
504         if(config.magnitude < 100)
505         {
506                 //int block_w = (int64_t)config.global_block_w[point] *
507                 //              current_global_ref->get_w() / 100;
508                 //int block_h = (int64_t)config.global_block_h[point] *
509                 //              current_global_ref->get_h() / 100;
510                 int block_x_orig = (int64_t)(config.block_x[point] *
511                         current_global_ref->get_w() /
512                         100);
513                 int block_y_orig = (int64_t)(config.block_y[point] *
514                         current_global_ref->get_h() /
515                         100);
516
517                 int max_block_x = (int64_t)(current_global_ref->get_w() - block_x_orig) *
518                         OVERSAMPLE *
519                         config.magnitude /
520                         100;
521                 int max_block_y = (int64_t)(current_global_ref->get_h() - block_y_orig) *
522                         OVERSAMPLE *
523                         config.magnitude /
524                         100;
525                 int min_block_x = (int64_t)-block_x_orig *
526                         OVERSAMPLE *
527                         config.magnitude /
528                         100;
529                 int min_block_y = (int64_t)-block_y_orig *
530                         OVERSAMPLE *
531                         config.magnitude /
532                         100;
533
534                 CLAMP(total_dx[point], min_block_x, max_block_x);
535                 CLAMP(total_dy[point], min_block_y, max_block_y);
536         }
537
538 // printf("MotionMain2::scan_motion %d %d %d %d\n",
539 // __LINE__,
540 // point,
541 // total_dx[point],
542 // total_dy[point]);
543
544
545 }
546
547
548
549
550 void MotionMain2::apply_motion()
551 {
552         if(config.tracking_object != MotionScan::TRACK_SINGLE)
553         {
554 // Transfer current reference frame to previous reference frame and update
555 // counter.
556                 prev_global_ref->copy_from(current_global_ref);
557                 previous_frame_number = get_source_position();
558         }
559
560 // Decide what to do with target based on requested operation
561         //int interpolation; //   variable set but not used
562         float origin_x[TOTAL_POINTS];
563         float origin_y[TOTAL_POINTS];
564         float end_x[TOTAL_POINTS];
565         float end_y[TOTAL_POINTS];
566         for(int i = 0; i < TOTAL_POINTS; i++)
567         {
568                 get_current_vector(&origin_x[i],
569                         &origin_y[i],
570                         0,
571                         0,
572                         &end_x[i],
573                         &end_y[i],
574                         i);
575         }
576
577 // Calculate rotation if 2 points
578         double angle = 0.0;
579         double angle0 = 0.0;
580         double zoom = 1.0;
581         if(config.global[ROTATION_POINT])
582         {
583                         if(origin_x[1] - origin_x[0])
584                                 angle0 = atan((double)(origin_y[0] - origin_y[1]) /
585                                         (double)(origin_x[0] - origin_x[1]));
586                         if(end_x[1] - end_x[0])
587                                 angle = atan((double)(end_y[0] - end_y[1]) /
588                                         (double)(end_x[0] - end_x[1]));
589 // printf("MotionMain2::apply_motion %d angle0=%f angle=%f\n",
590 // __LINE__,
591 // angle0 * 360 / 2 / M_PI,
592 // angle * 360 / 2 / M_PI);
593
594                         angle -= angle0;
595
596 // Calculate zoom
597 //                      zoom = DISTANCE(origin_x[1], origin_y[1], origin_x[0], origin_y[0]) /
598 //                              DISTANCE(end_x[1], end_y[1], end_x[0], end_y[0]);
599
600         }
601
602 printf("MotionMain2::apply_motion %d total_dx=%.02f total_dy=%.02f angle=%f zoom=%f\n",
603 __LINE__,
604 (float)total_dx[TRANSLATION_POINT] / OVERSAMPLE,
605 (float)total_dy[TRANSLATION_POINT] / OVERSAMPLE,
606 angle * 360 / 2 / M_PI,
607 zoom);
608
609 // Calculate translation
610         float dx = 0.0;
611         float dy = 0.0;
612         switch(config.action)
613         {
614                 case MotionScan::NOTHING:
615                         global_target_dst->copy_from(global_target_src);
616                         break;
617                 case MotionScan::TRACK:
618                         //interpolation = CUBIC_LINEAR;
619                         dx = (float)total_dx[0] / OVERSAMPLE;
620                         dy = (float)total_dy[0] / OVERSAMPLE;
621                         break;
622                 case MotionScan::TRACK_PIXEL:
623                         //interpolation = NEAREST_NEIGHBOR;
624                         dx = (int)(total_dx[0] / OVERSAMPLE);
625                         dy = (int)(total_dy[0] / OVERSAMPLE);
626                         break;
627                         //interpolation = NEAREST_NEIGHBOR;
628                         dx = -(int)(total_dx[0] / OVERSAMPLE);
629                         dy = -(int)(total_dy[0] / OVERSAMPLE);
630                         angle *= -1;
631                         break;
632                 case MotionScan::STABILIZE:
633                         //interpolation = CUBIC_LINEAR;
634                         dx = -(float)total_dx[0] / OVERSAMPLE;
635                         dy = -(float)total_dy[0] / OVERSAMPLE;
636                         angle *= -1;
637                         break;
638         }
639
640
641
642
643
644         if(config.action != MotionScan::NOTHING)
645         {
646                 double w = get_output()->get_w();
647                 double h = get_output()->get_h();
648                 double pivot_x = end_x[0];
649                 double pivot_y = end_y[0];
650                 double angle1 = atan((double)pivot_y / (double)pivot_x) + angle;
651                 double angle2 = atan((double)(w - pivot_x) / (double)pivot_y) + angle;
652                 double angle3 = atan((double)(h - pivot_y) / (double)(w - pivot_x)) + angle;
653                 double angle4 = atan((double)pivot_x / (double)(h - pivot_y)) + angle;
654                 double radius1 = DISTANCE(0, 0, pivot_x, pivot_y) * zoom;
655                 double radius2 = DISTANCE(w, 0, pivot_x, pivot_y) * zoom;
656                 double radius3 = DISTANCE(w, h, pivot_x, pivot_y) * zoom;
657                 double radius4 = DISTANCE(0, h, pivot_x, pivot_y) * zoom;
658
659
660                 float x1 = (dx + pivot_x - cos(angle1) * radius1) * 100 / w;
661                 float y1 = (dy + pivot_y - sin(angle1) * radius1) * 100 / h;
662                 float x2 = (dx + pivot_x + sin(angle2) * radius2) * 100 / w;
663                 float y2 = (dy + pivot_y - cos(angle2) * radius2) * 100 / h;
664                 float x3 = (dx + pivot_x + cos(angle3) * radius3) * 100 / w;
665                 float y3 = (dy + pivot_y + sin(angle3) * radius3) * 100 / h;
666                 float x4 = (dx + pivot_x - sin(angle4) * radius4) * 100 / w;
667                 float y4 = (dy + pivot_y + cos(angle4) * radius4) * 100 / h;
668
669
670                 if(!affine)
671                         affine = new AffineEngine(PluginClient::get_project_smp() + 1,
672                                 PluginClient::get_project_smp() + 1);
673                 global_target_dst->clear_frame();
674
675
676 // printf("MotionMain2::apply_motion %d %.02f %.02f %.02f %.02f %.02f %.02f %.02f %.02f\n",
677 // __LINE__,
678 // x1,
679 // y1,
680 // x2,
681 // y2,
682 // x3,
683 // y3,
684 // x4,
685 // y4);
686
687                 affine->process(global_target_dst,
688                         global_target_src,
689                         0,
690                         AffineEngine::PERSPECTIVE,
691                         x1,
692                         y1,
693                         x2,
694                         y2,
695                         x3,
696                         y3,
697                         x4,
698                         y4,
699                         1);
700         }
701 }
702
703
704
705
706
707
708 int MotionMain2::process_buffer(VFrame **frame,
709         int64_t start_position,
710         double frame_rate)
711 {
712         int need_reconfigure = load_configuration();
713         int color_model = frame[0]->get_color_model();
714         w = frame[0]->get_w();
715         h = frame[0]->get_h();
716
717
718 #ifdef DEBUG
719 printf("MotionMain2::process_buffer 1 start_position=%jd\n", start_position);
720 #endif
721
722
723 // Calculate the source and destination pointers for each of the operations.
724 // Get the layer to track motion in.
725         reference_layer = config.bottom_is_master ?
726                 PluginClient::total_in_buffers - 1 :
727                 0;
728 // Get the layer to apply motion in.
729         target_layer = config.bottom_is_master ?
730                 0 :
731                 PluginClient::total_in_buffers - 1;
732
733
734         output_frame = frame[target_layer];
735
736
737 // Get the position of previous reference frame.
738         int64_t actual_previous_number;
739 // Skip if match frame not available
740         int skip_current = 0;
741
742
743         if(config.tracking_object == MotionScan::TRACK_SINGLE)
744         {
745                 actual_previous_number = config.track_frame;
746                 if(get_direction() == PLAY_REVERSE)
747                         actual_previous_number++;
748                 if(actual_previous_number == start_position)
749                         skip_current = 1;
750         }
751         else
752         {
753                 actual_previous_number = start_position;
754                 if(get_direction() == PLAY_FORWARD)
755                 {
756                         actual_previous_number--;
757                         if(actual_previous_number < get_source_start())
758                                 skip_current = 1;
759                         else
760                         {
761                                 KeyFrame *keyframe = get_prev_keyframe(start_position, 1);
762                                 if(keyframe->position > 0 &&
763                                         actual_previous_number < keyframe->position)
764                                         skip_current = 1;
765                         }
766                 }
767                 else
768                 {
769                         actual_previous_number++;
770                         if(actual_previous_number >= get_source_start() + get_total_len())
771                                 skip_current = 1;
772                         else
773                         {
774                                 KeyFrame *keyframe = get_next_keyframe(start_position, 1);
775                                 if(keyframe->position > 0 &&
776                                         actual_previous_number >= keyframe->position)
777                                         skip_current = 1;
778                         }
779                 }
780
781 // Only count motion since last keyframe
782
783
784         }
785
786
787 // Point 0 must be tracked for any other points to be tracked
788 // Action and Calculation must be something
789         if( !config.global[0] || ( config.action == MotionScan::NOTHING &&
790                         config.calculation == MotionScan::NO_CALCULATE) )
791                 skip_current = 1;
792
793
794 // printf("process_buffer %d %lld %lld %d\n",
795 // skip_current,
796 // previous_frame_number,
797 // actual_previous_number,
798 // need_reconfigure);
799 // Load match frame and reset vectors
800         int need_reload = !skip_current &&
801                 (previous_frame_number != actual_previous_number ||
802                 need_reconfigure);
803         if(need_reload)
804         {
805                 for(int i = 0; i < TOTAL_POINTS; i++)
806                 {
807                         total_dx[i] = 0;
808                         total_dy[i] = 0;
809                 }
810                 previous_frame_number = actual_previous_number;
811         }
812
813
814         if(skip_current)
815         {
816                 for(int i = 0; i < TOTAL_POINTS; i++)
817                 {
818                         total_dx[i] = 0;
819                         total_dy[i] = 0;
820                         current_dx[i] = 0;
821                         current_dy[i] = 0;
822                 }
823         }
824
825
826
827
828 // Get the global pointers.  Here we walk through the sequence of events.
829         if(config.global[0])
830         {
831 // Global reads previous frame and compares
832 // with current frame to get the current translation.
833 // The center of the search area is fixed in compensate mode or
834 // the user value + the accumulation vector in track mode.
835                 if(!prev_global_ref)
836                         prev_global_ref = new VFrame(w, h, color_model, 0);
837                 if(!current_global_ref)
838                         current_global_ref = new VFrame(w, h, color_model, 0);
839
840 // Global loads the current target frame into the src and
841 // writes it to the dst frame with desired translation.
842                 if(!global_target_src)
843                         global_target_src = new VFrame(w, h, color_model, 0);
844                 if(!global_target_dst)
845                         global_target_dst = new VFrame(w, h, color_model, 0);
846
847
848 // Load the global frames
849                 if(need_reload)
850                 {
851                         read_frame(prev_global_ref,
852                                 reference_layer,
853                                 previous_frame_number,
854                                 frame_rate,
855                                 0);
856                 }
857
858                 read_frame(current_global_ref,
859                         reference_layer,
860                         start_position,
861                         frame_rate,
862                         0);
863                 read_frame(global_target_src,
864                         target_layer,
865                         start_position,
866                         frame_rate,
867                         0);
868         }
869
870
871
872
873
874
875
876
877         if(!skip_current)
878         {
879 // Get position change from previous frame to current frame
880                 if(config.global[0])
881                 {
882                         for(int i = 0; i < TOTAL_POINTS; i++)
883                                 if(config.global[i]) scan_motion(i);
884                 }
885
886                 apply_motion();
887         }
888
889
890
891
892 //printf("MotionMain2::process_buffer 90 %d\n", skip_current);
893
894 // Transfer the relevant target frame to the output
895         if(!skip_current)
896         {
897                 frame[target_layer]->copy_from(global_target_dst);
898         }
899         else
900 // Read the target destination directly
901         {
902                 read_frame(frame[target_layer],
903                         target_layer,
904                         start_position,
905                         frame_rate,
906                         0);
907         }
908
909         if(config.draw_vectors)
910         {
911                 for(int i = 0; i < TOTAL_POINTS; i++)
912                         draw_vectors(frame[target_layer], i);
913         }
914
915 #ifdef DEBUG
916 printf("MotionMain2::process_buffer 100 skip_current=%d\n", skip_current);
917 #endif
918         return 0;
919 }
920
921
922
923 #if 0
924
925 void MotionMain2::clamp_scan(int w,
926         int h,
927         int *block_x1,
928         int *block_y1,
929         int *block_x2,
930         int *block_y2,
931         int *scan_x1,
932         int *scan_y1,
933         int *scan_x2,
934         int *scan_y2,
935         int use_absolute)
936 {
937 // printf("MotionMain2::clamp_scan 1 w=%d h=%d block=%d %d %d %d scan=%d %d %d %d absolute=%d\n",
938 // w,
939 // h,
940 // *block_x1,
941 // *block_y1,
942 // *block_x2,
943 // *block_y2,
944 // *scan_x1,
945 // *scan_y1,
946 // *scan_x2,
947 // *scan_y2,
948 // use_absolute);
949
950         if(use_absolute)
951         {
952 // scan is always out of range before block.
953                 if(*scan_x1 < 0)
954                 {
955                         int difference = -*scan_x1;
956                         *block_x1 += difference;
957                         *scan_x1 = 0;
958                 }
959
960                 if(*scan_y1 < 0)
961                 {
962                         int difference = -*scan_y1;
963                         *block_y1 += difference;
964                         *scan_y1 = 0;
965                 }
966
967                 if(*scan_x2 > w)
968                 {
969                         int difference = *scan_x2 - w;
970                         *block_x2 -= difference;
971                         *scan_x2 -= difference;
972                 }
973
974                 if(*scan_y2 > h)
975                 {
976                         int difference = *scan_y2 - h;
977                         *block_y2 -= difference;
978                         *scan_y2 -= difference;
979                 }
980
981                 CLAMP(*scan_x1, 0, w);
982                 CLAMP(*scan_y1, 0, h);
983                 CLAMP(*scan_x2, 0, w);
984                 CLAMP(*scan_y2, 0, h);
985         }
986         else
987         {
988                 if(*scan_x1 < 0)
989                 {
990                         int difference = -*scan_x1;
991                         *block_x1 += difference;
992                         *scan_x2 += difference;
993                         *scan_x1 = 0;
994                 }
995
996                 if(*scan_y1 < 0)
997                 {
998                         int difference = -*scan_y1;
999                         *block_y1 += difference;
1000                         *scan_y2 += difference;
1001                         *scan_y1 = 0;
1002                 }
1003
1004                 if(*scan_x2 - *block_x1 + *block_x2 > w)
1005                 {
1006                         int difference = *scan_x2 - *block_x1 + *block_x2 - w;
1007                         *block_x2 -= difference;
1008                 }
1009
1010                 if(*scan_y2 - *block_y1 + *block_y2 > h)
1011                 {
1012                         int difference = *scan_y2 - *block_y1 + *block_y2 - h;
1013                         *block_y2 -= difference;
1014                 }
1015
1016 //              CLAMP(*scan_x1, 0, w - (*block_x2 - *block_x1));
1017 //              CLAMP(*scan_y1, 0, h - (*block_y2 - *block_y1));
1018 //              CLAMP(*scan_x2, 0, w - (*block_x2 - *block_x1));
1019 //              CLAMP(*scan_y2, 0, h - (*block_y2 - *block_y1));
1020         }
1021
1022 // Sanity checks which break the calculation but should never happen if the
1023 // center of the block is inside the frame.
1024         CLAMP(*block_x1, 0, w);
1025         CLAMP(*block_x2, 0, w);
1026         CLAMP(*block_y1, 0, h);
1027         CLAMP(*block_y2, 0, h);
1028
1029 // printf("MotionMain2::clamp_scan 2 w=%d h=%d block=%d %d %d %d scan=%d %d %d %d absolute=%d\n",
1030 // w,
1031 // h,
1032 // *block_x1,
1033 // *block_y1,
1034 // *block_x2,
1035 // *block_y2,
1036 // *scan_x1,
1037 // *scan_y1,
1038 // *scan_x2,
1039 // *scan_y2,
1040 // use_absolute);
1041 }
1042
1043
1044 #endif // 0
1045
1046 void MotionMain2::get_current_vector(float *origin_x,
1047         float *origin_y,
1048         float *current_x1,
1049         float *current_y1,
1050         float *current_x2,
1051         float *current_y2,
1052         int point)
1053 {
1054         int w = get_output()->get_w();
1055         int h = get_output()->get_h();
1056         float temp1;
1057         float temp2;
1058         float temp3;
1059         float temp4;
1060         float temp5;
1061         float temp6;
1062         if(!origin_x) origin_x = &temp1;
1063         if(!origin_y) origin_y = &temp2;
1064         if(!current_x1) current_x1 = &temp3;
1065         if(!current_y1) current_y1 = &temp4;
1066         if(!current_x2) current_x2 = &temp5;
1067         if(!current_y2) current_y2 = &temp6;
1068
1069         *origin_x = 0;
1070         *origin_y = 0;
1071         *current_x1 = 0.0;
1072         *current_y1 = 0.0;
1073         *current_x2 = 0.0;
1074         *current_y2 = 0.0;
1075
1076
1077         if(config.global[point])
1078         {
1079 // Get vector
1080 // Start of vector is center of previous block.
1081 // End of vector is total accumulation.
1082                 if(config.tracking_object == MotionScan::TRACK_SINGLE)
1083                 {
1084                         (*origin_x) = (*current_x1) = ((float)config.block_x[point] *
1085                                 w /
1086                                 100);
1087                         (*origin_y) = (*current_y1) = ((float)config.block_y[point] *
1088                                 h /
1089                                 100);
1090                         (*current_x2) = (*current_x1) + (float)total_dx[point] / OVERSAMPLE;
1091                         (*current_y2) = (*current_y1) + (float)total_dy[point] / OVERSAMPLE;
1092                 }
1093                 else
1094 // Start of vector is center of previous block.
1095 // End of vector is current change.
1096                 if(config.tracking_object == MotionScan::PREVIOUS_SAME_BLOCK)
1097                 {
1098                         (*origin_x) = (*current_x1) = ((float)config.block_x[point] *
1099                                 w /
1100                                 100);
1101                         (*origin_y) = (*current_y1) = ((float)config.block_y[point] *
1102                                 h /
1103                                 100);
1104                         (*current_x2) = (*origin_x) + (float)current_dx[point] / OVERSAMPLE;
1105                         (*current_y2) = (*origin_y) + (float)current_dy[point] / OVERSAMPLE;
1106                 }
1107                 else
1108                 {
1109                         (*origin_x) = (float)config.block_x[point] *
1110                                 w /
1111                                 100;
1112                         (*origin_y) = (float)config.block_y[point] *
1113                                 h /
1114                                 100;
1115                         (*current_x1) = ((*origin_x) +
1116                                 (float)(total_dx[point] - current_dx[point]) /
1117                                 OVERSAMPLE);
1118                         (*current_y1) = ((*origin_y) +
1119                                 (float)(total_dy[point] - current_dy[point]) /
1120                                 OVERSAMPLE);
1121                         (*current_x2) = ((*origin_x) +
1122                                 (float)total_dx[point] /
1123                                 OVERSAMPLE);
1124                         (*current_y2) = ((*origin_y) +
1125                                 (float)total_dy[point] /
1126                                 OVERSAMPLE);
1127                 }
1128         }
1129 }
1130
1131
1132 void MotionMain2::draw_vectors(VFrame *frame, int point)
1133 {
1134         int w = frame->get_w();
1135         int h = frame->get_h();
1136         float global_x1, global_y1;
1137         float global_x2, global_y2;
1138         int block_x, block_y;
1139         int block_w, block_h;
1140         int block_x1, block_y1;
1141         int block_x2, block_y2;
1142         int search_w, search_h;
1143         int search_x1, search_y1;
1144         int search_x2, search_y2;
1145         int origin_offset_x;
1146         int origin_offset_y;
1147
1148         if(!config.draw_vectors[point]) return;
1149
1150
1151         if(config.global[point])
1152         {
1153 // Get vector
1154                 get_current_vector(0,
1155                         0,
1156                         &global_x1,
1157                         &global_y1,
1158                         &global_x2,
1159                         &global_y2,
1160                         point);
1161
1162
1163 // Draw destination rectangle
1164                 if(config.action == MotionScan::NOTHING ||
1165                         config.action == MotionScan::TRACK)
1166                 {
1167                         block_x = (int)global_x2;
1168                         block_y = (int)global_y2;
1169                 }
1170                 else
1171 // Draw source rectangle
1172                 {
1173                         block_x = (int)global_x1;
1174                         block_y = (int)global_y1;
1175                 }
1176                 block_w = config.global_block_w[point] * w / 100;
1177                 block_h = config.global_block_h[point] * h / 100;
1178                 origin_offset_x = config.global_origin_x[point] * w / 100;
1179                 origin_offset_y = config.global_origin_y[point] * h / 100;
1180                 block_x1 = block_x - block_w / 2;
1181                 block_y1 = block_y - block_h / 2;
1182                 block_x2 = block_x + block_w / 2;
1183                 block_y2 = block_y + block_h / 2;
1184                 search_w = config.global_range_w[point] * w / 100;
1185                 search_h = config.global_range_h[point] * h / 100;
1186                 search_x1 = block_x1 + origin_offset_x - search_w / 2;
1187                 search_y1 = block_y1 + origin_offset_y - search_h / 2;
1188                 search_x2 = block_x2 + origin_offset_x + search_w / 2;
1189                 search_y2 = block_y2 + origin_offset_y + search_h / 2;
1190
1191 // printf("MotionMain2::draw_vectors %d %d %d %d %d %d %d %d %d %d %d %d\n",
1192 // global_x1,
1193 // global_y1,
1194 // block_w,
1195 // block_h,
1196 // block_x1,
1197 // block_y1,
1198 // block_x2,
1199 // block_y2,
1200 // search_x1,
1201 // search_y1,
1202 // search_x2,
1203 // search_y2);
1204
1205                 MotionScan::clamp_scan(w,
1206                         h,
1207                         &block_x1,
1208                         &block_y1,
1209                         &block_x2,
1210                         &block_y2,
1211                         &search_x1,
1212                         &search_y1,
1213                         &search_x2,
1214                         &search_y2,
1215                         1);
1216
1217 // Vector
1218                 draw_arrow(frame, (int)global_x1, (int)global_y1, (int)global_x2, (int)global_y2);
1219
1220 // Macroblock
1221                 draw_line(frame, block_x1, block_y1, block_x2, block_y1);
1222                 draw_line(frame, block_x2, block_y1, block_x2, block_y2);
1223                 draw_line(frame, block_x2, block_y2, block_x1, block_y2);
1224                 draw_line(frame, block_x1, block_y2, block_x1, block_y1);
1225
1226
1227 // Search area
1228                 draw_line(frame, search_x1, search_y1, search_x2, search_y1);
1229                 draw_line(frame, search_x2, search_y1, search_x2, search_y2);
1230                 draw_line(frame, search_x2, search_y2, search_x1, search_y2);
1231                 draw_line(frame, search_x1, search_y2, search_x1, search_y1);
1232         }
1233 }
1234
1235
1236 Motion2VVFrame::Motion2VVFrame(VFrame *vfrm, int n)
1237  : VFrame(vfrm->get_data(), -1, vfrm->get_y()-vfrm->get_data(),
1238         vfrm->get_u()-vfrm->get_data(), vfrm->get_v()-vfrm->get_data(),
1239         vfrm->get_w(), vfrm->get_h(), vfrm->get_color_model(),
1240         vfrm->get_bytes_per_line())
1241 {
1242         this->n = n;
1243 }
1244
1245 int Motion2VVFrame::draw_pixel(int x, int y)
1246 {
1247         VFrame::draw_pixel(x+0, y+0);
1248         for( int i=1; i<n; ++i ) {
1249                 VFrame::draw_pixel(x-i, y-i);
1250                 VFrame::draw_pixel(x+i, y+i);
1251         }
1252         return 0;
1253 }
1254
1255
1256 void MotionMain2::draw_line(VFrame *frame, int x1, int y1, int x2, int y2)
1257 {
1258         int iw = frame->get_w(), ih = frame->get_h();
1259         int mx = iw > ih ? iw : ih;
1260         int n = mx/800 + 1;
1261         Motion2VVFrame vfrm(frame, n);
1262         vfrm.set_pixel_color(WHITE);
1263         int m = 2;  while( m < n ) m <<= 1;
1264         vfrm.set_stiple(2*m);
1265         vfrm.draw_line(x1,y1, x2,y2);
1266 }
1267
1268
1269 #define ARROW_SIZE 10
1270 void MotionMain2::draw_arrow(VFrame *frame, int x1, int y1, int x2, int y2)
1271 {
1272         double angle = atan((float)(y2 - y1) / (float)(x2 - x1));
1273         double angle1 = angle + (float)145 / 360 * 2 * 3.14159265;
1274         double angle2 = angle - (float)145 / 360 * 2 * 3.14159265;
1275         int x3;
1276         int y3;
1277         int x4;
1278         int y4;
1279         if(x2 < x1)
1280         {
1281                 x3 = x2 - (int)(ARROW_SIZE * cos(angle1));
1282                 y3 = y2 - (int)(ARROW_SIZE * sin(angle1));
1283                 x4 = x2 - (int)(ARROW_SIZE * cos(angle2));
1284                 y4 = y2 - (int)(ARROW_SIZE * sin(angle2));
1285         }
1286         else
1287         {
1288                 x3 = x2 + (int)(ARROW_SIZE * cos(angle1));
1289                 y3 = y2 + (int)(ARROW_SIZE * sin(angle1));
1290                 x4 = x2 + (int)(ARROW_SIZE * cos(angle2));
1291                 y4 = y2 + (int)(ARROW_SIZE * sin(angle2));
1292         }
1293
1294 // Main vector
1295         draw_line(frame, x1, y1, x2, y2);
1296 //      draw_line(frame, x1, y1 + 1, x2, y2 + 1);
1297
1298 // Arrow line
1299         if(abs(y2 - y1) || abs(x2 - x1)) draw_line(frame, x2, y2, x3, y3);
1300 //      draw_line(frame, x2, y2 + 1, x3, y3 + 1);
1301 // Arrow line
1302         if(abs(y2 - y1) || abs(x2 - x1)) draw_line(frame, x2, y2, x4, y4);
1303 //      draw_line(frame, x2, y2 + 1, x4, y4 + 1);
1304 }
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315 #if 0
1316
1317
1318
1319 #define ABS_DIFF(type, temp_type, multiplier, components) \
1320 { \
1321         temp_type result_temp = 0; \
1322         for(int i = 0; i < h; i++) \
1323         { \
1324                 type *prev_row = (type*)prev_ptr; \
1325                 type *current_row = (type*)current_ptr; \
1326                 for(int j = 0; j < w; j++) \
1327                 { \
1328                         for(int k = 0; k < 3; k++) \
1329                         { \
1330                                 temp_type difference; \
1331                                 difference = *prev_row++ - *current_row++; \
1332                                 if(difference < 0) \
1333                                         result_temp -= difference; \
1334                                 else \
1335                                         result_temp += difference; \
1336                         } \
1337                         if(components == 4) \
1338                         { \
1339                                 prev_row++; \
1340                                 current_row++; \
1341                         } \
1342                 } \
1343                 prev_ptr += row_bytes; \
1344                 current_ptr += row_bytes; \
1345         } \
1346         result = (int64_t)(result_temp * multiplier); \
1347 }
1348
1349 int64_t MotionMain2::abs_diff(unsigned char *prev_ptr,
1350         unsigned char *current_ptr,
1351         int row_bytes,
1352         int w,
1353         int h,
1354         int color_model)
1355 {
1356         int64_t result = 0;
1357         switch(color_model)
1358         {
1359                 case BC_RGB888:
1360                         ABS_DIFF(unsigned char, int64_t, 1, 3)
1361                         break;
1362                 case BC_RGBA8888:
1363                         ABS_DIFF(unsigned char, int64_t, 1, 4)
1364                         break;
1365                 case BC_RGB_FLOAT:
1366                         ABS_DIFF(float, double, 0x10000, 3)
1367                         break;
1368                 case BC_RGBA_FLOAT:
1369                         ABS_DIFF(float, double, 0x10000, 4)
1370                         break;
1371                 case BC_YUV888:
1372                         ABS_DIFF(unsigned char, int64_t, 1, 3)
1373                         break;
1374                 case BC_YUVA8888:
1375                         ABS_DIFF(unsigned char, int64_t, 1, 4)
1376                         break;
1377                 case BC_YUV161616:
1378                         ABS_DIFF(uint16_t, int64_t, 1, 3)
1379                         break;
1380                 case BC_YUVA16161616:
1381                         ABS_DIFF(uint16_t, int64_t, 1, 4)
1382                         break;
1383         }
1384         return result;
1385 }
1386
1387
1388
1389 #define ABS_DIFF_SUB(type, temp_type, multiplier, components) \
1390 { \
1391         temp_type result_temp = 0; \
1392         temp_type y2_fraction = sub_y * 0x100 / OVERSAMPLE; \
1393         temp_type y1_fraction = 0x100 - y2_fraction; \
1394         temp_type x2_fraction = sub_x * 0x100 / OVERSAMPLE; \
1395         temp_type x1_fraction = 0x100 - x2_fraction; \
1396         for(int i = 0; i < h_sub; i++) \
1397         { \
1398                 type *prev_row1 = (type*)prev_ptr; \
1399                 type *prev_row2 = (type*)prev_ptr + components; \
1400                 type *prev_row3 = (type*)(prev_ptr + row_bytes); \
1401                 type *prev_row4 = (type*)(prev_ptr + row_bytes) + components; \
1402                 type *current_row = (type*)current_ptr; \
1403                 for(int j = 0; j < w_sub; j++) \
1404                 { \
1405                         for(int k = 0; k < 3; k++) \
1406                         { \
1407                                 temp_type difference; \
1408                                 temp_type prev_value = \
1409                                         (*prev_row1++ * x1_fraction * y1_fraction + \
1410                                         *prev_row2++ * x2_fraction * y1_fraction + \
1411                                         *prev_row3++ * x1_fraction * y2_fraction + \
1412                                         *prev_row4++ * x2_fraction * y2_fraction) / \
1413                                         0x100 / 0x100; \
1414                                 temp_type current_value = *current_row++; \
1415                                 difference = prev_value - current_value; \
1416                                 if(difference < 0) \
1417                                         result_temp -= difference; \
1418                                 else \
1419                                         result_temp += difference; \
1420                         } \
1421  \
1422                         if(components == 4) \
1423                         { \
1424                                 prev_row1++; \
1425                                 prev_row2++; \
1426                                 prev_row3++; \
1427                                 prev_row4++; \
1428                                 current_row++; \
1429                         } \
1430                 } \
1431                 prev_ptr += row_bytes; \
1432                 current_ptr += row_bytes; \
1433         } \
1434         result = (int64_t)(result_temp * multiplier); \
1435 }
1436
1437
1438
1439
1440 int64_t MotionMain2::abs_diff_sub(unsigned char *prev_ptr,
1441         unsigned char *current_ptr,
1442         int row_bytes,
1443         int w,
1444         int h,
1445         int color_model,
1446         int sub_x,
1447         int sub_y)
1448 {
1449         int h_sub = h - 1;
1450         int w_sub = w - 1;
1451         int64_t result = 0;
1452
1453         switch(color_model)
1454         {
1455                 case BC_RGB888:
1456                         ABS_DIFF_SUB(unsigned char, int64_t, 1, 3)
1457                         break;
1458                 case BC_RGBA8888:
1459                         ABS_DIFF_SUB(unsigned char, int64_t, 1, 4)
1460                         break;
1461                 case BC_RGB_FLOAT:
1462                         ABS_DIFF_SUB(float, double, 0x10000, 3)
1463                         break;
1464                 case BC_RGBA_FLOAT:
1465                         ABS_DIFF_SUB(float, double, 0x10000, 4)
1466                         break;
1467                 case BC_YUV888:
1468                         ABS_DIFF_SUB(unsigned char, int64_t, 1, 3)
1469                         break;
1470                 case BC_YUVA8888:
1471                         ABS_DIFF_SUB(unsigned char, int64_t, 1, 4)
1472                         break;
1473                 case BC_YUV161616:
1474                         ABS_DIFF_SUB(uint16_t, int64_t, 1, 3)
1475                         break;
1476                 case BC_YUVA16161616:
1477                         ABS_DIFF_SUB(uint16_t, int64_t, 1, 4)
1478                         break;
1479         }
1480         return result;
1481 }
1482
1483
1484
1485
1486
1487 MotionScanPackage::MotionScanPackage()
1488  : LoadPackage()
1489 {
1490         valid = 1;
1491 }
1492
1493
1494
1495
1496
1497
1498 MotionScanUnit::MotionScanUnit(MotionScan *server,
1499         MotionMain2 *plugin)
1500  : LoadClient(server)
1501 {
1502         this->plugin = plugin;
1503         this->server = server;
1504         cache_lock = new Mutex("MotionScanUnit::cache_lock");
1505 }
1506
1507 MotionScanUnit::~MotionScanUnit()
1508 {
1509         delete cache_lock;
1510 }
1511
1512
1513
1514 void MotionScanUnit::process_package(LoadPackage *package)
1515 {
1516         MotionScanPackage *pkg = (MotionScanPackage*)package;
1517         int w = server->current_frame->get_w();
1518         int h = server->current_frame->get_h();
1519         int color_model = server->current_frame->get_color_model();
1520         int pixel_size = cmodel_calculate_pixelsize(color_model);
1521         int row_bytes = server->current_frame->get_bytes_per_line();
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535 // Single pixel
1536         if(!server->subpixel)
1537         {
1538                 int search_x = pkg->scan_x1 + (pkg->pixel % (pkg->scan_x2 - pkg->scan_x1));
1539                 int search_y = pkg->scan_y1 + (pkg->pixel / (pkg->scan_x2 - pkg->scan_x1));
1540
1541 // Try cache
1542                 pkg->difference1 = server->get_cache(search_x, search_y);
1543                 if(pkg->difference1 < 0)
1544                 {
1545 //printf("MotionScanUnit::process_package 1 %d %d\n",
1546 //search_x, search_y, pkg->block_x2 - pkg->block_x1, pkg->block_y2 - pkg->block_y1);
1547 // Pointers to first pixel in each block
1548                         unsigned char *prev_ptr = server->previous_frame->get_rows()[
1549                                 search_y] +
1550                                 search_x * pixel_size;
1551                         unsigned char *current_ptr = server->current_frame->get_rows()[
1552                                 pkg->block_y1] +
1553                                 pkg->block_x1 * pixel_size;
1554 // Scan block
1555                         pkg->difference1 = plugin->abs_diff(prev_ptr,
1556                                 current_ptr,
1557                                 row_bytes,
1558                                 pkg->block_x2 - pkg->block_x1,
1559                                 pkg->block_y2 - pkg->block_y1,
1560                                 color_model);
1561 //printf("MotionScanUnit::process_package 2\n");
1562                         server->put_cache(search_x, search_y, pkg->difference1);
1563                 }
1564         }
1565
1566
1567
1568
1569
1570
1571
1572         else
1573
1574
1575
1576
1577
1578
1579
1580
1581 // Sub pixel
1582         {
1583                 int sub_x = pkg->pixel % (OVERSAMPLE * 2 - 1) + 1;
1584                 int sub_y = pkg->pixel / (OVERSAMPLE * 2 - 1) + 1;
1585
1586                 if(plugin->config.horizontal_only)
1587                 {
1588                         sub_y = 0;
1589                 }
1590
1591                 if(plugin->config.vertical_only)
1592                 {
1593                         sub_x = 0;
1594                 }
1595
1596                 int search_x = pkg->scan_x1 + sub_x / OVERSAMPLE;
1597                 int search_y = pkg->scan_y1 + sub_y / OVERSAMPLE;
1598                 sub_x %= OVERSAMPLE;
1599                 sub_y %= OVERSAMPLE;
1600
1601
1602                 unsigned char *prev_ptr = server->previous_frame->get_rows()[
1603                         search_y] +
1604                         search_x * pixel_size;
1605                 unsigned char *current_ptr = server->current_frame->get_rows()[
1606                         pkg->block_y1] +
1607                         pkg->block_x1 * pixel_size;
1608
1609 // With subpixel, there are two ways to compare each position, one by shifting
1610 // the previous frame and two by shifting the current frame.
1611                 pkg->difference1 = plugin->abs_diff_sub(prev_ptr,
1612                         current_ptr,
1613                         row_bytes,
1614                         pkg->block_x2 - pkg->block_x1,
1615                         pkg->block_y2 - pkg->block_y1,
1616                         color_model,
1617                         sub_x,
1618                         sub_y);
1619                 pkg->difference2 = plugin->abs_diff_sub(current_ptr,
1620                         prev_ptr,
1621                         row_bytes,
1622                         pkg->block_x2 - pkg->block_x1,
1623                         pkg->block_y2 - pkg->block_y1,
1624                         color_model,
1625                         sub_x,
1626                         sub_y);
1627 // printf("MotionScanUnit::process_package sub_x=%d sub_y=%d search_x=%d search_y=%d diff1=%lld diff2=%lld\n",
1628 // sub_x,
1629 // sub_y,
1630 // search_x,
1631 // search_y,
1632 // pkg->difference1,
1633 // pkg->difference2);
1634         }
1635
1636
1637
1638
1639
1640 }
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651 int64_t MotionScanUnit::get_cache(int x, int y)
1652 {
1653         int64_t result = -1;
1654         cache_lock->lock("MotionScanUnit::get_cache");
1655         for(int i = 0; i < cache.total; i++)
1656         {
1657                 MotionScanCache *ptr = cache.values[i];
1658                 if(ptr->x == x && ptr->y == y)
1659                 {
1660                         result = ptr->difference;
1661                         break;
1662                 }
1663         }
1664         cache_lock->unlock();
1665         return result;
1666 }
1667
1668 void MotionScanUnit::put_cache(int x, int y, int64_t difference)
1669 {
1670         MotionScanCache *ptr = new MotionScanCache(x, y, difference);
1671         cache_lock->lock("MotionScanUnit::put_cache");
1672         cache.append(ptr);
1673         cache_lock->unlock();
1674 }
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686 MotionScan::MotionScan(MotionMain2 *plugin,
1687         int total_clients,
1688         int total_packages)
1689  : LoadServer(
1690 //1, 1
1691 total_clients, total_packages
1692 )
1693 {
1694         this->plugin = plugin;
1695         cache_lock = new Mutex("MotionScan::cache_lock");
1696 }
1697
1698 MotionScan::~MotionScan()
1699 {
1700         delete cache_lock;
1701 }
1702
1703
1704 void MotionScan::init_packages()
1705 {
1706 // Set package coords
1707         for(int i = 0; i < get_total_packages(); i++)
1708         {
1709                 MotionScanPackage *pkg = (MotionScanPackage*)get_package(i);
1710
1711                 pkg->block_x1 = block_x1;
1712                 pkg->block_x2 = block_x2;
1713                 pkg->block_y1 = block_y1;
1714                 pkg->block_y2 = block_y2;
1715                 pkg->scan_x1 = scan_x1;
1716                 pkg->scan_x2 = scan_x2;
1717                 pkg->scan_y1 = scan_y1;
1718                 pkg->scan_y2 = scan_y2;
1719                 pkg->pixel = (int64_t)i * (int64_t)total_pixels / (int64_t)total_steps;
1720                 pkg->difference1 = 0;
1721                 pkg->difference2 = 0;
1722                 pkg->dx = 0;
1723                 pkg->dy = 0;
1724                 pkg->valid = 1;
1725         }
1726 }
1727
1728 LoadClient* MotionScan::new_client()
1729 {
1730         return new MotionScanUnit(this, plugin);
1731 }
1732
1733 LoadPackage* MotionScan::new_package()
1734 {
1735         return new MotionScanPackage;
1736 }
1737
1738
1739 void MotionScan::scan_frame(VFrame *previous_frame,
1740         VFrame *current_frame,
1741         int point)
1742 {
1743         this->previous_frame = previous_frame;
1744         this->current_frame = current_frame;
1745         this->point = point;
1746         subpixel = 0;
1747
1748         cache.remove_all_objects();
1749
1750
1751 // Single macroblock
1752         int w = current_frame->get_w();
1753         int h = current_frame->get_h();
1754
1755 // Initial search parameters
1756         int scan_w = w * plugin->config.global_range_w[point] / 100;
1757         int scan_h = h * plugin->config.global_range_h[point] / 100;
1758         int block_w = w * plugin->config.global_block_w[point] / 100;
1759         int block_h = h * plugin->config.global_block_h[point] / 100;
1760
1761 // Location of block in previous frame
1762         block_x1 = (int)(w * plugin->config.block_x[point] / 100 - block_w / 2);
1763         block_y1 = (int)(h * plugin->config.block_y[point] / 100 - block_h / 2);
1764         block_x2 = (int)(w * plugin->config.block_x[point] / 100 + block_w / 2);
1765         block_y2 = (int)(h * plugin->config.block_y[point] / 100 + block_h / 2);
1766
1767 // Offset to location of previous block.  This offset needn't be very accurate
1768 // since it's the offset of the previous image and current image we want.
1769         if(plugin->config.tracking_object == MotionScan::TRACK_PREVIOUS)
1770         {
1771                 block_x1 += plugin->total_dx[point] / OVERSAMPLE;
1772                 block_y1 += plugin->total_dy[point] / OVERSAMPLE;
1773                 block_x2 += plugin->total_dx[point] / OVERSAMPLE;
1774                 block_y2 += plugin->total_dy[point] / OVERSAMPLE;
1775         }
1776
1777         skip = 0;
1778
1779         switch(plugin->config.calculation)
1780         {
1781 // Don't calculate
1782                 case MotionScan::NO_CALCULATE:
1783                         dx_result = 0;
1784                         dy_result = 0;
1785                         skip = 1;
1786                         break;
1787
1788                 case MotionScan::LOAD:
1789                 {
1790 printf("MotionScan::scan_frame %d\n", __LINE__);
1791 // Load result from disk
1792                         char string[BCTEXTLEN];
1793                         sprintf(string, "%s%06d",
1794                                 MOTION_FILE,
1795                                 plugin->get_source_position());
1796                         FILE *input;
1797                         input = fopen(string, "r");
1798                         if(input)
1799                         {
1800                                 for(int i = 0; i <= point; i++)
1801                                 {
1802                                         fscanf(input,
1803                                                 "%d %d",
1804                                                 &dx_result,
1805                                                 &dy_result);
1806                                 }
1807                                 fclose(input);
1808                                 skip = 1;
1809                         }
1810                         break;
1811                 }
1812
1813 // Scan from scratch
1814                 default:
1815                         skip = 0;
1816                         break;
1817         }
1818
1819 // Perform scan
1820         if(!skip)
1821         {
1822 printf("MotionScan::scan_frame %d\n", __LINE__);
1823 // Calculate center of search area in current frame
1824                 int origin_offset_x = plugin->config.global_origin_x[point] * w / 100;
1825                 int origin_offset_y = plugin->config.global_origin_y[point] * h / 100;
1826                 int x_result = block_x1 + origin_offset_x;
1827                 int y_result = block_y1 + origin_offset_y;
1828
1829 // printf("MotionScan::scan_frame 1 %d %d %d %d %d %d %d %d\n",
1830 // block_x1 + block_w / 2,
1831 // block_y1 + block_h / 2,
1832 // block_w,
1833 // block_h,
1834 // block_x1,
1835 // block_y1,
1836 // block_x2,
1837 // block_y2);
1838
1839                 while(1)
1840                 {
1841                         scan_x1 = x_result - scan_w / 2;
1842                         scan_y1 = y_result - scan_h / 2;
1843                         scan_x2 = x_result + scan_w / 2;
1844                         scan_y2 = y_result + scan_h / 2;
1845
1846
1847
1848 // Zero out requested values
1849                         if(plugin->config.horizontal_only)
1850                         {
1851                                 scan_y1 = block_y1;
1852                                 scan_y2 = block_y1 + 1;
1853                         }
1854                         if(plugin->config.vertical_only)
1855                         {
1856                                 scan_x1 = block_x1;
1857                                 scan_x2 = block_x1 + 1;
1858                         }
1859
1860 // printf("MotionScan::scan_frame 1 %d %d %d %d %d %d %d %d\n",
1861 // block_x1,
1862 // block_y1,
1863 // block_x2,
1864 // block_y2,
1865 // scan_x1,
1866 // scan_y1,
1867 // scan_x2,
1868 // scan_y2);
1869 // Clamp the block coords before the scan so we get useful scan coords.
1870                         MotionScan::clamp_scan(w,
1871                                 h,
1872                                 &block_x1,
1873                                 &block_y1,
1874                                 &block_x2,
1875                                 &block_y2,
1876                                 &scan_x1,
1877                                 &scan_y1,
1878                                 &scan_x2,
1879                                 &scan_y2,
1880                                 0);
1881 // printf("MotionScan::scan_frame 1\n    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",
1882 // block_x1,
1883 // block_y1,
1884 // block_x2,
1885 // block_y2,
1886 // scan_x1,
1887 // scan_y1,
1888 // scan_x2,
1889 // scan_y2,
1890 // x_result,
1891 // y_result);
1892
1893
1894 // Give up if invalid coords.
1895                         if(scan_y2 <= scan_y1 ||
1896                                 scan_x2 <= scan_x1 ||
1897                                 block_x2 <= block_x1 ||
1898                                 block_y2 <= block_y1)
1899                                 break;
1900
1901
1902 // For subpixel, the top row and left column are skipped
1903                         if(subpixel)
1904                         {
1905
1906                                 if(plugin->config.horizontal_only ||
1907                                         plugin->config.vertical_only)
1908                                 {
1909                                         total_pixels = 4 * OVERSAMPLE * OVERSAMPLE - 4 * OVERSAMPLE;
1910                                 }
1911                                 else
1912                                 {
1913                                         total_pixels = 4 * OVERSAMPLE;
1914                                 }
1915
1916                                 total_steps = total_pixels;
1917
1918                                 set_package_count(total_steps);
1919                                 process_packages();
1920
1921 // Get least difference
1922                                 int64_t min_difference = -1;
1923                                 for(int i = 0; i < get_total_packages(); i++)
1924                                 {
1925                                         MotionScanPackage *pkg = (MotionScanPackage*)get_package(i);
1926                                         if(pkg->difference1 < min_difference || min_difference == -1)
1927                                         {
1928                                                 min_difference = pkg->difference1;
1929
1930                                                 if(plugin->config.vertical_only)
1931                                                         x_result = scan_x1 * OVERSAMPLE;
1932                                                 else
1933                                                         x_result = scan_x1 * OVERSAMPLE +
1934                                                                 (pkg->pixel % (OVERSAMPLE * 2 - 1)) + 1;
1935
1936                                                 if(plugin->config.horizontal_only)
1937                                                         y_result = scan_y1 * OVERSAMPLE;
1938                                                 else
1939                                                         y_result = scan_y1 * OVERSAMPLE +
1940                                                                 (pkg->pixel / (OVERSAMPLE * 2 - 1)) + 1;
1941
1942
1943 // Fill in results
1944                                                 dx_result = block_x1 * OVERSAMPLE - x_result;
1945                                                 dy_result = block_y1 * OVERSAMPLE - y_result;
1946                                         }
1947
1948                                         if(pkg->difference2 < min_difference)
1949                                         {
1950                                                 min_difference = pkg->difference2;
1951
1952                                                 if(plugin->config.vertical_only)
1953                                                         x_result = scan_x1 * OVERSAMPLE;
1954                                                 else
1955                                                         x_result = scan_x2 * OVERSAMPLE -
1956                                                                 ((pkg->pixel % (OVERSAMPLE * 2 - 1)) + 1);
1957
1958                                                 if(plugin->config.horizontal_only)
1959                                                         y_result = scan_y1 * OVERSAMPLE;
1960                                                 else
1961                                                         y_result = scan_y2 * OVERSAMPLE -
1962                                                                 ((pkg->pixel / (OVERSAMPLE * 2 - 1)) + 1);
1963
1964                                                 dx_result = block_x1 * OVERSAMPLE - x_result;
1965                                                 dy_result = block_y1 * OVERSAMPLE - y_result;
1966                                         }
1967                                 }
1968
1969
1970 //printf("MotionScan::scan_frame 1 %d %d %d %d\n", block_x1, block_y1, x_result, y_result);
1971                                 break;
1972                         }
1973                         else
1974                         {
1975
1976                                 total_pixels = (scan_x2 - scan_x1) * (scan_y2 - scan_y1);
1977                                 total_steps = MIN(plugin->config.global_positions, total_pixels);
1978
1979                                 set_package_count(total_steps);
1980                                 process_packages();
1981
1982 // Get least difference
1983                                 int64_t min_difference = -1;
1984                                 for(int i = 0; i < get_total_packages(); i++)
1985                                 {
1986                                         MotionScanPackage *pkg = (MotionScanPackage*)get_package(i);
1987                                         if(pkg->difference1 < min_difference || min_difference == -1)
1988                                         {
1989                                                 min_difference = pkg->difference1;
1990                                                 x_result = scan_x1 + (pkg->pixel % (scan_x2 - scan_x1));
1991                                                 y_result = scan_y1 + (pkg->pixel / (scan_x2 - scan_x1));
1992                                                 x_result *= OVERSAMPLE;
1993                                                 y_result *= OVERSAMPLE;
1994                                         }
1995                                 }
1996
1997
1998
1999 // printf("MotionScan::scan_frame 10 total_steps=%d total_pixels=%d subpixel=%d\n",
2000 // total_steps,
2001 // total_pixels,
2002 // subpixel);
2003 //
2004 // printf("     scan w=%d h=%d scan x1=%d y1=%d x2=%d y2=%d\n",
2005 // scan_w,
2006 // scan_h,
2007 // scan_x1,
2008 // scan_y1,
2009 // scan_x2,
2010 // scan_y2);
2011 //
2012 // printf("MotionScan::scan_frame 2 block x1=%d y1=%d x2=%d y2=%d result x=%.2f y=%.2f\n",
2013 // block_x1,
2014 // block_y1,
2015 // block_x2,
2016 // block_y2,
2017 // (float)x_result / 4,
2018 // (float)y_result / 4);
2019
2020
2021 // If a new search is required, rescale results back to pixels.
2022                                 if(total_steps >= total_pixels)
2023                                 {
2024 // Single pixel accuracy reached.  Now do exhaustive subpixel search.
2025                                         if(plugin->config.action == MotionScan::STABILIZE ||
2026                                                 plugin->config.action == MotionScan::TRACK ||
2027                                                 plugin->config.action == MotionScan::NOTHING)
2028                                         {
2029                                                 x_result /= OVERSAMPLE;
2030                                                 y_result /= OVERSAMPLE;
2031                                                 scan_w = 2;
2032                                                 scan_h = 2;
2033                                                 subpixel = 1;
2034                                         }
2035                                         else
2036                                         {
2037 // Fill in results and quit
2038                                                 dx_result = block_x1 * OVERSAMPLE - x_result;
2039                                                 dy_result = block_y1 * OVERSAMPLE - y_result;
2040                                                 break;
2041                                         }
2042                                 }
2043                                 else
2044 // Reduce scan area and try again
2045                                 {
2046                                         scan_w = (scan_x2 - scan_x1) / 2;
2047                                         scan_h = (scan_y2 - scan_y1) / 2;
2048                                         x_result /= OVERSAMPLE;
2049                                         y_result /= OVERSAMPLE;
2050                                 }
2051                         }
2052                 }
2053
2054                 dx_result *= -1;
2055                 dy_result *= -1;
2056         }
2057
2058
2059
2060
2061
2062
2063 // Write results
2064         if(plugin->config.calculation == MotionScan::SAVE)
2065         {
2066                 char string[BCTEXTLEN];
2067                 sprintf(string,
2068                         "%s%06d",
2069                         MOTION_FILE,
2070                         plugin->get_source_position());
2071                 FILE *output;
2072                 if(point == 0)
2073                         output = fopen(string, "w");
2074                 else
2075                         output = fopen(string, "a");
2076                 if(output)
2077                 {
2078                         fprintf(output,
2079                                 "%d %d\n",
2080                                 dx_result,
2081                                 dy_result);
2082                         fclose(output);
2083                 }
2084                 else
2085                 {
2086                         perror("MotionScan::scan_frame SAVE 1");
2087                 }
2088         }
2089
2090 #ifdef DEBUG
2091 printf("MotionScan::scan_frame 10 point=%d dx=%.2f dy=%.2f\n",
2092 point,
2093 (float)this->dx_result / OVERSAMPLE,
2094 (float)this->dy_result / OVERSAMPLE);
2095 #endif
2096 }
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114 int64_t MotionScan::get_cache(int x, int y)
2115 {
2116         int64_t result = -1;
2117         cache_lock->lock("MotionScan::get_cache");
2118         for(int i = 0; i < cache.total; i++)
2119         {
2120                 MotionScanCache *ptr = cache.values[i];
2121                 if(ptr->x == x && ptr->y == y)
2122                 {
2123                         result = ptr->difference;
2124                         break;
2125                 }
2126         }
2127         cache_lock->unlock();
2128         return result;
2129 }
2130
2131 void MotionScan::put_cache(int x, int y, int64_t difference)
2132 {
2133         MotionScanCache *ptr = new MotionScanCache(x, y, difference);
2134         cache_lock->lock("MotionScan::put_cache");
2135         cache.append(ptr);
2136         cache_lock->unlock();
2137 }
2138
2139
2140
2141
2142
2143 MotionScanCache::MotionScanCache(int x, int y, int64_t difference)
2144 {
2145         this->x = x;
2146         this->y = y;
2147         this->difference = difference;
2148 }
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159 #endif
2160
2161
2162