Merging r42896 through r42944 from trunk into soc-2911-tomato
[blender.git] / source / blender / blenkernel / intern / tracking.c
index 1a0007c5bfe3b94668c3593da8e5e2c09f6f1c2f..b75a9ff0037f0beae0b76d31256606273fcb4b4a 100644 (file)
@@ -55,6 +55,7 @@
 #include "BKE_movieclip.h"
 #include "BKE_object.h"
 #include "BKE_scene.h"
+#include "BKE_main.h"  // XXX: ...
 
 #include "IMB_imbuf_types.h"
 #include "IMB_imbuf.h"
@@ -85,11 +86,14 @@ void BKE_tracking_init_settings(MovieTracking *tracking)
        tracking->settings.keyframe1= 1;
        tracking->settings.keyframe2= 30;
        tracking->settings.dist= 1;
+       tracking->settings.object_distance= 1;
 
        tracking->stabilization.scaleinf= 1.0f;
        tracking->stabilization.locinf= 1.0f;
        tracking->stabilization.rotinf= 1.0f;
        tracking->stabilization.maxscale= 2.0f;
+
+       BKE_tracking_new_object(tracking, "Camera");
 }
 
 void BKE_tracking_clamp_track(MovieTrackingTrack *track, int event)
@@ -208,7 +212,7 @@ void BKE_tracking_track_flag(MovieTrackingTrack *track, int area, int flag, int
        }
 }
 
