Cleanup: comments (long lines) in blenkernel
[blender.git] / source / blender / blenkernel / intern / tracking_auto.c
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 <stdlib.h>
25 #include "atomic_ops.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_utildefines.h"
33 #include "BLI_listbase.h"
34 #include "BLI_task.h"
35 #include "BLI_threads.h"
36 #include "BLI_math.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 belogs 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    * Wither find a more clear 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
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
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
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
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
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   int i;
131   libmv_marker->clip = clip;
132   libmv_marker->frame = marker->framenr;
133   libmv_marker->track = track_index;
134
135   normalized_to_libmv_frame(marker->pos, frame_dimensions, libmv_marker->center);
136   for (i = 0; i < 4; ++i) {
137     normalized_relative_to_libmv_frame(
138         marker->pattern_corners[i], marker->pos, frame_dimensions, libmv_marker->patch[i]);
139   }
140
141   normalized_relative_to_libmv_frame(
142       marker->search_min, marker->pos, frame_dimensions, libmv_marker->search_region_min);
143
144   normalized_relative_to_libmv_frame(
145       marker->search_max, marker->pos, frame_dimensions, libmv_marker->search_region_max);
146
147   /* TODO(sergey): All the markers does have 1.0 weight. */
148   libmv_marker->weight = 1.0f;
149
150   if (marker->flag & MARKER_TRACKED) {
151     libmv_marker->source = LIBMV_MARKER_SOURCE_TRACKED;
152   }
153   else {
154     libmv_marker->source = LIBMV_MARKER_SOURCE_MANUAL;
155   }
156   libmv_marker->status = LIBMV_MARKER_STATUS_UNKNOWN;
157   libmv_marker->model_type = LIBMV_MARKER_MODEL_TYPE_POINT;
158   libmv_marker->model_id = 0;
159
160   /* TODO(sergey): We currently don't support reference marker from
161    * different clip.
162    */
163   libmv_marker->reference_clip = clip;
164
165   if (track->pattern_match == TRACK_MATCH_KEYFRAME) {
166     MovieTrackingMarker *keyframe_marker = tracking_get_keyframed_marker(
167         track, marker->framenr, backwards);
168     libmv_marker->reference_frame = keyframe_marker->framenr;
169   }
170   else {
171     libmv_marker->reference_frame = backwards ? marker->framenr - 1 : marker->framenr;
172   }
173
174   libmv_marker->disabled_channels =
175       ((track->flag & TRACK_DISABLE_RED) ? LIBMV_MARKER_CHANNEL_R : 0) |
176       ((track->flag & TRACK_DISABLE_GREEN) ? LIBMV_MARKER_CHANNEL_G : 0) |
177       ((track->flag & TRACK_DISABLE_BLUE) ? LIBMV_MARKER_CHANNEL_B : 0);
178 }
179
180 static void libmv_marker_to_dna_marker(libmv_Marker *libmv_marker,
181                                        int frame_width,
182                                        int frame_height,
183                                        MovieTrackingMarker *marker)
184 {
185   const int frame_dimensions[2] = {frame_width, frame_height};
186   int i;
187   marker->framenr = libmv_marker->frame;
188
189   libmv_frame_to_normalized(libmv_marker->center, frame_dimensions, marker->pos);
190   for (i = 0; i < 4; ++i) {
191     libmv_frame_to_normalized_relative(libmv_marker->patch[i],
192                                        libmv_marker->center,
193                                        frame_dimensions,
194                                        marker->pattern_corners[i]);
195   }
196
197   libmv_frame_to_normalized_relative(
198       libmv_marker->search_region_min, libmv_marker->center, frame_dimensions, marker->search_min);
199
200   libmv_frame_to_normalized_relative(
201       libmv_marker->search_region_max, libmv_marker->center, frame_dimensions, marker->search_max);
202
203   marker->flag = 0;
204   if (libmv_marker->source == LIBMV_MARKER_SOURCE_TRACKED) {
205     marker->flag |= MARKER_TRACKED;
206   }
207   else {
208     marker->flag &= ~MARKER_TRACKED;
209   }
210 }
211
212 static bool check_track_trackable(const MovieClip *clip,
213                                   MovieTrackingTrack *track,
214                                   const MovieClipUser *user)
215 {
216   if (TRACK_SELECTED(track) && (track->flag & (TRACK_LOCKED | TRACK_HIDDEN)) == 0) {
217     int frame = BKE_movieclip_remap_scene_to_clip_frame(clip, user->framenr);
218     const MovieTrackingMarker *marker = BKE_tracking_marker_get(track, frame);
219     return (marker->flag & MARKER_DISABLED) == 0;
220   }
221   return false;
222 }
223
224 /* Returns false if marker crossed margin area from frame bounds. */
225 static bool tracking_check_marker_margin(libmv_Marker *libmv_marker,
226                                          int margin,
227                                          int frame_width,
228                                          int frame_height)
229 {
230   float patch_min[2], patch_max[2];
231   float margin_left, margin_top, margin_right, margin_bottom;
232
233   INIT_MINMAX2(patch_min, patch_max);
234   minmax_v2v2_v2(patch_min, patch_max, libmv_marker->patch[0]);
235   minmax_v2v2_v2(patch_min, patch_max, libmv_marker->patch[1]);
236   minmax_v2v2_v2(patch_min, patch_max, libmv_marker->patch[2]);
237   minmax_v2v2_v2(patch_min, patch_max, libmv_marker->patch[3]);
238
239   margin_left = max_ff(libmv_marker->center[0] - patch_min[0], margin);
240   margin_top = max_ff(patch_max[1] - libmv_marker->center[1], margin);
241   margin_right = max_ff(patch_max[0] - libmv_marker->center[0], margin);
242   margin_bottom = max_ff(libmv_marker->center[1] - patch_min[1], margin);
243
244   if (libmv_marker->center[0] < margin_left ||
245       libmv_marker->center[0] > frame_width - margin_right ||
246       libmv_marker->center[1] < margin_bottom ||
247       libmv_marker->center[1] > frame_height - margin_top) {
248     return false;
249   }
250
251   return true;
252 }
253
254 /* Provide Libmv side of auto track all information about given tracks. */
255 static void fill_autotrack_tracks(const int frame_width,
256                                   const int frame_height,
257                                   const ListBase *tracksbase,
258                                   const bool backwards,
259                                   struct libmv_AutoTrack *autotrack)
260 {
261   /* Count number of markers to be put to a context. */
262   size_t num_trackable_markers = 0;
263   for (MovieTrackingTrack *track = tracksbase->first; track != NULL; track = track->next) {
264     for (int i = 0; i < track->markersnr; ++i) {
265       const MovieTrackingMarker *marker = track->markers + i;
266       if ((marker->flag & MARKER_DISABLED) == 0) {
267         num_trackable_markers++;
268       }
269     }
270   }
271   /* Early output if we don't have any markers. */
272   if (num_trackable_markers == 0) {
273     return;
274   }
275   /* Allocate memory for all the markers. */
276   libmv_Marker *libmv_markers = MEM_mallocN(sizeof(libmv_Marker) * num_trackable_markers,
277                                             "libmv markers array");
278   /* Fill in markers array. */
279   int track_index = 0, num_filled_libmv_markers = 0;
280   for (MovieTrackingTrack *track = tracksbase->first; track != NULL; track = track->next) {
281     for (int i = 0; i < track->markersnr; ++i) {
282       MovieTrackingMarker *marker = track->markers + i;
283       if ((marker->flag & MARKER_DISABLED) != 0) {
284         continue;
285       }
286       dna_marker_to_libmv_marker(track,
287                                  marker,
288                                  0,
289                                  track_index,
290                                  frame_width,
291                                  frame_height,
292                                  backwards,
293                                  &libmv_markers[num_filled_libmv_markers++]);
294     }
295     /* Put all markers to autotrack at once. */
296     track_index++;
297   }
298   /* Add all markers to autotrack. */
299   libmv_autoTrackSetMarkers(autotrack, libmv_markers, num_trackable_markers);
300   /* Free temporary memory. */
301   MEM_freeN(libmv_markers);
302 }
303
304 static void create_per_track_tracking_options(const MovieClip *clip,
305                                               const MovieClipUser *user,
306                                               const ListBase *tracksbase,
307                                               AutoTrackContext *context)
308 {
309   /* Count number of trackable tracks. */
310   for (MovieTrackingTrack *track = tracksbase->first; track != NULL; track = track->next) {
311     if (check_track_trackable(clip, track, user)) {
312       context->num_tracks++;
313     }
314   }
315   /* Allocate required memory. */
316   context->options = MEM_callocN(sizeof(AutoTrackOptions) * context->num_tracks,
317                                  "auto track options");
318   /* Fill in all the settings. */
319   int i = 0, track_index = 0;
320   for (MovieTrackingTrack *track = tracksbase->first; track != NULL; track = track->next) {
321     if (!check_track_trackable(clip, track, user)) {
322       ++track_index;
323       continue;
324     }
325     AutoTrackOptions *options = &context->options[i++];
326     /* TODO(sergey): Single clip only for now. */
327     options->clip_index = 0;
328     options->track_index = track_index;
329     options->track = track;
330     tracking_configure_tracker(track, NULL, &options->track_region_options);
331     options->use_keyframe_match = track->pattern_match == TRACK_MATCH_KEYFRAME;
332     context->tracks[track_index] = track;
333     ++track_index;
334   }
335 }
336
337 AutoTrackContext *BKE_autotrack_context_new(MovieClip *clip,
338                                             MovieClipUser *user,
339                                             const bool backwards,
340                                             const bool sequence)
341 {
342   AutoTrackContext *context = MEM_callocN(sizeof(AutoTrackContext), "autotrack context");
343   MovieTracking *tracking = &clip->tracking;
344   ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
345   int frame_width, frame_height;
346   /* get size of frame to convert normalized coordinates to a picture ones. */
347   BKE_movieclip_get_size(clip, user, &frame_width, &frame_height);
348   /* TODO(sergey): Currently using only a single clip. */
349   context->clips[0] = clip;
350   context->num_clips = 1;
351   context->user = *user;
352   context->user.render_size = MCLIP_PROXY_RENDER_SIZE_FULL;
353   context->user.render_flag = 0;
354   context->frame_width = frame_width;
355   context->frame_height = frame_height;
356   context->backwards = backwards;
357   context->sequence = sequence;
358   context->first_frame = user->framenr;
359   context->sync_frame = user->framenr;
360   context->first_sync = true;
361   BLI_spin_init(&context->spin_lock);
362   const int num_total_tracks = BLI_listbase_count(tracksbase);
363   context->tracks = MEM_callocN(sizeof(MovieTrackingTrack *) * num_total_tracks,
364                                 "auto track pointers");
365   /* Initialize image accessor. */
366   context->image_accessor = tracking_image_accessor_new(
367       context->clips, 1, context->tracks, num_total_tracks, user->framenr);
368   /* Initialize auto track context and provide all information about currently
369    * tracked markers.
370    */
371   context->autotrack = libmv_autoTrackNew(context->image_accessor->libmv_accessor);
372   fill_autotrack_tracks(frame_width, frame_height, tracksbase, backwards, context->autotrack);
373   /* Create per-track tracking options. */
374   create_per_track_tracking_options(clip, user, tracksbase, context);
375   return context;
376 }
377
378 static void autotrack_context_step_cb(void *__restrict userdata,
379                                       const int track,
380                                       const ParallelRangeTLS *__restrict UNUSED(tls))
381 {
382   AutoTrackContext *context = userdata;
383   const int frame_delta = context->backwards ? -1 : 1;
384
385   AutoTrackOptions *options = &context->options[track];
386   if (options->is_failed) {
387     return;
388   }
389   libmv_Marker libmv_current_marker, libmv_reference_marker, libmv_tracked_marker;
390   libmv_TrackRegionResult libmv_result;
391   const int frame = BKE_movieclip_remap_scene_to_clip_frame(context->clips[options->clip_index],
392                                                             context->user.framenr);
393   BLI_spin_lock(&context->spin_lock);
394   const bool has_marker = libmv_autoTrackGetMarker(
395       context->autotrack, options->clip_index, frame, options->track_index, &libmv_current_marker);
396   BLI_spin_unlock(&context->spin_lock);
397   /* Check whether we've got marker to sync with. */
398   if (!has_marker) {
399     return;
400   }
401   /* Check whether marker is going outside of allowed frame margin. */
402   if (!tracking_check_marker_margin(&libmv_current_marker,
403                                     options->track->margin,
404                                     context->frame_width,
405                                     context->frame_height)) {
406     return;
407   }
408   libmv_tracked_marker = libmv_current_marker;
409   libmv_tracked_marker.frame = frame + frame_delta;
410   /* Update reference frame. */
411   if (options->use_keyframe_match) {
412     libmv_tracked_marker.reference_frame = libmv_current_marker.reference_frame;
413     libmv_autoTrackGetMarker(context->autotrack,
414                              options->clip_index,
415                              libmv_tracked_marker.reference_frame,
416                              options->track_index,
417                              &libmv_reference_marker);
418   }
419   else {
420     libmv_tracked_marker.reference_frame = frame;
421     libmv_reference_marker = libmv_current_marker;
422   }
423   /* Perform actual tracking. */
424   if (libmv_autoTrackMarker(context->autotrack,
425                             &options->track_region_options,
426                             &libmv_tracked_marker,
427                             &libmv_result)) {
428     BLI_spin_lock(&context->spin_lock);
429     libmv_autoTrackAddMarker(context->autotrack, &libmv_tracked_marker);
430     BLI_spin_unlock(&context->spin_lock);
431   }
432   else {
433     options->is_failed = true;
434     options->failed_frame = frame + frame_delta;
435   }
436
437   /* Note: Atomic is probably not actually needed here, I doubt we could get
438    *       any other result than a true bool anyway.
439    *       But for sake of consistency, and since it costs nothing...
440    */
441   atomic_fetch_and_or_uint8((uint8_t *)&context->step_ok, true);
442 }
443
444 bool BKE_autotrack_context_step(AutoTrackContext *context)
445 {
446   const int frame_delta = context->backwards ? -1 : 1;
447   context->step_ok = false;
448
449   ParallelRangeSettings settings;
450   BLI_parallel_range_settings_defaults(&settings);
451   settings.use_threading = (context->num_tracks > 1);
452   BLI_task_parallel_range(0, context->num_tracks, context, autotrack_context_step_cb, &settings);
453
454   /* Advance the frame. */
455   BLI_spin_lock(&context->spin_lock);
456   context->user.framenr += frame_delta;
457   BLI_spin_unlock(&context->spin_lock);
458   return context->step_ok;
459 }
460
461 void BKE_autotrack_context_sync(AutoTrackContext *context)
462 {
463   int newframe, frame_delta = context->backwards ? -1 : 1;
464   int frame;
465
466   BLI_spin_lock(&context->spin_lock);
467   newframe = context->user.framenr;
468   for (frame = context->sync_frame; frame != (context->backwards ? newframe - 1 : newframe + 1);
469        frame += frame_delta) {
470     MovieTrackingMarker marker;
471     libmv_Marker libmv_marker;
472     int clip = 0;
473     int track;
474     for (track = 0; track < context->num_tracks; ++track) {
475       AutoTrackOptions *options = &context->options[track];
476       int track_frame = BKE_movieclip_remap_scene_to_clip_frame(
477           context->clips[options->clip_index], frame);
478       if (options->is_failed) {
479         if (options->failed_frame == track_frame) {
480           MovieTrackingMarker *prev_marker = BKE_tracking_marker_get_exact(
481               options->track, context->backwards ? frame + 1 : frame - 1);
482           if (prev_marker) {
483             marker = *prev_marker;
484             marker.framenr = track_frame;
485             marker.flag |= MARKER_DISABLED;
486             BKE_tracking_marker_insert(options->track, &marker);
487             continue;
488           }
489         }
490         if ((context->backwards && options->failed_frame > track_frame) ||
491             (!context->backwards && options->failed_frame < track_frame)) {
492           continue;
493         }
494       }
495       if (libmv_autoTrackGetMarker(
496               context->autotrack, clip, track_frame, options->track_index, &libmv_marker)) {
497         libmv_marker_to_dna_marker(
498             &libmv_marker, context->frame_width, context->frame_height, &marker);
499         if (context->first_sync && frame == context->sync_frame) {
500           tracking_marker_insert_disabled(options->track, &marker, !context->backwards, false);
501         }
502         BKE_tracking_marker_insert(options->track, &marker);
503         tracking_marker_insert_disabled(options->track, &marker, context->backwards, false);
504       }
505     }
506   }
507   BLI_spin_unlock(&context->spin_lock);
508
509   for (int clip = 0; clip < context->num_clips; ++clip) {
510     MovieTracking *tracking = &context->clips[clip]->tracking;
511     BKE_tracking_dopesheet_tag_update(tracking);
512   }
513
514   context->sync_frame = newframe;
515   context->first_sync = false;
516 }
517
518 void BKE_autotrack_context_sync_user(AutoTrackContext *context, MovieClipUser *user)
519 {
520   user->framenr = context->sync_frame;
521 }
522
523 void BKE_autotrack_context_finish(AutoTrackContext *context)
524 {
525   int clip_index;
526
527   for (clip_index = 0; clip_index < context->num_clips; ++clip_index) {
528     MovieClip *clip = context->clips[clip_index];
529     ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking);
530     MovieTrackingPlaneTrack *plane_track;
531
532     for (plane_track = plane_tracks_base->first; plane_track; plane_track = plane_track->next) {
533       if ((plane_track->flag & PLANE_TRACK_AUTOKEY) == 0) {
534         int track;
535         for (track = 0; track < context->num_tracks; ++track) {
536           if (BKE_tracking_plane_track_has_point_track(plane_track,
537                                                        context->options[track].track)) {
538             BKE_tracking_track_plane_from_existing_motion(plane_track, context->first_frame);
539             break;
540           }
541         }
542       }
543     }
544   }
545 }
546
547 void BKE_autotrack_context_free(AutoTrackContext *context)
548 {
549   libmv_autoTrackDestroy(context->autotrack);
550   tracking_image_accessor_destroy(context->image_accessor);
551   MEM_freeN(context->options);
552   MEM_freeN(context->tracks);
553   BLI_spin_end(&context->spin_lock);
554   MEM_freeN(context);
555 }