diff options
-rw-r--r-- | source/blender/blenkernel/intern/tracking_auto.c | 744 |
1 files changed, 493 insertions, 251 deletions
diff --git a/source/blender/blenkernel/intern/tracking_auto.c b/source/blender/blenkernel/intern/tracking_auto.c index edd798b162a..05d1e427c14 100644 --- a/source/blender/blenkernel/intern/tracking_auto.c +++ b/source/blender/blenkernel/intern/tracking_auto.c @@ -41,39 +41,65 @@ #include "libmv-capi.h" #include "tracking_private.h" -typedef struct AutoTrackOptions { - int clip_index; /** Index of the clip this track belongs to. */ - int track_index; /* Index of the track in AutoTrack tracks structure. */ - MovieTrackingTrack *track; /* Pointer to an original track/ */ - libmv_TrackRegionOptions track_region_options; /* Options for the region tracker. */ - - /* Define which frame is used for reference marker. */ - eTrackFrameMatch frame_match; - - /* TODO(sergey): A bit awkward to keep it in here, only used to - * place a disabled marker once the tracking fails, - * Either find a clearer way to do it or call it track context - * or state, not options. - */ - bool is_failed; - int failed_frame; -} AutoTrackOptions; +typedef struct AutoTrackClip { + MovieClip *clip; + + /* Dimensions of movie frame, in pixels. + * + * NOTE: All frames within a clip are expected to have match3ed dimensions. */ + int width, height; +} AutoTrackClip; + +typedef struct AutoTrackTrack { + /* Index of a clip from `AutoTrackContext::autotrack_clips` this track belongs to. */ + int clip_index; + + MovieTrackingTrack *track; + + /* Options for the region tracker. */ + libmv_TrackRegionOptions track_region_options; + + /* Denotes whether this track will be tracked. + * Is usually initialized based on track's selection. Non-trackable tracks are still added to the + * context to provide AutoTrack all knowledge about what is going on in the scene. */ + bool is_trackable; +} AutoTrackTrack; + +typedef struct AutoTrackMarker { + libmv_Marker libmv_marker; +} AutoTrackMarker; + +/* Result of tracking step for a single marker. + * + * On success both marker and result are fully initialized to the position on the new frame. + * + * On failure marker's frame number is initialized to frame number where it was attempted to be + * tracked to. The position and other fields of tracked marker are the same as the input. */ +typedef struct AutoTrackTrackingResult { + struct AutoTrackTrackingResult *next, *prev; + + bool success; + libmv_Marker libmv_marker; + libmv_TrackRegionResult libmv_result; +} AutoTrackTrackingResult; typedef struct AutoTrackContext { + /* -------------------------------------------------------------------- + * Invariant part. + * Stays unchanged during the tracking process. + * If not the initialization process, all the fields here should be treated as `const`. + */ + /* Frame at which tracking process started. * NOTE: Measured in scene time frames, */ int start_scene_frame; - /* Scene frame number from which tracker will perform the trackign step. - * The direction of the step is denoted by `is_backwards`. */ - int current_scene_frame; - /* True when tracking backwards (from higher frame number to lower frame number.) */ bool is_backwards; /* Movie clips used during the trackign process. */ int num_clips; - MovieClip *clips[MAX_ACCESSOR_CLIP]; + AutoTrackClip autotrack_clips[MAX_ACCESSOR_CLIP]; /* Tracks for which the context has been created for. * This is a flat array of all tracks coming from all clips, regardless of whether track is @@ -82,35 +108,41 @@ typedef struct AutoTrackContext { * * Indexed by AutoTrackOptions::track_index. */ int num_all_tracks; - MovieTrackingTrack **all_tracks; - - /* Dimensions of movie frame, in pixels. - * - * NOTE: All clips and frames within a clip are expected to have match3ed dimensions. - * - * TODO(sergey): Make it more flexible to fully support multiple-clip tracking. Could either be - * stored as a `pair<MovieClip, Dimensions>` or even be replaced with actual frame size access - * to support variadic frame dimensions. */ - int frame_width, frame_height; + AutoTrackTrack *all_autotrack_tracks; /* Accessor for images of clip. Used by the autotrack context. */ TrackingImageAccessor *image_accessor; + /* -------------------------------------------------------------------- + * Variant part. + * Denotes tracing state and tracking result. + */ + /* Auto-track context. * * NOTE: Is accessed from multiple threads at once. */ struct libmv_AutoTrack *autotrack; - int num_track_options; - AutoTrackOptions *track_options; /* Per-tracking track options. */ + /* Markers from the current frame which will be tracked to the next frame upon the tracking + * context step. + * + * NOTE: This array is re-used across tracking steps, which might make it appear that the array + * is over-allocated when some tracks has failed to track. */ + int num_autotrack_markers; + AutoTrackMarker *autotrack_markers; - int sync_frame; - bool first_sync; - SpinLock spin_lock; + /* Tracking results which are to be synchronized from the AutoTrack context to the Blender's + * DNA to make the results visible for users. */ + ListBase results_to_sync; + int synchronized_scene_frame; - bool step_ok; + SpinLock spin_lock; } AutoTrackContext; +/* -------------------------------------------------------------------- */ +/** \name Marker coordinate system conversion. + * \{ */ + static void normalized_to_libmv_frame(const float normalized[2], const int frame_dimensions[2], float result[2]) @@ -145,8 +177,14 @@ static void libmv_frame_to_normalized_relative(const float frame_coord[2], result[1] = (frame_coord[1] - origin[1]) / frame_dimensions[1]; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Coversion of markers between Blender's DNA and Libmv. + * \{ */ + static void dna_marker_to_libmv_marker(/*const*/ MovieTrackingTrack *track, - /*const*/ MovieTrackingMarker *marker, + const MovieTrackingMarker *marker, int clip, int track_index, int frame_width, @@ -171,7 +209,9 @@ static void dna_marker_to_libmv_marker(/*const*/ MovieTrackingTrack *track, normalized_relative_to_libmv_frame( marker->search_max, marker->pos, frame_dimensions, libmv_marker->search_region_max); - /* TODO(sergey): All the markers does have 1.0 weight. */ + /* NOTE: All the markers does have 1.0 weight. + * Might support in the future, but will require more elaborated process which will involve + * F-Curve evaluation. */ libmv_marker->weight = 1.0f; if (marker->flag & MARKER_TRACKED) { @@ -184,13 +224,11 @@ static void dna_marker_to_libmv_marker(/*const*/ MovieTrackingTrack *track, libmv_marker->model_type = LIBMV_MARKER_MODEL_TYPE_POINT; libmv_marker->model_id = 0; - /* TODO(sergey): We currently don't support reference marker from - * different clip. - */ + /* NOTE: We currently don't support reference marker from different clip. */ libmv_marker->reference_clip = clip; if (track->pattern_match == TRACK_MATCH_KEYFRAME) { - MovieTrackingMarker *keyframe_marker = tracking_get_keyframed_marker( + const MovieTrackingMarker *keyframe_marker = tracking_get_keyframed_marker( track, marker->framenr, backwards); libmv_marker->reference_frame = keyframe_marker->framenr; } @@ -235,20 +273,17 @@ static void libmv_marker_to_dna_marker(libmv_Marker *libmv_marker, } } -static bool check_track_trackable(const MovieClip *clip, - MovieTrackingTrack *track, - const MovieClipUser *user) -{ - if (TRACK_SELECTED(track) && (track->flag & (TRACK_LOCKED | TRACK_HIDDEN)) == 0) { - int frame = BKE_movieclip_remap_scene_to_clip_frame(clip, user->framenr); - const MovieTrackingMarker *marker = BKE_tracking_marker_get(track, frame); - return (marker->flag & MARKER_DISABLED) == 0; - } - return false; -} +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name General helpers. + * + * TODO(sergey): Should be moved to tracking_util.c + * + * \{ */ /* Returns false if marker crossed margin area from frame bounds. */ -static bool tracking_check_marker_margin(libmv_Marker *libmv_marker, +static bool tracking_check_marker_margin(const libmv_Marker *libmv_marker, int margin, int frame_width, int frame_height) @@ -277,91 +312,234 @@ static bool tracking_check_marker_margin(libmv_Marker *libmv_marker, return true; } -/* Provide Libmv side of auto track all information about given tracks. */ -static void fill_autotrack_tracks(const int frame_width, - const int frame_height, - const ListBase *tracksbase, - const bool backwards, - struct libmv_AutoTrack *autotrack) +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Autotrack context initialization. + * \{ */ + +static bool autotrack_is_marker_usable(const MovieTrackingMarker *marker) { - /* Count number of markers to be put to a context. */ - size_t num_trackable_markers = 0; - LISTBASE_FOREACH (MovieTrackingTrack *, track, tracksbase) { - for (int i = 0; i < track->markersnr; i++) { - const MovieTrackingMarker *marker = track->markers + i; - if ((marker->flag & MARKER_DISABLED) == 0) { - num_trackable_markers++; + if ((marker->flag & MARKER_DISABLED)) { + return false; + } + return true; +} + +static bool autotrack_is_track_trackable(const AutoTrackContext *context, + const AutoTrackTrack *autotrack_track) +{ + /*const*/ MovieTrackingTrack *track = autotrack_track->track; + if (TRACK_SELECTED(track) && (track->flag & (TRACK_LOCKED | TRACK_HIDDEN)) == 0) { + const AutoTrackClip *autotrack_clip = &context->autotrack_clips[autotrack_track->clip_index]; + MovieClip *clip = autotrack_clip->clip; + const int clip_frame_number = BKE_movieclip_remap_scene_to_clip_frame( + clip, context->start_scene_frame); + + const MovieTrackingMarker *marker = BKE_tracking_marker_get(track, clip_frame_number); + return autotrack_is_marker_usable(marker); + } + return false; +} + +static void autotrack_context_init_clips(AutoTrackContext *context, + MovieClip *clip, + MovieClipUser *user) +{ + /* NOTE: Currently only tracking within a single clip. */ + + context->num_clips = 1; + + context->autotrack_clips[0].clip = clip; + BKE_movieclip_get_size( + clip, user, &context->autotrack_clips[0].width, &context->autotrack_clips[0].height); +} + +/* Initialize flat list of tracks for quick index-based access for the specified clip. + * All the tracks from this clip are added at the end of the array of already-collected tracks. + * + * NOTE: Clips should be initialized first. */ +static void autotrack_context_init_tracks_for_clip(AutoTrackContext *context, int clip_index) +{ + BLI_assert(clip_index >= 0); + BLI_assert(clip_index < context->num_clips); + + const AutoTrackClip *autotrack_clip = &context->autotrack_clips[clip_index]; + MovieClip *clip = autotrack_clip->clip; + MovieTracking *tracking = &clip->tracking; + ListBase *tracks_base = BKE_tracking_get_active_tracks(tracking); + + const int num_clip_tracks = BLI_listbase_count(tracks_base); + if (num_clip_tracks == 0) { + return; + } + + context->all_autotrack_tracks = MEM_reallocN(context->all_autotrack_tracks, + (context->num_all_tracks + num_clip_tracks) * + sizeof(AutoTrackTrack)); + + LISTBASE_FOREACH (MovieTrackingTrack *, track, tracks_base) { + AutoTrackTrack *autotrack_track = &context->all_autotrack_tracks[context->num_all_tracks++]; + autotrack_track->clip_index = clip_index; + autotrack_track->track = track; + autotrack_track->is_trackable = autotrack_is_track_trackable(context, autotrack_track); + + tracking_configure_tracker(track, NULL, &autotrack_track->track_region_options); + } +} + +/* Initialize flat list of tracks for quick index-based access for all clips used for tracking. + * + * NOTE: Clips should be initialized first. */ +static void autotrack_context_init_tracks(AutoTrackContext *context) +{ + BLI_assert(context->num_clips >= 1); + + for (int clip_index = 0; clip_index < context->num_clips; ++clip_index) { + autotrack_context_init_tracks_for_clip(context, clip_index); + } +} + +/* NOTE: Clips should be initialized first. */ +static void autotrack_context_init_image_accessor(AutoTrackContext *context) +{ + BLI_assert(context->num_clips >= 1); + + /* Planarize arrays of clips and tracks, storing pointers to their base "objects". + * This allows image accessor to be independent, but adds some overhead here. Could be solved + * by either more strongly coupling accessor API with the AutoTrack, or by giving some functors + * to the accessor to access clip/track from their indices. */ + + MovieClip *clips[MAX_ACCESSOR_CLIP]; + for (int i = 0; i < context->num_clips; ++i) { + clips[i] = context->autotrack_clips[i].clip; + } + + MovieTrackingTrack **tracks = MEM_malloc_arrayN( + context->num_all_tracks, sizeof(MovieTrackingTrack *), "image accessor init tracks"); + for (int i = 0; i < context->num_all_tracks; ++i) { + tracks[i] = context->all_autotrack_tracks[i].track; + } + + context->image_accessor = tracking_image_accessor_new(clips, 1, tracks, context->num_all_tracks); + + MEM_freeN(tracks); +} + +/* Count markers which are usable to be passed to the AutoTrack context. */ +static size_t autotrack_count_all_usable_markers(AutoTrackContext *context) +{ + size_t num_usable_markers = 0; + for (int track_index = 0; track_index < context->num_all_tracks; ++track_index) { + const MovieTrackingTrack *track = context->all_autotrack_tracks[track_index].track; + for (int marker_index = 0; marker_index < track->markersnr; ++marker_index) { + const MovieTrackingMarker *marker = &track->markers[marker_index]; + if (!autotrack_is_marker_usable(marker)) { + continue; } + num_usable_markers++; + } + } + return num_usable_markers; +} + +static int autotrack_count_trackable_markers(AutoTrackContext *context) +{ + int num_trackable_markers = 0; + for (int track_index = 0; track_index < context->num_all_tracks; ++track_index) { + const AutoTrackTrack *autotrack_track = &context->all_autotrack_tracks[track_index]; + if (!autotrack_track->is_trackable) { + continue; } + num_trackable_markers++; } - /* Early output if we don't have any markers. */ + return num_trackable_markers; +} + +/* Provide Libmv side of auto track all information about given tracks. + * Information from all clips is passed to the auto tracker. + * + * NOTE: Clips and all tracks are to be initialized before calling this. */ +static void autotrack_context_init_autotrack(AutoTrackContext *context) +{ + context->autotrack = libmv_autoTrackNew(context->image_accessor->libmv_accessor); + + /* Count number of markers to be put to a context. */ + const size_t num_trackable_markers = autotrack_count_all_usable_markers(context); if (num_trackable_markers == 0) { return; } + /* Allocate memory for all the markers. */ - libmv_Marker *libmv_markers = MEM_mallocN(sizeof(libmv_Marker) * num_trackable_markers, - "libmv markers array"); + libmv_Marker *libmv_markers = MEM_malloc_arrayN( + sizeof(libmv_Marker), num_trackable_markers, "libmv markers array"); + /* Fill in markers array. */ - int track_index = 0, num_filled_libmv_markers = 0; - LISTBASE_FOREACH (MovieTrackingTrack *, track, tracksbase) { - for (int i = 0; i < track->markersnr; i++) { - MovieTrackingMarker *marker = track->markers + i; - if ((marker->flag & MARKER_DISABLED) != 0) { + int num_filled_libmv_markers = 0; + for (int track_index = 0; track_index < context->num_all_tracks; ++track_index) { + const AutoTrackTrack *autotrack_track = &context->all_autotrack_tracks[track_index]; + /*const*/ MovieTrackingTrack *track = autotrack_track->track; + for (int marker_index = 0; marker_index < track->markersnr; ++marker_index) { + /*const*/ MovieTrackingMarker *marker = &track->markers[marker_index]; + if (!autotrack_is_marker_usable(marker)) { continue; } + const AutoTrackClip *autotrack_clip = &context->autotrack_clips[autotrack_track->clip_index]; dna_marker_to_libmv_marker(track, marker, - 0, + autotrack_track->clip_index, track_index, - frame_width, - frame_height, - backwards, + autotrack_clip->width, + autotrack_clip->height, + context->is_backwards, &libmv_markers[num_filled_libmv_markers++]); } - /* Put all markers to autotrack at once. */ - track_index++; } + /* Add all markers to autotrack. */ - libmv_autoTrackSetMarkers(autotrack, libmv_markers, num_trackable_markers); + libmv_autoTrackSetMarkers(context->autotrack, libmv_markers, num_trackable_markers); + /* Free temporary memory. */ MEM_freeN(libmv_markers); } -static void create_per_track_tracking_options(const MovieClip *clip, - const MovieClipUser *user, - const ListBase *tracksbase, - AutoTrackContext *context) +static void autotrack_context_init_markers(AutoTrackContext *context) { /* Count number of trackable tracks. */ - LISTBASE_FOREACH (MovieTrackingTrack *, track, tracksbase) { - if (check_track_trackable(clip, track, user)) { - context->num_track_options++; - } + context->num_autotrack_markers = autotrack_count_trackable_markers(context); + if (context->num_autotrack_markers == 0) { + return; } + /* Allocate required memory. */ - context->track_options = MEM_callocN(sizeof(AutoTrackOptions) * context->num_track_options, - "auto track options"); - /* Fill in all the settings. */ - int i = 0, track_index = 0; - LISTBASE_FOREACH (MovieTrackingTrack *, track, tracksbase) { - context->all_tracks[track_index] = track; - - if (!check_track_trackable(clip, track, user)) { - track_index++; + context->autotrack_markers = MEM_calloc_arrayN( + sizeof(AutoTrackMarker), context->num_autotrack_markers, "auto track options"); + + /* Fill in all the markers. */ + int autotrack_marker_index = 0; + for (int track_index = 0; track_index < context->num_all_tracks; ++track_index) { + const AutoTrackTrack *autotrack_track = &context->all_autotrack_tracks[track_index]; + if (!autotrack_track->is_trackable) { continue; } - AutoTrackOptions *track_options = &context->track_options[i++]; - - /* TODO(sergey): Single clip only for now. */ - track_options->clip_index = 0; - track_options->track_index = track_index; - track_options->track = track; - track_options->frame_match = track->pattern_match; - - tracking_configure_tracker(track, NULL, &track_options->track_region_options); + const AutoTrackClip *autotrack_clip = &context->autotrack_clips[autotrack_track->clip_index]; + MovieClip *clip = autotrack_clip->clip; + const int clip_frame_number = BKE_movieclip_remap_scene_to_clip_frame( + clip, context->start_scene_frame); - track_index++; + /*const*/ MovieTrackingTrack *track = context->all_autotrack_tracks[track_index].track; + const MovieTrackingMarker *marker = BKE_tracking_marker_get(track, clip_frame_number); + + AutoTrackMarker *autotrack_marker = &context->autotrack_markers[autotrack_marker_index++]; + dna_marker_to_libmv_marker(track, + marker, + autotrack_track->clip_index, + track_index, + autotrack_clip->width, + autotrack_clip->height, + context->is_backwards, + &autotrack_marker->libmv_marker); } } @@ -370,198 +548,247 @@ AutoTrackContext *BKE_autotrack_context_new(MovieClip *clip, const bool is_backwards) { AutoTrackContext *context = MEM_callocN(sizeof(AutoTrackContext), "autotrack context"); - MovieTracking *tracking = &clip->tracking; - ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking); - int frame_width, frame_height; - /* get size of frame to convert normalized coordinates to a picture ones. */ - BKE_movieclip_get_size(clip, user, &frame_width, &frame_height); - /* TODO(sergey): Currently using only a single clip. */ - context->clips[0] = clip; - context->num_clips = 1; - context->current_scene_frame = user->framenr; - context->frame_width = frame_width; - context->frame_height = frame_height; - context->is_backwards = is_backwards; + context->start_scene_frame = user->framenr; - context->sync_frame = user->framenr; - context->first_sync = true; + context->is_backwards = is_backwards; + context->synchronized_scene_frame = context->start_scene_frame; + + autotrack_context_init_clips(context, clip, user); + autotrack_context_init_tracks(context); + autotrack_context_init_image_accessor(context); + autotrack_context_init_autotrack(context); + autotrack_context_init_markers(context); + BLI_spin_init(&context->spin_lock); - context->num_all_tracks = BLI_listbase_count(tracksbase); - context->all_tracks = MEM_callocN(sizeof(MovieTrackingTrack *) * context->num_all_tracks, - "auto track pointers"); - /* Create per-track tracking options. */ - create_per_track_tracking_options(clip, user, tracksbase, context); - /* Initialize image accessor. */ - context->image_accessor = tracking_image_accessor_new( - context->clips, 1, context->all_tracks, context->num_all_tracks); - /* Initialize auto track context and provide all information about currently - * tracked markers. - */ - context->autotrack = libmv_autoTrackNew(context->image_accessor->libmv_accessor); - fill_autotrack_tracks(frame_width, frame_height, tracksbase, is_backwards, context->autotrack); + return context; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Threaded context step (tracking process). + * \{ */ + +/* NOTE: This is a TLS in a sense that this struct is never accessed from multiple threads, and + * that threads are re-using the struct as much as possible. */ +typedef struct AutoTrackTLS { + ListBase results; /* Elements of `AutoTrackTrackingResult`. */ +} AutoTrackTLS; + static void autotrack_context_step_cb(void *__restrict userdata, - const int track, - const TaskParallelTLS *__restrict UNUSED(tls)) + const int marker_index, + const TaskParallelTLS *__restrict tls) { AutoTrackContext *context = userdata; - const int frame_delta = context->is_backwards ? -1 : 1; + AutoTrackTLS *autotrack_tls = (AutoTrackTLS *)tls->userdata_chunk; - AutoTrackOptions *track_options = &context->track_options[track]; - if (track_options->is_failed) { - return; - } + const AutoTrackMarker *autotrack_marker = &context->autotrack_markers[marker_index]; + const libmv_Marker *libmv_current_marker = &autotrack_marker->libmv_marker; - const int track_index = track_options->track_index; - const int clip_index = track_options->clip_index; + const int frame_delta = context->is_backwards ? -1 : 1; + const int clip_index = libmv_current_marker->clip; + const int track_index = libmv_current_marker->track; - libmv_Marker libmv_current_marker, libmv_reference_marker, libmv_tracked_marker; - libmv_TrackRegionResult libmv_result; + const AutoTrackClip *autotrack_clip = &context->autotrack_clips[clip_index]; + const AutoTrackTrack *autotrack_track = &context->all_autotrack_tracks[track_index]; + const MovieTrackingTrack *track = autotrack_track->track; - MovieClip *clip = context->clips[clip_index]; - const int frame = BKE_movieclip_remap_scene_to_clip_frame(clip, context->current_scene_frame); - BLI_spin_lock(&context->spin_lock); - const bool has_marker = libmv_autoTrackGetMarker( - context->autotrack, clip_index, frame, track_index, &libmv_current_marker); - BLI_spin_unlock(&context->spin_lock); - /* Check whether we've got marker to sync with. */ - if (!has_marker) { - return; - } /* Check whether marker is going outside of allowed frame margin. */ - if (!tracking_check_marker_margin(&libmv_current_marker, - track_options->track->margin, - context->frame_width, - context->frame_height)) { + if (!tracking_check_marker_margin( + libmv_current_marker, track->margin, autotrack_clip->width, autotrack_clip->height)) { return; } - libmv_tracked_marker = libmv_current_marker; - libmv_tracked_marker.frame = frame + frame_delta; + + const int new_marker_frame = libmv_current_marker->frame + frame_delta; + + AutoTrackTrackingResult *autotrack_result = MEM_mallocN(sizeof(AutoTrackTrackingResult), + "autotrack result"); + autotrack_result->libmv_marker = *libmv_current_marker; + autotrack_result->libmv_marker.frame = new_marker_frame; + /* Update reference frame. */ - if (track_options->frame_match == TRACK_MATCH_KEYFRAME) { - libmv_tracked_marker.reference_frame = libmv_current_marker.reference_frame; + libmv_Marker libmv_reference_marker; + if (track->pattern_match == TRACK_MATCH_KEYFRAME) { + autotrack_result->libmv_marker.reference_frame = libmv_current_marker->reference_frame; libmv_autoTrackGetMarker(context->autotrack, - track_options->clip_index, - libmv_tracked_marker.reference_frame, - track_options->track_index, + clip_index, + autotrack_result->libmv_marker.reference_frame, + track_index, &libmv_reference_marker); } else { - BLI_assert(track_options->frame_match == TRACK_MATCH_PREVIOS_FRAME); - libmv_tracked_marker.reference_frame = frame; - libmv_reference_marker = libmv_current_marker; + BLI_assert(track->pattern_match == TRACK_MATCH_PREVIOS_FRAME); + autotrack_result->libmv_marker.reference_frame = libmv_current_marker->frame; + libmv_reference_marker = *libmv_current_marker; } + /* Perform actual tracking. */ - if (libmv_autoTrackMarker(context->autotrack, - &track_options->track_region_options, - &libmv_tracked_marker, - &libmv_result)) { - BLI_spin_lock(&context->spin_lock); - libmv_autoTrackAddMarker(context->autotrack, &libmv_tracked_marker); - BLI_spin_unlock(&context->spin_lock); + autotrack_result->success = libmv_autoTrackMarker(context->autotrack, + &autotrack_track->track_region_options, + &autotrack_result->libmv_marker, + &autotrack_result->libmv_result); + + /* If tracking failed restore initial position. + * This is how Blender side is currently expecting failed track to be handled. Without this the + * marker is left in an arbitrary position which did not provide good correlation. */ + if (!autotrack_result->success) { + autotrack_result->libmv_marker = *libmv_current_marker; + autotrack_result->libmv_marker.frame = new_marker_frame; } - else { - track_options->is_failed = true; - track_options->failed_frame = frame + frame_delta; + + BLI_addtail(&autotrack_tls->results, autotrack_result); +} + +static void autotrack_context_reduce(const void *__restrict UNUSED(userdata), + void *__restrict chunk_join, + void *__restrict chunk) +{ + AutoTrackTLS *autotrack_tls = (AutoTrackTLS *)chunk; + if (BLI_listbase_is_empty(&autotrack_tls->results)) { + /* Nothing to be joined from. */ + return; } - /* Note: Atomic is probably not actually needed here, I doubt we could get - * any other result than a true bool anyway. - * But for sake of consistency, and since it costs nothing... - */ - atomic_fetch_and_or_uint8((uint8_t *)&context->step_ok, true); + AutoTrackTLS *autotrack_tls_join = (AutoTrackTLS *)chunk_join; + BLI_movelisttolist(&autotrack_tls_join->results, &autotrack_tls->results); } bool BKE_autotrack_context_step(AutoTrackContext *context) { - const int frame_delta = context->is_backwards ? -1 : 1; - context->step_ok = false; + if (context->num_autotrack_markers == 0) { + return false; + } + + AutoTrackTLS tls; + BLI_listbase_clear(&tls.results); TaskParallelSettings settings; BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = (context->num_track_options > 1); + settings.use_threading = (context->num_autotrack_markers > 1); + settings.userdata_chunk = &tls; + settings.userdata_chunk_size = sizeof(AutoTrackTLS); + settings.func_reduce = autotrack_context_reduce; + BLI_task_parallel_range( - 0, context->num_track_options, context, autotrack_context_step_cb, &settings); + 0, context->num_autotrack_markers, context, autotrack_context_step_cb, &settings); + + /* Prepare next tracking step by updating the AutoTrack context with new markers and moving + * tracked markers as an input for the next iteration. */ + context->num_autotrack_markers = 0; + LISTBASE_FOREACH (AutoTrackTrackingResult *, autotrack_result, &tls.results) { + if (!autotrack_result->success) { + continue; + } + + /* Insert tracking results to the AutoTrack context to make them usable for the next frame + * tracking iteration. */ + libmv_autoTrackAddMarker(context->autotrack, &autotrack_result->libmv_marker); + + /* Update the list of markers which will be tracked on the next iteration. */ + context->autotrack_markers[context->num_autotrack_markers++].libmv_marker = + autotrack_result->libmv_marker; + } - /* Advance the frame. */ BLI_spin_lock(&context->spin_lock); - context->current_scene_frame += frame_delta; + BLI_movelisttolist(&context->results_to_sync, &tls.results); BLI_spin_unlock(&context->spin_lock); - return context->step_ok; + + return true; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Context data synchronization. + * + * Used to copy trackign result to Blender side, while the trackign is still happening in its + * thread. + * + * \{ */ + void BKE_autotrack_context_sync(AutoTrackContext *context) { - int newframe, frame_delta = context->is_backwards ? -1 : 1; + const int frame_delta = context->is_backwards ? -1 : 1; BLI_spin_lock(&context->spin_lock); - newframe = context->current_scene_frame; - for (int frame = context->sync_frame; - frame != (context->is_backwards ? newframe - 1 : newframe + 1); - frame += frame_delta) { + ListBase results_to_sync = context->results_to_sync; + BLI_listbase_clear(&context->results_to_sync); + BLI_spin_unlock(&context->spin_lock); + + LISTBASE_FOREACH_MUTABLE (AutoTrackTrackingResult *, autotrack_result, &results_to_sync) { + const libmv_Marker *libmv_marker = &autotrack_result->libmv_marker; + const int clip_index = libmv_marker->clip; + const int track_index = libmv_marker->track; + const AutoTrackClip *autotrack_clip = &context->autotrack_clips[clip_index]; + const MovieClip *clip = autotrack_clip->clip; + const AutoTrackTrack *autotrack_track = &context->all_autotrack_tracks[track_index]; + MovieTrackingTrack *track = autotrack_track->track; + + const int start_clip_frame = BKE_movieclip_remap_scene_to_clip_frame( + clip, context->start_scene_frame); + const int first_result_frame = start_clip_frame + frame_delta; + + /* Insert marker which corresponds to the tracking result. */ MovieTrackingMarker marker; - libmv_Marker libmv_marker; - int clip = 0; - for (int i = 0; i < context->num_track_options; i++) { - AutoTrackOptions *track_options = &context->track_options[i]; - MovieTrackingTrack *track = track_options->track; - const int clip_index = track_options->clip_index; - const int track_index = track_options->track_index; - const int track_frame = BKE_movieclip_remap_scene_to_clip_frame(context->clips[clip_index], - frame); - if (track_options->is_failed) { - if (track_options->failed_frame == track_frame) { - MovieTrackingMarker *prev_marker = BKE_tracking_marker_get_exact( - track, context->is_backwards ? frame + 1 : frame - 1); - if (prev_marker) { - marker = *prev_marker; - marker.framenr = track_frame; - marker.flag |= MARKER_DISABLED; - BKE_tracking_marker_insert(track, &marker); - continue; - } - } - if ((context->is_backwards && track_options->failed_frame > track_frame) || - (!context->is_backwards && track_options->failed_frame < track_frame)) { - continue; - } - } - if (libmv_autoTrackGetMarker( - context->autotrack, clip, track_frame, track_index, &libmv_marker)) { - libmv_marker_to_dna_marker( - &libmv_marker, context->frame_width, context->frame_height, &marker); - if (context->first_sync && frame == context->sync_frame) { - tracking_marker_insert_disabled(track, &marker, !context->is_backwards, false); - } - BKE_tracking_marker_insert(track, &marker); - tracking_marker_insert_disabled(track, &marker, context->is_backwards, false); - } + libmv_marker_to_dna_marker( + &autotrack_result->libmv_marker, autotrack_clip->width, autotrack_clip->height, &marker); + if (!autotrack_result->success) { + marker.flag |= MARKER_DISABLED; } + BKE_tracking_marker_insert(track, &marker); + + /* Insetr disabled marker at the end of tracked segment. + * When tracking forward the disabled marker is added at the next frame from the result, + * when tracking backwards the marker is added at the previous frame. */ + tracking_marker_insert_disabled(track, &marker, context->is_backwards, false); + + if (marker.framenr == first_result_frame) { + MovieTrackingMarker *prev_marker = BKE_tracking_marker_get_exact( + track, marker.framenr - frame_delta); + BLI_assert(prev_marker != NULL); + + tracking_marker_insert_disabled(track, prev_marker, !context->is_backwards, false); + } + + /* Update synchronized frame to the latest tracked fame from the current results. */ + const int marker_scene_frame = BKE_movieclip_remap_clip_to_scene_frame(clip, marker.framenr); + if (context->is_backwards) { + context->synchronized_scene_frame = min_ii(context->synchronized_scene_frame, + marker_scene_frame); + } + else { + context->synchronized_scene_frame = max_ii(context->synchronized_scene_frame, + marker_scene_frame); + } + + MEM_freeN(autotrack_result); } - BLI_spin_unlock(&context->spin_lock); - for (int clip = 0; clip < context->num_clips; clip++) { - MovieTracking *tracking = &context->clips[clip]->tracking; + for (int clip_index = 0; clip_index < context->num_clips; clip_index++) { + MovieTracking *tracking = &context->autotrack_clips[clip_index].clip->tracking; BKE_tracking_dopesheet_tag_update(tracking); } - - context->sync_frame = newframe; - context->first_sync = false; } /* TODO(sergey): Find a way to avoid this, somehow making all needed logic in * BKE_autotrack_context_sync(). */ void BKE_autotrack_context_sync_user(AutoTrackContext *context, MovieClipUser *user) { - user->framenr = context->sync_frame; + user->framenr = context->synchronized_scene_frame; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Finalization. + * \{ */ + void BKE_autotrack_context_finish(AutoTrackContext *context) { for (int clip_index = 0; clip_index < context->num_clips; clip_index++) { - MovieClip *clip = context->clips[clip_index]; + const AutoTrackClip *autotrack_clip = &context->autotrack_clips[clip_index]; + MovieClip *clip = autotrack_clip->clip; ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking); const int start_clip_frame = BKE_movieclip_remap_scene_to_clip_frame( clip, context->start_scene_frame); @@ -570,9 +797,12 @@ void BKE_autotrack_context_finish(AutoTrackContext *context) if ((plane_track->flag & PLANE_TRACK_AUTOKEY)) { continue; } - for (int i = 0; i < context->num_track_options; i++) { - const AutoTrackOptions *track_options = &context->track_options[i]; - MovieTrackingTrack *track = track_options->track; + for (int track_index = 0; track_index < context->num_all_tracks; track_index++) { + const AutoTrackTrack *autotrack_track = &context->all_autotrack_tracks[track_index]; + if (!autotrack_track->is_trackable) { + continue; + } + MovieTrackingTrack *track = autotrack_track->track; if (BKE_tracking_plane_track_has_point_track(plane_track, track)) { BKE_tracking_track_plane_from_existing_motion(plane_track, start_clip_frame); break; @@ -584,10 +814,22 @@ void BKE_autotrack_context_finish(AutoTrackContext *context) void BKE_autotrack_context_free(AutoTrackContext *context) { - libmv_autoTrackDestroy(context->autotrack); - tracking_image_accessor_destroy(context->image_accessor); - MEM_freeN(context->track_options); - MEM_freeN(context->all_tracks); + if (context->autotrack != NULL) { + libmv_autoTrackDestroy(context->autotrack); + } + + if (context->image_accessor != NULL) { + tracking_image_accessor_destroy(context->image_accessor); + } + + MEM_SAFE_FREE(context->all_autotrack_tracks); + MEM_SAFE_FREE(context->autotrack_markers); + + BLI_freelistN(&context->results_to_sync); + BLI_spin_end(&context->spin_lock); + MEM_freeN(context); } + +/** \} */ |