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