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