Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/blenkernel/intern/tracking_auto.c744
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);
}
+
+/** \} */