Blender V4.3
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
9#include "MEM_guardedalloc.h"
10
11#include "BLI_time.h"
12#include "BLI_utildefines.h"
13
14#include "BLT_translation.hh"
15
16#include "BKE_context.hh"
17#include "BKE_global.hh"
18#include "BKE_main.hh"
19#include "BKE_movieclip.h"
20#include "BKE_tracking.h"
21
22#include "WM_api.hh"
23#include "WM_types.hh"
24
25#include "ED_clip.hh"
26
27#include "RNA_access.hh"
28#include "RNA_define.hh"
29
30#include "DEG_depsgraph.hh"
31
32#include "clip_intern.hh" /* own include */
34
35/********************** Track operator *********************/
36
38 AutoTrackContext *context; /* Tracking context */
39 int sfra, efra, lastfra; /* Start, end and recently tracked frames */
40 int backwards; /* Backwards tracking flag */
41 MovieClip *clip; /* Clip which is tracking */
42 float delay; /* Delay in milliseconds to allow
43 * tracking at fixed FPS */
44
49};
50
52{
53 return G.is_break;
54}
55
56static int track_count_markers(SpaceClip *sc, MovieClip *clip, const int framenr)
57{
58 int tot = 0;
59 const MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(&clip->tracking);
60 LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking_object->tracks) {
61 bool selected = (sc != nullptr) ? TRACK_VIEW_SELECTED(sc, track) : TRACK_SELECTED(track);
62 if (selected && (track->flag & TRACK_LOCKED) == 0) {
63 MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
64 if (!marker || (marker->flag & MARKER_DISABLED) == 0) {
65 tot++;
66 }
67 }
68 }
69 return tot;
70}
71
73 MovieClip *clip,
74 const int framenr,
75 int *r_frames_limit)
76{
77 const MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(&clip->tracking);
78 int frames_limit = 0;
79 if (sc != nullptr) {
81 }
82 LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking_object->tracks) {
83 bool selected = (sc != nullptr) ? TRACK_VIEW_SELECTED(sc, track) : TRACK_SELECTED(track);
84 if (selected) {
85 if ((track->flag & TRACK_HIDDEN) == 0 && (track->flag & TRACK_LOCKED) == 0) {
86 BKE_tracking_marker_ensure(track, framenr);
87 if (track->frames_limit) {
88 if (frames_limit == 0) {
89 frames_limit = track->frames_limit;
90 }
91 else {
92 frames_limit = min_ii(frames_limit, int(track->frames_limit));
93 }
94 }
95 }
96 }
97 }
98 *r_frames_limit = frames_limit;
99}
100
101static bool track_markers_check_direction(int backwards, int curfra, int efra)
102{
103 if (backwards) {
104 if (curfra < efra) {
105 return false;
106 }
107 }
108 else {
109 if (curfra > efra) {
110 return false;
111 }
112 }
113
114 return true;
115}
116
117static bool track_markers_initjob(bContext *C, TrackMarkersJob *tmj, bool backwards, bool sequence)
118{
121 Scene *scene = CTX_data_scene(C);
122 MovieTrackingSettings *settings = &clip->tracking.settings;
123 int frames_limit;
124 int framenr = ED_space_clip_get_clip_frame_number(sc);
125
126 track_init_markers(sc, clip, framenr, &frames_limit);
127
128 tmj->sfra = framenr;
129 tmj->clip = clip;
130 tmj->backwards = backwards;
131
132 if (sequence) {
133 if (backwards) {
134 tmj->efra = scene->r.sfra;
135 }
136 else {
137 tmj->efra = scene->r.efra;
138 }
140 }
141 else {
142 if (backwards) {
143 tmj->efra = tmj->sfra - 1;
144 }
145 else {
146 tmj->efra = tmj->sfra + 1;
147 }
148 }
149
150 /* Limit frames to be tracked by user setting. */
151 if (frames_limit) {
152 if (backwards) {
153 tmj->efra = std::max(tmj->efra, tmj->sfra - frames_limit);
154 }
155 else {
156 tmj->efra = std::min(tmj->efra, tmj->sfra + frames_limit);
157 }
158 }
159
160 if (settings->speed != TRACKING_SPEED_FASTEST) {
161 tmj->delay = 1.0f / scene->r.frs_sec * 1000.0f;
162
163 if (settings->speed == TRACKING_SPEED_HALF) {
164 tmj->delay *= 2;
165 }
166 else if (settings->speed == TRACKING_SPEED_QUARTER) {
167 tmj->delay *= 4;
168 }
169 else if (settings->speed == TRACKING_SPEED_DOUBLE) {
170 tmj->delay /= 2;
171 }
172 }
173
174 tmj->context = BKE_autotrack_context_new(clip, &sc->user, backwards);
175
176 clip->tracking_context = tmj->context;
177
178 tmj->lastfra = tmj->sfra;
179
180 /* XXX: silly to store this, but this data is needed to update scene and
181 * movie-clip numbers when tracking is finished. This introduces
182 * better feedback for artists.
183 * Maybe there's another way to solve this problem,
184 * but can't think better way at the moment.
185 * Anyway, this way isn't more unstable as animation rendering
186 * animation which uses the same approach (except storing screen).
187 */
188 tmj->scene = scene;
189 tmj->main = CTX_data_main(C);
190 tmj->screen = CTX_wm_screen(C);
191
192 tmj->wm = CTX_wm_manager(C);
193
194 if (!track_markers_check_direction(backwards, tmj->sfra, tmj->efra)) {
195 return false;
196 }
197
198 WM_set_locked_interface(tmj->wm, true);
199
200 return true;
201}
202
203static void track_markers_startjob(void *tmv, wmJobWorkerStatus *worker_status)
204{
205 TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
206 int framenr = tmj->sfra;
207
209
210 while (framenr != tmj->efra) {
211 if (tmj->delay > 0) {
212 /* Tracking should happen with fixed fps. Calculate time
213 * using current timer value before tracking frame and after.
214 *
215 * Small (and maybe unneeded optimization): do not calculate
216 * exec_time for "Fastest" tracking
217 */
218
219 double start_time = BLI_time_now_seconds(), exec_time;
220
222 break;
223 }
224
225 exec_time = BLI_time_now_seconds() - start_time;
226 if (tmj->delay > float(exec_time)) {
227 BLI_time_sleep_ms(tmj->delay - float(exec_time));
228 }
229 }
230 else if (!BKE_autotrack_context_step(tmj->context)) {
231 break;
232 }
233
234 worker_status->do_update = true;
235 worker_status->progress = float(framenr - tmj->sfra) / (tmj->efra - tmj->sfra);
236
237 if (tmj->backwards) {
238 framenr--;
239 }
240 else {
241 framenr++;
242 }
243
244 tmj->lastfra = framenr;
245
246 if (worker_status->stop || track_markers_testbreak()) {
247 break;
248 }
249 }
250}
251
252static void track_markers_updatejob(void *tmv)
253{
254 TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
256}
257
258static void track_markers_endjob(void *tmv)
259{
260 TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
261 wmWindowManager *wm = static_cast<wmWindowManager *>(tmj->main->wm.first);
262
263 tmj->clip->tracking_context = nullptr;
265 if (wm != nullptr) {
266 /* XXX */
267 // ED_update_for_newframe(tmj->main, tmj->scene);
268 }
269
272
275}
276
277static void track_markers_freejob(void *tmv)
278{
279 TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
280 tmj->clip->tracking_context = nullptr;
281 WM_set_locked_interface(tmj->wm, false);
283 MEM_freeN(tmj);
284}
285
286static int track_markers(bContext *C, wmOperator *op, bool use_job)
287{
288 TrackMarkersJob *tmj;
291 wmJob *wm_job;
292 bool backwards = RNA_boolean_get(op->ptr, "backwards");
293 bool sequence = RNA_boolean_get(op->ptr, "sequence");
294 int framenr = ED_space_clip_get_clip_frame_number(sc);
295
297 /* Only one tracking is allowed at a time. */
298 return OPERATOR_CANCELLED;
299 }
300
301 if (clip->tracking_context) {
302 return OPERATOR_CANCELLED;
303 }
304
305 if (track_count_markers(sc, clip, framenr) == 0) {
306 return OPERATOR_CANCELLED;
307 }
308
309 tmj = MEM_cnew<TrackMarkersJob>("TrackMarkersJob data");
310 if (!track_markers_initjob(C, tmj, backwards, sequence)) {
312 return OPERATOR_CANCELLED;
313 }
314
315 /* Setup job. */
316 if (use_job && sequence) {
317 wm_job = WM_jobs_get(CTX_wm_manager(C),
318 CTX_wm_window(C),
320 "Track Markers",
324
325 /* If there's delay set in tracking job, tracking should happen
326 * with fixed FPS. To deal with editor refresh we have to synchronize
327 * tracks from job and tracks in clip. Do this in timer callback
328 * to prevent threading conflicts. */
329 if (tmj->delay > 0) {
330 WM_jobs_timer(wm_job, tmj->delay / 1000.0f, NC_MOVIECLIP | NA_EVALUATED, 0);
331 }
332 else {
333 WM_jobs_timer(wm_job, 0.2, NC_MOVIECLIP | NA_EVALUATED, 0);
334 }
335
338
339 G.is_break = false;
340
341 WM_jobs_start(CTX_wm_manager(C), wm_job);
342 WM_cursor_wait(false);
343
344 /* Add modal handler for ESC. */
346
348 }
349
350 wmJobWorkerStatus worker_status = {};
351 track_markers_startjob(tmj, &worker_status);
354 return OPERATOR_FINISHED;
355}
356
358{
359 return track_markers(C, op, false);
360}
361
362static int track_markers_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
363{
364 return track_markers(C, op, true);
365}
366
367static int track_markers_modal(bContext *C, wmOperator * /*op*/, const wmEvent *event)
368{
369 /* No running tracking, remove handler and pass through. */
372 }
373
374 /* Running tracking. */
375 switch (event->type) {
376 case EVT_ESCKEY:
378 }
379
381}
382
383static std::string track_markers_get_description(bContext * /*C*/,
384 wmOperatorType * /*ot*/,
386{
387 const bool backwards = RNA_boolean_get(ptr, "backwards");
388 const bool sequence = RNA_boolean_get(ptr, "sequence");
389
390 if (backwards && sequence) {
391 return TIP_("Track the selected markers backward for the entire clip");
392 }
393 if (backwards && !sequence) {
394 return TIP_("Track the selected markers backward by one frame");
395 }
396 if (!backwards && sequence) {
397 return TIP_("Track the selected markers forward for the entire clip");
398 }
399 if (!backwards && !sequence) {
400 return TIP_("Track the selected markers forward by one frame");
401 }
402
403 /* Use default description. */
404 return "";
405}
406
408{
409 /* identifiers */
410 ot->name = "Track Markers";
411 ot->description = "Track selected markers";
412 ot->idname = "CLIP_OT_track_markers";
413
414 /* api callbacks */
420
421 /* flags */
423
424 /* properties */
425 RNA_def_boolean(ot->srna, "backwards", false, "Backwards", "Do backwards tracking");
427 "sequence",
428 false,
429 "Track Sequence",
430 "Track marker during image sequence rather than "
431 "single image");
432}
433
434/********************** Refine track position operator *********************/
435
437{
440 const MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(&clip->tracking);
441 const bool backwards = RNA_boolean_get(op->ptr, "backwards");
442 const int framenr = ED_space_clip_get_clip_frame_number(sc);
443
444 LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking_object->tracks) {
445 if (TRACK_VIEW_SELECTED(sc, track)) {
446 MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
447 BKE_tracking_refine_marker(clip, track, marker, backwards);
448 }
449 }
450
453
454 return OPERATOR_FINISHED;
455}
456
458{
459 /* identifiers */
460 ot->name = "Refine Markers";
461 ot->description =
462 "Refine selected markers positions "
463 "by running the tracker from track's reference "
464 "to current frame";
465 ot->idname = "CLIP_OT_refine_markers";
466
467 /* api callbacks */
470
471 /* flags */
473
474 /* properties */
475 RNA_def_boolean(ot->srna, "backwards", false, "Backwards", "Do backwards tracking");
476}
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.c:85
double BLI_time_now_seconds(void)
Definition time.c:65
#define TIP_(msgid)
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1085
@ TRACKING_SPEED_DOUBLE
@ TRACKING_SPEED_HALF
@ TRACKING_SPEED_FASTEST
@ TRACKING_SPEED_QUARTER
@ TRACK_HIDDEN
@ TRACK_LOCKED
@ MARKER_DISABLED
@ 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.
@ WM_JOB_TYPE_ANY
Definition WM_api.hh:1575
@ WM_JOB_TYPE_CLIP_TRACK_MARKERS
Definition WM_api.hh:1589
@ WM_JOB_PROGRESS
Definition WM_api.hh:1566
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_REGISTER
Definition WM_types.hh:160
#define NA_EVALUATED
Definition WM_types.hh:551
#define NC_MOVIECLIP
Definition WM_types.hh:364
#define NC_SCENE
Definition WM_types.hh:345
#define ND_FRAME
Definition WM_types.hh:401
draw_view in_light_buf[] float
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
#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:239
void * tracking_context
struct RenderData r
struct MovieClipUser user
wmWindowManager * wm
AutoTrackContext * context
short type
Definition WM_types.hh:722
const char * name
Definition WM_types.hh:990
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
std::string(* get_description)(bContext *C, wmOperatorType *ot, PointerRNA *ptr)
Definition WM_types.hh:1074
const char * idname
Definition WM_types.hh:992
int(* modal)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1036
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1022
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1006
const char * description
Definition WM_types.hh:996
StructRNA * srna
Definition WM_types.hh:1080
struct PointerRNA * ptr
void clip_tracking_clear_invisible_track_selection(SpaceClip *sc, MovieClip *clip)
static void track_markers_endjob(void *tmv)
static bool track_markers_check_direction(int backwards, int curfra, int efra)
static int track_markers_invoke(bContext *C, wmOperator *op, const wmEvent *)
void CLIP_OT_track_markers(wmOperatorType *ot)
static int refine_marker_exec(bContext *C, wmOperator *op)
static int track_markers_modal(bContext *C, wmOperator *, const wmEvent *event)
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 int track_markers(bContext *C, wmOperator *op, bool use_job)
static int track_markers_exec(bContext *C, wmOperator *op)
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 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_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)
void WM_set_locked_interface(wmWindowManager *wm, bool lock)
@ EVT_ESCKEY
PointerRNA * ptr
Definition wm_files.cc:4126
wmOperatorType * ot
Definition wm_files.cc:4125
void WM_jobs_timer(wmJob *wm_job, double time_step, uint note, uint endnote)
Definition wm_jobs.cc:352
void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
Definition wm_jobs.cc:455
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:189
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:364
bool WM_jobs_test(const wmWindowManager *wm, const void *owner, int job_type)
Definition wm_jobs.cc:223
void WM_jobs_customdata_set(wmJob *wm_job, void *customdata, void(*free)(void *customdata))
Definition wm_jobs.cc:336