Blender V5.0
tracking_ops_track.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2016 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "MEM_guardedalloc.h"
10
11#include "BLI_listbase.h"
12#include "BLI_math_base.h"
13#include "BLI_time.h"
14
15#include "BLT_translation.hh"
16
17#include "BKE_context.hh"
18#include "BKE_global.hh"
19#include "BKE_main.hh"
20#include "BKE_movieclip.h"
21#include "BKE_tracking.h"
22
23#include "WM_api.hh"
24#include "WM_types.hh"
25
26#include "ED_clip.hh"
27
28#include "RNA_access.hh"
29#include "RNA_define.hh"
30
31#include "DEG_depsgraph.hh"
32
33#include "clip_intern.hh" /* own include */
35
36/********************** Track operator *********************/
37
39 AutoTrackContext *context; /* Tracking context */
40 int sfra, efra, lastfra; /* Start, end and recently tracked frames */
41 int backwards; /* Backwards tracking flag */
42 MovieClip *clip; /* Clip which is tracking */
43 float delay; /* Delay in milliseconds to allow
44 * tracking at fixed FPS */
45
50};
51
53{
54 return G.is_break;
55}
56
57static int track_count_markers(SpaceClip *sc, MovieClip *clip, const int framenr)
58{
59 int tot = 0;
60 const MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(&clip->tracking);
61 LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking_object->tracks) {
62 bool selected = (sc != nullptr) ? TRACK_VIEW_SELECTED(sc, track) : TRACK_SELECTED(track);
63 if (selected && (track->flag & TRACK_LOCKED) == 0) {
64 MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
65 if (!marker || (marker->flag & MARKER_DISABLED) == 0) {
66 tot++;
67 }
68 }
69 }
70 return tot;
71}
72
74 MovieClip *clip,
75 const int framenr,
76 int *r_frames_limit)
77{
78 const MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(&clip->tracking);
79 int frames_limit = 0;
80 if (sc != nullptr) {
82 }
83 LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking_object->tracks) {
84 bool selected = (sc != nullptr) ? TRACK_VIEW_SELECTED(sc, track) : TRACK_SELECTED(track);
85 if (selected) {
86 if ((track->flag & TRACK_HIDDEN) == 0 && (track->flag & TRACK_LOCKED) == 0) {
87 BKE_tracking_marker_ensure(track, framenr);
88 if (track->frames_limit) {
89 if (frames_limit == 0) {
90 frames_limit = track->frames_limit;
91 }
92 else {
93 frames_limit = min_ii(frames_limit, int(track->frames_limit));
94 }
95 }
96 }
97 }
98 }
99 *r_frames_limit = frames_limit;
100}
101
102static bool track_markers_check_direction(int backwards, int curfra, int efra)
103{
104 if (backwards) {
105 if (curfra < efra) {
106 return false;
107 }
108 }
109 else {
110 if (curfra > efra) {
111 return false;
112 }
113 }
114
115 return true;
116}
117
118static bool track_markers_initjob(bContext *C, TrackMarkersJob *tmj, bool backwards, bool sequence)
119{
122 Scene *scene = CTX_data_scene(C);
123 MovieTrackingSettings *settings = &clip->tracking.settings;
124 int frames_limit;
125 int framenr = ED_space_clip_get_clip_frame_number(sc);
126
127 track_init_markers(sc, clip, framenr, &frames_limit);
128
129 tmj->sfra = framenr;
130 tmj->clip = clip;
131 tmj->backwards = backwards;
132
133 if (sequence) {
134 if (backwards) {
135 tmj->efra = scene->r.sfra;
136 }
137 else {
138 tmj->efra = scene->r.efra;
139 }
141 }
142 else {
143 if (backwards) {
144 tmj->efra = tmj->sfra - 1;
145 }
146 else {
147 tmj->efra = tmj->sfra + 1;
148 }
149 }
150
151 /* Limit frames to be tracked by user setting. */
152 if (frames_limit) {
153 if (backwards) {
154 tmj->efra = std::max(tmj->efra, tmj->sfra - frames_limit);
155 }
156 else {
157 tmj->efra = std::min(tmj->efra, tmj->sfra + frames_limit);
158 }
159 }
160
161 if (settings->speed != TRACKING_SPEED_FASTEST) {
162 tmj->delay = 1.0f / scene->r.frs_sec * 1000.0f;
163
164 if (settings->speed == TRACKING_SPEED_HALF) {
165 tmj->delay *= 2;
166 }
167 else if (settings->speed == TRACKING_SPEED_QUARTER) {
168 tmj->delay *= 4;
169 }
170 else if (settings->speed == TRACKING_SPEED_DOUBLE) {
171 tmj->delay /= 2;
172 }
173 }
174
175 tmj->context = BKE_autotrack_context_new(clip, &sc->user, backwards);
176
177 clip->tracking_context = tmj->context;
178
179 tmj->lastfra = tmj->sfra;
180
181 /* XXX: silly to store this, but this data is needed to update scene and
182 * movie-clip numbers when tracking is finished. This introduces
183 * better feedback for artists.
184 * Maybe there's another way to solve this problem,
185 * but can't think better way at the moment.
186 * Anyway, this way isn't more unstable as animation rendering
187 * animation which uses the same approach (except storing screen).
188 */
189 tmj->scene = scene;
190 tmj->main = CTX_data_main(C);
191 tmj->screen = CTX_wm_screen(C);
192
193 tmj->wm = CTX_wm_manager(C);
194
195 if (!track_markers_check_direction(backwards, tmj->sfra, tmj->efra)) {
196 return false;
197 }
198
199 WM_locked_interface_set(tmj->wm, true);
200
201 return true;
202}
203
204static void track_markers_startjob(void *tmv, wmJobWorkerStatus *worker_status)
205{
206 TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
207 int framenr = tmj->sfra;
208
210
211 while (framenr != tmj->efra) {
212 if (tmj->delay > 0) {
213 /* Tracking should happen with fixed fps. Calculate time
214 * using current timer value before tracking frame and after.
215 *
216 * Small (and maybe unneeded optimization): do not calculate
217 * exec_time for "Fastest" tracking
218 */
219
220 double start_time = BLI_time_now_seconds(), exec_time;
221
223 break;
224 }
225
226 exec_time = BLI_time_now_seconds() - start_time;
227 if (tmj->delay > float(exec_time)) {
228 BLI_time_sleep_ms(tmj->delay - float(exec_time));
229 }
230 }
231 else if (!BKE_autotrack_context_step(tmj->context)) {
232 break;
233 }
234
235 worker_status->do_update = true;
236 worker_status->progress = float(framenr - tmj->sfra) / (tmj->efra - tmj->sfra);
237
238 if (tmj->backwards) {
239 framenr--;
240 }
241 else {
242 framenr++;
243 }
244
245 tmj->lastfra = framenr;
246
247 if (worker_status->stop || track_markers_testbreak()) {
248 break;
249 }
250 }
251}
252
253static void track_markers_updatejob(void *tmv)
254{
255 TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
257}
258
259static void track_markers_endjob(void *tmv)
260{
261 TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
262 wmWindowManager *wm = static_cast<wmWindowManager *>(tmj->main->wm.first);
263
264 tmj->clip->tracking_context = nullptr;
266 if (wm != nullptr) {
267 /* XXX */
268 // ED_update_for_newframe(tmj->main, tmj->scene);
269 }
270
273
276}
277
278static void track_markers_freejob(void *tmv)
279{
280 TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
281 tmj->clip->tracking_context = nullptr;
282 WM_locked_interface_set(tmj->wm, false);
284 MEM_freeN(tmj);
285}
286
288{
289 TrackMarkersJob *tmj;
292 wmJob *wm_job;
293 bool backwards = RNA_boolean_get(op->ptr, "backwards");
294 bool sequence = RNA_boolean_get(op->ptr, "sequence");
295 int framenr = ED_space_clip_get_clip_frame_number(sc);
296
298 /* Only one tracking is allowed at a time. */
299 return OPERATOR_CANCELLED;
300 }
301
302 if (clip->tracking_context) {
303 return OPERATOR_CANCELLED;
304 }
305
306 if (track_count_markers(sc, clip, framenr) == 0) {
307 return OPERATOR_CANCELLED;
308 }
309
310 tmj = MEM_callocN<TrackMarkersJob>("TrackMarkersJob data");
311 if (!track_markers_initjob(C, tmj, backwards, sequence)) {
313 return OPERATOR_CANCELLED;
314 }
315
316 /* Setup job. */
317 if (use_job && sequence) {
318 wm_job = WM_jobs_get(CTX_wm_manager(C),
321 "Tracking markers...",
325
326 /* If there's delay set in tracking job, tracking should happen
327 * with fixed FPS. To deal with editor refresh we have to synchronize
328 * tracks from job and tracks in clip. Do this in timer callback
329 * to prevent threading conflicts. */
330 if (tmj->delay > 0) {
331 WM_jobs_timer(wm_job, tmj->delay / 1000.0f, NC_MOVIECLIP | NA_EVALUATED, 0);
332 }
333 else {
334 WM_jobs_timer(wm_job, 0.2, NC_MOVIECLIP | NA_EVALUATED, 0);
335 }
336
339
340 G.is_break = false;
341
343 WM_cursor_wait(false);
344
345 /* Add modal handler for ESC. */
347
349 }
350
351 wmJobWorkerStatus worker_status = {};
352 track_markers_startjob(tmj, &worker_status);
355 return OPERATOR_FINISHED;
356}
357
359{
360 return track_markers(C, op, false);
361}
362
364 wmOperator *op,
365 const wmEvent * /*event*/)
366{
367 return track_markers(C, op, true);
368}
369
371{
372 /* No running tracking, remove handler and pass through. */
375 }
376
377 /* Running tracking. */
378 switch (event->type) {
379 case EVT_ESCKEY:
381 default: {
382 break;
383 }
384 }
385
387}
388
389static std::string track_markers_get_description(bContext * /*C*/,
390 wmOperatorType * /*ot*/,
392{
393 const bool backwards = RNA_boolean_get(ptr, "backwards");
394 const bool sequence = RNA_boolean_get(ptr, "sequence");
395
396 if (backwards && sequence) {
397 return TIP_("Track the selected markers backward for the entire clip");
398 }
399 if (backwards && !sequence) {
400 return TIP_("Track the selected markers backward by one frame");
401 }
402 if (!backwards && sequence) {
403 return TIP_("Track the selected markers forward for the entire clip");
404 }
405 if (!backwards && !sequence) {
406 return TIP_("Track the selected markers forward by one frame");
407 }
408
409 /* Use default description. */
410 return "";
411}
412
414{
415 /* identifiers */
416 ot->name = "Track Markers";
417 ot->description = "Track selected markers";
418 ot->idname = "CLIP_OT_track_markers";
419
420 /* API callbacks. */
421 ot->exec = track_markers_exec;
422 ot->invoke = track_markers_invoke;
423 ot->modal = track_markers_modal;
425 ot->get_description = track_markers_get_description;
426
427 /* flags */
428 ot->flag = OPTYPE_UNDO;
429
430 /* properties */
431 RNA_def_boolean(ot->srna, "backwards", false, "Backwards", "Do backwards tracking");
432 RNA_def_boolean(ot->srna,
433 "sequence",
434 false,
435 "Track Sequence",
436 "Track marker during image sequence rather than "
437 "single image");
438}
439
440/********************** Refine track position operator *********************/
441
443{
446 const MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(&clip->tracking);
447 const bool backwards = RNA_boolean_get(op->ptr, "backwards");
448 const int framenr = ED_space_clip_get_clip_frame_number(sc);
449
450 LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking_object->tracks) {
451 if (TRACK_VIEW_SELECTED(sc, track)) {
452 MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
453 BKE_tracking_refine_marker(clip, track, marker, backwards);
454 }
455 }
456
459
460 return OPERATOR_FINISHED;
461}
462
464{
465 /* identifiers */
466 ot->name = "Refine Markers";
467 ot->description =
468 "Refine selected markers positions "
469 "by running the tracker from track's reference "
470 "to current frame";
471 ot->idname = "CLIP_OT_refine_markers";
472
473 /* API callbacks. */
474 ot->exec = refine_marker_exec;
476
477 /* flags */
479
480 /* properties */
481 RNA_def_boolean(ot->srna, "backwards", false, "Backwards", "Do backwards tracking");
482}
bScreen * CTX_wm_screen(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
SpaceClip * CTX_wm_space_clip(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
float BKE_movieclip_remap_scene_to_clip_frame(const struct MovieClip *clip, float framenr)
float BKE_movieclip_remap_clip_to_scene_frame(const struct MovieClip *clip, float framenr)
struct AutoTrackContext * BKE_autotrack_context_new(struct MovieClip *clip, struct MovieClipUser *user, bool is_backwards)
void BKE_autotrack_context_finish(struct AutoTrackContext *context)
struct MovieTrackingMarker * BKE_tracking_marker_ensure(struct MovieTrackingTrack *track, int framenr)
Definition tracking.cc:1402
bool BKE_autotrack_context_step(struct AutoTrackContext *context)
#define TRACK_SELECTED(track)
void BKE_autotrack_context_free(struct AutoTrackContext *context)
struct MovieTrackingMarker * BKE_tracking_marker_get(struct MovieTrackingTrack *track, int framenr)
Definition tracking.cc:1358
struct MovieTrackingObject * BKE_tracking_object_get_active(const struct MovieTracking *tracking)
void BKE_tracking_refine_marker(struct MovieClip *clip, struct MovieTrackingTrack *track, struct MovieTrackingMarker *marker, bool backwards)
#define TRACK_VIEW_SELECTED(sc, track)
void BKE_autotrack_context_start(struct AutoTrackContext *context)
void BKE_autotrack_context_sync(struct AutoTrackContext *context)
#define LISTBASE_FOREACH(type, var, list)
MINLINE int min_ii(int a, int b)
Platform independent time functions.
void BLI_time_sleep_ms(int ms)
Definition time.cc:133
double BLI_time_now_seconds(void)
Definition time.cc:113
#define TIP_(msgid)
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1118
@ TRACKING_SPEED_DOUBLE
@ TRACKING_SPEED_HALF
@ TRACKING_SPEED_FASTEST
@ TRACKING_SPEED_QUARTER
@ TRACK_HIDDEN
@ TRACK_LOCKED
@ MARKER_DISABLED
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
MovieClip * ED_space_clip_get_clip(const SpaceClip *sc)
int ED_space_clip_get_clip_frame_number(const SpaceClip *sc)
bool ED_space_clip_tracking_poll(bContext *C)
Read Guarded memory(de)allocation.
#define C
Definition RandGen.cpp:29
@ WM_JOB_TYPE_ANY
Definition WM_api.hh:1775
@ WM_JOB_TYPE_CLIP_TRACK_MARKERS
Definition WM_api.hh:1789
@ WM_JOB_PROGRESS
Definition WM_api.hh:1766
#define NA_EVALUATED
Definition WM_types.hh:585
#define NC_MOVIECLIP
Definition WM_types.hh:397
#define NC_SCENE
Definition WM_types.hh:378
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define ND_FRAME
Definition WM_types.hh:434
nullptr float
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
#define G(x, y, z)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void * first
ListBase wm
Definition BKE_main.hh:307
void * tracking_context
struct MovieTracking tracking
MovieTrackingSettings settings
struct RenderData r
struct MovieClipUser user
wmWindowManager * wm
AutoTrackContext * context
wmEventType type
Definition WM_types.hh:757
struct PointerRNA * ptr
void clip_tracking_clear_invisible_track_selection(SpaceClip *sc, MovieClip *clip)
static wmOperatorStatus track_markers_exec(bContext *C, wmOperator *op)
static wmOperatorStatus refine_marker_exec(bContext *C, wmOperator *op)
static void track_markers_endjob(void *tmv)
static bool track_markers_check_direction(int backwards, int curfra, int efra)
static wmOperatorStatus track_markers(bContext *C, wmOperator *op, bool use_job)
void CLIP_OT_track_markers(wmOperatorType *ot)
static void track_markers_startjob(void *tmv, wmJobWorkerStatus *worker_status)
static std::string track_markers_get_description(bContext *, wmOperatorType *, PointerRNA *ptr)
static void track_markers_updatejob(void *tmv)
static wmOperatorStatus track_markers_modal(bContext *C, wmOperator *, const wmEvent *event)
static bool track_markers_initjob(bContext *C, TrackMarkersJob *tmj, bool backwards, bool sequence)
static bool track_markers_testbreak()
void CLIP_OT_refine_markers(wmOperatorType *ot)
static wmOperatorStatus track_markers_invoke(bContext *C, wmOperator *op, const wmEvent *)
static void track_markers_freejob(void *tmv)
static int track_count_markers(SpaceClip *sc, MovieClip *clip, const int framenr)
static void track_init_markers(SpaceClip *sc, MovieClip *clip, const int framenr, int *r_frames_limit)
void WM_cursor_wait(bool val)
void WM_locked_interface_set(wmWindowManager *wm, bool lock)
void WM_main_add_notifier(uint type, void *reference)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
@ EVT_ESCKEY
PointerRNA * ptr
Definition wm_files.cc:4238
wmOperatorType * ot
Definition wm_files.cc:4237
void WM_jobs_timer(wmJob *wm_job, double time_step, uint note, uint endnote)
Definition wm_jobs.cc:376
void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
Definition wm_jobs.cc:479
wmJob * WM_jobs_get(wmWindowManager *wm, wmWindow *win, const void *owner, const char *name, const eWM_JobFlag flag, const eWM_JobType job_type)
Definition wm_jobs.cc:211
void WM_jobs_callbacks(wmJob *wm_job, wm_jobs_start_callback startjob, void(*initjob)(void *), void(*update)(void *), void(*endjob)(void *))
Definition wm_jobs.cc:388
bool WM_jobs_test(const wmWindowManager *wm, const void *owner, int job_type)
Definition wm_jobs.cc:247
void WM_jobs_customdata_set(wmJob *wm_job, void *customdata, void(*free)(void *customdata))
Definition wm_jobs.cc:360