Blender  V2.93
tracking_ops_track.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2016 Blender Foundation.
17  * All rights reserved.
18  */
19 
24 #include "MEM_guardedalloc.h"
25 
26 #include "BLI_math.h"
27 #include "BLI_string.h"
28 #include "BLI_utildefines.h"
29 
30 #include "BLT_translation.h"
31 
32 #include "BKE_context.h"
33 #include "BKE_global.h"
34 #include "BKE_main.h"
35 #include "BKE_movieclip.h"
36 #include "BKE_tracking.h"
37 
38 #include "WM_api.h"
39 #include "WM_types.h"
40 
41 #include "ED_clip.h"
42 #include "ED_screen.h"
43 
44 #include "RNA_access.h"
45 #include "RNA_define.h"
46 
47 #include "PIL_time.h"
48 
49 #include "DEG_depsgraph.h"
50 
51 #include "clip_intern.h" /* own include */
52 #include "tracking_ops_intern.h"
53 
54 /********************** Track operator *********************/
55 
56 typedef struct TrackMarkersJob {
57  struct AutoTrackContext *context; /* Tracking context */
58  int sfra, efra, lastfra; /* Start, end and recently tracked frames */
59  int backwards; /* Backwards tracking flag */
60  MovieClip *clip; /* Clip which is tracking */
61  float delay; /* Delay in milliseconds to allow
62  * tracking at fixed FPS */
63 
65  struct Main *main;
66  struct Scene *scene;
67  struct bScreen *screen;
69 
70 static bool track_markers_testbreak(void)
71 {
72  return G.is_break;
73 }
74 
75 static int track_count_markers(SpaceClip *sc, MovieClip *clip, int framenr)
76 {
77  int tot = 0;
78  ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
79  for (MovieTrackingTrack *track = tracksbase->first; track != NULL; track = track->next) {
80  bool selected = (sc != NULL) ? TRACK_VIEW_SELECTED(sc, track) : TRACK_SELECTED(track);
81  if (selected && (track->flag & TRACK_LOCKED) == 0) {
82  MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
83  if (!marker || (marker->flag & MARKER_DISABLED) == 0) {
84  tot++;
85  }
86  }
87  }
88  return tot;
89 }
90 
91 static void track_init_markers(SpaceClip *sc, MovieClip *clip, int framenr, int *r_frames_limit)
92 {
93  ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
94  int frames_limit = 0;
95  if (sc != NULL) {
97  }
98  for (MovieTrackingTrack *track = tracksbase->first; track != NULL; track = track->next) {
99  bool selected = (sc != NULL) ? TRACK_VIEW_SELECTED(sc, track) : TRACK_SELECTED(track);
100  if (selected) {
101  if ((track->flag & TRACK_HIDDEN) == 0 && (track->flag & TRACK_LOCKED) == 0) {
102  BKE_tracking_marker_ensure(track, framenr);
103  if (track->frames_limit) {
104  if (frames_limit == 0) {
105  frames_limit = track->frames_limit;
106  }
107  else {
108  frames_limit = min_ii(frames_limit, (int)track->frames_limit);
109  }
110  }
111  }
112  }
113  }
114  *r_frames_limit = frames_limit;
115 }
116 
117 static bool track_markers_check_direction(int backwards, int curfra, int efra)
118 {
119  if (backwards) {
120  if (curfra < efra) {
121  return false;
122  }
123  }
124  else {
125  if (curfra > efra) {
126  return false;
127  }
128  }
129 
130  return true;
131 }
132 
133 static bool track_markers_initjob(bContext *C, TrackMarkersJob *tmj, bool backwards, bool sequence)
134 {
136  MovieClip *clip = ED_space_clip_get_clip(sc);
138  MovieTrackingSettings *settings = &clip->tracking.settings;
139  int frames_limit;
140  int framenr = ED_space_clip_get_clip_frame_number(sc);
141 
142  track_init_markers(sc, clip, framenr, &frames_limit);
143 
144  tmj->sfra = framenr;
145  tmj->clip = clip;
146  tmj->backwards = backwards;
147 
148  if (sequence) {
149  if (backwards) {
150  tmj->efra = SFRA;
151  }
152  else {
153  tmj->efra = EFRA;
154  }
156  }
157  else {
158  if (backwards) {
159  tmj->efra = tmj->sfra - 1;
160  }
161  else {
162  tmj->efra = tmj->sfra + 1;
163  }
164  }
165 
166  /* Limit frames to be tracked by user setting. */
167  if (frames_limit) {
168  if (backwards) {
169  tmj->efra = MAX2(tmj->efra, tmj->sfra - frames_limit);
170  }
171  else {
172  tmj->efra = MIN2(tmj->efra, tmj->sfra + frames_limit);
173  }
174  }
175 
176  if (settings->speed != TRACKING_SPEED_FASTEST) {
177  tmj->delay = 1.0f / scene->r.frs_sec * 1000.0f;
178 
179  if (settings->speed == TRACKING_SPEED_HALF) {
180  tmj->delay *= 2;
181  }
182  else if (settings->speed == TRACKING_SPEED_QUARTER) {
183  tmj->delay *= 4;
184  }
185  else if (settings->speed == TRACKING_SPEED_DOUBLE) {
186  tmj->delay /= 2;
187  }
188  }
189 
190  tmj->context = BKE_autotrack_context_new(clip, &sc->user, backwards);
191 
192  clip->tracking_context = tmj->context;
193 
194  tmj->lastfra = tmj->sfra;
195 
196  /* XXX: silly to store this, but this data is needed to update scene and
197  * movie-clip numbers when tracking is finished. This introduces
198  * better feedback for artists.
199  * Maybe there's another way to solve this problem, but can't think
200  * better way atm.
201  * Anyway, this way isn't more unstable as animation rendering
202  * animation which uses the same approach (except storing screen).
203  */
204  tmj->scene = scene;
205  tmj->main = CTX_data_main(C);
206  tmj->screen = CTX_wm_screen(C);
207 
208  tmj->wm = CTX_wm_manager(C);
209 
210  if (!track_markers_check_direction(backwards, tmj->sfra, tmj->efra)) {
211  return false;
212  }
213 
214  WM_set_locked_interface(tmj->wm, true);
215 
216  return true;
217 }
218 
220  void *tmv,
221  /* Cannot be const, this function implements wm_jobs_start_callback.
222  * NOLINTNEXTLINE: readability-non-const-parameter. */
223  short *stop,
224  short *do_update,
225  float *progress)
226 {
227  TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
228  int framenr = tmj->sfra;
229 
230  while (framenr != tmj->efra) {
231  if (tmj->delay > 0) {
232  /* Tracking should happen with fixed fps. Calculate time
233  * using current timer value before tracking frame and after.
234  *
235  * Small (and maybe unneeded optimization): do not calculate
236  * exec_time for "Fastest" tracking
237  */
238 
239  double start_time = PIL_check_seconds_timer(), exec_time;
240 
241  if (!BKE_autotrack_context_step(tmj->context)) {
242  break;
243  }
244 
245  exec_time = PIL_check_seconds_timer() - start_time;
246  if (tmj->delay > (float)exec_time) {
247  PIL_sleep_ms(tmj->delay - (float)exec_time);
248  }
249  }
250  else if (!BKE_autotrack_context_step(tmj->context)) {
251  break;
252  }
253 
254  *do_update = true;
255  *progress = (float)(framenr - tmj->sfra) / (tmj->efra - tmj->sfra);
256 
257  if (tmj->backwards) {
258  framenr--;
259  }
260  else {
261  framenr++;
262  }
263 
264  tmj->lastfra = framenr;
265 
266  if (*stop || track_markers_testbreak()) {
267  break;
268  }
269  }
270 }
271 
272 static void track_markers_updatejob(void *tmv)
273 {
274  TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
276 }
277 
278 static void track_markers_endjob(void *tmv)
279 {
280  TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
281  wmWindowManager *wm = tmj->main->wm.first;
282 
283  tmj->clip->tracking_context = NULL;
285  if (wm != NULL) {
286  /* XXX */
287  // ED_update_for_newframe(tmj->main, tmj->scene);
288  }
289 
292 
295 }
296 
297 static void track_markers_freejob(void *tmv)
298 {
299  TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
300  tmj->clip->tracking_context = NULL;
301  WM_set_locked_interface(tmj->wm, false);
303  MEM_freeN(tmj);
304 }
305 
306 static int track_markers(bContext *C, wmOperator *op, bool use_job)
307 {
308  TrackMarkersJob *tmj;
310  MovieClip *clip = ED_space_clip_get_clip(sc);
311  wmJob *wm_job;
312  bool backwards = RNA_boolean_get(op->ptr, "backwards");
313  bool sequence = RNA_boolean_get(op->ptr, "sequence");
314  int framenr = ED_space_clip_get_clip_frame_number(sc);
315 
317  /* Only one tracking is allowed at a time. */
318  return OPERATOR_CANCELLED;
319  }
320 
321  if (clip->tracking_context) {
322  return OPERATOR_CANCELLED;
323  }
324 
325  if (track_count_markers(sc, clip, framenr) == 0) {
326  return OPERATOR_CANCELLED;
327  }
328 
329  tmj = MEM_callocN(sizeof(TrackMarkersJob), "TrackMarkersJob data");
330  if (!track_markers_initjob(C, tmj, backwards, sequence)) {
332  return OPERATOR_CANCELLED;
333  }
334 
335  /* Setup job. */
336  if (use_job && sequence) {
337  wm_job = WM_jobs_get(CTX_wm_manager(C),
338  CTX_wm_window(C),
339  CTX_data_scene(C),
340  "Track Markers",
344 
345  /* If there's delay set in tracking job, tracking should happen
346  * with fixed FPS. To deal with editor refresh we have to synchronize
347  * tracks from job and tracks in clip. Do this in timer callback
348  * to prevent threading conflicts. */
349  if (tmj->delay > 0) {
350  WM_jobs_timer(wm_job, tmj->delay / 1000.0f, NC_MOVIECLIP | NA_EVALUATED, 0);
351  }
352  else {
353  WM_jobs_timer(wm_job, 0.2, NC_MOVIECLIP | NA_EVALUATED, 0);
354  }
355 
358 
359  G.is_break = false;
360 
361  WM_jobs_start(CTX_wm_manager(C), wm_job);
362  WM_cursor_wait(false);
363 
364  /* Add modal handler for ESC. */
366 
367  return OPERATOR_RUNNING_MODAL;
368  }
369 
370  short stop = 0, do_update = 0;
371  float progress = 0.0f;
372  track_markers_startjob(tmj, &stop, &do_update, &progress);
375  return OPERATOR_FINISHED;
376 }
377 
379 {
380  return track_markers(C, op, false);
381 }
382 
383 static int track_markers_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
384 {
385  return track_markers(C, op, true);
386 }
387 
388 static int track_markers_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
389 {
390  /* No running tracking, remove handler and pass through. */
393  }
394 
395  /* Running tracking. */
396  switch (event->type) {
397  case EVT_ESCKEY:
398  return OPERATOR_RUNNING_MODAL;
399  }
400 
401  return OPERATOR_PASS_THROUGH;
402 }
403 
405 {
406  const bool backwards = RNA_boolean_get(ptr, "backwards");
407  const bool sequence = RNA_boolean_get(ptr, "sequence");
408 
409  if (backwards && sequence) {
410  return BLI_strdup(TIP_("Track the selected markers backward for the entire clip"));
411  }
412  if (backwards && !sequence) {
413  return BLI_strdup(TIP_("Track the selected markers backward by one frame"));
414  }
415  if (!backwards && sequence) {
416  return BLI_strdup(TIP_("Track the selected markers forward for the entire clip"));
417  }
418  if (!backwards && !sequence) {
419  return BLI_strdup(TIP_("Track the selected markers forward by one frame"));
420  }
421 
422  /* Use default description. */
423  return NULL;
424 }
425 
427 {
428  /* identifiers */
429  ot->name = "Track Markers";
430  ot->description = "Track selected markers";
431  ot->idname = "CLIP_OT_track_markers";
432 
433  /* api callbacks */
439 
440  /* flags */
441  ot->flag = OPTYPE_UNDO;
442 
443  /* properties */
444  RNA_def_boolean(ot->srna, "backwards", 0, "Backwards", "Do backwards tracking");
446  "sequence",
447  0,
448  "Track Sequence",
449  "Track marker during image sequence rather than "
450  "single image");
451 }
452 
453 /********************** Refine track position operator *********************/
454 
456 {
458  MovieClip *clip = ED_space_clip_get_clip(sc);
459  MovieTracking *tracking = &clip->tracking;
460  ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
461  bool backwards = RNA_boolean_get(op->ptr, "backwards");
462  int framenr = ED_space_clip_get_clip_frame_number(sc);
463 
464  for (MovieTrackingTrack *track = tracksbase->first; track != NULL; track = track->next) {
465  if (TRACK_VIEW_SELECTED(sc, track)) {
466  MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
467  BKE_tracking_refine_marker(clip, track, marker, backwards);
468  }
469  }
470 
473 
474  return OPERATOR_FINISHED;
475 }
476 
478 {
479  /* identifiers */
480  ot->name = "Refine Markers";
481  ot->description =
482  "Refine selected markers positions "
483  "by running the tracker from track's reference "
484  "to current frame";
485  ot->idname = "CLIP_OT_refine_markers";
486 
487  /* api callbacks */
490 
491  /* flags */
493 
494  /* properties */
495  RNA_def_boolean(ot->srna, "backwards", 0, "Backwards", "Do backwards tracking");
496 }
typedef float(TangentPoint)[2]
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1034
struct SpaceClip * CTX_wm_space_clip(const bContext *C)
Definition: context.c:899
struct wmWindowManager * CTX_wm_manager(const bContext *C)
Definition: context.c:689
struct bScreen * CTX_wm_screen(const bContext *C)
Definition: context.c:709
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1018
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:699
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:365
bool BKE_autotrack_context_step(struct AutoTrackContext *context)
struct AutoTrackContext * BKE_autotrack_context_new(struct MovieClip *clip, struct MovieClipUser *user, const bool is_backwards)
#define TRACK_SELECTED(track)
Definition: BKE_tracking.h:489
struct MovieTrackingMarker * BKE_tracking_marker_ensure(struct MovieTrackingTrack *track, int framenr)
Definition: tracking.c:1567
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:497
void BKE_autotrack_context_sync(struct AutoTrackContext *context)
struct MovieTrackingMarker * BKE_tracking_marker_get(struct MovieTrackingTrack *track, int framenr)
Definition: tracking.c:1523
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:70
#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:654
#define SFRA
#define EFRA
@ TRACK_HIDDEN
@ TRACK_LOCKED
@ TRACKING_SPEED_DOUBLE
@ TRACKING_SPEED_HALF
@ TRACKING_SPEED_FASTEST
@ TRACKING_SPEED_QUARTER
@ MARKER_DISABLED
@ 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:227
bool ED_space_clip_tracking_poll(struct bContext *C)
Definition: clip_editor.c:98
struct MovieClip * ED_space_clip_get_clip(struct SpaceClip *sc)
Definition: clip_editor.c:572
Read Guarded memory(de)allocation.
Platform independent time functions.
#define C
Definition: RandGen.cpp:39
@ WM_JOB_TYPE_ANY
Definition: WM_api.h:734
@ WM_JOB_TYPE_CLIP_TRACK_MARKERS
Definition: WM_api.h:744
@ WM_JOB_PROGRESS
Definition: WM_api.h:726
@ OPTYPE_UNDO
Definition: WM_types.h:155
@ OPTYPE_REGISTER
Definition: WM_types.h:153
#define NA_EVALUATED
Definition: WM_types.h:463
#define NC_MOVIECLIP
Definition: WM_types.h:298
#define NC_SCENE
Definition: WM_types.h:279
#define ND_FRAME
Definition: WM_types.h:334
Scene scene
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6261
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3481
void * first
Definition: DNA_listBase.h:47
Definition: BKE_main.h:116
ListBase wm
Definition: BKE_main.h:175
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:577
Definition: wm_jobs.c:73
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:752
const char * name
Definition: WM_types.h:721
int(* modal)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:768
const char * idname
Definition: WM_types.h:723
char *(* get_description)(struct bContext *C, struct wmOperatorType *, struct PointerRNA *)
Definition: WM_types.h:799
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:776
struct StructRNA * srna
Definition: WM_types.h:802
const char * description
Definition: WM_types.h:726
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:736
struct PointerRNA * ptr
void PIL_sleep_ms(int ms)
Definition: time.c:100
double PIL_check_seconds_timer(void)
Definition: time.c:80
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)
#define G(x, y, z)
void WM_cursor_wait(bool val)
Definition: wm_cursors.c:226
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:3157
wmOperatorType * ot
Definition: wm_files.c:3156
void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
Definition: wm_jobs.c:450
wmJob * WM_jobs_get(wmWindowManager *wm, wmWindow *win, void *owner, const char *name, int flag, int job_type)
Definition: wm_jobs.c:196
bool WM_jobs_test(wmWindowManager *wm, void *owner, int job_type)
Definition: wm_jobs.c:223
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:372
void WM_jobs_customdata_set(wmJob *wm_job, void *customdata, void(*free)(void *))
Definition: wm_jobs.c:344
void WM_jobs_timer(wmJob *wm_job, double timestep, unsigned int note, unsigned int endnote)
Definition: wm_jobs.c:360