-MovieTrackingTrack *BKE_tracking_add_track(MovieTracking *tracking, float x, float y,
+MovieTrackingTrack *BKE_tracking_add_track(MovieTracking *tracking, ListBase *tracksbase, float x, float y,
                        int framenr, int width, int height)
 {
        MovieTrackingTrack *track;
@@ -251,8 +255,8 @@ MovieTrackingTrack *BKE_tracking_add_track(MovieTracking *tracking, float x, flo
        if(track->tracker == TRACKER_KLT)
                BKE_tracking_clamp_track(track, CLAMP_PYRAMID_LEVELS);
 
-       BLI_addtail(&tracking->tracks, track);
-       BKE_track_unique_name(tracking, track);
+       BLI_addtail(tracksbase, track);
+       BKE_track_unique_name(tracksbase, track);
 
        return track;
 }
@@ -524,18 +528,44 @@ void BKE_tracking_join_tracks(MovieTrackingTrack *dst_track, MovieTrackingTrack
        dst_track->markersnr= tot;
 }
 
-void BKE_tracking_free(MovieTracking *tracking)
+static void tracking_tracks_free(ListBase *tracks)
 {
        MovieTrackingTrack *track;
 
-       for(track= tracking->tracks.first; track; track= track->next) {
+       for(track= tracks->first; track; track= track->next) {
                BKE_tracking_free_track(track);
        }
 
-       BLI_freelistN(&tracking->tracks);
+       BLI_freelistN(tracks);
+}
+
+static void tracking_reconstruction_free(MovieTrackingReconstruction *reconstruction)
+{
+       if(reconstruction->cameras)
+               MEM_freeN(reconstruction->cameras);
+}
+
+static void tracking_object_free(MovieTrackingObject *object)
+{
+       tracking_tracks_free(&object->tracks);
+       tracking_reconstruction_free(&object->reconstruction);
+}
+
+static void tracking_objects_free(ListBase *objects)
+{
+       MovieTrackingObject *object;
+
+       for(object= objects->first; object; object= object->next)
+               tracking_object_free(object);
 
-       if(tracking->reconstruction.cameras)
-               MEM_freeN(tracking->reconstruction.cameras);
+       BLI_freelistN(objects);
+}
+
+void BKE_tracking_free(MovieTracking *tracking)
+{
+       tracking_tracks_free(&tracking->tracks);
+       tracking_reconstruction_free(&tracking->reconstruction);
+       tracking_objects_free(&tracking->objects);
 
        if(tracking->stabilization.scaleibuf)
                IMB_freeImBuf(tracking->stabilization.scaleibuf);
@@ -547,6 +577,9 @@ void BKE_tracking_free(MovieTracking *tracking)
 /*********************** tracks map *************************/
 
 typedef struct TracksMap {
+       char object_name[32];
+       int is_camera;
+
        int num_tracks;
        int customdata_size;
 
@@ -558,10 +591,13 @@ typedef struct TracksMap {
        int ptr;
 } TracksMap;
 
-static TracksMap *tracks_map_new(int num_tracks, int customdata_size)
+static TracksMap *tracks_map_new(const char *object_name, int is_camera, int num_tracks, int customdata_size)
 {
        TracksMap *map= MEM_callocN(sizeof(TracksMap), "TrackingsMap");
 
+       strcpy(map->object_name, object_name);
+       map->is_camera= is_camera;
+
        map->num_tracks= num_tracks;
        map->customdata_size= customdata_size;
 
@@ -607,10 +643,24 @@ static void tracks_map_insert(TracksMap *map, MovieTrackingTrack *track, void *c
 static void tracks_map_merge(TracksMap *map, MovieTracking *tracking)
 {
        MovieTrackingTrack *track;
+       MovieTrackingTrack *act_track= BKE_tracking_active_track(tracking);
        ListBase tracks= {NULL, NULL}, new_tracks= {NULL, NULL};
-       ListBase *old_tracks= &tracking->tracks;
+       ListBase *old_tracks;
        int a;
 
+       if(map->is_camera) {
+               old_tracks= &tracking->tracks;
+       } else {
+               MovieTrackingObject *object= BKE_tracking_named_object(tracking, map->object_name);
+
+               if(!object) {
+                       /* object was deleted by user, create new one */
+                       object= BKE_tracking_new_object(tracking, map->object_name);
+               }
+
+               old_tracks= &object->tracks;
+       }
+
        /* duplicate currently operating tracks to temporary list.
           this is needed to keep names in unique state and it's faster to change names
           of currently operating tracks (if needed) */
@@ -634,7 +684,7 @@ static void tracks_map_merge(TracksMap *map, MovieTracking *tracking)
 
                        /* original track was found, re-use flags and remove this track */
                        if(cur) {
-                               if(cur==tracking->act_track)
+                               if(act_track)
                                        replace_sel= 1;
 
                                track->flag= cur->flag;
@@ -685,7 +735,7 @@ static void tracks_map_merge(TracksMap *map, MovieTracking *tracking)
                track= next;
        }
 
-       tracking->tracks= new_tracks;
+       *old_tracks= new_tracks;
 }
 
 static void tracks_map_free(TracksMap *map, void (*customdata_free) (void *customdata))
@@ -737,27 +787,28 @@ typedef struct MovieTrackingContext {
        MovieTrackingSettings settings;
        TracksMap *tracks_map;
 
-       short backwards, disable_failed, sequence;
+       short backwards, sequence;
        int sync_frame;
 } MovieTrackingContext;
 
-MovieTrackingContext *BKE_tracking_context_new(MovieClip *clip, MovieClipUser *user, short backwards, short disable_failed, short sequence)
+MovieTrackingContext *BKE_tracking_context_new(MovieClip *clip, MovieClipUser *user, short backwards, short sequence)
 {
        MovieTrackingContext *context= MEM_callocN(sizeof(MovieTrackingContext), "trackingContext");
        MovieTracking *tracking= &clip->tracking;
        MovieTrackingSettings *settings= &tracking->settings;
+       ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
        MovieTrackingTrack *track;
+       MovieTrackingObject *object= BKE_tracking_active_object(tracking);
        int num_tracks= 0;
 
        context->settings= *settings;
        context->backwards= backwards;
-       context->disable_failed= disable_failed;
        context->sync_frame= user->framenr;
        context->first_time= 1;
        context->sequence= sequence;
 
        /* count */
-       track= tracking->tracks.first;
+       track= tracksbase->first;
        while(track) {
                if(TRACK_SELECTED(track) && (track->flag&TRACK_LOCKED)==0) {
                        MovieTrackingMarker *marker= BKE_tracking_get_marker(track, user->framenr);
@@ -772,12 +823,13 @@ MovieTrackingContext *BKE_tracking_context_new(MovieClip *clip, MovieClipUser *u
        if(num_tracks) {
                int width, height;
 
-               context->tracks_map= tracks_map_new(num_tracks, sizeof(TrackContext));
+               context->tracks_map= tracks_map_new(object->name, object->flag & TRACKING_OBJECT_CAMERA,
+                                       num_tracks, sizeof(TrackContext));
 
                BKE_movieclip_get_size(clip, user, &width, &height);
 
                /* create tracking data */
-               track= tracking->tracks.first;
+               track= tracksbase->first;
                while(track) {
                        if(TRACK_SELECTED(track) && (track->flag&TRACK_LOCKED)==0) {
                                MovieTrackingMarker *marker= BKE_tracking_get_marker(track, user->framenr);
@@ -883,29 +935,53 @@ void BKE_tracking_context_free(MovieTrackingContext *context)
        MEM_freeN(context);
 }
 
-static void disable_imbuf_channels(ImBuf *ibuf, MovieTrackingTrack *track)
+/* zap channels from the imbuf that are disabled by the user. this can lead to
+ * better tracks sometimes. however, instead of simply zeroing the channels
+ * out, do a partial grayscale conversion so the display is better. */
+static void disable_imbuf_channels(ImBuf *ibuf, MovieTrackingTrack *track, int grayscale)
 {
        int x, y;
+       float scale;
 
-       if((track->flag&(TRACK_DISABLE_RED|TRACK_DISABLE_GREEN|TRACK_DISABLE_BLUE))==0)
+       if((track->flag&(TRACK_DISABLE_RED|TRACK_DISABLE_GREEN|TRACK_DISABLE_BLUE))==0 && !grayscale)
                return;
 
+       /* If only some components are selected, it's important to rescale the result
+        * appropriately so that e.g. if only blue is selected, it's not zeroed out. */
+       scale = ((track->flag&TRACK_DISABLE_RED  ) ? 0.0f : 0.2126f) +
+               ((track->flag&TRACK_DISABLE_GREEN) ? 0.0f : 0.7152f) +
+               ((track->flag&TRACK_DISABLE_BLUE)  ? 0.0f : 0.0722f);
+
        for(y= 0; y<ibuf->y; y++) {
                for (x= 0; x<ibuf->x; x++) {
                        int pixel= ibuf->x*y + x;
 
                        if(ibuf->rect_float) {
                                float *rrgbf= ibuf->rect_float + pixel*4;
-
-                               if(track->flag&TRACK_DISABLE_RED)       rrgbf[0]= 0;
-                               if(track->flag&TRACK_DISABLE_GREEN)     rrgbf[1]= 0;
-                               if(track->flag&TRACK_DISABLE_BLUE)      rrgbf[2]= 0;
+                               float r = (track->flag&TRACK_DISABLE_RED)   ? 0.0f : rrgbf[0];
+                               float g = (track->flag&TRACK_DISABLE_GREEN) ? 0.0f : rrgbf[1];
+                               float b = (track->flag&TRACK_DISABLE_BLUE)  ? 0.0f : rrgbf[2];
+                               if (grayscale) {
+                                       float gray = (0.2126f*r + 0.7152f*g + 0.0722f*b) / scale;
+                                       rrgbf[0] = rrgbf[1] = rrgbf[2] = gray;
+                               } else {
+                                       rrgbf[0] = r;
+                                       rrgbf[1] = g;
+                                       rrgbf[2] = b;
+                               }
                        } else {
                                char *rrgb= (char*)ibuf->rect + pixel*4;
-
-                               if(track->flag&TRACK_DISABLE_RED)       rrgb[0]= 0;
-                               if(track->flag&TRACK_DISABLE_GREEN)     rrgb[1]= 0;
-                               if(track->flag&TRACK_DISABLE_BLUE)      rrgb[2]= 0;
+                               char r = (track->flag&TRACK_DISABLE_RED)   ? 0 : rrgb[0];
+                               char g = (track->flag&TRACK_DISABLE_GREEN) ? 0 : rrgb[1];
+                               char b = (track->flag&TRACK_DISABLE_BLUE)  ? 0 : rrgb[2];
+                               if (grayscale) {
+                                       float gray = (0.2126f*r + 0.7152f*g + 0.0722f*b) / scale;
+                                       rrgb[0] = rrgb[1] = rrgb[2] = gray;
+                               } else {
+                                       rrgb[0] = r;
+                                       rrgb[1] = g;
+                                       rrgb[2] = b;
+                               }
                        }
                }
        }
@@ -947,7 +1023,12 @@ static ImBuf *get_area_imbuf(ImBuf *ibuf, MovieTrackingTrack *track, MovieTracki
                origin[1]= y1-margin;
        }
 
-       disable_imbuf_channels(tmpibuf, track);
+       if ((track->flag & TRACK_PREVIEW_GRAYSCALE) ||
+                       (track->flag & TRACK_DISABLE_RED)       ||
+                       (track->flag & TRACK_DISABLE_GREEN)     ||
+                       (track->flag & TRACK_DISABLE_BLUE) ) {
+               disable_imbuf_channels(tmpibuf, track, 1 /* grayscale */);
+       }
 
        return tmpibuf;
 }
@@ -976,7 +1057,7 @@ static float *get_search_floatbuf(ImBuf *ibuf, MovieTrackingTrack *track, MovieT
        height= (track->search_max[1]-track->search_min[1])*ibuf->y;
 
        tmpibuf= BKE_tracking_get_search_imbuf(ibuf, track, marker, 0, 0, pos, origin);
-       disable_imbuf_channels(tmpibuf, track);
+       disable_imbuf_channels(tmpibuf, track, 0 /* don't grayscale */);
 
        *width_r= width;
        *height_r= height;
@@ -988,14 +1069,11 @@ static float *get_search_floatbuf(ImBuf *ibuf, MovieTrackingTrack *track, MovieT
 
                        if(tmpibuf->rect_float) {
                                float *rrgbf= tmpibuf->rect_float + pixel*4;
-
                                *fp= 0.2126*rrgbf[0] + 0.7152*rrgbf[1] + 0.0722*rrgbf[2];
                        } else {
                                unsigned char *rrgb= (unsigned char*)tmpibuf->rect + pixel*4;
-
                                *fp= (0.2126*rrgb[0] + 0.7152*rrgb[1] + 0.0722*rrgb[2])/255.0f;
                        }
-
                        fp++;
                }
        }
@@ -1017,14 +1095,11 @@ static unsigned char *get_ucharbuf(ImBuf *ibuf)
 
                        if(ibuf->rect_float) {
                                float *rrgbf= ibuf->rect_float + pixel*4;
-
                                *cp= FTOCHAR(0.2126f*rrgbf[0] + 0.7152f*rrgbf[1] + 0.0722f*rrgbf[2]);
                        } else {
                                unsigned char *rrgb= (unsigned char*)ibuf->rect + pixel*4;
-
                                *cp= 0.2126f*rrgb[0] + 0.7152f*rrgb[1] + 0.0722f*rrgb[2];
                        }
-
                        cp++;
                }
        }
@@ -1039,7 +1114,7 @@ static unsigned char *get_search_bytebuf(ImBuf *ibuf, MovieTrackingTrack *track,
        unsigned char *pixels;
 
        tmpibuf= BKE_tracking_get_search_imbuf(ibuf, track, marker, 0, 0, pos, origin);
-       disable_imbuf_channels(tmpibuf, track);
+       disable_imbuf_channels(tmpibuf, track, 0 /* don't grayscale */);
 
        *width_r= tmpibuf->x;
        *height_r= tmpibuf->y;
@@ -1302,8 +1377,8 @@ int BKE_tracking_next(MovieTrackingContext *context)
                                MEM_freeN(image_new);
                        }
 
-                       coords_correct= !onbound && !isnan(x2) && !isnan(y2) && finite(x2) && finite(y2);
-                       if(coords_correct && (tracked || !context->disable_failed)) {
+                       coords_correct= !isnan(x2) && !isnan(y2) && finite(x2) && finite(y2);
+                       if(coords_correct && !onbound && tracked) {
                                if(context->first_time) {
                                        #pragma omp critical
                                        {
@@ -1370,6 +1445,8 @@ typedef struct MovieReconstructContext {
 
        struct libmv_Reconstruction *reconstruction;
 #endif
+       char object_name[32];
+       int is_camera;
 
        float focal_length;
        float principal_point[2];
@@ -1391,13 +1468,13 @@ typedef struct ReconstructProgressData {
 } ReconstructProgressData;
 
 #if WITH_LIBMV
-static struct libmv_Tracks *create_libmv_tracks(MovieTracking *tracking, int width, int height)
+static struct libmv_Tracks *create_libmv_tracks(ListBase *tracksbase, int width, int height)
 {
        int tracknr= 0;
        MovieTrackingTrack *track;
        struct libmv_Tracks *tracks= libmv_tracksNew();
 
-       track= tracking->tracks.first;
+       track= tracksbase->first;
        while(track) {
                int a= 0;
 
@@ -1441,16 +1518,28 @@ static void retrieve_libmv_reconstruct_intrinscis(MovieReconstructContext *conte
 static int retrieve_libmv_reconstruct_tracks(MovieReconstructContext *context, MovieTracking *tracking)
 {
        struct libmv_Reconstruction *libmv_reconstruction= context->reconstruction;
-       MovieTrackingReconstruction *reconstruction= &tracking->reconstruction;
+       MovieTrackingReconstruction *reconstruction= NULL;
        MovieReconstructedCamera *reconstructed;
        MovieTrackingTrack *track;
+       ListBase *tracksbase=  NULL;
        int ok= 1, tracknr= 0, a, origin_set= 0;
        int sfra= context->sfra, efra= context->efra;
        float imat[4][4];
 
+       if(context->is_camera) {
+               tracksbase= &tracking->tracks;
+               reconstruction= &tracking->reconstruction;
+       }
+       else {
+               MovieTrackingObject *object= BKE_tracking_named_object(tracking, context->object_name);
+
+               tracksbase= &object->tracks;
+               reconstruction= &object->reconstruction;
+       }
+
        unit_m4(imat);
 
-       track= tracking->tracks.first;
+       track= tracksbase->first;
        while(track) {
                double pos[3];
 
@@ -1516,7 +1605,7 @@ static int retrieve_libmv_reconstruct_tracks(MovieReconstructContext *context, M
        }
 
        if(origin_set) {
-               track= tracking->tracks.first;
+               track= tracksbase->first;
                while(track) {
                        if(track->flag&TRACK_HAS_BUNDLE)
                                mul_v3_m4v3(track->bundle_pos, imat, track->bundle_pos);
@@ -1532,19 +1621,20 @@ static int retrieve_libmv_reconstruct_tracks(MovieReconstructContext *context, M
 
 static int retrieve_libmv_reconstruct(MovieReconstructContext *context, MovieTracking *tracking)
 {
-       tracks_map_merge(context->tracks_map, tracking);
-
        /* take the intrinscis back from libmv */
        retrieve_libmv_reconstruct_intrinscis(context, tracking);
 
        return retrieve_libmv_reconstruct_tracks(context, tracking);
 }
 
-static int get_refine_intrinsics_flags(MovieTracking *tracking)
+static int get_refine_intrinsics_flags(MovieTracking *tracking, MovieTrackingObject *object)
 {
        int refine= tracking->settings.refine_camera_intrinsics;
        int flags= 0;
 
+       if((object->flag&TRACKING_OBJECT_CAMERA)==0)
+               return 0;
+
        if(refine&REFINE_FOCAL_LENGTH)
                flags|= LIBMV_REFINE_FOCAL_LENGTH;
 
@@ -1560,13 +1650,13 @@ static int get_refine_intrinsics_flags(MovieTracking *tracking)
        return flags;
 }
 
-static int count_tracks_on_both_keyframes(MovieTracking *tracking)
+static int count_tracks_on_both_keyframes(MovieTracking *tracking, ListBase *tracksbase)
 {
        int tot= 0;
        int frame1= tracking->settings.keyframe1, frame2= tracking->settings.keyframe2;
        MovieTrackingTrack *track;
 
-       track= tracking->tracks.first;
+       track= tracksbase->first;
        while(track) {
                if(BKE_tracking_has_marker(track, frame1))
                        if(BKE_tracking_has_marker(track, frame2))
@@ -1579,10 +1669,12 @@ static int count_tracks_on_both_keyframes(MovieTracking *tracking)
 }
 #endif
 
-int BKE_tracking_can_reconstruct(MovieTracking *tracking, char *error_msg, int error_size)
+int BKE_tracking_can_reconstruct(MovieTracking *tracking, MovieTrackingObject *object, char *error_msg, int error_size)
 {
 #if WITH_LIBMV
-       if(count_tracks_on_both_keyframes(tracking)<8) {
+       ListBase *tracksbase= BKE_tracking_object_tracks(tracking, object);
+
+       if(count_tracks_on_both_keyframes(tracking, tracksbase)<8) {
                BLI_strncpy(error_msg, "At least 8 tracks on both of keyframes are needed for reconstruction", error_size);
                return 0;
        }
@@ -1597,17 +1689,22 @@ int BKE_tracking_can_reconstruct(MovieTracking *tracking, char *error_msg, int e
 }
 
 MovieReconstructContext* BKE_tracking_reconstruction_context_new(MovieTracking *tracking,
-                       int keyframe1, int keyframe2, int width, int height)
+                       MovieTrackingObject *object, int keyframe1, int keyframe2, int width, int height)
 {
        MovieReconstructContext *context= MEM_callocN(sizeof(MovieReconstructContext), "MovieReconstructContext data");
        MovieTrackingCamera *camera= &tracking->camera;
+       ListBase *tracksbase= BKE_tracking_object_tracks(tracking, object);
        float aspy= 1.0f/tracking->camera.pixel_aspect;
-       int num_tracks= BLI_countlist(&tracking->tracks);
+       int num_tracks= BLI_countlist(tracksbase);
        int sfra= INT_MAX, efra= INT_MIN;
        MovieTrackingTrack *track;
 
-       context->tracks_map= tracks_map_new(num_tracks, 0);
-       track= tracking->tracks.first;
+       strcpy(context->object_name, object->name);
+       context->is_camera = object->flag&TRACKING_OBJECT_CAMERA;
+
+       context->tracks_map= tracks_map_new(context->object_name, context->is_camera, num_tracks, 0);
+
+       track= tracksbase->first;
        while(track) {
                int first= 0, last= track->markersnr;
                MovieTrackingMarker *first_marker= &track->markers[0];
@@ -1640,10 +1737,10 @@ MovieReconstructContext* BKE_tracking_reconstruction_context_new(MovieTracking *
        context->efra= efra;
 
 #ifdef WITH_LIBMV
-       context->tracks= create_libmv_tracks(tracking, width, height*aspy);
+       context->tracks= create_libmv_tracks(tracksbase, width, height*aspy);
        context->keyframe1= keyframe1;
        context->keyframe2= keyframe2;
-       context->refine_flags= get_refine_intrinsics_flags(tracking);
+       context->refine_flags= get_refine_intrinsics_flags(tracking, object);
 #else
        (void) width;
        (void) height;
@@ -1740,8 +1837,22 @@ void BKE_tracking_solve_reconstruction(MovieReconstructContext *context, short *
 
 int BKE_tracking_finish_reconstruction(MovieReconstructContext *context, MovieTracking *tracking)
 {
-       tracking->reconstruction.error= context->reprojection_error;
-       tracking->reconstruction.flag|= TRACKING_RECONSTRUCTED;
+       MovieTrackingReconstruction *reconstruction;
+
+       tracks_map_merge(context->tracks_map, tracking);
+
+       if(context->is_camera) {
+               reconstruction= &tracking->reconstruction;
+       }
+       else {
+               MovieTrackingObject *object;
+
+               object= BKE_tracking_named_object(tracking, context->object_name);
+               reconstruction= &object->reconstruction;
+       }
+
+       reconstruction->error= context->reprojection_error;
+       reconstruction->flag|= TRACKING_RECONSTRUCTED;
 
 #ifdef WITH_LIBMV
        if(!retrieve_libmv_reconstruct(context, tracking))
@@ -1751,14 +1862,15 @@ int BKE_tracking_finish_reconstruction(MovieReconstructContext *context, MovieTr
        return 1;
 }
 
-void BKE_track_unique_name(MovieTracking *tracking, MovieTrackingTrack *track)
+void BKE_track_unique_name(ListBase *tracksbase, MovieTrackingTrack *track)
 {
-       BLI_uniquename(&tracking->tracks, track, "Track", '.', offsetof(MovieTrackingTrack, name), sizeof(track->name));
+       BLI_uniquename(tracksbase, track, "Track", '.', offsetof(MovieTrackingTrack, name), sizeof(track->name));
 }
 
-MovieTrackingTrack *BKE_tracking_named_track(MovieTracking *tracking, const char *name)
+MovieTrackingTrack *BKE_tracking_named_track(MovieTracking *tracking, MovieTrackingObject *object, const char *name)
 {
-       MovieTrackingTrack *track= tracking->tracks.first;
+       ListBase *tracksbase= BKE_tracking_object_tracks(tracking, object);
+       MovieTrackingTrack *track= tracksbase->first;
 
        while(track) {
                if(!strcmp(track->name, name))
@@ -1770,9 +1882,8 @@ MovieTrackingTrack *BKE_tracking_named_track(MovieTracking *tracking, const char
        return NULL;
 }
 
-static int reconstruction_camera_index(MovieTracking *tracking, int framenr, int nearest)
+static int reconstruction_camera_index(MovieTrackingReconstruction *reconstruction, int framenr, int nearest)
 {
-       MovieTrackingReconstruction *reconstruction= &tracking->reconstruction;
        MovieReconstructedCamera *cameras= reconstruction->cameras;
        int a= 0, d= 1;
 
@@ -1824,21 +1935,41 @@ static int reconstruction_camera_index(MovieTracking *tracking, int framenr, int
        return -1;
 }
 
-MovieReconstructedCamera *BKE_tracking_get_reconstructed_camera(MovieTracking *tracking, int framenr)
+static void scale_reconstructed_camera(MovieTrackingObject *object, float mat[4][4])
 {
-       int a= reconstruction_camera_index(tracking, framenr, 0);
+       if((object->flag&TRACKING_OBJECT_CAMERA)==0) {
+               float smat[4][4];
+
+               scale_m4_fl(smat, 1.0f/object->scale);
+               mult_m4_m4m4(mat, mat, smat);
+       }
+}
+
+MovieReconstructedCamera *BKE_tracking_get_reconstructed_camera(MovieTracking *tracking,
+                       MovieTrackingObject *object, int framenr)
+{
+       MovieTrackingReconstruction *reconstruction;
+       int a;
+
+       reconstruction= BKE_tracking_object_reconstruction(tracking, object);
+       a= reconstruction_camera_index(reconstruction, framenr, 0);
 
        if(a==-1)
                return NULL;
 
-       return &tracking->reconstruction.cameras[a];
+       return &reconstruction->cameras[a];
 }
 
-void BKE_tracking_get_interpolated_camera(MovieTracking *tracking, int framenr, float mat[4][4])
+void BKE_tracking_get_interpolated_camera(MovieTracking *tracking, MovieTrackingObject *object,
+                       int framenr, float mat[4][4])
 {
-       MovieTrackingReconstruction *reconstruction= &tracking->reconstruction;
-       MovieReconstructedCamera *cameras= reconstruction->cameras;
-       int a= reconstruction_camera_index(tracking, framenr, 1);
+       MovieTrackingReconstruction *reconstruction;
+       MovieReconstructedCamera *cameras;
+       int a;
+
+       reconstruction= BKE_tracking_object_reconstruction(tracking, object);
+       cameras= reconstruction->cameras;
+       a= reconstruction_camera_index(reconstruction, framenr, 1);
 
        if(a==-1) {
                unit_m4(mat);
@@ -1852,6 +1983,8 @@ void BKE_tracking_get_interpolated_camera(MovieTracking *tracking, int framenr,
        } else {
                copy_m4_m4(mat, cameras[a].mat);
        }
+
+       scale_reconstructed_camera(object, mat);
 }
 
 void BKE_get_tracking_mat(Scene *scene, Object *ob, float mat[4][4])
@@ -1890,7 +2023,8 @@ void BKE_tracking_camera_to_blender(MovieTracking *tracking, Scene *scene, Camer
        BKE_tracking_camera_shift(tracking, width, height, &camera->shiftx, &camera->shifty);
 }
 
-void BKE_tracking_projection_matrix(MovieTracking *tracking, int framenr, int winx, int winy, float mat[4][4])
+void BKE_tracking_projection_matrix(MovieTracking *tracking, MovieTrackingObject *object,
+                       int framenr, int winx, int winy, float mat[4][4])
 {
        MovieReconstructedCamera *camera;
        float lens= tracking->camera.focal*tracking->camera.sensor_width/(float)winx;
@@ -1923,7 +2057,8 @@ void BKE_tracking_projection_matrix(MovieTracking *tracking, int framenr, int wi
 
        perspective_m4(winmat, left, right, bottom, top, clipsta, clipend);
 
-       camera= BKE_tracking_get_reconstructed_camera(tracking, framenr);
+       camera= BKE_tracking_get_reconstructed_camera(tracking, object, framenr);
+
        if(camera) {
                float imat[4][4];
 
@@ -1932,6 +2067,77 @@ void BKE_tracking_projection_matrix(MovieTracking *tracking, int framenr, int wi
        } else copy_m4_m4(mat, winmat);
 }
 
+ListBase *BKE_tracking_get_tracks(MovieTracking *tracking)
+{
+       MovieTrackingObject *object= BKE_tracking_active_object(tracking);
+
+       if(object && (object->flag & TRACKING_OBJECT_CAMERA) == 0) {
+               return &object->tracks;
+       }
+
+       return &tracking->tracks;
+}
+
+MovieTrackingTrack *BKE_tracking_active_track(MovieTracking *tracking)
+{
+       ListBase *tracksbase;
+
+       if(!tracking->act_track)
+               return NULL;
+
+       tracksbase= BKE_tracking_get_tracks(tracking);
+
+       /* check that active track is in current tracks list */
+       if(BLI_findindex(tracksbase, tracking->act_track) >= 0)
+               return tracking->act_track;
+
+       return NULL;
+}
+
+MovieTrackingObject *BKE_tracking_active_object(MovieTracking *tracking)
+{
+       return BLI_findlink(&tracking->objects, tracking->objectnr);
+}
+
+MovieTrackingObject *BKE_tracking_get_camera_object(MovieTracking *tracking)
+{
+       MovieTrackingObject *object= tracking->objects.first;
+
+       while(object) {
+               if(object->flag & TRACKING_OBJECT_CAMERA)
+                       return object;
+
+               object= object->next;
+       }
+
+       return NULL;
+}
+
+ListBase *BKE_tracking_object_tracks(MovieTracking *tracking, MovieTrackingObject *object)
+{
+       if(object->flag & TRACKING_OBJECT_CAMERA) {
+               return &tracking->tracks;
+       }
+
+       return &object->tracks;
+}
+
+MovieTrackingReconstruction *BKE_tracking_object_reconstruction(MovieTracking *tracking, MovieTrackingObject *object)
+{
+       if(object->flag & TRACKING_OBJECT_CAMERA) {
+               return &tracking->reconstruction;
+       }
+
+       return &object->reconstruction;
+}
+
+MovieTrackingReconstruction *BKE_tracking_get_reconstruction(MovieTracking *tracking)
+{
+       MovieTrackingObject *object= BKE_tracking_active_object(tracking);
+
+       return BKE_tracking_object_reconstruction(tracking, object);
+}
+
 void BKE_tracking_apply_intrinsics(MovieTracking *tracking, float co[2], float nco[2])
 {
        MovieTrackingCamera *camera= &tracking->camera;
@@ -2018,8 +2224,9 @@ static int point_in_layer(bGPDlayer *layer, float x, float y)
        return 0;
 }
 
-static void retrieve_libmv_features(MovieTracking *tracking, struct libmv_Features *features,
-                       int framenr, int width, int height, bGPDlayer *layer, int place_outside_layer)
+static void retrieve_libmv_features(MovieTracking *tracking, ListBase *tracksbase,
+                       struct libmv_Features *features, int framenr, int width, int height,
+                       bGPDlayer *layer, int place_outside_layer)
 {
        int a;
 
@@ -2039,7 +2246,7 @@ static void retrieve_libmv_features(MovieTracking *tracking, struct libmv_Featur
                        ok= point_in_layer(layer, xu, yu)!=place_outside_layer;
 
                if(ok) {
-                       track= BKE_tracking_add_track(tracking, xu, yu, framenr, width, height);
+                       track= BKE_tracking_add_track(tracking, tracksbase, xu, yu, framenr, width, height);
                        track->flag|= SELECT;
                        track->pat_flag|= SELECT;
                        track->search_flag|= SELECT;
@@ -2048,7 +2255,7 @@ static void retrieve_libmv_features(MovieTracking *tracking, struct libmv_Featur
 }
 #endif
 
-void BKE_tracking_detect_fast(MovieTracking *tracking, ImBuf *ibuf,
+void BKE_tracking_detect_fast(MovieTracking *tracking, ListBase *tracksbase, ImBuf *ibuf,
                        int framenr, int margin, int min_trackness, int min_distance, bGPDlayer *layer,
                        int place_outside_layer)
 {
@@ -2056,11 +2263,13 @@ void BKE_tracking_detect_fast(MovieTracking *tracking, ImBuf *ibuf,
        struct libmv_Features *features;
        unsigned char *pixels= get_ucharbuf(ibuf);
 
-       features= libmv_detectFeaturesFAST(pixels, ibuf->x, ibuf->y, ibuf->x, margin, min_trackness, min_distance);
+       features= libmv_detectFeaturesFAST(pixels, ibuf->x, ibuf->y, ibuf->x,
+                       margin, min_trackness, min_distance);
 
        MEM_freeN(pixels);
 
-       retrieve_libmv_features(tracking, features, framenr, ibuf->x, ibuf->y, layer, place_outside_layer);
+       retrieve_libmv_features(tracking, tracksbase, features, framenr,
+                       ibuf->x, ibuf->y, layer, place_outside_layer);
 
        libmv_destroyFeatures(features);
 #else
@@ -2075,22 +2284,34 @@ void BKE_tracking_detect_fast(MovieTracking *tracking, ImBuf *ibuf,
 #endif
 }
 
-MovieTrackingTrack *BKE_tracking_indexed_track(MovieTracking *tracking, int tracknr)
+MovieTrackingTrack *BKE_tracking_indexed_track(MovieTracking *tracking, int tracknr, ListBase **tracksbase_r)
 {
-       MovieTrackingTrack *track= tracking->tracks.first;
+       MovieTrackingObject *object;
        int cur= 1;
 
-       while(track) {
-               if(track->flag&TRACK_HAS_BUNDLE) {
-                       if(cur==tracknr)
-                               return track;
+       object= tracking->objects.first;
+       while(object) {
+               ListBase *tracksbase= BKE_tracking_object_tracks(tracking, object);
+               MovieTrackingTrack *track= tracksbase->first;
+
+               while(track) {
+                       if(track->flag&TRACK_HAS_BUNDLE) {
+                               if(cur==tracknr) {
+                                       *tracksbase_r= tracksbase;
+                                       return track;
+                               }
+
+                               cur++;
+                       }
 
-                       cur++;
+                       track= track->next;
                }
 
-               track= track->next;
+               object= object->next;
        }
 
+       *tracksbase_r= NULL;
+
        return NULL;
 }
 
@@ -2102,6 +2323,8 @@ static int stabilization_median_point(MovieTracking *tracking, int framenr, floa
 
        INIT_MINMAX2(min, max);
 
+       (void) tracking;
+
        track= tracking->tracks.first;
        while(track) {
                if(track->flag&TRACK_USE_2D_STAB) {
@@ -2539,12 +2762,12 @@ ImBuf *BKE_tracking_distort(MovieTracking *tracking, ImBuf *ibuf, int width, int
 }
 
 /* area - which part of marker should be selected. see TRACK_AREA_* constants */
-void BKE_tracking_select_track(MovieTracking *tracking, MovieTrackingTrack *track, int area, int extend)
+void BKE_tracking_select_track(ListBase *tracksbase, MovieTrackingTrack *track, int area, int extend)
 {
        if(extend) {
                BKE_tracking_track_flag(track, area, SELECT, 0);
        } else {
-               MovieTrackingTrack *cur= tracking->tracks.first;
+               MovieTrackingTrack *cur= tracksbase->first;
 
                while(cur) {
                        if(cur==track) {
@@ -2564,3 +2787,78 @@ void BKE_tracking_deselect_track(MovieTrackingTrack *track, int area)
 {
        BKE_tracking_track_flag(track, area, SELECT, 1);
 }
+
+MovieTrackingObject *BKE_tracking_new_object(MovieTracking *tracking, const char *name)
+{
+       MovieTrackingObject *object= MEM_callocN(sizeof(MovieTrackingObject), "tracking object");
+
+       if(tracking->tot_object==0) {
+               /* first object is always camera */
+               BLI_strncpy(object->name, "Camera", sizeof(object->name));
+
+               object->flag|= TRACKING_OBJECT_CAMERA;
+       }
+       else {
+               BLI_strncpy(object->name, name, sizeof(object->name));
+       }
+
+       BLI_addtail(&tracking->objects, object);
+
+       tracking->tot_object++;
+       tracking->objectnr= BLI_countlist(&tracking->objects) - 1;
+
+       BKE_tracking_object_unique_name(tracking, object);
+
+       return object;
+}
+
+void BKE_tracking_remove_object(MovieTracking *tracking, MovieTrackingObject *object)
+{
+       MovieTrackingTrack *track;
+       int index= BLI_findindex(&tracking->objects, object);
+
+       if(index<0)
+               return;
+
+       if(object->flag & TRACKING_OBJECT_CAMERA) {
+               /* object used for camera solving can't be deleted */
+               return;
+       }
+
+       track= object->tracks.first;
+       while(track) {
+               if(track==tracking->act_track)
+                       tracking->act_track= NULL;
+
+               track= track->next;
+       }
+
+       tracking_object_free(object);
+       BLI_freelinkN(&tracking->objects, object);
+
+       tracking->tot_object--;
+
+       if(index>0)
+               tracking->objectnr= index-1;
+       else
+               tracking->objectnr= 0;
+}
+
+void BKE_tracking_object_unique_name(MovieTracking *tracking, MovieTrackingObject *object)
+{
+       BLI_uniquename(&tracking->objects, object, "Object", '.', offsetof(MovieTrackingObject, name), sizeof(object->name));
+}
+
+MovieTrackingObject *BKE_tracking_named_object(MovieTracking *tracking, const char *name)
+{
+       MovieTrackingObject *object= tracking->objects.first;
+
+       while(object) {
+               if(!strcmp(object->name, name))
+                       return object;
+
+               object= object->next;
+       }
+
+       return NULL;
+}