Cleanup: style, use braces for blenkernel
[blender.git] / source / blender / blenkernel / intern / tracking_util.c
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) 2011 Blender Foundation.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup bke
22  *
23  * This file contains implementation of function which are used
24  * by multiple tracking files but which should not be public.
25  */
26
27 #include <stddef.h>
28
29 #include "MEM_guardedalloc.h"
30
31 #include "DNA_movieclip_types.h"
32
33 #include "BLI_utildefines.h"
34 #include "BLI_math.h"
35 #include "BLI_listbase.h"
36 #include "BLI_ghash.h"
37 #include "BLI_string.h"
38 #include "BLI_string_utils.h"
39
40 #include "BLT_translation.h"
41
42 #include "BKE_movieclip.h"
43 #include "BKE_tracking.h"
44
45 #include "IMB_imbuf_types.h"
46 #include "IMB_imbuf.h"
47 #include "IMB_moviecache.h"
48
49 #include "tracking_private.h"
50
51 #include "libmv-capi.h"
52
53 /* Uncomment this to have caching-specific debug prints. */
54 // #define DEBUG_CACHE
55
56 #ifdef DEBUG_CACHE
57 #  define CACHE_PRINTF(...) printf(__VA_ARGS__)
58 #else
59 #  define CACHE_PRINTF(...)
60 #endif
61
62 /*********************** Tracks map *************************/
63
64 TracksMap *tracks_map_new(const char *object_name,
65                           bool is_camera,
66                           int num_tracks,
67                           int customdata_size)
68 {
69   TracksMap *map = MEM_callocN(sizeof(TracksMap), "TrackingsMap");
70
71   BLI_strncpy(map->object_name, object_name, sizeof(map->object_name));
72   map->is_camera = is_camera;
73
74   map->num_tracks = num_tracks;
75   map->customdata_size = customdata_size;
76
77   map->tracks = MEM_callocN(sizeof(MovieTrackingTrack) * num_tracks, "TrackingsMap tracks");
78
79   if (customdata_size) {
80     map->customdata = MEM_callocN(customdata_size * num_tracks, "TracksMap customdata");
81   }
82
83   map->hash = BLI_ghash_ptr_new("TracksMap hash");
84
85   BLI_spin_init(&map->spin_lock);
86
87   return map;
88 }
89
90 int tracks_map_get_size(TracksMap *map)
91 {
92   return map->num_tracks;
93 }
94
95 void tracks_map_get_indexed_element(TracksMap *map,
96                                     int index,
97                                     MovieTrackingTrack **track,
98                                     void **customdata)
99 {
100   *track = &map->tracks[index];
101
102   if (map->customdata) {
103     *customdata = &map->customdata[index * map->customdata_size];
104   }
105 }
106
107 void tracks_map_insert(TracksMap *map, MovieTrackingTrack *track, void *customdata)
108 {
109   MovieTrackingTrack new_track = *track;
110
111   new_track.markers = MEM_dupallocN(new_track.markers);
112
113   map->tracks[map->ptr] = new_track;
114
115   if (customdata) {
116     memcpy(&map->customdata[map->ptr * map->customdata_size], customdata, map->customdata_size);
117   }
118
119   BLI_ghash_insert(map->hash, &map->tracks[map->ptr], track);
120
121   map->ptr++;
122 }
123
124 void tracks_map_merge(TracksMap *map, MovieTracking *tracking)
125 {
126   MovieTrackingTrack *track;
127   ListBase tracks = {NULL, NULL}, new_tracks = {NULL, NULL};
128   ListBase *old_tracks;
129   int a;
130
131   if (map->is_camera) {
132     old_tracks = &tracking->tracks;
133   }
134   else {
135     MovieTrackingObject *object = BKE_tracking_object_get_named(tracking, map->object_name);
136
137     if (!object) {
138       /* object was deleted by user, create new one */
139       object = BKE_tracking_object_add(tracking, map->object_name);
140     }
141
142     old_tracks = &object->tracks;
143   }
144
145   /* duplicate currently operating tracks to temporary list.
146    * this is needed to keep names in unique state and it's faster to change names
147    * of currently operating tracks (if needed)
148    */
149   for (a = 0; a < map->num_tracks; a++) {
150     MovieTrackingTrack *old_track;
151     bool mapped_to_old = false;
152
153     track = &map->tracks[a];
154
155     /* find original of operating track in list of previously displayed tracks */
156     old_track = BLI_ghash_lookup(map->hash, track);
157     if (old_track) {
158       if (BLI_findindex(old_tracks, old_track) != -1) {
159         BLI_remlink(old_tracks, old_track);
160
161         BLI_spin_lock(&map->spin_lock);
162
163         /* Copy flags like selection back to the track map. */
164         track->flag = old_track->flag;
165         track->pat_flag = old_track->pat_flag;
166         track->search_flag = old_track->search_flag;
167
168         /* Copy all the rest settings back from the map to the actual tracks. */
169         MEM_freeN(old_track->markers);
170         *old_track = *track;
171         old_track->markers = MEM_dupallocN(old_track->markers);
172
173         BLI_spin_unlock(&map->spin_lock);
174
175         BLI_addtail(&tracks, old_track);
176
177         mapped_to_old = true;
178       }
179     }
180
181     if (mapped_to_old == false) {
182       MovieTrackingTrack *new_track = BKE_tracking_track_duplicate(track);
183
184       /* Update old-new track mapping */
185       BLI_ghash_reinsert(map->hash, track, new_track, NULL, NULL);
186
187       BLI_addtail(&tracks, new_track);
188     }
189   }
190
191   /* move all tracks, which aren't operating */
192   track = old_tracks->first;
193   while (track) {
194     MovieTrackingTrack *next = track->next;
195     BLI_addtail(&new_tracks, track);
196     track = next;
197   }
198
199   /* now move all tracks which are currently operating and keep their names unique */
200   track = tracks.first;
201   while (track) {
202     MovieTrackingTrack *next = track->next;
203
204     BLI_remlink(&tracks, track);
205
206     track->next = track->prev = NULL;
207     BLI_addtail(&new_tracks, track);
208
209     BLI_uniquename(&new_tracks,
210                    track,
211                    CTX_DATA_(BLT_I18NCONTEXT_ID_MOVIECLIP, "Track"),
212                    '.',
213                    offsetof(MovieTrackingTrack, name),
214                    sizeof(track->name));
215
216     track = next;
217   }
218
219   *old_tracks = new_tracks;
220 }
221
222 void tracks_map_free(TracksMap *map, void (*customdata_free)(void *customdata))
223 {
224   int i = 0;
225
226   BLI_ghash_free(map->hash, NULL, NULL);
227
228   for (i = 0; i < map->num_tracks; i++) {
229     if (map->customdata && customdata_free) {
230       customdata_free(&map->customdata[i * map->customdata_size]);
231     }
232
233     BKE_tracking_track_free(&map->tracks[i]);
234   }
235
236   if (map->customdata) {
237     MEM_freeN(map->customdata);
238   }
239
240   MEM_freeN(map->tracks);
241
242   BLI_spin_end(&map->spin_lock);
243
244   MEM_freeN(map);
245 }
246
247 /*********************** Space transformation functions *************************/
248
249 /* Three coordinate frames: Frame, Search, and Marker
250  * Two units: Pixels, Unified
251  * Notation: {coordinate frame}_{unit}; for example, "search_pixel" are search
252  * window relative coordinates in pixels, and "frame_unified" are unified 0..1
253  * coordinates relative to the entire frame.
254  */
255 static void unified_to_pixel(int frame_width,
256                              int frame_height,
257                              const float unified_coords[2],
258                              float pixel_coords[2])
259 {
260   pixel_coords[0] = unified_coords[0] * frame_width;
261   pixel_coords[1] = unified_coords[1] * frame_height;
262 }
263
264 static void marker_to_frame_unified(const MovieTrackingMarker *marker,
265                                     const float marker_unified_coords[2],
266                                     float frame_unified_coords[2])
267 {
268   frame_unified_coords[0] = marker_unified_coords[0] + marker->pos[0];
269   frame_unified_coords[1] = marker_unified_coords[1] + marker->pos[1];
270 }
271
272 static void marker_unified_to_frame_pixel_coordinates(int frame_width,
273                                                       int frame_height,
274                                                       const MovieTrackingMarker *marker,
275                                                       const float marker_unified_coords[2],
276                                                       float frame_pixel_coords[2])
277 {
278   marker_to_frame_unified(marker, marker_unified_coords, frame_pixel_coords);
279   unified_to_pixel(frame_width, frame_height, frame_pixel_coords, frame_pixel_coords);
280 }
281
282 void tracking_get_search_origin_frame_pixel(int frame_width,
283                                             int frame_height,
284                                             const MovieTrackingMarker *marker,
285                                             float frame_pixel[2])
286 {
287   /* Get the lower left coordinate of the search window and snap to pixel coordinates */
288   marker_unified_to_frame_pixel_coordinates(
289       frame_width, frame_height, marker, marker->search_min, frame_pixel);
290   frame_pixel[0] = (int)frame_pixel[0];
291   frame_pixel[1] = (int)frame_pixel[1];
292 }
293
294 static void pixel_to_unified(int frame_width,
295                              int frame_height,
296                              const float pixel_coords[2],
297                              float unified_coords[2])
298 {
299   unified_coords[0] = pixel_coords[0] / frame_width;
300   unified_coords[1] = pixel_coords[1] / frame_height;
301 }
302
303 static void marker_unified_to_search_pixel(int frame_width,
304                                            int frame_height,
305                                            const MovieTrackingMarker *marker,
306                                            const float marker_unified[2],
307                                            float search_pixel[2])
308 {
309   float frame_pixel[2];
310   float search_origin_frame_pixel[2];
311
312   marker_unified_to_frame_pixel_coordinates(
313       frame_width, frame_height, marker, marker_unified, frame_pixel);
314   tracking_get_search_origin_frame_pixel(
315       frame_width, frame_height, marker, search_origin_frame_pixel);
316   sub_v2_v2v2(search_pixel, frame_pixel, search_origin_frame_pixel);
317 }
318
319 static void search_pixel_to_marker_unified(int frame_width,
320                                            int frame_height,
321                                            const MovieTrackingMarker *marker,
322                                            const float search_pixel[2],
323                                            float marker_unified[2])
324 {
325   float frame_unified[2];
326   float search_origin_frame_pixel[2];
327
328   tracking_get_search_origin_frame_pixel(
329       frame_width, frame_height, marker, search_origin_frame_pixel);
330   add_v2_v2v2(frame_unified, search_pixel, search_origin_frame_pixel);
331   pixel_to_unified(frame_width, frame_height, frame_unified, frame_unified);
332
333   /* marker pos is in frame unified */
334   sub_v2_v2v2(marker_unified, frame_unified, marker->pos);
335 }
336
337 /* Each marker has 5 coordinates associated with it that get warped with
338  * tracking: the four corners ("pattern_corners"), and the center ("pos").
339  * This function puts those 5 points into the appropriate frame for tracking
340  * (the "search" coordinate frame).
341  */
342 void tracking_get_marker_coords_for_tracking(int frame_width,
343                                              int frame_height,
344                                              const MovieTrackingMarker *marker,
345                                              double search_pixel_x[5],
346                                              double search_pixel_y[5])
347 {
348   int i;
349   float unified_coords[2];
350   float pixel_coords[2];
351
352   /* Convert the corners into search space coordinates. */
353   for (i = 0; i < 4; i++) {
354     marker_unified_to_search_pixel(
355         frame_width, frame_height, marker, marker->pattern_corners[i], pixel_coords);
356     search_pixel_x[i] = pixel_coords[0] - 0.5f;
357     search_pixel_y[i] = pixel_coords[1] - 0.5f;
358   }
359
360   /* Convert the center position (aka "pos"); this is the origin */
361   unified_coords[0] = 0.0f;
362   unified_coords[1] = 0.0f;
363   marker_unified_to_search_pixel(frame_width, frame_height, marker, unified_coords, pixel_coords);
364
365   search_pixel_x[4] = pixel_coords[0] - 0.5f;
366   search_pixel_y[4] = pixel_coords[1] - 0.5f;
367 }
368
369 /* Inverse of above. */
370 void tracking_set_marker_coords_from_tracking(int frame_width,
371                                               int frame_height,
372                                               MovieTrackingMarker *marker,
373                                               const double search_pixel_x[5],
374                                               const double search_pixel_y[5])
375 {
376   int i;
377   float marker_unified[2];
378   float search_pixel[2];
379
380   /* Convert the corners into search space coordinates. */
381   for (i = 0; i < 4; i++) {
382     search_pixel[0] = search_pixel_x[i] + 0.5;
383     search_pixel[1] = search_pixel_y[i] + 0.5;
384     search_pixel_to_marker_unified(
385         frame_width, frame_height, marker, search_pixel, marker->pattern_corners[i]);
386   }
387
388   /* Convert the center position (aka "pos"); this is the origin */
389   search_pixel[0] = search_pixel_x[4] + 0.5;
390   search_pixel[1] = search_pixel_y[4] + 0.5;
391   search_pixel_to_marker_unified(frame_width, frame_height, marker, search_pixel, marker_unified);
392
393   /* If the tracker tracked nothing, then "marker_unified" would be zero.
394    * Otherwise, the entire patch shifted, and that delta should be applied to
395    * all the coordinates.
396    */
397   for (i = 0; i < 4; i++) {
398     marker->pattern_corners[i][0] -= marker_unified[0];
399     marker->pattern_corners[i][1] -= marker_unified[1];
400   }
401
402   marker->pos[0] += marker_unified[0];
403   marker->pos[1] += marker_unified[1];
404 }
405
406 /*********************** General purpose utility functions *************************/
407
408 /* Place a disabled marker before or after specified ref_marker.
409  *
410  * If before is truth, disabled marker is placed before reference
411  * one, and it's placed after it otherwise.
412  *
413  * If there's already a marker at the frame where disabled one
414  * is expected to be placed, nothing will happen if overwrite
415  * is false.
416  */
417 void tracking_marker_insert_disabled(MovieTrackingTrack *track,
418                                      const MovieTrackingMarker *ref_marker,
419                                      bool before,
420                                      bool overwrite)
421 {
422   MovieTrackingMarker marker_new;
423
424   marker_new = *ref_marker;
425   marker_new.flag &= ~MARKER_TRACKED;
426   marker_new.flag |= MARKER_DISABLED;
427
428   if (before) {
429     marker_new.framenr--;
430   }
431   else {
432     marker_new.framenr++;
433   }
434
435   if (overwrite || !BKE_tracking_track_has_marker_at_frame(track, marker_new.framenr)) {
436     BKE_tracking_marker_insert(track, &marker_new);
437   }
438 }
439
440 /* Fill in Libmv C-API camera intrinsics options from tracking structure. */
441 void tracking_cameraIntrinscisOptionsFromTracking(
442     MovieTracking *tracking,
443     int calibration_width,
444     int calibration_height,
445     libmv_CameraIntrinsicsOptions *camera_intrinsics_options)
446 {
447   MovieTrackingCamera *camera = &tracking->camera;
448   float aspy = 1.0f / tracking->camera.pixel_aspect;
449
450   camera_intrinsics_options->focal_length = camera->focal;
451
452   camera_intrinsics_options->principal_point_x = camera->principal[0];
453   camera_intrinsics_options->principal_point_y = camera->principal[1] * aspy;
454
455   switch (camera->distortion_model) {
456     case TRACKING_DISTORTION_MODEL_POLYNOMIAL:
457       camera_intrinsics_options->distortion_model = LIBMV_DISTORTION_MODEL_POLYNOMIAL;
458       camera_intrinsics_options->polynomial_k1 = camera->k1;
459       camera_intrinsics_options->polynomial_k2 = camera->k2;
460       camera_intrinsics_options->polynomial_k3 = camera->k3;
461       camera_intrinsics_options->polynomial_p1 = 0.0;
462       camera_intrinsics_options->polynomial_p2 = 0.0;
463       break;
464     case TRACKING_DISTORTION_MODEL_DIVISION:
465       camera_intrinsics_options->distortion_model = LIBMV_DISTORTION_MODEL_DIVISION;
466       camera_intrinsics_options->division_k1 = camera->division_k1;
467       camera_intrinsics_options->division_k2 = camera->division_k2;
468       break;
469     default:
470       BLI_assert(!"Unknown distortion model");
471       break;
472   }
473
474   camera_intrinsics_options->image_width = calibration_width;
475   camera_intrinsics_options->image_height = (int)(calibration_height * aspy);
476 }
477
478 void tracking_trackingCameraFromIntrinscisOptions(
479     MovieTracking *tracking, const libmv_CameraIntrinsicsOptions *camera_intrinsics_options)
480 {
481   float aspy = 1.0f / tracking->camera.pixel_aspect;
482   MovieTrackingCamera *camera = &tracking->camera;
483
484   camera->focal = camera_intrinsics_options->focal_length;
485
486   camera->principal[0] = camera_intrinsics_options->principal_point_x;
487   camera->principal[1] = camera_intrinsics_options->principal_point_y / (double)aspy;
488
489   switch (camera_intrinsics_options->distortion_model) {
490     case LIBMV_DISTORTION_MODEL_POLYNOMIAL:
491       camera->distortion_model = TRACKING_DISTORTION_MODEL_POLYNOMIAL;
492       camera->k1 = camera_intrinsics_options->polynomial_k1;
493       camera->k2 = camera_intrinsics_options->polynomial_k2;
494       camera->k3 = camera_intrinsics_options->polynomial_k3;
495       break;
496     case LIBMV_DISTORTION_MODEL_DIVISION:
497       camera->distortion_model = TRACKING_DISTORTION_MODEL_DIVISION;
498       camera->division_k1 = camera_intrinsics_options->division_k1;
499       camera->division_k2 = camera_intrinsics_options->division_k2;
500       break;
501     default:
502       BLI_assert(!"Unknown distortion model");
503       break;
504   }
505 }
506
507 /* Get previous keyframed marker. */
508 MovieTrackingMarker *tracking_get_keyframed_marker(MovieTrackingTrack *track,
509                                                    int current_frame,
510                                                    bool backwards)
511 {
512   MovieTrackingMarker *marker_keyed = NULL;
513   MovieTrackingMarker *marker_keyed_fallback = NULL;
514   int a = BKE_tracking_marker_get(track, current_frame) - track->markers;
515
516   while (a >= 0 && a < track->markersnr) {
517     int next = backwards ? a + 1 : a - 1;
518     bool is_keyframed = false;
519     MovieTrackingMarker *cur_marker = &track->markers[a];
520     MovieTrackingMarker *next_marker = NULL;
521
522     if (next >= 0 && next < track->markersnr) {
523       next_marker = &track->markers[next];
524     }
525
526     if ((cur_marker->flag & MARKER_DISABLED) == 0) {
527       /* If it'll happen so we didn't find a real keyframe marker,
528        * fallback to the first marker in current tracked segment
529        * as a keyframe.
530        */
531       if (next_marker == NULL) {
532         /* Could happen when trying to get reference marker for the fist
533          * one on the segment which isn't surrounded by disabled markers.
534          *
535          * There's no really good choice here, just use the reference
536          * marker which looks correct..
537          */
538         if (marker_keyed_fallback == NULL) {
539           marker_keyed_fallback = cur_marker;
540         }
541       }
542       else if (next_marker->flag & MARKER_DISABLED) {
543         if (marker_keyed_fallback == NULL) {
544           marker_keyed_fallback = cur_marker;
545         }
546       }
547
548       is_keyframed |= (cur_marker->flag & MARKER_TRACKED) == 0;
549     }
550
551     if (is_keyframed) {
552       marker_keyed = cur_marker;
553
554       break;
555     }
556
557     a = next;
558   }
559
560   if (marker_keyed == NULL) {
561     marker_keyed = marker_keyed_fallback;
562   }
563
564   return marker_keyed;
565 }
566
567 /*********************** Frame accessr *************************/
568
569 typedef struct AccessCacheKey {
570   int clip_index;
571   int frame;
572   int downscale;
573   libmv_InputMode input_mode;
574   bool has_region;
575   float region_min[2], region_max[2];
576   int64_t transform_key;
577 } AccessCacheKey;
578
579 static unsigned int accesscache_hashhash(const void *key_v)
580 {
581   const AccessCacheKey *key = (const AccessCacheKey *)key_v;
582   /* TODP(sergey): Need better hashing here for faster frame access. */
583   return key->clip_index << 16 | key->frame;
584 }
585
586 static bool accesscache_hashcmp(const void *a_v, const void *b_v)
587 {
588   const AccessCacheKey *a = (const AccessCacheKey *)a_v;
589   const AccessCacheKey *b = (const AccessCacheKey *)b_v;
590   if (a->clip_index != b->clip_index || a->frame != b->frame || a->downscale != b->downscale ||
591       a->input_mode != b->input_mode || a->has_region != b->has_region ||
592       a->transform_key != b->transform_key) {
593     return true;
594   }
595   /* If there is region applied, compare it. */
596   if (a->has_region) {
597     if (!equals_v2v2(a->region_min, b->region_min) || !equals_v2v2(a->region_max, b->region_max)) {
598       return true;
599     }
600   }
601   return false;
602 }
603
604 static void accesscache_construct_key(AccessCacheKey *key,
605                                       int clip_index,
606                                       int frame,
607                                       libmv_InputMode input_mode,
608                                       int downscale,
609                                       const libmv_Region *region,
610                                       int64_t transform_key)
611 {
612   key->clip_index = clip_index;
613   key->frame = frame;
614   key->input_mode = input_mode;
615   key->downscale = downscale;
616   key->has_region = (region != NULL);
617   if (key->has_region) {
618     copy_v2_v2(key->region_min, region->min);
619     copy_v2_v2(key->region_max, region->max);
620   }
621   key->transform_key = transform_key;
622 }
623
624 static void accesscache_put(TrackingImageAccessor *accessor,
625                             int clip_index,
626                             int frame,
627                             libmv_InputMode input_mode,
628                             int downscale,
629                             const libmv_Region *region,
630                             int64_t transform_key,
631                             ImBuf *ibuf)
632 {
633   AccessCacheKey key;
634   accesscache_construct_key(&key, clip_index, frame, input_mode, downscale, region, transform_key);
635   IMB_moviecache_put(accessor->cache, &key, ibuf);
636 }
637
638 static ImBuf *accesscache_get(TrackingImageAccessor *accessor,
639                               int clip_index,
640                               int frame,
641                               libmv_InputMode input_mode,
642                               int downscale,
643                               const libmv_Region *region,
644                               int64_t transform_key)
645 {
646   AccessCacheKey key;
647   accesscache_construct_key(&key, clip_index, frame, input_mode, downscale, region, transform_key);
648   return IMB_moviecache_get(accessor->cache, &key);
649 }
650
651 static ImBuf *accessor_get_preprocessed_ibuf(TrackingImageAccessor *accessor,
652                                              int clip_index,
653                                              int frame)
654 {
655   MovieClip *clip;
656   MovieClipUser user;
657   ImBuf *ibuf;
658   int scene_frame;
659
660   BLI_assert(clip_index < accessor->num_clips);
661
662   clip = accessor->clips[clip_index];
663   scene_frame = BKE_movieclip_remap_clip_to_scene_frame(clip, frame);
664   BKE_movieclip_user_set_frame(&user, scene_frame);
665   user.render_size = MCLIP_PROXY_RENDER_SIZE_FULL;
666   user.render_flag = 0;
667   ibuf = BKE_movieclip_get_ibuf(clip, &user);
668
669   return ibuf;
670 }
671
672 static ImBuf *make_grayscale_ibuf_copy(ImBuf *ibuf)
673 {
674   ImBuf *grayscale = IMB_allocImBuf(ibuf->x, ibuf->y, 32, 0);
675   size_t size;
676   int i;
677
678   BLI_assert(ibuf->channels == 3 || ibuf->channels == 4);
679
680   /* TODO(sergey): Bummer, currently IMB API only allows to create 4 channels
681    * float buffer, so we do it manually here.
682    *
683    * Will generalize it later.
684    */
685   size = (size_t)grayscale->x * (size_t)grayscale->y * sizeof(float);
686   grayscale->channels = 1;
687   if ((grayscale->rect_float = MEM_mapallocN(size, "tracking grayscale image")) != NULL) {
688     grayscale->mall |= IB_rectfloat;
689     grayscale->flags |= IB_rectfloat;
690
691     for (i = 0; i < grayscale->x * grayscale->y; ++i) {
692       const float *pixel = ibuf->rect_float + ibuf->channels * i;
693
694       grayscale->rect_float[i] = 0.2126f * pixel[0] + 0.7152f * pixel[1] + 0.0722f * pixel[2];
695     }
696   }
697
698   return grayscale;
699 }
700
701 static void ibuf_to_float_image(const ImBuf *ibuf, libmv_FloatImage *float_image)
702 {
703   BLI_assert(ibuf->rect_float != NULL);
704   float_image->buffer = ibuf->rect_float;
705   float_image->width = ibuf->x;
706   float_image->height = ibuf->y;
707   float_image->channels = ibuf->channels;
708 }
709
710 static ImBuf *float_image_to_ibuf(libmv_FloatImage *float_image)
711 {
712   ImBuf *ibuf = IMB_allocImBuf(float_image->width, float_image->height, 32, 0);
713   size_t size = (size_t)ibuf->x * (size_t)ibuf->y * float_image->channels * sizeof(float);
714   ibuf->channels = float_image->channels;
715   if ((ibuf->rect_float = MEM_mapallocN(size, "tracking grayscale image")) != NULL) {
716     ibuf->mall |= IB_rectfloat;
717     ibuf->flags |= IB_rectfloat;
718
719     memcpy(ibuf->rect_float, float_image->buffer, size);
720   }
721   return ibuf;
722 }
723
724 static ImBuf *accessor_get_ibuf(TrackingImageAccessor *accessor,
725                                 int clip_index,
726                                 int frame,
727                                 libmv_InputMode input_mode,
728                                 int downscale,
729                                 const libmv_Region *region,
730                                 const libmv_FrameTransform *transform)
731 {
732   ImBuf *ibuf, *orig_ibuf, *final_ibuf;
733   int64_t transform_key = 0;
734   if (transform != NULL) {
735     transform_key = libmv_frameAccessorgetTransformKey(transform);
736   }
737   /* First try to get fully processed image from the cache. */
738   BLI_spin_lock(&accessor->cache_lock);
739   ibuf = accesscache_get(
740       accessor, clip_index, frame, input_mode, downscale, region, transform_key);
741   BLI_spin_unlock(&accessor->cache_lock);
742   if (ibuf != NULL) {
743     CACHE_PRINTF("Used cached buffer for frame %d\n", frame);
744     /* This is a little heuristic here: if we re-used image once, this is
745      * a high probability of the image to be related to a keyframe matched
746      * reference image. Those images we don't want to be thrown away because
747      * if we toss them out we'll be re-calculating them at the next
748      * iteration.
749      */
750     ibuf->userflags |= IB_PERSISTENT;
751     return ibuf;
752   }
753   CACHE_PRINTF("Calculate new buffer for frame %d\n", frame);
754   /* And now we do postprocessing of the original frame. */
755   orig_ibuf = accessor_get_preprocessed_ibuf(accessor, clip_index, frame);
756   if (orig_ibuf == NULL) {
757     return NULL;
758   }
759   /* Cut a region if requested. */
760   if (region != NULL) {
761     int width = region->max[0] - region->min[0], height = region->max[1] - region->min[1];
762
763     /* If the requested region goes outside of the actual frame we still
764      * return the requested region size, but only fill it's partially with
765      * the data we can.
766      */
767     int clamped_origin_x = max_ii((int)region->min[0], 0),
768         clamped_origin_y = max_ii((int)region->min[1], 0);
769     int dst_offset_x = clamped_origin_x - (int)region->min[0],
770         dst_offset_y = clamped_origin_y - (int)region->min[1];
771     int clamped_width = width - dst_offset_x, clamped_height = height - dst_offset_y;
772     clamped_width = min_ii(clamped_width, orig_ibuf->x - clamped_origin_x);
773     clamped_height = min_ii(clamped_height, orig_ibuf->y - clamped_origin_y);
774
775     final_ibuf = IMB_allocImBuf(width, height, 32, IB_rectfloat);
776
777     if (orig_ibuf->rect_float != NULL) {
778       IMB_rectcpy(final_ibuf,
779                   orig_ibuf,
780                   dst_offset_x,
781                   dst_offset_y,
782                   clamped_origin_x,
783                   clamped_origin_y,
784                   clamped_width,
785                   clamped_height);
786     }
787     else {
788       int y;
789       /* TODO(sergey): We don't do any color space or alpha conversion
790        * here. Probably Libmv is better to work in the linear space,
791        * but keep sRGB space here for compatibility for now.
792        */
793       for (y = 0; y < clamped_height; ++y) {
794         int x;
795         for (x = 0; x < clamped_width; ++x) {
796           int src_x = x + clamped_origin_x, src_y = y + clamped_origin_y;
797           int dst_x = x + dst_offset_x, dst_y = y + dst_offset_y;
798           int dst_index = (dst_y * width + dst_x) * 4,
799               src_index = (src_y * orig_ibuf->x + src_x) * 4;
800           rgba_uchar_to_float(final_ibuf->rect_float + dst_index,
801                               (unsigned char *)orig_ibuf->rect + src_index);
802         }
803       }
804     }
805   }
806   else {
807     /* Libmv only works with float images,
808      *
809      * This would likely make it so loads of float buffers are being stored
810      * in the cache which is nice on the one hand (faster re-use of the
811      * frames) but on the other hand it bumps the memory usage up.
812      */
813     BLI_thread_lock(LOCK_MOVIECLIP);
814     IMB_float_from_rect(orig_ibuf);
815     BLI_thread_unlock(LOCK_MOVIECLIP);
816     final_ibuf = orig_ibuf;
817   }
818   /* Downscale if needed. */
819   if (downscale > 0) {
820     if (final_ibuf == orig_ibuf) {
821       final_ibuf = IMB_dupImBuf(orig_ibuf);
822     }
823     IMB_scaleImBuf(final_ibuf, orig_ibuf->x / (1 << downscale), orig_ibuf->y / (1 << downscale));
824   }
825   /* Apply possible transformation. */
826   if (transform != NULL) {
827     libmv_FloatImage input_image, output_image;
828     ibuf_to_float_image(final_ibuf, &input_image);
829     libmv_frameAccessorgetTransformRun(transform, &input_image, &output_image);
830     if (final_ibuf != orig_ibuf) {
831       IMB_freeImBuf(final_ibuf);
832     }
833     final_ibuf = float_image_to_ibuf(&output_image);
834     libmv_floatImageDestroy(&output_image);
835   }
836   /* Transform number of channels. */
837   if (input_mode == LIBMV_IMAGE_MODE_RGBA) {
838     BLI_assert(orig_ibuf->channels == 3 || orig_ibuf->channels == 4);
839     /* pass */
840   }
841   else /* if (input_mode == LIBMV_IMAGE_MODE_MONO) */ {
842     BLI_assert(input_mode == LIBMV_IMAGE_MODE_MONO);
843     if (final_ibuf->channels != 1) {
844       ImBuf *grayscale_ibuf = make_grayscale_ibuf_copy(final_ibuf);
845       if (final_ibuf != orig_ibuf) {
846         /* We dereference original frame later. */
847         IMB_freeImBuf(final_ibuf);
848       }
849       final_ibuf = grayscale_ibuf;
850     }
851   }
852   /* It's possible processing still didn't happen at this point,
853    * but we really need a copy of the buffer to be transformed
854    * and to be put to the cache.
855    */
856   if (final_ibuf == orig_ibuf) {
857     final_ibuf = IMB_dupImBuf(orig_ibuf);
858   }
859   IMB_freeImBuf(orig_ibuf);
860   BLI_spin_lock(&accessor->cache_lock);
861   /* Put final buffer to cache. */
862   accesscache_put(
863       accessor, clip_index, frame, input_mode, downscale, region, transform_key, final_ibuf);
864   BLI_spin_unlock(&accessor->cache_lock);
865   return final_ibuf;
866 }
867
868 static libmv_CacheKey accessor_get_image_callback(struct libmv_FrameAccessorUserData *user_data,
869                                                   int clip_index,
870                                                   int frame,
871                                                   libmv_InputMode input_mode,
872                                                   int downscale,
873                                                   const libmv_Region *region,
874                                                   const libmv_FrameTransform *transform,
875                                                   float **destination,
876                                                   int *width,
877                                                   int *height,
878                                                   int *channels)
879 {
880   TrackingImageAccessor *accessor = (TrackingImageAccessor *)user_data;
881   ImBuf *ibuf;
882
883   BLI_assert(clip_index >= 0 && clip_index < accessor->num_clips);
884
885   ibuf = accessor_get_ibuf(accessor, clip_index, frame, input_mode, downscale, region, transform);
886
887   if (ibuf) {
888     *destination = ibuf->rect_float;
889     *width = ibuf->x;
890     *height = ibuf->y;
891     *channels = ibuf->channels;
892   }
893   else {
894     *destination = NULL;
895     *width = 0;
896     *height = 0;
897     *channels = 0;
898   }
899
900   return ibuf;
901 }
902
903 static void accessor_release_image_callback(libmv_CacheKey cache_key)
904 {
905   ImBuf *ibuf = (ImBuf *)cache_key;
906   IMB_freeImBuf(ibuf);
907 }
908
909 static libmv_CacheKey accessor_get_mask_for_track_callback(libmv_FrameAccessorUserData *user_data,
910                                                            int clip_index,
911                                                            int frame,
912                                                            int track_index,
913                                                            const libmv_Region *region,
914                                                            float **r_destination,
915                                                            int *r_width,
916                                                            int *r_height)
917 {
918   /* Perform sanity checks first. */
919   TrackingImageAccessor *accessor = (TrackingImageAccessor *)user_data;
920   BLI_assert(clip_index < accessor->num_clips);
921   BLI_assert(track_index < accessor->num_tracks);
922   MovieTrackingTrack *track = accessor->tracks[track_index];
923   /* Early output, track does not use mask. */
924   if ((track->algorithm_flag & TRACK_ALGORITHM_FLAG_USE_MASK) == 0) {
925     return NULL;
926   }
927   MovieClip *clip = accessor->clips[clip_index];
928   /* Construct fake user so we can access movie clip. */
929   MovieClipUser user;
930   int scene_frame = BKE_movieclip_remap_clip_to_scene_frame(clip, frame);
931   BKE_movieclip_user_set_frame(&user, scene_frame);
932   user.render_size = MCLIP_PROXY_RENDER_SIZE_FULL;
933   user.render_flag = 0;
934   /* Get frame width and height so we can convert stroke coordinates
935    * and other things from normalized to pixel space.
936    */
937   int frame_width, frame_height;
938   BKE_movieclip_get_size(clip, &user, &frame_width, &frame_height);
939   /* Actual mask sampling. */
940   MovieTrackingMarker *marker = BKE_tracking_marker_get_exact(track, frame);
941   const float region_min[2] = {
942       region->min[0] - marker->pos[0] * frame_width,
943       region->min[1] - marker->pos[1] * frame_height,
944   };
945   const float region_max[2] = {
946       region->max[0] - marker->pos[0] * frame_width,
947       region->max[1] - marker->pos[1] * frame_height,
948   };
949   *r_destination = tracking_track_get_mask_for_region(
950       frame_width, frame_height, region_min, region_max, track);
951   *r_width = region->max[0] - region->min[0];
952   *r_height = region->max[1] - region->min[1];
953   return *r_destination;
954 }
955
956 static void accessor_release_mask_callback(libmv_CacheKey cache_key)
957 {
958   if (cache_key != NULL) {
959     float *mask = (float *)cache_key;
960     MEM_freeN(mask);
961   }
962 }
963
964 TrackingImageAccessor *tracking_image_accessor_new(MovieClip *clips[MAX_ACCESSOR_CLIP],
965                                                    int num_clips,
966                                                    MovieTrackingTrack **tracks,
967                                                    int num_tracks,
968                                                    int start_frame)
969 {
970   TrackingImageAccessor *accessor = MEM_callocN(sizeof(TrackingImageAccessor),
971                                                 "tracking image accessor");
972
973   BLI_assert(num_clips <= MAX_ACCESSOR_CLIP);
974
975   accessor->cache = IMB_moviecache_create(
976       "frame access cache", sizeof(AccessCacheKey), accesscache_hashhash, accesscache_hashcmp);
977
978   memcpy(accessor->clips, clips, num_clips * sizeof(MovieClip *));
979   accessor->num_clips = num_clips;
980   accessor->tracks = tracks;
981   accessor->num_tracks = num_tracks;
982   accessor->start_frame = start_frame;
983
984   accessor->libmv_accessor = libmv_FrameAccessorNew((libmv_FrameAccessorUserData *)accessor,
985                                                     accessor_get_image_callback,
986                                                     accessor_release_image_callback,
987                                                     accessor_get_mask_for_track_callback,
988                                                     accessor_release_mask_callback);
989
990   BLI_spin_init(&accessor->cache_lock);
991
992   return accessor;
993 }
994
995 void tracking_image_accessor_destroy(TrackingImageAccessor *accessor)
996 {
997   IMB_moviecache_free(accessor->cache);
998   libmv_FrameAccessorDestroy(accessor->libmv_accessor);
999   BLI_spin_end(&accessor->cache_lock);
1000   MEM_freeN(accessor);
1001 }