93b4e4a3bff95b561a0888e1d03a31299c69c1b0
[blender.git] / source / blender / blenkernel / intern / tracking.c
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2011 Blender Foundation.
21  * All rights reserved.
22  *
23  * Contributor(s): Blender Foundation,
24  *                 Sergey Sharybin
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 /** \file blender/blenkernel/intern/tracking.c
30  *  \ingroup bke
31  */
32
33 #include <stddef.h>
34 #include <limits.h>
35
36 #include "MEM_guardedalloc.h"
37
38 #include "DNA_movieclip_types.h"
39 #include "DNA_object_types.h"   /* SELECT */
40
41 #include "BLI_utildefines.h"
42 #include "BLI_math.h"
43 #include "BLI_listbase.h"
44 #include "BLI_ghash.h"
45
46 #include "BKE_tracking.h"
47 #include "BKE_movieclip.h"
48 #include "BKE_global.h"
49
50 #include "IMB_imbuf_types.h"
51 #include "IMB_imbuf.h"
52
53 #ifdef WITH_LIBMV
54 #include "libmv-capi.h"
55 #endif
56
57 /*********************** common functions *************************/
58
59 void BKE_tracking_clamp_track(MovieTrackingTrack *track, int event)
60 {
61         int a;
62
63         /* sort */
64         for(a= 0; a<2; a++) {
65                 if(track->pat_min[a]>track->pat_max[a])
66                         SWAP(float, track->pat_min[a], track->pat_max[a]);
67
68                 if(track->search_min[a]>track->search_max[a])
69                         SWAP(float, track->search_min[a], track->search_max[a]);
70         }
71
72         if(event==CLAMP_PAT_DIM) {
73                 for(a= 0; a<2; a++) {
74                         /* pattern shouldn't be resized bigger than search */
75                         track->pat_min[a]= MAX2(track->pat_min[a], track->search_min[a]);
76                         track->pat_max[a]= MIN2(track->pat_max[a], track->search_max[a]);
77                 }
78         }
79         else if(event==CLAMP_PAT_POS) {
80                 float dim[2];
81                 sub_v2_v2v2(dim, track->pat_max, track->pat_min);
82
83                 for(a= 0; a<2; a++) {
84                         /* pattern shouldn't be moved outside of search */
85                         if(track->pat_min[a] < track->search_min[a]) {
86                                 track->pat_min[a]= track->search_min[a];
87                                 track->pat_max[a]= track->pat_min[a]+dim[a];
88                         }
89                         if(track->pat_max[a] > track->search_max[a]) {
90                                 track->pat_max[a]= track->search_max[a];
91                                 track->pat_min[a]= track->pat_max[a]-dim[a];
92                         }
93                 }
94         }
95         else if(event==CLAMP_SEARCH_DIM) {
96                 for(a= 0; a<2; a++) {
97                         /* search shouldn't be resized smaller than pattern */
98                         track->search_min[a]= MIN2(track->pat_min[a], track->search_min[a]);
99                         track->search_max[a]= MAX2(track->pat_max[a], track->search_max[a]);
100                 }
101         }
102         else if(event==CLAMP_SEARCH_POS) {
103                 float dim[2];
104                 sub_v2_v2v2(dim, track->search_max, track->search_min);
105
106                 for(a= 0; a<2; a++) {
107                         /* search shouldn't be moved inside pattern */
108                         if(track->search_min[a] > track->pat_min[a]) {
109                                 track->search_min[a]= track->pat_min[a];
110                                 track->search_max[a]= track->search_min[a]+dim[a];
111                         }
112                         if(track->search_max[a] < track->pat_max[a]) {
113                                 track->search_max[a]= track->pat_max[a];
114                                 track->search_min[a]= track->search_max[a]-dim[a];
115                         }
116                 }
117         }
118
119         /* marker's center should be inside pattern */
120         if(event==CLAMP_PAT_DIM || event==CLAMP_PAT_POS) {
121                 float dim[2];
122                 sub_v2_v2v2(dim, track->pat_max, track->pat_min);
123
124                 for(a= 0; a<2; a++) {
125                         if(track->pat_min[a] > 0.0f) {
126                                 track->pat_min[a]= 0.0f;
127                                 track->pat_max[a]= dim[a];
128                         }
129                         if(track->pat_max[a] < 0.0f) {
130                                 track->pat_max[a]= 0.0f;
131                                 track->pat_min[a]= -dim[a];
132                         }
133                 }
134         }
135 }
136
137 void BKE_tracking_track_flag(MovieTrackingTrack *track, int area, int flag, int clear)
138 {
139         if(area==TRACK_AREA_NONE)
140                 return;
141
142         if(clear) {
143                 if(area&TRACK_AREA_POINT)       track->flag&= ~flag;
144                 if(area&TRACK_AREA_PAT)         track->pat_flag&= ~flag;
145                 if(area&TRACK_AREA_SEARCH)      track->search_flag&= ~flag;
146         } else {
147                 if(area&TRACK_AREA_POINT)       track->flag|= flag;
148                 if(area&TRACK_AREA_PAT)         track->pat_flag|= flag;
149                 if(area&TRACK_AREA_SEARCH)      track->search_flag|= flag;
150         }
151 }
152
153 void BKE_tracking_insert_marker(MovieTrackingTrack *track, MovieTrackingMarker *marker)
154 {
155         MovieTrackingMarker *old_marker= BKE_tracking_get_marker(track, marker->framenr);
156
157         if(old_marker && old_marker->framenr==marker->framenr) {
158                 *old_marker= *marker;
159         } else {
160                 int a= track->markersnr;
161
162                 while(a--) {
163                         if(track->markers[a].framenr<marker->framenr)
164                                 break;
165                 }
166
167                 track->markersnr++;
168
169                 if(track->markers) track->markers= MEM_reallocN(track->markers, sizeof(MovieTrackingMarker)*track->markersnr);
170                 else track->markers= MEM_callocN(sizeof(MovieTrackingMarker), "MovieTracking markers");
171
172                 memmove(track->markers+a+2, track->markers+a+1, (track->markersnr-a-2)*sizeof(MovieTrackingMarker));
173                 track->markers[a+1]= *marker;
174
175                 track->last_marker= a+1;
176         }
177 }
178
179 void BKE_tracking_delete_marker(MovieTrackingTrack *track, int framenr)
180 {
181         int a= 1;
182
183         while(a<track->markersnr) {
184                 if(track->markers[a].framenr==framenr) {
185                         if(track->markersnr>1) {
186                                 memmove(track->markers+a, track->markers+a+1, (track->markersnr-a-1)*sizeof(MovieTrackingMarker));
187                                 track->markersnr--;
188                                 track->markers= MEM_reallocN(track->markers, sizeof(MovieTrackingMarker)*track->markersnr);
189                         } else {
190                                 MEM_freeN(track->markers);
191                                 track->markers= NULL;
192                                 track->markersnr= 0;
193                         }
194
195                         break;
196                 }
197
198                 a++;
199         }}
200
201 MovieTrackingMarker *BKE_tracking_get_marker(MovieTrackingTrack *track, int framenr)
202 {
203         int a= track->markersnr-1;
204
205         if(!track->markersnr)
206                 return NULL;
207
208         /* approximate pre-first framenr marker with first marker */
209         if(framenr<track->markers[0].framenr)
210                 return &track->markers[0];
211
212         if(track->last_marker<track->markersnr)
213                 a= track->last_marker;
214
215         if(track->markers[a].framenr<=framenr) {
216                 while(a<track->markersnr && track->markers[a].framenr<=framenr) {
217                         if(track->markers[a].framenr==framenr) {
218                                 track->last_marker= a;
219                                 return &track->markers[a];
220                         }
221                         a++;
222                 }
223
224                 /* if there's no marker for exact position, use nearest marker from left side */
225                 return &track->markers[a-1];
226         } else {
227                 while(a>=0 && track->markers[a].framenr>=framenr) {
228                         if(track->markers[a].framenr==framenr) {
229                                 track->last_marker= a;
230                                 return &track->markers[a];
231                         }
232
233                         a--;
234                 }
235
236                 /* if there's no marker for exact position, use nearest marker from left side */
237                 return &track->markers[a];
238         }
239
240         return NULL;
241 }
242
243 MovieTrackingMarker *BKE_tracking_ensure_marker(MovieTrackingTrack *track, int framenr)
244 {
245         MovieTrackingMarker *marker= BKE_tracking_get_marker(track, framenr);
246
247         if(marker && marker->framenr!=framenr) {
248                 MovieTrackingMarker marker_new;
249
250                 marker_new= *marker;
251                 marker_new.framenr= framenr;
252
253                 BKE_tracking_insert_marker(track, &marker_new);
254                 marker= BKE_tracking_get_marker(track, framenr);
255         }
256
257         return marker;
258 }
259
260 MovieTrackingMarker *BKE_tracking_exact_marker(MovieTrackingTrack *track, int framenr)
261 {
262         MovieTrackingMarker *marker= BKE_tracking_get_marker(track, framenr);
263
264         if(marker && marker->framenr!=framenr)
265                 return NULL;
266
267         return marker;
268 }
269
270 int BKE_tracking_has_marker(MovieTrackingTrack *track, int framenr)
271 {
272         return BKE_tracking_get_marker(track, framenr) != 0;
273 }
274
275 void BKE_tracking_free_track(MovieTrackingTrack *track)
276 {
277         if(track->markers) MEM_freeN(track->markers);
278 }
279
280 MovieTrackingTrack *BKE_tracking_copy_track(MovieTrackingTrack *track)
281 {
282         MovieTrackingTrack *new_track= MEM_dupallocN(track);
283
284         new_track->next= new_track->prev= NULL;
285
286         if(new_track->markers)
287                 new_track->markers= MEM_dupallocN(new_track->markers);
288
289         return new_track;
290 }
291
292 void BKE_tracking_clear_path(MovieTrackingTrack *track, int ref_frame, int action)
293 {
294         int a;
295
296         if(action==TRACK_CLEAR_REMAINED) {
297                 a= 1;
298                 while(a<track->markersnr) {
299                         if(track->markers[a].framenr>ref_frame) {
300                                 track->markersnr= a;
301                                 track->markers= MEM_reallocN(track->markers, sizeof(MovieTrackingMarker)*track->markersnr);
302
303                                 break;
304                         }
305
306                         a++;
307                 }
308         } else if(action==TRACK_CLEAR_UPTO) {
309                 a= track->markersnr-1;
310                 while(a>=0) {
311                         if(track->markers[a].framenr<=ref_frame) {
312                                 memmove(track->markers, track->markers+a, (track->markersnr-a)*sizeof(MovieTrackingMarker));
313
314                                 track->markersnr= track->markersnr-a;
315                                 track->markers= MEM_reallocN(track->markers, sizeof(MovieTrackingMarker)*track->markersnr);
316
317                                 break;
318                         }
319
320                         a--;
321                 }
322         } else if(action==TRACK_CLEAR_ALL) {
323                 MovieTrackingMarker *marker, marker_new;
324
325                 marker= BKE_tracking_get_marker(track, ref_frame);
326                 if(marker)
327                         marker_new= *marker;
328
329                 MEM_freeN(track->markers);
330                 track->markers= NULL;
331                 track->markersnr= 0;
332
333                 if(marker)
334                         BKE_tracking_insert_marker(track, &marker_new);
335         }
336 }
337
338 void BKE_tracking_free(MovieTracking *tracking)
339 {
340         MovieTrackingTrack *track;
341
342         for(track= tracking->tracks.first; track; track= track->next) {
343                 BKE_tracking_free_track(track);
344         }
345
346         BLI_freelistN(&tracking->tracks);
347
348         if(tracking->camera.reconstructed)
349                 MEM_freeN(tracking->camera.reconstructed);
350 }
351
352 /*********************** tracking *************************/
353
354 typedef struct MovieTrackingContext {
355         MovieClipUser user;
356         MovieClip *clip;
357
358 #ifdef WITH_LIBMV
359         struct libmv_RegionTracker *region_tracker;
360 #endif
361         ListBase tracks;
362         GHash *hash;
363         MovieTrackingSettings settings;
364
365         int backwards;
366         int sync_frame;
367 } MovieTrackingContext;
368
369 MovieTrackingContext *BKE_tracking_context_new(MovieClip *clip, MovieClipUser *user, int backwards)
370 {
371         MovieTrackingContext *context= MEM_callocN(sizeof(MovieTrackingContext), "trackingContext");
372         MovieTracking *tracking= &clip->tracking;
373         MovieTrackingSettings *settings= &tracking->settings;
374         MovieTrackingTrack *track;
375
376 #ifdef WITH_LIBMV
377         context->region_tracker= libmv_regionTrackerNew(100, 3, 0.2);
378 #endif
379
380         context->settings= *settings;
381         context->backwards= backwards;
382         context->hash= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "tracking trackHash");
383
384         track= tracking->tracks.first;
385         while(track) {
386                 if(TRACK_SELECTED(track)) {
387                         MovieTrackingTrack *new_track= BKE_tracking_copy_track(track);
388
389                         BLI_addtail(&context->tracks, new_track);
390                         BLI_ghash_insert(context->hash, new_track, track);
391                 }
392
393                 track= track->next;
394         }
395
396         context->clip= clip;
397         context->user= *user;
398
399         return context;
400 }
401
402 void BKE_tracking_context_free(MovieTrackingContext *context)
403 {
404         MovieTrackingTrack *track;
405
406 #if WITH_LIBMV
407         libmv_regionTrackerDestroy(context->region_tracker);
408 #endif
409
410         track= context->tracks.first;
411         while(track) {
412                 BKE_tracking_free_track(track);
413                 track= track->next;
414         }
415         BLI_freelistN(&context->tracks);
416
417         BLI_ghash_free(context->hash, NULL, NULL);
418
419         MEM_freeN(context);
420 }
421
422 static void disable_imbuf_channels(ImBuf *ibuf, MovieTrackingTrack *track)
423 {
424         int x, y;
425
426         if((track->flag&(TRACK_DISABLE_RED|TRACK_DISABLE_GREEN|TRACK_DISABLE_BLUE))==0)
427                 return;
428
429         for(y= 0; y<ibuf->y; y++) {
430                 for (x= 0; x<ibuf->x; x++) {
431                         int pixel= ibuf->x*y + x;
432                         char *rrgb= (char*)ibuf->rect + pixel*4;
433
434                         if(track->flag&TRACK_DISABLE_RED)       rrgb[0]= 0;
435                         if(track->flag&TRACK_DISABLE_GREEN)     rrgb[1]= 0;
436                         if(track->flag&TRACK_DISABLE_BLUE)      rrgb[2]= 0;
437                 }
438         }
439 }
440
441 static ImBuf *acquire_area_imbuf(ImBuf *ibuf, MovieTrackingTrack *track, MovieTrackingMarker *marker,
442                         float min[2], float max[2], int margin, float pos[2], int origin[2])
443 {
444         ImBuf *tmpibuf;
445         int x, y;
446         int x1, y1, x2, y2, w, h;
447
448         x= marker->pos[0]*ibuf->x;
449         y= marker->pos[1]*ibuf->y;
450         x1= x-(int)(-min[0]*ibuf->x);
451         y1= y-(int)(-min[1]*ibuf->y);
452         x2= x+(int)(max[0]*ibuf->x);
453         y2= y+(int)(max[1]*ibuf->y);
454
455         /* dimensions should be odd */
456         w= (x2-x1)|1;
457         h= (y2-y1)|1;
458
459         /* happens due to rounding issues */
460         if(x1+w<=x) x1++;
461         if(y1+h<=y) y1++;
462
463         tmpibuf= IMB_allocImBuf(w+margin*2, h+margin*2, 32, IB_rect);
464         IMB_rectcpy(tmpibuf, ibuf, 0, 0, x1-margin, y1-margin, w+margin*2, h+margin*2);
465
466         if(pos != NULL) {
467                 pos[0]= x-x1+(marker->pos[0]*ibuf->x-x)+margin;
468                 pos[1]= y-y1+(marker->pos[1]*ibuf->y-y)+margin;
469         }
470
471         if(origin != NULL) {
472                 origin[0]= x1-margin;
473                 origin[1]= y1-margin;
474         }
475
476         disable_imbuf_channels(tmpibuf, track);
477
478         return tmpibuf;
479 }
480
481 ImBuf *BKE_tracking_acquire_pattern_imbuf(ImBuf *ibuf, MovieTrackingTrack *track, MovieTrackingMarker *marker,
482                         int margin, float pos[2], int origin[2])
483 {
484         return acquire_area_imbuf(ibuf, track, marker, track->pat_min, track->pat_max, margin, pos, origin);
485 }
486
487 ImBuf *BKE_tracking_acquire_search_imbuf(ImBuf *ibuf, MovieTrackingTrack *track, MovieTrackingMarker *marker,
488                         int margin, float pos[2], int origin[2])
489 {
490         return acquire_area_imbuf(ibuf, track, marker, track->search_min, track->search_max, margin, pos, origin);
491 }
492
493 #ifdef WITH_LIBMV
494 static float *acquire_search_floatbuf(ImBuf *ibuf, MovieTrackingTrack *track, MovieTrackingMarker *marker,
495                         int *width_r, int *height_r, float pos[2], int origin[2])
496 {
497         ImBuf *tmpibuf;
498         float *pixels, *fp;
499         int x, y, width, height;
500
501         width= (track->search_max[0]-track->search_min[0])*ibuf->x;
502         height= (track->search_max[1]-track->search_min[1])*ibuf->y;
503
504         tmpibuf= BKE_tracking_acquire_search_imbuf(ibuf, track, marker, 0, pos, origin);
505         disable_imbuf_channels(tmpibuf, track);
506
507         *width_r= width;
508         *height_r= height;
509
510         fp= pixels= MEM_callocN(width*height*sizeof(float), "tracking floatBuf");
511         for(y= 0; y<(int)height; y++) {
512                 for (x= 0; x<(int)width; x++) {
513                         int pixel= tmpibuf->x*y + x;
514                         char *rrgb= (char*)tmpibuf->rect + pixel*4;
515
516                         *fp= (0.2126*rrgb[0] + 0.7152*rrgb[1] + 0.0722*rrgb[2])/255;
517                         fp++;
518                 }
519         }
520
521         IMB_freeImBuf(tmpibuf);
522
523         return pixels;
524 }
525 #endif
526
527 void BKE_tracking_sync(MovieTrackingContext *context)
528 {
529         MovieTrackingTrack *track;
530         ListBase tracks= {NULL, NULL};
531         ListBase *old_tracks= &context->clip->tracking.tracks;
532         int sel_type, newframe;
533         void *sel;
534
535         BKE_movieclip_last_selection(context->clip, &sel_type, &sel);
536
537         /* duplicate currently tracking tracks to list of displaying tracks */
538         track= context->tracks.first;
539         while(track) {
540                 int replace_sel= 0;
541                 MovieTrackingTrack *new_track, *old;
542
543                 /* find original of tracking track in list of previously displayed tracks */
544                 old= BLI_ghash_lookup(context->hash, track);
545                 if(old) {
546                         MovieTrackingTrack *cur= old_tracks->first;
547
548                         while(cur) {
549                                 if(cur==old)
550                                         break;
551
552                                 cur= cur->next;
553                         }
554
555                         /* original track was found, re-use flags and remove this track */
556                         if(cur) {
557                                 if(sel_type==MCLIP_SEL_TRACK && sel==cur)
558                                         replace_sel= 1;
559
560                                 track->flag= cur->flag;
561                                 track->pat_flag= cur->pat_flag;
562                                 track->search_flag= cur->search_flag;
563
564                                 BKE_tracking_free_track(cur);
565                                 BLI_freelinkN(old_tracks, cur);
566                         }
567                 }
568
569                 new_track= BKE_tracking_copy_track(track);
570
571                 BLI_ghash_remove(context->hash, track, NULL, NULL); /* XXX: are we actually need this */
572                 BLI_ghash_insert(context->hash, track, new_track);
573
574                 if(replace_sel)         /* update current selection in clip */
575                         BKE_movieclip_set_selection(context->clip, MCLIP_SEL_TRACK, new_track);
576
577                 BLI_addtail(&tracks, new_track);
578
579                 track= track->next;
580         }
581
582         /* move tracks, which could be added by user during tracking */
583         track= old_tracks->first;
584         while(track) {
585                 MovieTrackingTrack *next= track->next;
586
587                 track->next= track->prev= NULL;
588                 BLI_addtail(&tracks, track);
589
590                 track= next;
591         }
592
593         context->clip->tracking.tracks= tracks;
594
595         if(context->backwards) newframe= context->user.framenr+1;
596         else newframe= context->user.framenr-1;
597
598         context->sync_frame= newframe;
599 }
600
601 void BKE_tracking_sync_user(MovieClipUser *user, MovieTrackingContext *context)
602 {
603         user->framenr= context->sync_frame;
604 }
605
606 int BKE_tracking_next(MovieTrackingContext *context)
607 {
608         ImBuf *ibuf, *ibuf_new;
609         MovieTrackingTrack *track;
610         int curfra= context->user.framenr;
611         int ok= 0;
612
613         /* nothing to track, avoid unneeded frames reading to save time and memory */
614         if(!context->tracks.first)
615                 return 0;
616
617         ibuf= BKE_movieclip_acquire_ibuf(context->clip, &context->user);
618         if(!ibuf) return 0;
619
620         if(context->backwards) context->user.framenr--;
621         else context->user.framenr++;
622
623         ibuf_new= BKE_movieclip_acquire_ibuf(context->clip, &context->user);
624         if(!ibuf_new) {
625                 IMB_freeImBuf(ibuf);
626                 return 0;
627         }
628
629         track= context->tracks.first;
630         while(track) {
631                 MovieTrackingMarker *marker= BKE_tracking_get_marker(track, curfra);
632
633                 if(marker && (marker->flag&MARKER_DISABLED)==0 && marker->framenr==curfra) {
634 #ifdef WITH_LIBMV
635                         int width, height, origin[2];
636                         float pos[2];
637                         float *patch= acquire_search_floatbuf(ibuf, track, marker, &width, &height, pos, origin);
638                         float *patch_new= acquire_search_floatbuf(ibuf_new, track, marker, &width, &height, pos, origin);
639                         double x1= pos[0], y1= pos[1];
640                         double x2= x1, y2= y1;
641                         int wndx, wndy;
642                         MovieTrackingMarker marker_new;
643
644                         wndx= (int)((track->pat_max[0]-track->pat_min[0])*ibuf->x)/2;
645                         wndy= (int)((track->pat_max[1]-track->pat_min[1])*ibuf->y)/2;
646
647                         if(libmv_regionTrackerTrack(context->region_tracker, patch, patch_new,
648                                                 width, height, MAX2(wndx, wndy),
649                                                 x1, y1, &x2, &y2)) {
650                                 memset(&marker_new, 0, sizeof(marker_new));
651                                 marker_new.pos[0]= (origin[0]+x2)/ibuf_new->x;
652                                 marker_new.pos[1]= (origin[1]+y2)/ibuf_new->y;
653
654                                 if(context->backwards) marker_new.framenr= curfra-1;
655                                 else marker_new.framenr= curfra+1;
656
657                                 BKE_tracking_insert_marker(track, &marker_new);
658
659                         } else {
660                                 marker_new= *marker;
661                                 marker_new.framenr++;
662                                 marker_new.flag|= MARKER_DISABLED;
663
664                                 BKE_tracking_insert_marker(track, &marker_new);
665                         }
666
667                         ok= 1;
668
669                         MEM_freeN(patch);
670                         MEM_freeN(patch_new);
671 #endif
672                 }
673
674                 track= track->next;
675         }
676
677         IMB_freeImBuf(ibuf);
678         IMB_freeImBuf(ibuf_new);
679
680         return ok;
681 }
682
683 #if WITH_LIBMV
684 static struct libmv_Tracks *create_libmv_tracks(MovieClip *clip)
685 {
686         int width, height;
687         int tracknr= 0;
688         MovieTrackingTrack *track;
689         struct libmv_Tracks *tracks= libmv_tracksNew();;
690
691         /* XXX: could fail if footage uses images with different sizes */
692         BKE_movieclip_acquire_size(clip, NULL, &width, &height);
693
694         track= clip->tracking.tracks.first;
695         while(track) {
696                 int a= 0;
697
698                 for(a= 0; a<track->markersnr; a++) {
699                         MovieTrackingMarker *marker= &track->markers[a];
700
701                         libmv_tracksInsert(tracks, marker->framenr, tracknr, marker->pos[0]*width, marker->pos[1]*height);
702                 }
703
704                 track= track->next;
705                 tracknr++;
706         }
707
708         return tracks;
709 }
710
711 static void retrive_libmv_reconstruct(MovieClip *clip, struct libmv_Reconstruction *reconstruction)
712 {
713         int tracknr= 0;
714         int sfra= INT_MAX, efra= INT_MIN, a;
715         MovieTracking *tracking= &clip->tracking;
716         MovieTrackingTrack *track;
717         MovieTrackingCamera *camera;
718         MovieReconstructedCamera *reconstructed;
719
720         track= tracking->tracks.first;
721         while(track) {
722                 double pos[3];
723
724                 if(libmv_reporojectionPointForTrack(reconstruction, tracknr, pos)) {
725                         track->bundle_pos[0]= pos[0];
726                         track->bundle_pos[1]= pos[1];
727                         track->bundle_pos[2]= pos[2];
728
729                         track->flag|= TRACK_HAS_BUNDLE;
730                 } else {
731                         track->flag&= ~TRACK_HAS_BUNDLE;
732
733                         if (G.f & G_DEBUG)
734                                 printf("No bundle for track #%d '%s'\n", tracknr, track->name);
735                 }
736
737                 if(track->markersnr) {
738                         if(track->markers[0].framenr<sfra) sfra= track->markers[0].framenr;
739                         if(track->markers[track->markersnr-1].framenr>efra) efra= track->markers[track->markersnr-1].framenr;
740                 }
741
742                 track= track->next;
743                 tracknr++;
744         }
745
746         camera= &tracking->camera;
747
748         if(camera->reconstructed)
749                 MEM_freeN(camera->reconstructed);
750
751         camera->reconnr= 0;
752         reconstructed= MEM_callocN((efra-sfra+1)*sizeof(MovieReconstructedCamera), "temp reconstructed camera");
753
754         for(a= sfra; a<=efra; a++) {
755                 float mat[4][4];
756
757                 if(libmv_reporojectionCameraForImage(reconstruction, a, mat)) {
758                         copy_m4_m4(reconstructed[camera->reconnr].mat, mat);
759                         reconstructed[camera->reconnr].framenr= a;
760                         camera->reconnr++;
761                 } else if (G.f & G_DEBUG) {
762                         printf("No camera for image %d\n", a);
763                 }
764         }
765
766         camera->reconstructed= MEM_callocN(camera->reconnr*sizeof(MovieReconstructedCamera), "reconstructed camera");
767         memcpy(camera->reconstructed, reconstructed, camera->reconnr*sizeof(MovieReconstructedCamera));
768
769         MEM_freeN(reconstructed);
770 }
771
772 #endif
773
774 void BKE_tracking_solve_reconstruction(MovieClip *clip)
775 {
776 #if WITH_LIBMV
777         {
778                 MovieTrackingCamera *camera= &clip->tracking.camera;
779                 MovieTracking *tracking= &clip->tracking;
780                 struct libmv_Tracks *tracks= create_libmv_tracks(clip);
781                 struct libmv_Reconstruction *reconstruction = libmv_solveReconstruction(tracks,
782                         tracking->settings.keyframe1, tracking->settings.keyframe2,
783                         camera->focal, camera->principal[0], camera->principal[1],
784                         camera->k1, camera->k2, camera->k3);
785
786                 retrive_libmv_reconstruct(clip, reconstruction);
787
788                 libmv_destroyReconstruction(reconstruction);
789                 libmv_tracksDestroy(tracks);
790         }
791 #endif
792 }
793
794 void BKE_track_unique_name(MovieTracking *tracking, MovieTrackingTrack *track)
795 {
796         BLI_uniquename(&tracking->tracks, track, "Track", '.', offsetof(MovieTrackingTrack, name), sizeof(track->name));
797 }
798
799 MovieTrackingTrack *BKE_find_track_by_name(MovieTracking *tracking, const char *name)
800 {
801         MovieTrackingTrack *track= tracking->tracks.first;
802
803         while(track) {
804                 if(!strcmp(track->name, name))
805                         return track;
806
807                 track= track->next;
808         }
809
810         return NULL;
811 }
812
813 MovieReconstructedCamera *BKE_tracking_get_reconstructed_camera(MovieTracking *tracking, int framenr)
814 {
815         int a;
816
817         for (a= 0; a<tracking->camera.reconnr; a++ ) {
818                 if(tracking->camera.reconstructed[a].framenr==framenr)
819                         return &tracking->camera.reconstructed[a];
820         }
821
822         return NULL;
823 }