1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2011 Blender Foundation.
17  * All rights reserved.
18  */
19 
20 /** \file
21  * \ingroup bke
22  */
23 
24 #include "atomic_ops.h"
25 #include <stdlib.h>
26 
27 #include "MEM_guardedalloc.h"
28 
29 #include "DNA_movieclip_types.h"
30 #include "DNA_object_types.h" /* SELECT */
31 
32 #include "BLI_listbase.h"
33 #include "BLI_math.h"
34 #include "BLI_task.h"
35 #include "BLI_threads.h"
36 #include "BLI_utildefines.h"
37 
38 #include "BKE_movieclip.h"
39 #include "BKE_tracking.h"
40 
41 #include "libmv-capi.h"
42 #include "tracking_private.h"
43 
44 typedef struct AutoTrackOptions {
45   int clip_index;            /** Index of the clip this track belongs to. */
46   int track_index;           /* Index of the track in AutoTrack tracks structure. */
47   MovieTrackingTrack *track; /* Pointer to an original track/ */
48   libmv_TrackRegionOptions track_region_options; /* Options for the region tracker. */
49   bool use_keyframe_match;                       /* Keyframe pattern matching. */
50 
51   /* TODO(sergey): A bit awkward to keep it in here, only used to
52    * place a disabled marker once the tracking fails,
53    * Either find a clearer way to do it or call it track context
54    * or state, not options.
55    */
56   bool is_failed;
57   int failed_frame;
58 } AutoTrackOptions;
59 
60 typedef struct AutoTrackContext {
61   MovieClip *clips[MAX_ACCESSOR_CLIP];
62   int num_clips;
63 
64   MovieClipUser user;
65   int frame_width, frame_height;
66 
67   struct libmv_AutoTrack *autotrack;
68   TrackingImageAccessor *image_accessor;
69 
70   int num_tracks;            /* Number of tracks being tracked. */
71   AutoTrackOptions *options; /* Per-tracking track options. */
72 
73   /* Array of all tracks, indexed by track_index. */
74   MovieTrackingTrack **tracks;
75 
76   bool backwards;
77   bool sequence;
78   int first_frame;
79   int sync_frame;
80   bool first_sync;
81   SpinLock spin_lock;
82 
83   bool step_ok;
84 } AutoTrackContext;
85 
normalized_to_libmv_frame(const float normalized[2],const int frame_dimensions[2],float result[2])86 static void normalized_to_libmv_frame(const float normalized[2],
87                                       const int frame_dimensions[2],
88                                       float result[2])
89 {
90   result[0] = normalized[0] * frame_dimensions[0] - 0.5f;
91   result[1] = normalized[1] * frame_dimensions[1] - 0.5f;
92 }
93 
normalized_relative_to_libmv_frame(const float normalized[2],const float origin[2],const int frame_dimensions[2],float result[2])94 static void normalized_relative_to_libmv_frame(const float normalized[2],
95                                                const float origin[2],
96                                                const int frame_dimensions[2],
97                                                float result[2])
98 {
99   result[0] = (normalized[0] + origin[0]) * frame_dimensions[0] - 0.5f;
100   result[1] = (normalized[1] + origin[1]) * frame_dimensions[1] - 0.5f;
101 }
102 
libmv_frame_to_normalized(const float frame_coord[2],const int frame_dimensions[2],float result[2])103 static void libmv_frame_to_normalized(const float frame_coord[2],
104                                       const int frame_dimensions[2],
105                                       float result[2])
106 {
107   result[0] = (frame_coord[0] + 0.5f) / frame_dimensions[0];
108   result[1] = (frame_coord[1] + 0.5f) / frame_dimensions[1];
109 }
110 
libmv_frame_to_normalized_relative(const float frame_coord[2],const float origin[2],const int frame_dimensions[2],float result[2])111 static void libmv_frame_to_normalized_relative(const float frame_coord[2],
112                                                const float origin[2],
113                                                const int frame_dimensions[2],
114                                                float result[2])
115 {
116   result[0] = (frame_coord[0] - origin[0]) / frame_dimensions[0];
117   result[1] = (frame_coord[1] - origin[1]) / frame_dimensions[1];
118 }
119 
dna_marker_to_libmv_marker(MovieTrackingTrack * track,MovieTrackingMarker * marker,int clip,int track_index,int frame_width,int frame_height,bool backwards,libmv_Marker * libmv_marker)120 static void dna_marker_to_libmv_marker(/*const*/ MovieTrackingTrack *track,
121                                        /*const*/ MovieTrackingMarker *marker,
122                                        int clip,
123                                        int track_index,
124                                        int frame_width,
125                                        int frame_height,
126                                        bool backwards,
127                                        libmv_Marker *libmv_marker)
128 {
129   const int frame_dimensions[2] = {frame_width, frame_height};
130   libmv_marker->clip = clip;
131   libmv_marker->frame = marker->framenr;
132   libmv_marker->track = track_index;
133 
134   normalized_to_libmv_frame(marker->pos, frame_dimensions, libmv_marker->center);
135   for (int i = 0; i < 4; i++) {
136     normalized_relative_to_libmv_frame(
137         marker->pattern_corners[i], marker->pos, frame_dimensions, libmv_marker->patch[i]);
138   }
139 
140   normalized_relative_to_libmv_frame(
141       marker->search_min, marker->pos, frame_dimensions, libmv_marker->search_region_min);
142 
143   normalized_relative_to_libmv_frame(
144       marker->search_max, marker->pos, frame_dimensions, libmv_marker->search_region_max);
145 
146   /* TODO(sergey): All the markers does have 1.0 weight. */
147   libmv_marker->weight = 1.0f;
148 
149   if (marker->flag & MARKER_TRACKED) {
150     libmv_marker->source = LIBMV_MARKER_SOURCE_TRACKED;
151   }
152   else {
153     libmv_marker->source = LIBMV_MARKER_SOURCE_MANUAL;
154   }
155   libmv_marker->status = LIBMV_MARKER_STATUS_UNKNOWN;
156   libmv_marker->model_type = LIBMV_MARKER_MODEL_TYPE_POINT;
157   libmv_marker->model_id = 0;
158 
159   /* TODO(sergey): We currently don't support reference marker from
160    * different clip.
161    */
162   libmv_marker->reference_clip = clip;
163 
164   if (track->pattern_match == TRACK_MATCH_KEYFRAME) {
165     MovieTrackingMarker *keyframe_marker = tracking_get_keyframed_marker(
166         track, marker->framenr, backwards);
167     libmv_marker->reference_frame = keyframe_marker->framenr;
168   }
169   else {
170     libmv_marker->reference_frame = backwards ? marker->framenr - 1 : marker->framenr;
171   }
172 
173   libmv_marker->disabled_channels =
174       ((track->flag & TRACK_DISABLE_RED) ? LIBMV_MARKER_CHANNEL_R : 0) |
175       ((track->flag & TRACK_DISABLE_GREEN) ? LIBMV_MARKER_CHANNEL_G : 0) |
176       ((track->flag & TRACK_DISABLE_BLUE) ? LIBMV_MARKER_CHANNEL_B : 0);
177 }
178 
libmv_marker_to_dna_marker(libmv_Marker * libmv_marker,int frame_width,int frame_height,MovieTrackingMarker * marker)179 static void libmv_marker_to_dna_marker(libmv_Marker *libmv_marker,
180                                        int frame_width,
181                                        int frame_height,
182                                        MovieTrackingMarker *marker)
183 {
184   const int frame_dimensions[2] = {frame_width, frame_height};
185   marker->framenr = libmv_marker->frame;
186 
187   libmv_frame_to_normalized(libmv_marker->center, frame_dimensions, marker->pos);
188   for (int i = 0; i < 4; i++) {
189     libmv_frame_to_normalized_relative(libmv_marker->patch[i],
190                                        libmv_marker->center,
191                                        frame_dimensions,
192                                        marker->pattern_corners[i]);
193   }
194 
195   libmv_frame_to_normalized_relative(
196       libmv_marker->search_region_min, libmv_marker->center, frame_dimensions, marker->search_min);
197 
198   libmv_frame_to_normalized_relative(
199       libmv_marker->search_region_max, libmv_marker->center, frame_dimensions, marker->search_max);
200 
201   marker->flag = 0;
202   if (libmv_marker->source == LIBMV_MARKER_SOURCE_TRACKED) {
203     marker->flag |= MARKER_TRACKED;
204   }
205   else {
206     marker->flag &= ~MARKER_TRACKED;
207   }
208 }
209 
check_track_trackable(const MovieClip * clip,MovieTrackingTrack * track,const MovieClipUser * user)210 static bool check_track_trackable(const MovieClip *clip,
211                                   MovieTrackingTrack *track,
212                                   const MovieClipUser *user)
213 {
214   if (TRACK_SELECTED(track) && (track->flag & (TRACK_LOCKED | TRACK_HIDDEN)) == 0) {
215     int frame = BKE_movieclip_remap_scene_to_clip_frame(clip, user->framenr);
216     const MovieTrackingMarker *marker = BKE_tracking_marker_get(track, frame);
217     return (marker->flag & MARKER_DISABLED) == 0;
218   }
219   return false;
220 }
221 
222 /* Returns false if marker crossed margin area from frame bounds. */
tracking_check_marker_margin(libmv_Marker * libmv_marker,int margin,int frame_width,int frame_height)223 static bool tracking_check_marker_margin(libmv_Marker *libmv_marker,
224                                          int margin,
225                                          int frame_width,
226                                          int frame_height)
227 {
228   float patch_min[2], patch_max[2];
229   float margin_left, margin_top, margin_right, margin_bottom;
230 
231   INIT_MINMAX2(patch_min, patch_max);
232   minmax_v2v2_v2(patch_min, patch_max, libmv_marker->patch[0]);
233   minmax_v2v2_v2(patch_min, patch_max, libmv_marker->patch[1]);
234   minmax_v2v2_v2(patch_min, patch_max, libmv_marker->patch[2]);
235   minmax_v2v2_v2(patch_min, patch_max, libmv_marker->patch[3]);
236 
237   margin_left = max_ff(libmv_marker->center[0] - patch_min[0], margin);
238   margin_top = max_ff(patch_max[1] - libmv_marker->center[1], margin);
239   margin_right = max_ff(patch_max[0] - libmv_marker->center[0], margin);
240   margin_bottom = max_ff(libmv_marker->center[1] - patch_min[1], margin);
241 
242   if (libmv_marker->center[0] < margin_left ||
243       libmv_marker->center[0] > frame_width - margin_right ||
244       libmv_marker->center[1] < margin_bottom ||
245       libmv_marker->center[1] > frame_height - margin_top) {
246     return false;
247   }
248 
249   return true;
250 }
251 
252 /* Provide Libmv side of auto track all information about given tracks. */
fill_autotrack_tracks(const int frame_width,const int frame_height,const ListBase * tracksbase,const bool backwards,struct libmv_AutoTrack * autotrack)253 static void fill_autotrack_tracks(const int frame_width,
254                                   const int frame_height,
255                                   const ListBase *tracksbase,
256                                   const bool backwards,
257                                   struct libmv_AutoTrack *autotrack)
258 {
259   /* Count number of markers to be put to a context. */
260   size_t num_trackable_markers = 0;
261   LISTBASE_FOREACH (MovieTrackingTrack *, track, tracksbase) {
262     for (int i = 0; i < track->markersnr; i++) {
263       const MovieTrackingMarker *marker = track->markers + i;
264       if ((marker->flag & MARKER_DISABLED) == 0) {
265         num_trackable_markers++;
266       }
267     }
268   }
269   /* Early output if we don't have any markers. */
270   if (num_trackable_markers == 0) {
271     return;
272   }
273   /* Allocate memory for all the markers. */
274   libmv_Marker *libmv_markers = MEM_mallocN(sizeof(libmv_Marker) * num_trackable_markers,
275                                             "libmv markers array");
276   /* Fill in markers array. */
277   int track_index = 0, num_filled_libmv_markers = 0;
278   LISTBASE_FOREACH (MovieTrackingTrack *, track, tracksbase) {
279     for (int i = 0; i < track->markersnr; i++) {
280       MovieTrackingMarker *marker = track->markers + i;
281       if ((marker->flag & MARKER_DISABLED) != 0) {
282         continue;
283       }
284       dna_marker_to_libmv_marker(track,
285                                  marker,
286                                  0,
287                                  track_index,
288                                  frame_width,
289                                  frame_height,
290                                  backwards,
291                                  &libmv_markers[num_filled_libmv_markers++]);
292     }
293     /* Put all markers to autotrack at once. */
294     track_index++;
295   }
296   /* Add all markers to autotrack. */
297   libmv_autoTrackSetMarkers(autotrack, libmv_markers, num_trackable_markers);
298   /* Free temporary memory. */
299   MEM_freeN(libmv_markers);
300 }
301 
create_per_track_tracking_options(const MovieClip * clip,const MovieClipUser * user,const ListBase * tracksbase,AutoTrackContext * context)302 static void create_per_track_tracking_options(const MovieClip *clip,
303                                               const MovieClipUser *user,
304                                               const ListBase *tracksbase,
305                                               AutoTrackContext *context)
306 {
307   /* Count number of trackable tracks. */
308   LISTBASE_FOREACH (MovieTrackingTrack *, track, tracksbase) {
309     if (check_track_trackable(clip, track, user)) {
310       context->num_tracks++;
311     }
312   }
313   /* Allocate required memory. */
314   context->options = MEM_callocN(sizeof(AutoTrackOptions) * context->num_tracks,
315                                  "auto track options");
316   /* Fill in all the settings. */
317   int i = 0, track_index = 0;
318   LISTBASE_FOREACH (MovieTrackingTrack *, track, tracksbase) {
319     if (!check_track_trackable(clip, track, user)) {
320       track_index++;
321       continue;
322     }
323     AutoTrackOptions *options = &context->options[i++];
324     /* TODO(sergey): Single clip only for now. */
325     options->clip_index = 0;
326     options->track_index = track_index;
327     options->track = track;
328     tracking_configure_tracker(track, NULL, &options->track_region_options);
329     options->use_keyframe_match = track->pattern_match == TRACK_MATCH_KEYFRAME;
330     context->tracks[track_index] = track;
331     track_index++;
332   }
333 }
334 
BKE_autotrack_context_new(MovieClip * clip,MovieClipUser * user,const bool backwards,const bool sequence)335 AutoTrackContext *BKE_autotrack_context_new(MovieClip *clip,
336                                             MovieClipUser *user,
337                                             const bool backwards,
338                                             const bool sequence)
339 {
340   AutoTrackContext *context = MEM_callocN(sizeof(AutoTrackContext), "autotrack context");
341   MovieTracking *tracking = &clip->tracking;
342   ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
343   int frame_width, frame_height;
344   /* get size of frame to convert normalized coordinates to a picture ones. */
345   BKE_movieclip_get_size(clip, user, &frame_width, &frame_height);
346   /* TODO(sergey): Currently using only a single clip. */
347   context->clips[0] = clip;
348   context->num_clips = 1;
349   context->user = *user;
350   context->user.render_size = MCLIP_PROXY_RENDER_SIZE_FULL;
351   context->user.render_flag = 0;
352   context->frame_width = frame_width;
353   context->frame_height = frame_height;
354   context->backwards = backwards;
355   context->sequence = sequence;
356   context->first_frame = user->framenr;
357   context->sync_frame = user->framenr;
358   context->first_sync = true;
359   BLI_spin_init(&context->spin_lock);
360   const int num_total_tracks = BLI_listbase_count(tracksbase);
361   context->tracks = MEM_callocN(sizeof(MovieTrackingTrack *) * num_total_tracks,
362                                 "auto track pointers");
363   /* Initialize image accessor. */
364   context->image_accessor = tracking_image_accessor_new(
365       context->clips, 1, context->tracks, num_total_tracks, user->framenr);
366   /* Initialize auto track context and provide all information about currently
367    * tracked markers.
368    */
369   context->autotrack = libmv_autoTrackNew(context->image_accessor->libmv_accessor);
370   fill_autotrack_tracks(frame_width, frame_height, tracksbase, backwards, context->autotrack);
371   /* Create per-track tracking options. */
372   create_per_track_tracking_options(clip, user, tracksbase, context);
373   return context;
374 }
375 
autotrack_context_step_cb(void * __restrict userdata,const int track,const TaskParallelTLS * __restrict UNUSED (tls))376 static void autotrack_context_step_cb(void *__restrict userdata,
377                                       const int track,
378                                       const TaskParallelTLS *__restrict UNUSED(tls))
379 {
380   AutoTrackContext *context = userdata;
381   const int frame_delta = context->backwards ? -1 : 1;
382 
383   AutoTrackOptions *options = &context->options[track];
384   if (options->is_failed) {
385     return;
386   }
387   libmv_Marker libmv_current_marker, libmv_reference_marker, libmv_tracked_marker;
388   libmv_TrackRegionResult libmv_result;
389   const int frame = BKE_movieclip_remap_scene_to_clip_frame(context->clips[options->clip_index],
390                                                             context->user.framenr);
391   BLI_spin_lock(&context->spin_lock);
392   const bool has_marker = libmv_autoTrackGetMarker(
393       context->autotrack, options->clip_index, frame, options->track_index, &libmv_current_marker);
394   BLI_spin_unlock(&context->spin_lock);
395   /* Check whether we've got marker to sync with. */
396   if (!has_marker) {
397     return;
398   }
399   /* Check whether marker is going outside of allowed frame margin. */
400   if (!tracking_check_marker_margin(&libmv_current_marker,
401                                     options->track->margin,
402                                     context->frame_width,
403                                     context->frame_height)) {
404     return;
405   }
406   libmv_tracked_marker = libmv_current_marker;
407   libmv_tracked_marker.frame = frame + frame_delta;
408   /* Update reference frame. */
409   if (options->use_keyframe_match) {
410     libmv_tracked_marker.reference_frame = libmv_current_marker.reference_frame;
411     libmv_autoTrackGetMarker(context->autotrack,
412                              options->clip_index,
413                              libmv_tracked_marker.reference_frame,
414                              options->track_index,
415                              &libmv_reference_marker);
416   }
417   else {
418     libmv_tracked_marker.reference_frame = frame;
419     libmv_reference_marker = libmv_current_marker;
420   }
421   /* Perform actual tracking. */
422   if (libmv_autoTrackMarker(context->autotrack,
423                             &options->track_region_options,
424                             &libmv_tracked_marker,
425                             &libmv_result)) {
426     BLI_spin_lock(&context->spin_lock);
427     libmv_autoTrackAddMarker(context->autotrack, &libmv_tracked_marker);
428     BLI_spin_unlock(&context->spin_lock);
429   }
430   else {
431     options->is_failed = true;
432     options->failed_frame = frame + frame_delta;
433   }
434 
435   /* Note: Atomic is probably not actually needed here, I doubt we could get
436    *       any other result than a true bool anyway.
437    *       But for sake of consistency, and since it costs nothing...
438    */
439   atomic_fetch_and_or_uint8((uint8_t *)&context->step_ok, true);
440 }
441 
BKE_autotrack_context_step(AutoTrackContext * context)442 bool BKE_autotrack_context_step(AutoTrackContext *context)
443 {
444   const int frame_delta = context->backwards ? -1 : 1;
445   context->step_ok = false;
446 
447   TaskParallelSettings settings;
448   BLI_parallel_range_settings_defaults(&settings);
449   settings.use_threading = (context->num_tracks > 1);
450   BLI_task_parallel_range(0, context->num_tracks, context, autotrack_context_step_cb, &settings);
451 
452   /* Advance the frame. */
453   BLI_spin_lock(&context->spin_lock);
454   context->user.framenr += frame_delta;
455   BLI_spin_unlock(&context->spin_lock);
456   return context->step_ok;
457 }
458 
BKE_autotrack_context_sync(AutoTrackContext * context)459 void BKE_autotrack_context_sync(AutoTrackContext *context)
460 {
461   int newframe, frame_delta = context->backwards ? -1 : 1;
462 
463   BLI_spin_lock(&context->spin_lock);
464   newframe = context->user.framenr;
465   for (int frame = context->sync_frame;
466        frame != (context->backwards ? newframe - 1 : newframe + 1);
467        frame += frame_delta) {
468     MovieTrackingMarker marker;
469     libmv_Marker libmv_marker;
470     int clip = 0;
471     for (int track = 0; track < context->num_tracks; track++) {
472       AutoTrackOptions *options = &context->options[track];
473       int track_frame = BKE_movieclip_remap_scene_to_clip_frame(
474           context->clips[options->clip_index], frame);
475       if (options->is_failed) {
476         if (options->failed_frame == track_frame) {
477           MovieTrackingMarker *prev_marker = BKE_tracking_marker_get_exact(
478               options->track, context->backwards ? frame + 1 : frame - 1);
479           if (prev_marker) {
480             marker = *prev_marker;
481             marker.framenr = track_frame;
482             marker.flag |= MARKER_DISABLED;
483             BKE_tracking_marker_insert(options->track, &marker);
484             continue;
485           }
486         }
487         if ((context->backwards && options->failed_frame > track_frame) ||
488             (!context->backwards && options->failed_frame < track_frame)) {
489           continue;
490         }
491       }
492       if (libmv_autoTrackGetMarker(
493               context->autotrack, clip, track_frame, options->track_index, &libmv_marker)) {
494         libmv_marker_to_dna_marker(
495             &libmv_marker, context->frame_width, context->frame_height, &marker);
496         if (context->first_sync && frame == context->sync_frame) {
497           tracking_marker_insert_disabled(options->track, &marker, !context->backwards, false);
498         }
499         BKE_tracking_marker_insert(options->track, &marker);
500         tracking_marker_insert_disabled(options->track, &marker, context->backwards, false);
501       }
502     }
503   }
504   BLI_spin_unlock(&context->spin_lock);
505 
506   for (int clip = 0; clip < context->num_clips; clip++) {
507     MovieTracking *tracking = &context->clips[clip]->tracking;
508     BKE_tracking_dopesheet_tag_update(tracking);
509   }
510 
511   context->sync_frame = newframe;
512   context->first_sync = false;
513 }
514 
BKE_autotrack_context_sync_user(AutoTrackContext * context,MovieClipUser * user)515 void BKE_autotrack_context_sync_user(AutoTrackContext *context, MovieClipUser *user)
516 {
517   user->framenr = context->sync_frame;
518 }
519 
BKE_autotrack_context_finish(AutoTrackContext * context)520 void BKE_autotrack_context_finish(AutoTrackContext *context)
521 {
522   for (int clip_index = 0; clip_index < context->num_clips; clip_index++) {
523     MovieClip *clip = context->clips[clip_index];
524     ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking);
525 
526     LISTBASE_FOREACH (MovieTrackingPlaneTrack *, plane_track, plane_tracks_base) {
527       if ((plane_track->flag & PLANE_TRACK_AUTOKEY) == 0) {
528         for (int track = 0; track < context->num_tracks; track++) {
529           if (BKE_tracking_plane_track_has_point_track(plane_track,
530                                                        context->options[track].track)) {
531             BKE_tracking_track_plane_from_existing_motion(plane_track, context->first_frame);
532             break;
533           }
534         }
535       }
536     }
537   }
538 }
539 
BKE_autotrack_context_free(AutoTrackContext * context)540 void BKE_autotrack_context_free(AutoTrackContext *context)
541 {
542   libmv_autoTrackDestroy(context->autotrack);
543   tracking_image_accessor_destroy(context->image_accessor);
544   MEM_freeN(context->options);
545   MEM_freeN(context->tracks);
546   BLI_spin_end(&context->spin_lock);
547   MEM_freeN(context);
548 }
549