Blender  V3.3
tracking_ops_track.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2016 Blender Foundation. All rights reserved. */
3 
8 #include "MEM_guardedalloc.h"
9 
10 #include "BLI_math.h"
11 #include "BLI_string.h"
12 #include "BLI_utildefines.h"
13 
14 #include "BLT_translation.h"
15 
16 #include "BKE_context.h"
17 #include "BKE_global.h"
18 #include "BKE_main.h"
19 #include "BKE_movieclip.h"
20 #include "BKE_tracking.h"
21 
22 #include "WM_api.h"
23 #include "WM_types.h"
24 
25 #include "ED_clip.h"
26 #include "ED_screen.h"
27 
28 #include "RNA_access.h"
29 #include "RNA_define.h"
30 
31 #include "PIL_time.h"
32 
33 #include "DEG_depsgraph.h"
34 
35 #include "clip_intern.h" /* own include */
36 #include "tracking_ops_intern.h"
37 
38 /********************** Track operator *********************/
39 
40 typedef struct TrackMarkersJob {
41  struct AutoTrackContext *context; /* Tracking context */
42  int sfra, efra, lastfra; /* Start, end and recently tracked frames */
43  int backwards; /* Backwards tracking flag */
44  MovieClip *clip; /* Clip which is tracking */
45  float delay; /* Delay in milliseconds to allow
46  * tracking at fixed FPS */
47 
49  struct Main *main;
50  struct Scene *scene;
51  struct bScreen *screen;
53 
54 static bool track_markers_testbreak(void)
55 {
56  return G.is_break;
57 }
58 
59 static int track_count_markers(SpaceClip *sc, MovieClip *clip, int framenr)
60 {
61  int tot = 0;
62  ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
63  for (MovieTrackingTrack *track = tracksbase->first; track != NULL; track = track->next) {
64  bool selected = (sc != NULL) ? TRACK_VIEW_SELECTED(sc, track) : TRACK_SELECTED(track);
65  if (selected && (track->flag & TRACK_LOCKED) == 0) {
66  MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
67  if (!marker || (marker->flag & MARKER_DISABLED) == 0) {
68  tot++;
69  }
70  }
71  }
72  return tot;
73 }
74 
75 static void track_init_markers(SpaceClip *sc, MovieClip *clip, int framenr, int *r_frames_limit)
76 {
77  ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
78  int frames_limit = 0;
79  if (sc != NULL) {
81  }
82  for (MovieTrackingTrack *track = tracksbase->first; track != NULL; track = track->next) {
83  bool selected = (sc != NULL) ? 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 
101 static 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 
117 static bool track_markers_initjob(bContext *C, TrackMarkersJob *tmj, bool backwards, bool sequence)
118 {
120  MovieClip *clip = ED_space_clip_get_clip(sc);
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 = MAX2(tmj->efra, tmj->sfra - frames_limit);
154  }
155  else {
156  tmj->efra = MIN2(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 
204  void *tmv,
205  /* Cannot be const, this function implements wm_jobs_start_callback.
206  * NOLINTNEXTLINE: readability-non-const-parameter. */
207  short *stop,
208  short *do_update,
209  float *progress)
210 {
211  TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
212  int framenr = tmj->sfra;
213 
215 
216  while (framenr != tmj->efra) {
217  if (tmj->delay > 0) {
218  /* Tracking should happen with fixed fps. Calculate time
219  * using current timer value before tracking frame and after.
220  *
221  * Small (and maybe unneeded optimization): do not calculate
222  * exec_time for "Fastest" tracking
223  */
224 
225  double start_time = PIL_check_seconds_timer(), exec_time;
226 
227  if (!BKE_autotrack_context_step(tmj->context)) {
228  break;
229  }
230 
231  exec_time = PIL_check_seconds_timer() - start_time;
232  if (tmj->delay > (float)exec_time) {
233  PIL_sleep_ms(tmj->delay - (float)exec_time);
234  }
235  }
236  else if (!BKE_autotrack_context_step(tmj->context)) {
237  break;
238  }
239 
240  *do_update = true;
241  *progress = (float)(framenr - tmj->sfra) / (tmj->efra - tmj->sfra);
242 
243  if (tmj->backwards) {
244  framenr--;
245  }
246  else {
247  framenr++;
248  }
249 
250  tmj->lastfra = framenr;
251 
252  if (*stop || track_markers_testbreak()) {
253  break;
254  }
255  }
256 }
257 
258 static void track_markers_updatejob(void *tmv)
259 {
260  TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
262 }
263 
264 static void track_markers_endjob(void *tmv)
265 {
266  TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
267  wmWindowManager *wm = tmj->main->wm.first;
268 
269  tmj->clip->tracking_context = NULL;
271  if (wm != NULL) {
272  /* XXX */
273  // ED_update_for_newframe(tmj->main, tmj->scene);
274  }
275 
278 
281 }
282 
283 static void track_markers_freejob(void *tmv)
284 {
285  TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
286  tmj->clip->tracking_context = NULL;
287  WM_set_locked_interface(tmj->wm, false);
289  MEM_freeN(tmj);
290 }
291 
292 static int track_markers(bContext *C, wmOperator *op, bool use_job)
293 {
294  TrackMarkersJob *tmj;
296  MovieClip *clip = ED_space_clip_get_clip(sc);
297  wmJob *wm_job;
298  bool backwards = RNA_boolean_get(op->ptr, "backwards");
299  bool sequence = RNA_boolean_get(op->ptr, "sequence");
300  int framenr = ED_space_clip_get_clip_frame_number(sc);
301 
303  /* Only one tracking is allowed at a time. */
304  return OPERATOR_CANCELLED;
305  }
306 
307  if (clip->tracking_context) {
308  return OPERATOR_CANCELLED;
309  }
310 
311  if (track_count_markers(sc, clip, framenr) == 0) {
312  return OPERATOR_CANCELLED;
313  }
314 
315  tmj = MEM_callocN(sizeof(TrackMarkersJob), "TrackMarkersJob data");
316  if (!track_markers_initjob(C, tmj, backwards, sequence)) {
318  return OPERATOR_CANCELLED;
319  }
320 
321  /* Setup job. */
322  if (use_job && sequence) {
323  wm_job = WM_jobs_get(CTX_wm_manager(C),
324  CTX_wm_window(C),
325  CTX_data_scene(C),
326  "Track Markers",
330 
331  /* If there's delay set in tracking job, tracking should happen
332  * with fixed FPS. To deal with editor refresh we have to synchronize
333  * tracks from job and tracks in clip. Do this in timer callback
334  * to prevent threading conflicts. */
335  if (tmj->delay > 0) {
336  WM_jobs_timer(wm_job, tmj->delay / 1000.0f, NC_MOVIECLIP | NA_EVALUATED, 0);
337  }
338  else {
339  WM_jobs_timer(wm_job, 0.2, NC_MOVIECLIP | NA_EVALUATED, 0);
340  }
341 
344 
345  G.is_break = false;
346 
347  WM_jobs_start(CTX_wm_manager(C), wm_job);
348  WM_cursor_wait(false);
349 
350  /* Add modal handler for ESC. */
352 
353  return OPERATOR_RUNNING_MODAL;
354  }
355 
356  short stop = 0, do_update = 0;
357  float progress = 0.0f;
358  track_markers_startjob(tmj, &stop, &do_update, &progress);
361  return OPERATOR_FINISHED;
362 }
363 
365 {
366  return track_markers(C, op, false);
367 }
368 
369 static int track_markers_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
370 {
371  return track_markers(C, op, true);
372 }
373 
374 static int track_markers_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
375 {
376  /* No running tracking, remove handler and pass through. */
379  }
380 
381  /* Running tracking. */
382  switch (event->type) {
383  case EVT_ESCKEY:
384  return OPERATOR_RUNNING_MODAL;
385  }
386 
387  return OPERATOR_PASS_THROUGH;
388 }
389 
391 {
392  const bool backwards = RNA_boolean_get(ptr, "backwards");
393  const bool sequence = RNA_boolean_get(ptr, "sequence");
394 
395  if (backwards && sequence) {
396  return BLI_strdup(TIP_("Track the selected markers backward for the entire clip"));
397  }
398  if (backwards && !sequence) {
399  return BLI_strdup(TIP_("Track the selected markers backward by one frame"));
400  }
401  if (!backwards && sequence) {
402  return BLI_strdup(TIP_("Track the selected markers forward for the entire clip"));
403  }
404  if (!backwards && !sequence) {
405  return BLI_strdup(TIP_("Track the selected markers forward by one frame"));
406  }
407 
408  /* Use default description. */
409  return NULL;
410 }
411 
413 {
414  /* identifiers */
415  ot->name = "Track Markers";
416  ot->description = "Track selected markers";
417  ot->idname = "CLIP_OT_track_markers";
418 
419  /* api callbacks */
425 
426  /* flags */
427  ot->flag = OPTYPE_UNDO;
428 
429  /* properties */
430  RNA_def_boolean(ot->srna, "backwards", 0, "Backwards", "Do backwards tracking");
432  "sequence",
433  0,
434  "Track Sequence",
435  "Track marker during image sequence rather than "
436  "single image");
437 }
438 
439 /********************** Refine track position operator *********************/
440 
442 {
444  MovieClip *clip = ED_space_clip_get_clip(sc);
445  MovieTracking *tracking = &clip->tracking;
446  ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
447  bool backwards = RNA_boolean_get(op->ptr, "backwards");
448  int framenr = ED_space_clip_get_clip_frame_number(sc);
449 
450  for (MovieTrackingTrack *track = tracksbase->first; track != NULL; track = track->next) {
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 */
476 
477  /* flags */
479 
480  /* properties */
481  RNA_def_boolean(ot->srna, "backwards", 0, "Backwards", "Do backwards tracking");
482 }
typedef float(TangentPoint)[2]
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1090
struct SpaceClip * CTX_wm_space_clip(const bContext *C)
Definition: context.c:923
struct wmWindowManager * CTX_wm_manager(const bContext *C)
Definition: context.c:713
struct bScreen * CTX_wm_screen(const bContext *C)
Definition: context.c:733
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1074
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:723
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)
void BKE_autotrack_context_finish(struct AutoTrackContext *context)
struct ListBase * BKE_tracking_get_active_tracks(struct MovieTracking *tracking)
Definition: tracking.c:346
bool BKE_autotrack_context_step(struct AutoTrackContext *context)
struct AutoTrackContext * BKE_autotrack_context_new(struct MovieClip *clip, struct MovieClipUser *user, bool is_backwards)
#define TRACK_SELECTED(track)
Definition: BKE_tracking.h:823
struct MovieTrackingMarker * BKE_tracking_marker_ensure(struct MovieTrackingTrack *track, int framenr)
Definition: tracking.c:1468
void BKE_autotrack_context_free(struct AutoTrackContext *context)
void BKE_tracking_refine_marker(struct MovieClip *clip, struct MovieTrackingTrack *track, struct MovieTrackingMarker *marker, bool backwards)
#define TRACK_VIEW_SELECTED(sc, track)
Definition: BKE_tracking.h:831
void BKE_autotrack_context_start(struct AutoTrackContext *context)
void BKE_autotrack_context_sync(struct AutoTrackContext *context)
struct MovieTrackingMarker * BKE_tracking_marker_get(struct MovieTrackingTrack *track, int framenr)
Definition: tracking.c:1424
MINLINE int min_ii(int a, int b)
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL() ATTR_MALLOC
Definition: string.c:42
#define UNUSED(x)
#define MAX2(a, b)
#define MIN2(a, b)
#define TIP_(msgid)
void DEG_id_tag_update(struct ID *id, int flag)
@ ID_RECALC_COPY_ON_WRITE
Definition: DNA_ID.h:834
@ TRACKING_SPEED_DOUBLE
@ TRACKING_SPEED_HALF
@ TRACKING_SPEED_FASTEST
@ TRACKING_SPEED_QUARTER
@ MARKER_DISABLED
@ TRACK_HIDDEN
@ TRACK_LOCKED
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
int ED_space_clip_get_clip_frame_number(struct SpaceClip *sc)
Definition: clip_editor.c:231
bool ED_space_clip_tracking_poll(struct bContext *C)
Definition: clip_editor.c:83
struct MovieClip * ED_space_clip_get_clip(struct SpaceClip *sc)
Definition: clip_editor.c:570
Read Guarded memory(de)allocation.
Platform independent time functions.
#define C
Definition: RandGen.cpp:25
@ WM_JOB_PROGRESS
Definition: WM_api.h:1339
@ WM_JOB_TYPE_ANY
Definition: WM_api.h:1347
@ WM_JOB_TYPE_CLIP_TRACK_MARKERS
Definition: WM_api.h:1359
@ OPTYPE_UNDO
Definition: WM_types.h:148
@ OPTYPE_REGISTER
Definition: WM_types.h:146
#define NA_EVALUATED
Definition: WM_types.h:524
#define NC_MOVIECLIP
Definition: WM_types.h:347
#define NC_SCENE
Definition: WM_types.h:328
#define ND_FRAME
Definition: WM_types.h:382
Scene scene
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
#define G(x, y, z)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4863
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3493
void * first
Definition: DNA_listBase.h:31
Definition: BKE_main.h:121
ListBase wm
Definition: BKE_main.h:197
void * tracking_context
struct MovieTracking tracking
MovieTrackingSettings settings
struct RenderData r
struct MovieClipUser user
struct bScreen * screen
struct wmWindowManager * wm
struct Scene * scene
struct AutoTrackContext * context
struct Main * main
short type
Definition: WM_types.h:678
Definition: wm_jobs.c:57
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:919
const char * name
Definition: WM_types.h:888
int(* modal)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:935
const char * idname
Definition: WM_types.h:890
char *(* get_description)(struct bContext *C, struct wmOperatorType *, struct PointerRNA *)
Definition: WM_types.h:966
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:943
struct StructRNA * srna
Definition: WM_types.h:969
const char * description
Definition: WM_types.h:893
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:903
struct PointerRNA * ptr
void PIL_sleep_ms(int ms)
Definition: time.c:84
double PIL_check_seconds_timer(void)
Definition: time.c:64
void clip_tracking_clear_invisible_track_selection(struct SpaceClip *sc, struct MovieClip *clip)
struct TrackMarkersJob TrackMarkersJob
static void track_markers_startjob(void *tmv, short *stop, short *do_update, float *progress)
static void track_markers_endjob(void *tmv)
static bool track_markers_check_direction(int backwards, int curfra, int efra)
void CLIP_OT_track_markers(wmOperatorType *ot)
static int refine_marker_exec(bContext *C, wmOperator *op)
static int track_markers_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
static void track_markers_updatejob(void *tmv)
static int track_count_markers(SpaceClip *sc, MovieClip *clip, int framenr)
static bool track_markers_testbreak(void)
static int track_markers_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
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 void track_init_markers(SpaceClip *sc, MovieClip *clip, int framenr, int *r_frames_limit)
void CLIP_OT_refine_markers(wmOperatorType *ot)
static void track_markers_freejob(void *tmv)
static char * track_markers_desc(bContext *UNUSED(C), wmOperatorType *UNUSED(op), PointerRNA *ptr)
void WM_cursor_wait(bool val)
Definition: wm_cursors.c:209
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_main_add_notifier(unsigned int type, void *reference)
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.c:3480
wmOperatorType * ot
Definition: wm_files.c:3479
void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
Definition: wm_jobs.c:437
void WM_jobs_callbacks(wmJob *wm_job, wm_jobs_start_callback startjob, void(*initjob)(void *), void(*update)(void *), void(*endjob)(void *))
Definition: wm_jobs.c:351
bool WM_jobs_test(const wmWindowManager *wm, const void *owner, int job_type)
Definition: wm_jobs.c:214
void WM_jobs_customdata_set(wmJob *wm_job, void *customdata, void(*free)(void *))
Definition: wm_jobs.c:323
void WM_jobs_timer(wmJob *wm_job, double timestep, unsigned int note, unsigned int endnote)
Definition: wm_jobs.c:339
wmJob * WM_jobs_get(wmWindowManager *wm, wmWindow *win, const void *owner, const char *name, int flag, int job_type)
Definition: wm_jobs.c:184