4130e2d811c2126f7b0f9b1735d5b96a6f247f10
[goodguy/history.git] / cinelerra-5.1 / plugins / motion2point / motion.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 "affine.h"
23 #include "../motion/motionscan.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 _("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->get_data(), MESSAGESIZE);
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->get_data(), strlen(keyframe->get_data()));
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);
442 }
443
444
445
446 void MotionMain2::scan_motion(int point)
447 {
448         if(!engine) engine = new MotionScan(PluginClient::get_project_smp() + 1,
449                 PluginClient::get_project_smp() + 1);
450
451 // Get the current motion vector between the previous and current frame
452         engine->scan_frame(current_global_ref, 
453                 prev_global_ref, 
454                 config.global_range_w[point],
455                 config.global_range_h[point],
456                 config.global_block_w[point],
457                 config.global_block_h[point],
458                 config.block_x[point],
459                 config.block_y[point],
460                 config.tracking_object,
461                 config.calculation,
462                 config.action,
463                 config.horizontal_only,
464                 config.vertical_only,
465                 get_source_position(),
466                 config.global_positions,
467                 total_dx[point],
468                 total_dy[point],
469                 config.global_origin_x[point],
470                 config.global_origin_y[point]);
471
472 //              0,
473 //              0,
474 //              0,
475 //              0);
476         current_dx[point] = engine->dx_result;
477         current_dy[point] = engine->dy_result;
478
479 // Add current motion vector to accumulation vector.
480         if(config.tracking_object != MotionScan::TRACK_SINGLE)
481         {
482 // Retract over time
483                 total_dx[point] = (int64_t)total_dx[point] * (100 - config.return_speed) / 100;
484                 total_dy[point] = (int64_t)total_dy[point] * (100 - config.return_speed) / 100;
485                 total_dx[point] += engine->dx_result;
486                 total_dy[point] += engine->dy_result;
487         }
488         else
489 // Make accumulation vector current
490         {
491                 total_dx[point] = engine->dx_result;
492                 total_dy[point] = engine->dy_result;
493 // printf("MotionMain2::scan_motion %d %d %d %d\n", 
494 // __LINE__, 
495 // point,
496 // total_dx[point], 
497 // total_dy[point]);
498         }
499
500 // Clamp accumulation vector
501         if(config.magnitude < 100)
502         {
503                 //int block_w = (int64_t)config.global_block_w[point] * 
504                 //              current_global_ref->get_w() / 100;
505                 //int block_h = (int64_t)config.global_block_h[point] * 
506                 //              current_global_ref->get_h() / 100;
507                 int block_x_orig = (int64_t)(config.block_x[point] * 
508                         current_global_ref->get_w() / 
509                         100);
510                 int block_y_orig = (int64_t)(config.block_y[point] *
511                         current_global_ref->get_h() / 
512                         100);
513
514                 int max_block_x = (int64_t)(current_global_ref->get_w() - block_x_orig) *
515                         OVERSAMPLE * 
516                         config.magnitude / 
517                         100;
518                 int max_block_y = (int64_t)(current_global_ref->get_h() - block_y_orig) *
519                         OVERSAMPLE *
520                         config.magnitude / 
521                         100;
522                 int min_block_x = (int64_t)-block_x_orig * 
523                         OVERSAMPLE * 
524                         config.magnitude / 
525                         100;
526                 int min_block_y = (int64_t)-block_y_orig * 
527                         OVERSAMPLE * 
528                         config.magnitude / 
529                         100;
530
531                 CLAMP(total_dx[point], min_block_x, max_block_x);
532                 CLAMP(total_dy[point], min_block_y, max_block_y);
533         }
534
535 // printf("MotionMain2::scan_motion %d %d %d %d\n", 
536 // __LINE__, 
537 // point,
538 // total_dx[point], 
539 // total_dy[point]);
540
541
542 }
543
544
545
546
547 void MotionMain2::apply_motion()
548 {
549         if(config.tracking_object != MotionScan::TRACK_SINGLE)
550         {
551 // Transfer current reference frame to previous reference frame and update
552 // counter.
553                 prev_global_ref->copy_from(current_global_ref);
554                 previous_frame_number = get_source_position();
555         }
556
557 // Decide what to do with target based on requested operation
558         //int interpolation; //   variable set but not used
559         float origin_x[TOTAL_POINTS];
560         float origin_y[TOTAL_POINTS];
561         float end_x[TOTAL_POINTS];
562         float end_y[TOTAL_POINTS];
563         for(int i = 0; i < TOTAL_POINTS; i++)
564         {
565                 get_current_vector(&origin_x[i], 
566                         &origin_y[i], 
567                         0,
568                         0,
569                         &end_x[i], 
570                         &end_y[i], 
571                         i);
572         }
573
574 // Calculate rotation if 2 points
575         double angle = 0.0;
576         double angle0 = 0.0;
577         double zoom = 1.0;
578         if(config.global[ROTATION_POINT])
579         {
580                         if(origin_x[1] - origin_x[0])
581                                 angle0 = atan((double)(origin_y[0] - origin_y[1]) /
582                                         (double)(origin_x[0] - origin_x[1]));
583                         if(end_x[1] - end_x[0])
584                                 angle = atan((double)(end_y[0] - end_y[1]) /
585                                         (double)(end_x[0] - end_x[1]));
586 // printf("MotionMain2::apply_motion %d angle0=%f angle=%f\n", 
587 // __LINE__,
588 // angle0 * 360 / 2 / M_PI, 
589 // angle * 360 / 2 / M_PI);
590
591                         angle -= angle0;
592
593 // Calculate zoom
594 //                      zoom = DISTANCE(origin_x[1], origin_y[1], origin_x[0], origin_y[0]) /
595 //                              DISTANCE(end_x[1], end_y[1], end_x[0], end_y[0]);
596
597         }
598
599 printf("MotionMain2::apply_motion %d total_dx=%.02f total_dy=%.02f angle=%f zoom=%f\n", 
600 __LINE__,
601 (float)total_dx[TRANSLATION_POINT] / OVERSAMPLE,
602 (float)total_dy[TRANSLATION_POINT] / OVERSAMPLE, 
603 angle * 360 / 2 / M_PI,
604 zoom);
605
606 // Calculate translation
607         float dx = 0.0;
608         float dy = 0.0;
609         switch(config.action)
610         {
611                 case MotionScan::NOTHING:
612                         global_target_dst->copy_from(global_target_src);
613                         break;
614                 case MotionScan::TRACK:
615                         //interpolation = CUBIC_LINEAR;
616                         dx = (float)total_dx[0] / OVERSAMPLE;
617                         dy = (float)total_dy[0] / OVERSAMPLE;
618                         break;
619                 case MotionScan::TRACK_PIXEL:
620                         //interpolation = NEAREST_NEIGHBOR;
621                         dx = (int)(total_dx[0] / OVERSAMPLE);
622                         dy = (int)(total_dy[0] / OVERSAMPLE);
623                         break;
624                         //interpolation = NEAREST_NEIGHBOR;
625                         dx = -(int)(total_dx[0] / OVERSAMPLE);
626                         dy = -(int)(total_dy[0] / OVERSAMPLE);
627                         angle *= -1;
628                         break;
629                 case MotionScan::STABILIZE:
630                         //interpolation = CUBIC_LINEAR;
631                         dx = -(float)total_dx[0] / OVERSAMPLE;
632                         dy = -(float)total_dy[0] / OVERSAMPLE;
633                         angle *= -1;
634                         break;
635         }
636
637
638
639
640
641         if(config.action != MotionScan::NOTHING)
642         {
643                 double w = get_output()->get_w();
644                 double h = get_output()->get_h();
645                 double pivot_x = end_x[0];
646                 double pivot_y = end_y[0];
647                 double angle1 = atan((double)pivot_y / (double)pivot_x) + angle;
648                 double angle2 = atan((double)(w - pivot_x) / (double)pivot_y) + angle;
649                 double angle3 = atan((double)(h - pivot_y) / (double)(w - pivot_x)) + angle;
650                 double angle4 = atan((double)pivot_x / (double)(h - pivot_y)) + angle;
651                 double radius1 = DISTANCE(0, 0, pivot_x, pivot_y) * zoom;
652                 double radius2 = DISTANCE(w, 0, pivot_x, pivot_y) * zoom;
653                 double radius3 = DISTANCE(w, h, pivot_x, pivot_y) * zoom;
654                 double radius4 = DISTANCE(0, h, pivot_x, pivot_y) * zoom;
655
656
657                 float x1 = (dx + pivot_x - cos(angle1) * radius1) * 100 / w;
658                 float y1 = (dy + pivot_y - sin(angle1) * radius1) * 100 / h;
659                 float x2 = (dx + pivot_x + sin(angle2) * radius2) * 100 / w;
660                 float y2 = (dy + pivot_y - cos(angle2) * radius2) * 100 / h;
661                 float x3 = (dx + pivot_x + cos(angle3) * radius3) * 100 / w;
662                 float y3 = (dy + pivot_y + sin(angle3) * radius3) * 100 / h;
663                 float x4 = (dx + pivot_x - sin(angle4) * radius4) * 100 / w;
664                 float y4 = (dy + pivot_y + cos(angle4) * radius4) * 100 / h;
665
666
667                 if(!affine)
668                         affine = new AffineEngine(PluginClient::get_project_smp() + 1,
669                                 PluginClient::get_project_smp() + 1);
670                 global_target_dst->clear_frame();
671
672
673 // printf("MotionMain2::apply_motion %d %.02f %.02f %.02f %.02f %.02f %.02f %.02f %.02f\n",
674 // __LINE__,
675 // x1, 
676 // y1, 
677 // x2, 
678 // y2, 
679 // x3, 
680 // y3, 
681 // x4, 
682 // y4);
683
684                 affine->process(global_target_dst,
685                         global_target_src, 
686                         0,
687                         AffineEngine::PERSPECTIVE,
688                         x1, 
689                         y1, 
690                         x2, 
691                         y2, 
692                         x3, 
693                         y3, 
694                         x4, 
695                         y4,
696                         1);
697         }
698 }
699
700
701
702
703
704
705 int MotionMain2::process_buffer(VFrame **frame,
706         int64_t start_position,
707         double frame_rate)
708 {
709         int need_reconfigure = load_configuration();
710         int color_model = frame[0]->get_color_model();
711         w = frame[0]->get_w();
712         h = frame[0]->get_h();
713         
714
715 #ifdef DEBUG
716 printf("MotionMain2::process_buffer 1 start_position=%jd\n", start_position);
717 #endif
718
719
720 // Calculate the source and destination pointers for each of the operations.
721 // Get the layer to track motion in.
722         reference_layer = config.bottom_is_master ?
723                 PluginClient::total_in_buffers - 1 :
724                 0;
725 // Get the layer to apply motion in.
726         target_layer = config.bottom_is_master ?
727                 0 :
728                 PluginClient::total_in_buffers - 1;
729
730
731         output_frame = frame[target_layer];
732
733
734 // Get the position of previous reference frame.
735         int64_t actual_previous_number;
736 // Skip if match frame not available
737         int skip_current = 0;
738
739
740         if(config.tracking_object == MotionScan::TRACK_SINGLE)
741         {
742                 actual_previous_number = config.track_frame;
743                 if(get_direction() == PLAY_REVERSE)
744                         actual_previous_number++;
745                 if(actual_previous_number == start_position)
746                         skip_current = 1;
747         }
748         else
749         {
750                 actual_previous_number = start_position;
751                 if(get_direction() == PLAY_FORWARD)
752                 {
753                         actual_previous_number--;
754                         if(actual_previous_number < get_source_start())
755                                 skip_current = 1;
756                         else
757                         {
758                                 KeyFrame *keyframe = get_prev_keyframe(start_position, 1);
759                                 if(keyframe->position > 0 &&
760                                         actual_previous_number < keyframe->position)
761                                         skip_current = 1;
762                         }
763                 }
764                 else
765                 {
766                         actual_previous_number++;
767                         if(actual_previous_number >= get_source_start() + get_total_len())
768                                 skip_current = 1;
769                         else
770                         {
771                                 KeyFrame *keyframe = get_next_keyframe(start_position, 1);
772                                 if(keyframe->position > 0 &&
773                                         actual_previous_number >= keyframe->position)
774                                         skip_current = 1;
775                         }
776                 }
777
778 // Only count motion since last keyframe
779                 
780
781         }
782
783
784 // Point 0 must be tracked for any other points to be tracked
785 // Action and Calculation must be something
786         if( !config.global[0] || ( config.action == MotionScan::NOTHING &&
787                         config.calculation == MotionScan::NO_CALCULATE) )
788                 skip_current = 1;
789
790
791 // printf("process_buffer %d %lld %lld %d\n", 
792 // skip_current, 
793 // previous_frame_number, 
794 // actual_previous_number,
795 // need_reconfigure);
796 // Load match frame and reset vectors
797         int need_reload = !skip_current && 
798                 (previous_frame_number != actual_previous_number ||
799                 need_reconfigure);
800         if(need_reload)
801         {
802                 for(int i = 0; i < TOTAL_POINTS; i++)
803                 {
804                         total_dx[i] = 0;
805                         total_dy[i] = 0;
806                 }
807                 previous_frame_number = actual_previous_number;
808         }
809
810
811         if(skip_current)
812         {
813                 for(int i = 0; i < TOTAL_POINTS; i++)
814                 {
815                         total_dx[i] = 0;
816                         total_dy[i] = 0;
817                         current_dx[i] = 0;
818                         current_dy[i] = 0;
819                 }
820         }
821
822
823
824
825 // Get the global pointers.  Here we walk through the sequence of events.
826         if(config.global[0])
827         {
828 // Global reads previous frame and compares
829 // with current frame to get the current translation.
830 // The center of the search area is fixed in compensate mode or
831 // the user value + the accumulation vector in track mode.
832                 if(!prev_global_ref)
833                         prev_global_ref = new VFrame(w, h, color_model);
834                 if(!current_global_ref)
835                         current_global_ref = new VFrame(w, h, color_model);
836
837 // Global loads the current target frame into the src and 
838 // writes it to the dst frame with desired translation.
839                 if(!global_target_src)
840                         global_target_src = new VFrame(w, h, color_model);
841                 if(!global_target_dst)
842                         global_target_dst = new VFrame(w, h, color_model);
843
844
845 // Load the global frames
846                 if(need_reload)
847                 {
848                         read_frame(prev_global_ref, 
849                                 reference_layer, 
850                                 previous_frame_number, 
851                                 frame_rate,
852                                 0);
853                 }
854
855                 read_frame(current_global_ref, 
856                         reference_layer, 
857                         start_position, 
858                         frame_rate,
859                         0);
860                 read_frame(global_target_src,
861                         target_layer,
862                         start_position,
863                         frame_rate,
864                         0);
865         }
866
867
868
869
870
871
872
873
874         if(!skip_current)
875         {
876 // Get position change from previous frame to current frame
877                 if(config.global[0]) 
878                 {
879                         for(int i = 0; i < TOTAL_POINTS; i++)
880                                 if(config.global[i]) scan_motion(i);
881                 }
882                 
883                 apply_motion();
884         }
885
886
887
888
889 //printf("MotionMain2::process_buffer 90 %d\n", skip_current);
890
891 // Transfer the relevant target frame to the output
892         if(!skip_current)
893         {
894                 frame[target_layer]->copy_from(global_target_dst);
895         }
896         else
897 // Read the target destination directly
898         {
899                 read_frame(frame[target_layer],
900                         target_layer,
901                         start_position,
902                         frame_rate,
903                         0);
904         }
905
906         if(config.draw_vectors)
907         {
908                 for(int i = 0; i < TOTAL_POINTS; i++)
909                         draw_vectors(frame[target_layer], i);
910         }
911
912 #ifdef DEBUG
913 printf("MotionMain2::process_buffer 100 skip_current=%d\n", skip_current);
914 #endif
915         return 0;
916 }
917
918
919
920 #if 0
921
922 void MotionMain2::clamp_scan(int w, 
923         int h, 
924         int *block_x1,
925         int *block_y1,
926         int *block_x2,
927         int *block_y2,
928         int *scan_x1,
929         int *scan_y1,
930         int *scan_x2,
931         int *scan_y2,
932         int use_absolute)
933 {
934 // printf("MotionMain2::clamp_scan 1 w=%d h=%d block=%d %d %d %d scan=%d %d %d %d absolute=%d\n",
935 // w,
936 // h,
937 // *block_x1,
938 // *block_y1,
939 // *block_x2,
940 // *block_y2,
941 // *scan_x1,
942 // *scan_y1,
943 // *scan_x2,
944 // *scan_y2,
945 // use_absolute);
946
947         if(use_absolute)
948         {
949 // scan is always out of range before block.
950                 if(*scan_x1 < 0)
951                 {
952                         int difference = -*scan_x1;
953                         *block_x1 += difference;
954                         *scan_x1 = 0;
955                 }
956
957                 if(*scan_y1 < 0)
958                 {
959                         int difference = -*scan_y1;
960                         *block_y1 += difference;
961                         *scan_y1 = 0;
962                 }
963
964                 if(*scan_x2 > w)
965                 {
966                         int difference = *scan_x2 - w;
967                         *block_x2 -= difference;
968                         *scan_x2 -= difference;
969                 }
970
971                 if(*scan_y2 > h)
972                 {
973                         int difference = *scan_y2 - h;
974                         *block_y2 -= difference;
975                         *scan_y2 -= difference;
976                 }
977
978                 CLAMP(*scan_x1, 0, w);
979                 CLAMP(*scan_y1, 0, h);
980                 CLAMP(*scan_x2, 0, w);
981                 CLAMP(*scan_y2, 0, h);
982         }
983         else
984         {
985                 if(*scan_x1 < 0)
986                 {
987                         int difference = -*scan_x1;
988                         *block_x1 += difference;
989                         *scan_x2 += difference;
990                         *scan_x1 = 0;
991                 }
992
993                 if(*scan_y1 < 0)
994                 {
995                         int difference = -*scan_y1;
996                         *block_y1 += difference;
997                         *scan_y2 += difference;
998                         *scan_y1 = 0;
999                 }
1000
1001                 if(*scan_x2 - *block_x1 + *block_x2 > w)
1002                 {
1003                         int difference = *scan_x2 - *block_x1 + *block_x2 - w;
1004                         *block_x2 -= difference;
1005                 }
1006
1007                 if(*scan_y2 - *block_y1 + *block_y2 > h)
1008                 {
1009                         int difference = *scan_y2 - *block_y1 + *block_y2 - h;
1010                         *block_y2 -= difference;
1011                 }
1012
1013 //              CLAMP(*scan_x1, 0, w - (*block_x2 - *block_x1));
1014 //              CLAMP(*scan_y1, 0, h - (*block_y2 - *block_y1));
1015 //              CLAMP(*scan_x2, 0, w - (*block_x2 - *block_x1));
1016 //              CLAMP(*scan_y2, 0, h - (*block_y2 - *block_y1));
1017         }
1018
1019 // Sanity checks which break the calculation but should never happen if the
1020 // center of the block is inside the frame.
1021         CLAMP(*block_x1, 0, w);
1022         CLAMP(*block_x2, 0, w);
1023         CLAMP(*block_y1, 0, h);
1024         CLAMP(*block_y2, 0, h);
1025
1026 // printf("MotionMain2::clamp_scan 2 w=%d h=%d block=%d %d %d %d scan=%d %d %d %d absolute=%d\n",
1027 // w,
1028 // h,
1029 // *block_x1,
1030 // *block_y1,
1031 // *block_x2,
1032 // *block_y2,
1033 // *scan_x1,
1034 // *scan_y1,
1035 // *scan_x2,
1036 // *scan_y2,
1037 // use_absolute);
1038 }
1039
1040
1041 #endif // 0
1042
1043 void MotionMain2::get_current_vector(float *origin_x,
1044         float *origin_y,
1045         float *current_x1, 
1046         float *current_y1, 
1047         float *current_x2, 
1048         float *current_y2, 
1049         int point)
1050 {
1051         int w = get_output()->get_w();
1052         int h = get_output()->get_h();
1053         float temp1;
1054         float temp2;
1055         float temp3;
1056         float temp4;
1057         float temp5;
1058         float temp6;
1059         if(!origin_x) origin_x = &temp1;
1060         if(!origin_y) origin_y = &temp2;
1061         if(!current_x1) current_x1 = &temp3;
1062         if(!current_y1) current_y1 = &temp4;
1063         if(!current_x2) current_x2 = &temp5;
1064         if(!current_y2) current_y2 = &temp6;
1065
1066         *origin_x = 0;
1067         *origin_y = 0;
1068         *current_x1 = 0.0;
1069         *current_y1 = 0.0;
1070         *current_x2 = 0.0;
1071         *current_y2 = 0.0;
1072         
1073         
1074         if(config.global[point])
1075         {
1076 // Get vector
1077 // Start of vector is center of previous block.
1078 // End of vector is total accumulation.
1079                 if(config.tracking_object == MotionScan::TRACK_SINGLE)
1080                 {
1081                         (*origin_x) = (*current_x1) = ((float)config.block_x[point] * 
1082                                 w / 
1083                                 100);
1084                         (*origin_y) = (*current_y1) = ((float)config.block_y[point] *
1085                                 h / 
1086                                 100);
1087                         (*current_x2) = (*current_x1) + (float)total_dx[point] / OVERSAMPLE;
1088                         (*current_y2) = (*current_y1) + (float)total_dy[point] / OVERSAMPLE;
1089                 }
1090                 else
1091 // Start of vector is center of previous block.
1092 // End of vector is current change.
1093                 if(config.tracking_object == MotionScan::PREVIOUS_SAME_BLOCK)
1094                 {
1095                         (*origin_x) = (*current_x1) = ((float)config.block_x[point] * 
1096                                 w / 
1097                                 100);
1098                         (*origin_y) = (*current_y1) = ((float)config.block_y[point] *
1099                                 h / 
1100                                 100);
1101                         (*current_x2) = (*origin_x) + (float)current_dx[point] / OVERSAMPLE;
1102                         (*current_y2) = (*origin_y) + (float)current_dy[point] / OVERSAMPLE;
1103                 }
1104                 else
1105                 {
1106                         (*origin_x) = (float)config.block_x[point] * 
1107                                 w / 
1108                                 100;
1109                         (*origin_y) = (float)config.block_y[point] *
1110                                 h / 
1111                                 100;
1112                         (*current_x1) = ((*origin_x) + 
1113                                 (float)(total_dx[point] - current_dx[point]) / 
1114                                 OVERSAMPLE);
1115                         (*current_y1) = ((*origin_y) +
1116                                 (float)(total_dy[point] - current_dy[point]) /
1117                                 OVERSAMPLE);
1118                         (*current_x2) = ((*origin_x) + 
1119                                 (float)total_dx[point] / 
1120                                 OVERSAMPLE);
1121                         (*current_y2) = ((*origin_y) +
1122                                 (float)total_dy[point] /
1123                                 OVERSAMPLE);
1124                 }
1125         }
1126 }
1127
1128
1129 void MotionMain2::draw_vectors(VFrame *frame, int point)
1130 {
1131         int w = frame->get_w();
1132         int h = frame->get_h();
1133         float global_x1, global_y1;
1134         float global_x2, global_y2;
1135         int block_x, block_y;
1136         int block_w, block_h;
1137         int block_x1, block_y1;
1138         int block_x2, block_y2;
1139         int search_w, search_h;
1140         int search_x1, search_y1;
1141         int search_x2, search_y2;
1142         int origin_offset_x;
1143         int origin_offset_y;
1144
1145         if(!config.draw_vectors[point]) return;
1146
1147
1148         if(config.global[point])
1149         {
1150 // Get vector
1151                 get_current_vector(0,
1152                         0,
1153                         &global_x1, 
1154                         &global_y1, 
1155                         &global_x2, 
1156                         &global_y2, 
1157                         point);
1158
1159
1160 // Draw destination rectangle
1161                 if(config.action == MotionScan::NOTHING || 
1162                         config.action == MotionScan::TRACK)
1163                 {
1164                         block_x = (int)global_x2;
1165                         block_y = (int)global_y2;
1166                 }
1167                 else
1168 // Draw source rectangle
1169                 {
1170                         block_x = (int)global_x1;
1171                         block_y = (int)global_y1;
1172                 }
1173                 block_w = config.global_block_w[point] * w / 100;
1174                 block_h = config.global_block_h[point] * h / 100;
1175                 origin_offset_x = config.global_origin_x[point] * w / 100;
1176                 origin_offset_y = config.global_origin_y[point] * h / 100;
1177                 block_x1 = block_x - block_w / 2;
1178                 block_y1 = block_y - block_h / 2;
1179                 block_x2 = block_x + block_w / 2;
1180                 block_y2 = block_y + block_h / 2;
1181                 search_w = config.global_range_w[point] * w / 100;
1182                 search_h = config.global_range_h[point] * h / 100;
1183                 search_x1 = block_x1 + origin_offset_x - search_w / 2;
1184                 search_y1 = block_y1 + origin_offset_y - search_h / 2;
1185                 search_x2 = block_x2 + origin_offset_x + search_w / 2;
1186                 search_y2 = block_y2 + origin_offset_y + search_h / 2;
1187
1188 // printf("MotionMain2::draw_vectors %d %d %d %d %d %d %d %d %d %d %d %d\n",
1189 // global_x1,
1190 // global_y1,
1191 // block_w,
1192 // block_h,
1193 // block_x1,
1194 // block_y1,
1195 // block_x2,
1196 // block_y2,
1197 // search_x1,
1198 // search_y1,
1199 // search_x2,
1200 // search_y2);
1201
1202                 MotionScan::clamp_scan(w, 
1203                         h, 
1204                         &block_x1,
1205                         &block_y1,
1206                         &block_x2,
1207                         &block_y2,
1208                         &search_x1,
1209                         &search_y1,
1210                         &search_x2,
1211                         &search_y2,
1212                         1);
1213
1214 // Vector
1215                 draw_arrow(frame, (int)global_x1, (int)global_y1, (int)global_x2, (int)global_y2);
1216
1217 // Macroblock
1218                 draw_line(frame, block_x1, block_y1, block_x2, block_y1);
1219                 draw_line(frame, block_x2, block_y1, block_x2, block_y2);
1220                 draw_line(frame, block_x2, block_y2, block_x1, block_y2);
1221                 draw_line(frame, block_x1, block_y2, block_x1, block_y1);
1222
1223
1224 // Search area
1225                 draw_line(frame, search_x1, search_y1, search_x2, search_y1);
1226                 draw_line(frame, search_x2, search_y1, search_x2, search_y2);
1227                 draw_line(frame, search_x2, search_y2, search_x1, search_y2);
1228                 draw_line(frame, search_x1, search_y2, search_x1, search_y1);
1229         }
1230 }
1231
1232
1233
1234 void MotionMain2::draw_pixel(VFrame *frame, int x, int y)
1235 {
1236         if(!(x >= 0 && y >= 0 && x < frame->get_w() && y < frame->get_h())) return;
1237
1238 #define DRAW_PIXEL(x, y, components, do_yuv, max, type) \
1239 { \
1240         type **rows = (type**)frame->get_rows(); \
1241         rows[y][x * components] = max - rows[y][x * components]; \
1242         if(!do_yuv) \
1243         { \
1244                 rows[y][x * components + 1] = max - rows[y][x * components + 1]; \
1245                 rows[y][x * components + 2] = max - rows[y][x * components + 2]; \
1246         } \
1247         else \
1248         { \
1249                 rows[y][x * components + 1] = (max / 2 + 1) - rows[y][x * components + 1]; \
1250                 rows[y][x * components + 2] = (max / 2 + 1) - rows[y][x * components + 2]; \
1251         } \
1252         if(components == 4) \
1253                 rows[y][x * components + 3] = max; \
1254 }
1255
1256
1257         switch(frame->get_color_model())
1258         {
1259                 case BC_RGB888:
1260                         DRAW_PIXEL(x, y, 3, 0, 0xff, unsigned char);
1261                         break;
1262                 case BC_RGBA8888:
1263                         DRAW_PIXEL(x, y, 4, 0, 0xff, unsigned char);
1264                         break;
1265                 case BC_RGB_FLOAT:
1266                         DRAW_PIXEL(x, y, 3, 0, 1.0, float);
1267                         break;
1268                 case BC_RGBA_FLOAT:
1269                         DRAW_PIXEL(x, y, 4, 0, 1.0, float);
1270                         break;
1271                 case BC_YUV888:
1272                         DRAW_PIXEL(x, y, 3, 1, 0xff, unsigned char);
1273                         break;
1274                 case BC_YUVA8888:
1275                         DRAW_PIXEL(x, y, 4, 1, 0xff, unsigned char);
1276                         break;
1277                 case BC_RGB161616:
1278                         DRAW_PIXEL(x, y, 3, 0, 0xffff, uint16_t);
1279                         break;
1280                 case BC_YUV161616:
1281                         DRAW_PIXEL(x, y, 3, 1, 0xffff, uint16_t);
1282                         break;
1283                 case BC_RGBA16161616:
1284                         DRAW_PIXEL(x, y, 4, 0, 0xffff, uint16_t);
1285                         break;
1286                 case BC_YUVA16161616:
1287                         DRAW_PIXEL(x, y, 4, 1, 0xffff, uint16_t);
1288                         break;
1289         }
1290 }
1291
1292
1293 void MotionMain2::draw_line(VFrame *frame, int x1, int y1, int x2, int y2)
1294 {
1295         int w = labs(x2 - x1);
1296         int h = labs(y2 - y1);
1297 //printf("MotionMain2::draw_line 1 %d %d %d %d\n", x1, y1, x2, y2);
1298
1299         if(!w && !h)
1300         {
1301                 draw_pixel(frame, x1, y1);
1302         }
1303         else
1304         if(w > h)
1305         {
1306 // Flip coordinates so x1 < x2
1307                 if(x2 < x1)
1308                 {
1309                         y2 ^= y1;
1310                         y1 ^= y2;
1311                         y2 ^= y1;
1312                         x1 ^= x2;
1313                         x2 ^= x1;
1314                         x1 ^= x2;
1315                 }
1316                 int numerator = y2 - y1;
1317                 int denominator = x2 - x1;
1318                 for(int i = x1; i < x2; i++)
1319                 {
1320                         int y = y1 + (int64_t)(i - x1) * (int64_t)numerator / (int64_t)denominator;
1321                         draw_pixel(frame, i, y);
1322                 }
1323         }
1324         else
1325         {
1326 // Flip coordinates so y1 < y2
1327                 if(y2 < y1)
1328                 {
1329                         y2 ^= y1;
1330                         y1 ^= y2;
1331                         y2 ^= y1;
1332                         x1 ^= x2;
1333                         x2 ^= x1;
1334                         x1 ^= x2;
1335                 }
1336                 int numerator = x2 - x1;
1337                 int denominator = y2 - y1;
1338                 for(int i = y1; i < y2; i++)
1339                 {
1340                         int x = x1 + (int64_t)(i - y1) * (int64_t)numerator / (int64_t)denominator;
1341                         draw_pixel(frame, x, i);
1342                 }
1343         }
1344 //printf("MotionMain2::draw_line 2\n");
1345 }
1346
1347 #define ARROW_SIZE 10
1348 void MotionMain2::draw_arrow(VFrame *frame, int x1, int y1, int x2, int y2)
1349 {
1350         double angle = atan((float)(y2 - y1) / (float)(x2 - x1));
1351         double angle1 = angle + (float)145 / 360 * 2 * 3.14159265;
1352         double angle2 = angle - (float)145 / 360 * 2 * 3.14159265;
1353         int x3;
1354         int y3;
1355         int x4;
1356         int y4;
1357         if(x2 < x1)
1358         {
1359                 x3 = x2 - (int)(ARROW_SIZE * cos(angle1));
1360                 y3 = y2 - (int)(ARROW_SIZE * sin(angle1));
1361                 x4 = x2 - (int)(ARROW_SIZE * cos(angle2));
1362                 y4 = y2 - (int)(ARROW_SIZE * sin(angle2));
1363         }
1364         else
1365         {
1366                 x3 = x2 + (int)(ARROW_SIZE * cos(angle1));
1367                 y3 = y2 + (int)(ARROW_SIZE * sin(angle1));
1368                 x4 = x2 + (int)(ARROW_SIZE * cos(angle2));
1369                 y4 = y2 + (int)(ARROW_SIZE * sin(angle2));
1370         }
1371
1372 // Main vector
1373         draw_line(frame, x1, y1, x2, y2);
1374 //      draw_line(frame, x1, y1 + 1, x2, y2 + 1);
1375
1376 // Arrow line
1377         if(abs(y2 - y1) || abs(x2 - x1)) draw_line(frame, x2, y2, x3, y3);
1378 //      draw_line(frame, x2, y2 + 1, x3, y3 + 1);
1379 // Arrow line
1380         if(abs(y2 - y1) || abs(x2 - x1)) draw_line(frame, x2, y2, x4, y4);
1381 //      draw_line(frame, x2, y2 + 1, x4, y4 + 1);
1382 }
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393 #if 0
1394
1395
1396
1397 #define ABS_DIFF(type, temp_type, multiplier, components) \
1398 { \
1399         temp_type result_temp = 0; \
1400         for(int i = 0; i < h; i++) \
1401         { \
1402                 type *prev_row = (type*)prev_ptr; \
1403                 type *current_row = (type*)current_ptr; \
1404                 for(int j = 0; j < w; j++) \
1405                 { \
1406                         for(int k = 0; k < 3; k++) \
1407                         { \
1408                                 temp_type difference; \
1409                                 difference = *prev_row++ - *current_row++; \
1410                                 if(difference < 0) \
1411                                         result_temp -= difference; \
1412                                 else \
1413                                         result_temp += difference; \
1414                         } \
1415                         if(components == 4) \
1416                         { \
1417                                 prev_row++; \
1418                                 current_row++; \
1419                         } \
1420                 } \
1421                 prev_ptr += row_bytes; \
1422                 current_ptr += row_bytes; \
1423         } \
1424         result = (int64_t)(result_temp * multiplier); \
1425 }
1426
1427 int64_t MotionMain2::abs_diff(unsigned char *prev_ptr,
1428         unsigned char *current_ptr,
1429         int row_bytes,
1430         int w,
1431         int h,
1432         int color_model)
1433 {
1434         int64_t result = 0;
1435         switch(color_model)
1436         {
1437                 case BC_RGB888:
1438                         ABS_DIFF(unsigned char, int64_t, 1, 3)
1439                         break;
1440                 case BC_RGBA8888:
1441                         ABS_DIFF(unsigned char, int64_t, 1, 4)
1442                         break;
1443                 case BC_RGB_FLOAT:
1444                         ABS_DIFF(float, double, 0x10000, 3)
1445                         break;
1446                 case BC_RGBA_FLOAT:
1447                         ABS_DIFF(float, double, 0x10000, 4)
1448                         break;
1449                 case BC_YUV888:
1450                         ABS_DIFF(unsigned char, int64_t, 1, 3)
1451                         break;
1452                 case BC_YUVA8888:
1453                         ABS_DIFF(unsigned char, int64_t, 1, 4)
1454                         break;
1455                 case BC_YUV161616:
1456                         ABS_DIFF(uint16_t, int64_t, 1, 3)
1457                         break;
1458                 case BC_YUVA16161616:
1459                         ABS_DIFF(uint16_t, int64_t, 1, 4)
1460                         break;
1461         }
1462         return result;
1463 }
1464
1465
1466
1467 #define ABS_DIFF_SUB(type, temp_type, multiplier, components) \
1468 { \
1469         temp_type result_temp = 0; \
1470         temp_type y2_fraction = sub_y * 0x100 / OVERSAMPLE; \
1471         temp_type y1_fraction = 0x100 - y2_fraction; \
1472         temp_type x2_fraction = sub_x * 0x100 / OVERSAMPLE; \
1473         temp_type x1_fraction = 0x100 - x2_fraction; \
1474         for(int i = 0; i < h_sub; i++) \
1475         { \
1476                 type *prev_row1 = (type*)prev_ptr; \
1477                 type *prev_row2 = (type*)prev_ptr + components; \
1478                 type *prev_row3 = (type*)(prev_ptr + row_bytes); \
1479                 type *prev_row4 = (type*)(prev_ptr + row_bytes) + components; \
1480                 type *current_row = (type*)current_ptr; \
1481                 for(int j = 0; j < w_sub; j++) \
1482                 { \
1483                         for(int k = 0; k < 3; k++) \
1484                         { \
1485                                 temp_type difference; \
1486                                 temp_type prev_value = \
1487                                         (*prev_row1++ * x1_fraction * y1_fraction + \
1488                                         *prev_row2++ * x2_fraction * y1_fraction + \
1489                                         *prev_row3++ * x1_fraction * y2_fraction + \
1490                                         *prev_row4++ * x2_fraction * y2_fraction) / \
1491                                         0x100 / 0x100; \
1492                                 temp_type current_value = *current_row++; \
1493                                 difference = prev_value - current_value; \
1494                                 if(difference < 0) \
1495                                         result_temp -= difference; \
1496                                 else \
1497                                         result_temp += difference; \
1498                         } \
1499  \
1500                         if(components == 4) \
1501                         { \
1502                                 prev_row1++; \
1503                                 prev_row2++; \
1504                                 prev_row3++; \
1505                                 prev_row4++; \
1506                                 current_row++; \
1507                         } \
1508                 } \
1509                 prev_ptr += row_bytes; \
1510                 current_ptr += row_bytes; \
1511         } \
1512         result = (int64_t)(result_temp * multiplier); \
1513 }
1514
1515
1516
1517
1518 int64_t MotionMain2::abs_diff_sub(unsigned char *prev_ptr,
1519         unsigned char *current_ptr,
1520         int row_bytes,
1521         int w,
1522         int h,
1523         int color_model,
1524         int sub_x,
1525         int sub_y)
1526 {
1527         int h_sub = h - 1;
1528         int w_sub = w - 1;
1529         int64_t result = 0;
1530
1531         switch(color_model)
1532         {
1533                 case BC_RGB888:
1534                         ABS_DIFF_SUB(unsigned char, int64_t, 1, 3)
1535                         break;
1536                 case BC_RGBA8888:
1537                         ABS_DIFF_SUB(unsigned char, int64_t, 1, 4)
1538                         break;
1539                 case BC_RGB_FLOAT:
1540                         ABS_DIFF_SUB(float, double, 0x10000, 3)
1541                         break;
1542                 case BC_RGBA_FLOAT:
1543                         ABS_DIFF_SUB(float, double, 0x10000, 4)
1544                         break;
1545                 case BC_YUV888:
1546                         ABS_DIFF_SUB(unsigned char, int64_t, 1, 3)
1547                         break;
1548                 case BC_YUVA8888:
1549                         ABS_DIFF_SUB(unsigned char, int64_t, 1, 4)
1550                         break;
1551                 case BC_YUV161616:
1552                         ABS_DIFF_SUB(uint16_t, int64_t, 1, 3)
1553                         break;
1554                 case BC_YUVA16161616:
1555                         ABS_DIFF_SUB(uint16_t, int64_t, 1, 4)
1556                         break;
1557         }
1558         return result;
1559 }
1560
1561
1562
1563
1564
1565 MotionScanPackage::MotionScanPackage()
1566  : LoadPackage()
1567 {
1568         valid = 1;
1569 }
1570
1571
1572
1573
1574
1575
1576 MotionScanUnit::MotionScanUnit(MotionScan *server, 
1577         MotionMain2 *plugin)
1578  : LoadClient(server)
1579 {
1580         this->plugin = plugin;
1581         this->server = server;
1582         cache_lock = new Mutex("MotionScanUnit::cache_lock");
1583 }
1584
1585 MotionScanUnit::~MotionScanUnit()
1586 {
1587         delete cache_lock;
1588 }
1589
1590
1591
1592 void MotionScanUnit::process_package(LoadPackage *package)
1593 {
1594         MotionScanPackage *pkg = (MotionScanPackage*)package;
1595         int w = server->current_frame->get_w();
1596         int h = server->current_frame->get_h();
1597         int color_model = server->current_frame->get_color_model();
1598         int pixel_size = cmodel_calculate_pixelsize(color_model);
1599         int row_bytes = server->current_frame->get_bytes_per_line();
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613 // Single pixel
1614         if(!server->subpixel)
1615         {
1616                 int search_x = pkg->scan_x1 + (pkg->pixel % (pkg->scan_x2 - pkg->scan_x1));
1617                 int search_y = pkg->scan_y1 + (pkg->pixel / (pkg->scan_x2 - pkg->scan_x1));
1618
1619 // Try cache
1620                 pkg->difference1 = server->get_cache(search_x, search_y);
1621                 if(pkg->difference1 < 0)
1622                 {
1623 //printf("MotionScanUnit::process_package 1 %d %d\n", 
1624 //search_x, search_y, pkg->block_x2 - pkg->block_x1, pkg->block_y2 - pkg->block_y1);
1625 // Pointers to first pixel in each block
1626                         unsigned char *prev_ptr = server->previous_frame->get_rows()[
1627                                 search_y] +     
1628                                 search_x * pixel_size;
1629                         unsigned char *current_ptr = server->current_frame->get_rows()[
1630                                 pkg->block_y1] +
1631                                 pkg->block_x1 * pixel_size;
1632 // Scan block
1633                         pkg->difference1 = plugin->abs_diff(prev_ptr,
1634                                 current_ptr,
1635                                 row_bytes,
1636                                 pkg->block_x2 - pkg->block_x1,
1637                                 pkg->block_y2 - pkg->block_y1,
1638                                 color_model);
1639 //printf("MotionScanUnit::process_package 2\n");
1640                         server->put_cache(search_x, search_y, pkg->difference1);
1641                 }
1642         }
1643
1644
1645
1646
1647
1648
1649
1650         else
1651
1652
1653
1654
1655
1656
1657
1658
1659 // Sub pixel
1660         {
1661                 int sub_x = pkg->pixel % (OVERSAMPLE * 2 - 1) + 1;
1662                 int sub_y = pkg->pixel / (OVERSAMPLE * 2 - 1) + 1;
1663
1664                 if(plugin->config.horizontal_only)
1665                 {
1666                         sub_y = 0;
1667                 }
1668
1669                 if(plugin->config.vertical_only)
1670                 {
1671                         sub_x = 0;
1672                 }
1673
1674                 int search_x = pkg->scan_x1 + sub_x / OVERSAMPLE;
1675                 int search_y = pkg->scan_y1 + sub_y / OVERSAMPLE;
1676                 sub_x %= OVERSAMPLE;
1677                 sub_y %= OVERSAMPLE;
1678
1679
1680                 unsigned char *prev_ptr = server->previous_frame->get_rows()[
1681                         search_y] +
1682                         search_x * pixel_size;
1683                 unsigned char *current_ptr = server->current_frame->get_rows()[
1684                         pkg->block_y1] +
1685                         pkg->block_x1 * pixel_size;
1686
1687 // With subpixel, there are two ways to compare each position, one by shifting
1688 // the previous frame and two by shifting the current frame.
1689                 pkg->difference1 = plugin->abs_diff_sub(prev_ptr,
1690                         current_ptr,
1691                         row_bytes,
1692                         pkg->block_x2 - pkg->block_x1,
1693                         pkg->block_y2 - pkg->block_y1,
1694                         color_model,
1695                         sub_x,
1696                         sub_y);
1697                 pkg->difference2 = plugin->abs_diff_sub(current_ptr,
1698                         prev_ptr,
1699                         row_bytes,
1700                         pkg->block_x2 - pkg->block_x1,
1701                         pkg->block_y2 - pkg->block_y1,
1702                         color_model,
1703                         sub_x,
1704                         sub_y);
1705 // printf("MotionScanUnit::process_package sub_x=%d sub_y=%d search_x=%d search_y=%d diff1=%lld diff2=%lld\n",
1706 // sub_x,
1707 // sub_y,
1708 // search_x,
1709 // search_y,
1710 // pkg->difference1,
1711 // pkg->difference2);
1712         }
1713
1714
1715
1716
1717
1718 }
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729 int64_t MotionScanUnit::get_cache(int x, int y)
1730 {
1731         int64_t result = -1;
1732         cache_lock->lock("MotionScanUnit::get_cache");
1733         for(int i = 0; i < cache.total; i++)
1734         {
1735                 MotionScanCache *ptr = cache.values[i];
1736                 if(ptr->x == x && ptr->y == y)
1737                 {
1738                         result = ptr->difference;
1739                         break;
1740                 }
1741         }
1742         cache_lock->unlock();
1743         return result;
1744 }
1745
1746 void MotionScanUnit::put_cache(int x, int y, int64_t difference)
1747 {
1748         MotionScanCache *ptr = new MotionScanCache(x, y, difference);
1749         cache_lock->lock("MotionScanUnit::put_cache");
1750         cache.append(ptr);
1751         cache_lock->unlock();
1752 }
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764 MotionScan::MotionScan(MotionMain2 *plugin, 
1765         int total_clients,
1766         int total_packages)
1767  : LoadServer(
1768 //1, 1 
1769 total_clients, total_packages 
1770 )
1771 {
1772         this->plugin = plugin;
1773         cache_lock = new Mutex("MotionScan::cache_lock");
1774 }
1775
1776 MotionScan::~MotionScan()
1777 {
1778         delete cache_lock;
1779 }
1780
1781
1782 void MotionScan::init_packages()
1783 {
1784 // Set package coords
1785         for(int i = 0; i < get_total_packages(); i++)
1786         {
1787                 MotionScanPackage *pkg = (MotionScanPackage*)get_package(i);
1788
1789                 pkg->block_x1 = block_x1;
1790                 pkg->block_x2 = block_x2;
1791                 pkg->block_y1 = block_y1;
1792                 pkg->block_y2 = block_y2;
1793                 pkg->scan_x1 = scan_x1;
1794                 pkg->scan_x2 = scan_x2;
1795                 pkg->scan_y1 = scan_y1;
1796                 pkg->scan_y2 = scan_y2;
1797                 pkg->pixel = (int64_t)i * (int64_t)total_pixels / (int64_t)total_steps;
1798                 pkg->difference1 = 0;
1799                 pkg->difference2 = 0;
1800                 pkg->dx = 0;
1801                 pkg->dy = 0;
1802                 pkg->valid = 1;
1803         }
1804 }
1805
1806 LoadClient* MotionScan::new_client()
1807 {
1808         return new MotionScanUnit(this, plugin);
1809 }
1810
1811 LoadPackage* MotionScan::new_package()
1812 {
1813         return new MotionScanPackage;
1814 }
1815
1816
1817 void MotionScan::scan_frame(VFrame *previous_frame,
1818         VFrame *current_frame,
1819         int point)
1820 {
1821         this->previous_frame = previous_frame;
1822         this->current_frame = current_frame;
1823         this->point = point;
1824         subpixel = 0;
1825
1826         cache.remove_all_objects();
1827
1828
1829 // Single macroblock
1830         int w = current_frame->get_w();
1831         int h = current_frame->get_h();
1832
1833 // Initial search parameters
1834         int scan_w = w * plugin->config.global_range_w[point] / 100;
1835         int scan_h = h * plugin->config.global_range_h[point] / 100;
1836         int block_w = w * plugin->config.global_block_w[point] / 100;
1837         int block_h = h * plugin->config.global_block_h[point] / 100;
1838
1839 // Location of block in previous frame
1840         block_x1 = (int)(w * plugin->config.block_x[point] / 100 - block_w / 2);
1841         block_y1 = (int)(h * plugin->config.block_y[point] / 100 - block_h / 2);
1842         block_x2 = (int)(w * plugin->config.block_x[point] / 100 + block_w / 2);
1843         block_y2 = (int)(h * plugin->config.block_y[point] / 100 + block_h / 2);
1844
1845 // Offset to location of previous block.  This offset needn't be very accurate
1846 // since it's the offset of the previous image and current image we want.
1847         if(plugin->config.tracking_object == MotionScan::TRACK_PREVIOUS)
1848         {
1849                 block_x1 += plugin->total_dx[point] / OVERSAMPLE;
1850                 block_y1 += plugin->total_dy[point] / OVERSAMPLE;
1851                 block_x2 += plugin->total_dx[point] / OVERSAMPLE;
1852                 block_y2 += plugin->total_dy[point] / OVERSAMPLE;
1853         }
1854
1855         skip = 0;
1856
1857         switch(plugin->config.calculation)
1858         {
1859 // Don't calculate
1860                 case MotionScan::NO_CALCULATE:
1861                         dx_result = 0;
1862                         dy_result = 0;
1863                         skip = 1;
1864                         break;
1865
1866                 case MotionScan::LOAD:
1867                 {
1868 printf("MotionScan::scan_frame %d\n", __LINE__);
1869 // Load result from disk
1870                         char string[BCTEXTLEN];
1871                         sprintf(string, "%s%06d", 
1872                                 MOTION_FILE, 
1873                                 plugin->get_source_position());
1874                         FILE *input;
1875                         input = fopen(string, "r");
1876                         if(input)
1877                         {
1878                                 for(int i = 0; i <= point; i++)
1879                                 {
1880                                         fscanf(input, 
1881                                                 "%d %d", 
1882                                                 &dx_result,
1883                                                 &dy_result);
1884                                 }
1885                                 fclose(input);
1886                                 skip = 1;
1887                         }
1888                         break;
1889                 }
1890
1891 // Scan from scratch
1892                 default:
1893                         skip = 0;
1894                         break;
1895         }
1896
1897 // Perform scan
1898         if(!skip)
1899         {
1900 printf("MotionScan::scan_frame %d\n", __LINE__);
1901 // Calculate center of search area in current frame
1902                 int origin_offset_x = plugin->config.global_origin_x[point] * w / 100;
1903                 int origin_offset_y = plugin->config.global_origin_y[point] * h / 100;
1904                 int x_result = block_x1 + origin_offset_x;
1905                 int y_result = block_y1 + origin_offset_y;
1906
1907 // printf("MotionScan::scan_frame 1 %d %d %d %d %d %d %d %d\n",
1908 // block_x1 + block_w / 2,
1909 // block_y1 + block_h / 2,
1910 // block_w,
1911 // block_h,
1912 // block_x1,
1913 // block_y1,
1914 // block_x2,
1915 // block_y2);
1916
1917                 while(1)
1918                 {
1919                         scan_x1 = x_result - scan_w / 2;
1920                         scan_y1 = y_result - scan_h / 2;
1921                         scan_x2 = x_result + scan_w / 2;
1922                         scan_y2 = y_result + scan_h / 2;
1923
1924
1925
1926 // Zero out requested values
1927                         if(plugin->config.horizontal_only)
1928                         {
1929                                 scan_y1 = block_y1;
1930                                 scan_y2 = block_y1 + 1;
1931                         }
1932                         if(plugin->config.vertical_only)
1933                         {
1934                                 scan_x1 = block_x1;
1935                                 scan_x2 = block_x1 + 1;
1936                         }
1937
1938 // printf("MotionScan::scan_frame 1 %d %d %d %d %d %d %d %d\n",
1939 // block_x1,
1940 // block_y1,
1941 // block_x2,
1942 // block_y2,
1943 // scan_x1,
1944 // scan_y1,
1945 // scan_x2,
1946 // scan_y2);
1947 // Clamp the block coords before the scan so we get useful scan coords.
1948                         MotionScan::clamp_scan(w, 
1949                                 h, 
1950                                 &block_x1,
1951                                 &block_y1,
1952                                 &block_x2,
1953                                 &block_y2,
1954                                 &scan_x1,
1955                                 &scan_y1,
1956                                 &scan_x2,
1957                                 &scan_y2,
1958                                 0);
1959 // 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", 
1960 // block_x1,
1961 // block_y1,
1962 // block_x2,
1963 // block_y2,
1964 // scan_x1, 
1965 // scan_y1, 
1966 // scan_x2, 
1967 // scan_y2, 
1968 // x_result, 
1969 // y_result);
1970
1971
1972 // Give up if invalid coords.
1973                         if(scan_y2 <= scan_y1 ||
1974                                 scan_x2 <= scan_x1 ||
1975                                 block_x2 <= block_x1 ||
1976                                 block_y2 <= block_y1)
1977                                 break;
1978
1979
1980 // For subpixel, the top row and left column are skipped
1981                         if(subpixel)
1982                         {
1983
1984                                 if(plugin->config.horizontal_only ||
1985                                         plugin->config.vertical_only)
1986                                 {
1987                                         total_pixels = 4 * OVERSAMPLE * OVERSAMPLE - 4 * OVERSAMPLE;
1988                                 }
1989                                 else
1990                                 {
1991                                         total_pixels = 4 * OVERSAMPLE;
1992                                 }
1993
1994                                 total_steps = total_pixels;
1995
1996                                 set_package_count(total_steps);
1997                                 process_packages();
1998
1999 // Get least difference
2000                                 int64_t min_difference = -1;
2001                                 for(int i = 0; i < get_total_packages(); i++)
2002                                 {
2003                                         MotionScanPackage *pkg = (MotionScanPackage*)get_package(i);
2004                                         if(pkg->difference1 < min_difference || min_difference == -1)
2005                                         {
2006                                                 min_difference = pkg->difference1;
2007
2008                                                 if(plugin->config.vertical_only)
2009                                                         x_result = scan_x1 * OVERSAMPLE;
2010                                                 else
2011                                                         x_result = scan_x1 * OVERSAMPLE + 
2012                                                                 (pkg->pixel % (OVERSAMPLE * 2 - 1)) + 1;
2013                                                 
2014                                                 if(plugin->config.horizontal_only)
2015                                                         y_result = scan_y1 * OVERSAMPLE;
2016                                                 else
2017                                                         y_result = scan_y1 * OVERSAMPLE + 
2018                                                                 (pkg->pixel / (OVERSAMPLE * 2 - 1)) + 1;
2019
2020
2021 // Fill in results
2022                                                 dx_result = block_x1 * OVERSAMPLE - x_result;
2023                                                 dy_result = block_y1 * OVERSAMPLE - y_result;
2024                                         }
2025
2026                                         if(pkg->difference2 < min_difference)
2027                                         {
2028                                                 min_difference = pkg->difference2;
2029
2030                                                 if(plugin->config.vertical_only)
2031                                                         x_result = scan_x1 * OVERSAMPLE;
2032                                                 else
2033                                                         x_result = scan_x2 * OVERSAMPLE -
2034                                                                 ((pkg->pixel % (OVERSAMPLE * 2 - 1)) + 1);
2035
2036                                                 if(plugin->config.horizontal_only)
2037                                                         y_result = scan_y1 * OVERSAMPLE;
2038                                                 else
2039                                                         y_result = scan_y2 * OVERSAMPLE -
2040                                                                 ((pkg->pixel / (OVERSAMPLE * 2 - 1)) + 1);
2041
2042                                                 dx_result = block_x1 * OVERSAMPLE - x_result;
2043                                                 dy_result = block_y1 * OVERSAMPLE - y_result;
2044                                         }
2045                                 }
2046
2047
2048 //printf("MotionScan::scan_frame 1 %d %d %d %d\n", block_x1, block_y1, x_result, y_result);
2049                                 break;
2050                         }
2051                         else
2052                         {
2053
2054                                 total_pixels = (scan_x2 - scan_x1) * (scan_y2 - scan_y1);
2055                                 total_steps = MIN(plugin->config.global_positions, total_pixels);
2056
2057                                 set_package_count(total_steps);
2058                                 process_packages();
2059
2060 // Get least difference
2061                                 int64_t min_difference = -1;
2062                                 for(int i = 0; i < get_total_packages(); i++)
2063                                 {
2064                                         MotionScanPackage *pkg = (MotionScanPackage*)get_package(i);
2065                                         if(pkg->difference1 < min_difference || min_difference == -1)
2066                                         {
2067                                                 min_difference = pkg->difference1;
2068                                                 x_result = scan_x1 + (pkg->pixel % (scan_x2 - scan_x1));
2069                                                 y_result = scan_y1 + (pkg->pixel / (scan_x2 - scan_x1));
2070                                                 x_result *= OVERSAMPLE;
2071                                                 y_result *= OVERSAMPLE;
2072                                         }
2073                                 }
2074
2075
2076
2077 // printf("MotionScan::scan_frame 10 total_steps=%d total_pixels=%d subpixel=%d\n",
2078 // total_steps, 
2079 // total_pixels,
2080 // subpixel);
2081 // 
2082 // printf("     scan w=%d h=%d scan x1=%d y1=%d x2=%d y2=%d\n",
2083 // scan_w,
2084 // scan_h, 
2085 // scan_x1,
2086 // scan_y1,
2087 // scan_x2,
2088 // scan_y2);
2089 // 
2090 // printf("MotionScan::scan_frame 2 block x1=%d y1=%d x2=%d y2=%d result x=%.2f y=%.2f\n", 
2091 // block_x1, 
2092 // block_y1, 
2093 // block_x2,
2094 // block_y2,
2095 // (float)x_result / 4, 
2096 // (float)y_result / 4);
2097
2098
2099 // If a new search is required, rescale results back to pixels.
2100                                 if(total_steps >= total_pixels)
2101                                 {
2102 // Single pixel accuracy reached.  Now do exhaustive subpixel search.
2103                                         if(plugin->config.action == MotionScan::STABILIZE ||
2104                                                 plugin->config.action == MotionScan::TRACK ||
2105                                                 plugin->config.action == MotionScan::NOTHING)
2106                                         {
2107                                                 x_result /= OVERSAMPLE;
2108                                                 y_result /= OVERSAMPLE;
2109                                                 scan_w = 2;
2110                                                 scan_h = 2;
2111                                                 subpixel = 1;
2112                                         }
2113                                         else
2114                                         {
2115 // Fill in results and quit
2116                                                 dx_result = block_x1 * OVERSAMPLE - x_result;
2117                                                 dy_result = block_y1 * OVERSAMPLE - y_result;
2118                                                 break;
2119                                         }
2120                                 }
2121                                 else
2122 // Reduce scan area and try again
2123                                 {
2124                                         scan_w = (scan_x2 - scan_x1) / 2;
2125                                         scan_h = (scan_y2 - scan_y1) / 2;
2126                                         x_result /= OVERSAMPLE;
2127                                         y_result /= OVERSAMPLE;
2128                                 }
2129                         }
2130                 }
2131
2132                 dx_result *= -1;
2133                 dy_result *= -1;
2134         }
2135
2136
2137
2138
2139
2140
2141 // Write results
2142         if(plugin->config.calculation == MotionScan::SAVE)
2143         {
2144                 char string[BCTEXTLEN];
2145                 sprintf(string, 
2146                         "%s%06d", 
2147                         MOTION_FILE, 
2148                         plugin->get_source_position());
2149                 FILE *output;
2150                 if(point == 0)
2151                         output = fopen(string, "w");
2152                 else
2153                         output = fopen(string, "a");
2154                 if(output)
2155                 {
2156                         fprintf(output, 
2157                                 "%d %d\n",
2158                                 dx_result,
2159                                 dy_result);
2160                         fclose(output);
2161                 }
2162                 else
2163                 {
2164                         perror("MotionScan::scan_frame SAVE 1");
2165                 }
2166         }
2167
2168 #ifdef DEBUG
2169 printf("MotionScan::scan_frame 10 point=%d dx=%.2f dy=%.2f\n", 
2170 point,
2171 (float)this->dx_result / OVERSAMPLE,
2172 (float)this->dy_result / OVERSAMPLE);
2173 #endif
2174 }
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192 int64_t MotionScan::get_cache(int x, int y)
2193 {
2194         int64_t result = -1;
2195         cache_lock->lock("MotionScan::get_cache");
2196         for(int i = 0; i < cache.total; i++)
2197         {
2198                 MotionScanCache *ptr = cache.values[i];
2199                 if(ptr->x == x && ptr->y == y)
2200                 {
2201                         result = ptr->difference;
2202                         break;
2203                 }
2204         }
2205         cache_lock->unlock();
2206         return result;
2207 }
2208
2209 void MotionScan::put_cache(int x, int y, int64_t difference)
2210 {
2211         MotionScanCache *ptr = new MotionScanCache(x, y, difference);
2212         cache_lock->lock("MotionScan::put_cache");
2213         cache.append(ptr);
2214         cache_lock->unlock();
2215 }
2216
2217
2218
2219
2220
2221 MotionScanCache::MotionScanCache(int x, int y, int64_t difference)
2222 {
2223         this->x = x;
2224         this->y = y;
2225         this->difference = difference;
2226 }
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237 #endif
2238
2239
2240