Patch #34204: [Render Animation] Fails with "Error: Specified sample_fmt is not suppo...
[blender.git] / source / blender / blenkernel / intern / movieclip.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  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/blenkernel/intern/movieclip.c
28  *  \ingroup bke
29  */
30
31
32 #include <stdio.h>
33 #include <string.h>
34 #include <fcntl.h>
35
36 #ifndef WIN32
37 #include <unistd.h>
38 #else
39 #include <io.h>
40 #endif
41
42 #include <time.h>
43
44 #ifdef _WIN32
45 #define open _open
46 #define close _close
47 #endif
48
49 #include "MEM_guardedalloc.h"
50
51 #include "DNA_constraint_types.h"
52 #include "DNA_screen_types.h"
53 #include "DNA_space_types.h"
54 #include "DNA_movieclip_types.h"
55 #include "DNA_node_types.h"
56 #include "DNA_object_types.h"
57 #include "DNA_scene_types.h"
58 #include "DNA_view3d_types.h"
59
60 #include "BLI_utildefines.h"
61
62 #include "BLI_blenlib.h"
63 #include "BLI_ghash.h"
64 #include "BLI_math.h"
65 #include "BLI_mempool.h"
66 #include "BLI_threads.h"
67
68 #include "BKE_animsys.h"
69 #include "BKE_constraint.h"
70 #include "BKE_colortools.h"
71 #include "BKE_library.h"
72 #include "BKE_global.h"
73 #include "BKE_main.h"
74 #include "BKE_movieclip.h"
75 #include "BKE_node.h"
76 #include "BKE_image.h"  /* openanim */
77 #include "BKE_tracking.h"
78 #include "BKE_sequencer.h"
79
80 #include "IMB_colormanagement.h"
81 #include "IMB_imbuf_types.h"
82 #include "IMB_imbuf.h"
83 #include "IMB_moviecache.h"
84
85 #ifdef WITH_OPENEXR
86 #include "intern/openexr/openexr_multi.h"
87 #endif
88
89 /*********************** movieclip buffer loaders *************************/
90
91 static int sequence_guess_offset(const char *full_name, int head_len, unsigned short numlen)
92 {
93         char num[FILE_MAX] = {0};
94
95         BLI_strncpy(num, full_name + head_len, numlen + 1);
96
97         return atoi(num);
98 }
99
100 static int rendersize_to_proxy(MovieClipUser *user, int flag)
101 {
102         if ((flag & MCLIP_USE_PROXY) == 0)
103                 return IMB_PROXY_NONE;
104
105         switch (user->render_size) {
106                 case MCLIP_PROXY_RENDER_SIZE_25:
107                         return IMB_PROXY_25;
108
109                 case MCLIP_PROXY_RENDER_SIZE_50:
110                         return IMB_PROXY_50;
111
112                 case MCLIP_PROXY_RENDER_SIZE_75:
113                         return IMB_PROXY_75;
114
115                 case MCLIP_PROXY_RENDER_SIZE_100:
116                         return IMB_PROXY_100;
117
118                 case MCLIP_PROXY_RENDER_SIZE_FULL:
119                         return IMB_PROXY_NONE;
120         }
121
122         return IMB_PROXY_NONE;
123 }
124
125 static int rendersize_to_number(int render_size)
126 {
127         switch (render_size) {
128                 case MCLIP_PROXY_RENDER_SIZE_25:
129                         return 25;
130
131                 case MCLIP_PROXY_RENDER_SIZE_50:
132                         return 50;
133
134                 case MCLIP_PROXY_RENDER_SIZE_75:
135                         return 75;
136
137                 case MCLIP_PROXY_RENDER_SIZE_100:
138                         return 100;
139
140                 case MCLIP_PROXY_RENDER_SIZE_FULL:
141                         return 100;
142         }
143
144         return 100;
145 }
146
147 static int get_timecode(MovieClip *clip, int flag)
148 {
149         if ((flag & MCLIP_USE_PROXY) == 0)
150                 return IMB_TC_NONE;
151
152         return clip->proxy.tc;
153 }
154
155 static void get_sequence_fname(MovieClip *clip, int framenr, char *name)
156 {
157         unsigned short numlen;
158         char head[FILE_MAX], tail[FILE_MAX];
159         int offset;
160
161         BLI_strncpy(name, clip->name, sizeof(clip->name));
162         BLI_stringdec(name, head, tail, &numlen);
163
164         /* movieclips always points to first image from sequence,
165          * autoguess offset for now. could be something smarter in the future
166          */
167         offset = sequence_guess_offset(clip->name, strlen(head), numlen);
168
169         if (numlen)
170                 BLI_stringenc(name, head, tail, numlen, offset + framenr - clip->start_frame + clip->frame_offset);
171         else
172                 BLI_strncpy(name, clip->name, sizeof(clip->name));
173
174         BLI_path_abs(name, ID_BLEND_PATH(G.main, &clip->id));
175 }
176
177 /* supposed to work with sequences only */
178 static void get_proxy_fname(MovieClip *clip, int proxy_render_size, int undistorted, int framenr, char *name)
179 {
180         int size = rendersize_to_number(proxy_render_size);
181         char dir[FILE_MAX], clipdir[FILE_MAX], clipfile[FILE_MAX];
182         int proxynr = framenr - clip->start_frame + 1 + clip->frame_offset;
183
184         BLI_split_dirfile(clip->name, clipdir, clipfile, FILE_MAX, FILE_MAX);
185
186         if (clip->flag & MCLIP_USE_PROXY_CUSTOM_DIR) {
187                 BLI_strncpy(dir, clip->proxy.dir, sizeof(dir));
188         }
189         else {
190                 BLI_snprintf(dir, FILE_MAX, "%s/BL_proxy", clipdir);
191         }
192
193         if (undistorted)
194                 BLI_snprintf(name, FILE_MAX, "%s/%s/proxy_%d_undistorted/%08d", dir, clipfile, size, proxynr);
195         else
196                 BLI_snprintf(name, FILE_MAX, "%s/%s/proxy_%d/%08d", dir, clipfile, size, proxynr);
197
198         BLI_path_abs(name, G.main->name);
199         BLI_path_frame(name, 1, 0);
200
201         strcat(name, ".jpg");
202 }
203
204 static ImBuf *movieclip_load_sequence_file(MovieClip *clip, MovieClipUser *user, int framenr, int flag)
205 {
206         struct ImBuf *ibuf;
207         char name[FILE_MAX];
208         int loadflag, use_proxy = FALSE;
209         char *colorspace;
210
211         use_proxy = (flag & MCLIP_USE_PROXY) && user->render_size != MCLIP_PROXY_RENDER_SIZE_FULL;
212         if (use_proxy) {
213                 int undistort = user->render_flag & MCLIP_PROXY_RENDER_UNDISTORT;
214                 get_proxy_fname(clip, user->render_size, undistort, framenr, name);
215
216                 /* proxies were built using default color space settings */
217                 colorspace = NULL;
218         }
219         else {
220                 get_sequence_fname(clip, framenr, name);
221                 colorspace = clip->colorspace_settings.name;
222         }
223
224         loadflag = IB_rect | IB_multilayer | IB_alphamode_detect;
225
226         /* read ibuf */
227         ibuf = IMB_loadiffname(name, loadflag, colorspace);
228
229 #ifdef WITH_OPENEXR
230         if (ibuf) {
231                 if (ibuf->ftype == OPENEXR && ibuf->userdata) {
232                         IMB_exr_close(ibuf->userdata);
233                         ibuf->userdata = NULL;
234                 }
235         }
236 #endif
237
238         return ibuf;
239 }
240
241 static void movieclip_open_anim_file(MovieClip *clip)
242 {
243         char str[FILE_MAX];
244
245         if (!clip->anim) {
246                 BLI_strncpy(str, clip->name, FILE_MAX);
247                 BLI_path_abs(str, ID_BLEND_PATH(G.main, &clip->id));
248
249                 /* FIXME: make several stream accessible in image editor, too */
250                 clip->anim = openanim(str, IB_rect, 0, clip->colorspace_settings.name);
251
252                 if (clip->anim) {
253                         if (clip->flag & MCLIP_USE_PROXY_CUSTOM_DIR) {
254                                 char dir[FILE_MAX];
255                                 BLI_strncpy(dir, clip->proxy.dir, sizeof(dir));
256                                 BLI_path_abs(dir, G.main->name);
257                                 IMB_anim_set_index_dir(clip->anim, dir);
258                         }
259                 }
260         }
261 }
262
263 static ImBuf *movieclip_load_movie_file(MovieClip *clip, MovieClipUser *user, int framenr, int flag)
264 {
265         ImBuf *ibuf = NULL;
266         int tc = get_timecode(clip, flag);
267         int proxy = rendersize_to_proxy(user, flag);
268
269         movieclip_open_anim_file(clip);
270
271         if (clip->anim) {
272                 int dur;
273                 int fra;
274
275                 dur = IMB_anim_get_duration(clip->anim, tc);
276                 fra = framenr - clip->start_frame + clip->frame_offset;
277
278                 if (fra < 0)
279                         fra = 0;
280
281                 if (fra > (dur - 1))
282                         fra = dur - 1;
283
284                 ibuf = IMB_anim_absolute(clip->anim, fra, tc, proxy);
285         }
286
287         return ibuf;
288 }
289
290 static void movieclip_calc_length(MovieClip *clip)
291 {
292         if (clip->source == MCLIP_SRC_MOVIE) {
293                 movieclip_open_anim_file(clip);
294
295                 if (clip->anim) {
296                         clip->len = IMB_anim_get_duration(clip->anim, clip->proxy.tc);
297                 }
298         }
299         else if (clip->source == MCLIP_SRC_SEQUENCE) {
300                 int framenr = 1;
301                 unsigned short numlen;
302                 char name[FILE_MAX], head[FILE_MAX], tail[FILE_MAX];
303
304                 BLI_stringdec(clip->name, head, tail, &numlen);
305
306                 if (numlen == 0) {
307                         /* there's no number group in file name, assume it's single framed sequence */
308                         clip->len = framenr + 1;
309                 }
310                 else {
311                         for (;;) {
312                                 get_sequence_fname(clip, framenr, name);
313
314                                 if (!BLI_exists(name)) {
315                                         clip->len = framenr;
316                                         break;
317                                 }
318
319                                 framenr++;
320                         }
321                 }
322         }
323 }
324
325 /*********************** image buffer cache *************************/
326
327 typedef struct MovieClipCache {
328         /* regular movie cache */
329         struct MovieCache *moviecache;
330
331         /* cached postprocessed shot */
332         struct {
333                 ImBuf *ibuf;
334                 int framenr;
335                 int flag;
336
337                 /* cache for undistorted shot */
338                 float principal[2];
339                 float k1, k2, k3;
340                 short undistortion_used;
341
342                 int proxy;
343                 short render_flag;
344         } postprocessed;
345
346         /* cache for stable shot */
347         struct {
348                 ImBuf *reference_ibuf;
349
350                 ImBuf *ibuf;
351                 int framenr;
352                 int postprocess_flag;
353
354                 float loc[2], scale, angle, aspect;
355                 int proxy, filter;
356                 short render_flag;
357         } stabilized;
358 } MovieClipCache;
359
360 typedef struct MovieClipImBufCacheKey {
361         int framenr;
362         int proxy;
363         short render_flag;
364 } MovieClipImBufCacheKey;
365
366 typedef struct MovieClipCachePriorityData {
367         int framenr;
368 } MovieClipCachePriorityData;
369
370 static void moviecache_keydata(void *userkey, int *framenr, int *proxy, int *render_flags)
371 {
372         MovieClipImBufCacheKey *key = (MovieClipImBufCacheKey *)userkey;
373
374         *framenr = key->framenr;
375         *proxy = key->proxy;
376         *render_flags = key->render_flag;
377 }
378
379 static unsigned int moviecache_hashhash(const void *keyv)
380 {
381         MovieClipImBufCacheKey *key = (MovieClipImBufCacheKey *)keyv;
382         int rval = key->framenr;
383
384         return rval;
385 }
386
387 static int moviecache_hashcmp(const void *av, const void *bv)
388 {
389         const MovieClipImBufCacheKey *a = (MovieClipImBufCacheKey *)av;
390         const MovieClipImBufCacheKey *b = (MovieClipImBufCacheKey *)bv;
391
392         if (a->framenr < b->framenr)
393                 return -1;
394         else if (a->framenr > b->framenr)
395                 return 1;
396
397         if (a->proxy < b->proxy)
398                 return -1;
399         else if (a->proxy > b->proxy)
400                 return 1;
401
402         if (a->render_flag < b->render_flag)
403                 return -1;
404         else if (a->render_flag > b->render_flag)
405                 return 1;
406
407         return 0;
408 }
409
410 static void *moviecache_getprioritydata(void *key_v)
411 {
412         MovieClipImBufCacheKey *key = (MovieClipImBufCacheKey *) key_v;
413         MovieClipCachePriorityData *priority_data;
414
415         priority_data = MEM_callocN(sizeof(priority_data), "movie cache clip priority data");
416         priority_data->framenr = key->framenr;
417
418         return priority_data;
419 }
420
421 static int moviecache_getitempriority(void *last_userkey_v, void *priority_data_v)
422 {
423         MovieClipImBufCacheKey *last_userkey = (MovieClipImBufCacheKey *) last_userkey_v;
424         MovieClipCachePriorityData *priority_data = (MovieClipCachePriorityData *) priority_data_v;
425
426         return -abs(last_userkey->framenr - priority_data->framenr);
427 }
428
429 static void moviecache_prioritydeleter(void *priority_data_v)
430 {
431         MovieClipCachePriorityData *priority_data = (MovieClipCachePriorityData *) priority_data_v;
432
433         MEM_freeN(priority_data);
434 }
435
436 static ImBuf *get_imbuf_cache(MovieClip *clip, MovieClipUser *user, int flag)
437 {
438         if (clip->cache) {
439                 MovieClipImBufCacheKey key;
440
441                 key.framenr = user->framenr;
442
443                 if (flag & MCLIP_USE_PROXY) {
444                         key.proxy = rendersize_to_proxy(user, flag);
445                         key.render_flag = user->render_flag;
446                 }
447                 else {
448                         key.proxy = IMB_PROXY_NONE;
449                         key.render_flag = 0;
450                 }
451
452                 return IMB_moviecache_get(clip->cache->moviecache, &key);
453         }
454
455         return NULL;
456 }
457
458 static void put_imbuf_cache(MovieClip *clip, MovieClipUser *user, ImBuf *ibuf, int flag)
459 {
460         MovieClipImBufCacheKey key;
461
462         if (!clip->cache) {
463                 struct MovieCache *moviecache;
464
465                 // char cache_name[64];
466                 // BLI_snprintf(cache_name, sizeof(cache_name), "movie %s", clip->id.name);
467
468                 clip->cache = MEM_callocN(sizeof(MovieClipCache), "movieClipCache");
469
470                 moviecache = IMB_moviecache_create("movieclip", sizeof(MovieClipImBufCacheKey), moviecache_hashhash, moviecache_hashcmp);
471
472                 IMB_moviecache_set_getdata_callback(moviecache, moviecache_keydata);
473                 IMB_moviecache_set_priority_callback(moviecache, moviecache_getprioritydata, moviecache_getitempriority,
474                                                      moviecache_prioritydeleter);
475
476                 clip->cache->moviecache = moviecache;
477         }
478
479         key.framenr = user->framenr;
480
481         if (flag & MCLIP_USE_PROXY) {
482                 key.proxy = rendersize_to_proxy(user, flag);
483                 key.render_flag = user->render_flag;
484         }
485         else {
486                 key.proxy = IMB_PROXY_NONE;
487                 key.render_flag = 0;
488         }
489
490         IMB_moviecache_put(clip->cache->moviecache, &key, ibuf);
491 }
492
493 /*********************** common functions *************************/
494
495 /* only image block itself */
496 static MovieClip *movieclip_alloc(Main *bmain, const char *name)
497 {
498         MovieClip *clip;
499
500         clip = BKE_libblock_alloc(&bmain->movieclip, ID_MC, name);
501
502         clip->aspx = clip->aspy = 1.0f;
503
504         BKE_tracking_settings_init(&clip->tracking);
505         BKE_color_managed_colorspace_settings_init(&clip->colorspace_settings);
506
507         clip->proxy.build_size_flag = IMB_PROXY_25;
508         clip->proxy.build_tc_flag = IMB_TC_RECORD_RUN |
509                                     IMB_TC_FREE_RUN |
510                                     IMB_TC_INTERPOLATED_REC_DATE_FREE_RUN |
511                                     IMB_TC_RECORD_RUN_NO_GAPS;
512         clip->proxy.quality = 90;
513
514         clip->start_frame = 1;
515         clip->frame_offset = 0;
516
517         return clip;
518 }
519
520 static void movieclip_load_get_szie(MovieClip *clip)
521 {
522         int width, height;
523         MovieClipUser user = {0};
524
525         user.framenr = 1;
526         BKE_movieclip_get_size(clip, &user, &width, &height);
527
528         if (width && height) {
529                 clip->tracking.camera.principal[0] = ((float)width) / 2.0f;
530                 clip->tracking.camera.principal[1] = ((float)height) / 2.0f;
531         }
532         else {
533                 clip->lastsize[0] = clip->lastsize[1] = IMG_SIZE_FALLBACK;
534         }
535 }
536
537 static void detect_clip_source(MovieClip *clip)
538 {
539         ImBuf *ibuf;
540         char name[FILE_MAX];
541
542         BLI_strncpy(name, clip->name, sizeof(name));
543         BLI_path_abs(name, G.main->name);
544
545         ibuf = IMB_testiffname(name, IB_rect | IB_multilayer);
546         if (ibuf) {
547                 clip->source = MCLIP_SRC_SEQUENCE;
548                 IMB_freeImBuf(ibuf);
549         }
550         else {
551                 clip->source = MCLIP_SRC_MOVIE;
552         }
553 }
554
555 /* checks if image was already loaded, then returns same image
556  * otherwise creates new.
557  * does not load ibuf itself
558  * pass on optional frame for #name images */
559 MovieClip *BKE_movieclip_file_add(Main *bmain, const char *name)
560 {
561         MovieClip *clip;
562         int file, len;
563         const char *libname;
564         char str[FILE_MAX], strtest[FILE_MAX];
565
566         BLI_strncpy(str, name, sizeof(str));
567         BLI_path_abs(str, bmain->name);
568
569         /* exists? */
570         file = BLI_open(str, O_BINARY | O_RDONLY, 0);
571         if (file == -1)
572                 return NULL;
573         close(file);
574
575         /* ** first search an identical clip ** */
576         for (clip = bmain->movieclip.first; clip; clip = clip->id.next) {
577                 BLI_strncpy(strtest, clip->name, sizeof(clip->name));
578                 BLI_path_abs(strtest, G.main->name);
579
580                 if (strcmp(strtest, str) == 0) {
581                         BLI_strncpy(clip->name, name, sizeof(clip->name));  /* for stringcode */
582                         clip->id.us++;  /* officially should not, it doesn't link here! */
583
584                         return clip;
585                 }
586         }
587
588         /* ** add new movieclip ** */
589
590         /* create a short library name */
591         len = strlen(name);
592
593         while (len > 0 && name[len - 1] != '/' && name[len - 1] != '\\')
594                 len--;
595         libname = name + len;
596
597         clip = movieclip_alloc(bmain, libname);
598         BLI_strncpy(clip->name, name, sizeof(clip->name));
599
600         detect_clip_source(clip);
601
602         movieclip_load_get_szie(clip);
603         if (clip->lastsize[0]) {
604                 int width = clip->lastsize[0];
605
606                 clip->tracking.camera.focal = 24.0f * width / clip->tracking.camera.sensor_width;
607         }
608
609         movieclip_calc_length(clip);
610
611         return clip;
612 }
613
614 static void real_ibuf_size(MovieClip *clip, MovieClipUser *user, ImBuf *ibuf, int *width, int *height)
615 {
616         *width = ibuf->x;
617         *height = ibuf->y;
618
619         if (clip->flag & MCLIP_USE_PROXY) {
620                 switch (user->render_size) {
621                         case MCLIP_PROXY_RENDER_SIZE_25:
622                                 (*width) *= 4;
623                                 (*height) *= 4;
624                                 break;
625
626                         case MCLIP_PROXY_RENDER_SIZE_50:
627                                 (*width) *= 2.0f;
628                                 (*height) *= 2.0f;
629                                 break;
630
631                         case MCLIP_PROXY_RENDER_SIZE_75:
632                                 *width = ((float)*width) * 4.0f / 3.0f;
633                                 *height = ((float)*height) * 4.0f / 3.0f;
634                                 break;
635                 }
636         }
637 }
638
639 static ImBuf *get_undistorted_ibuf(MovieClip *clip, struct MovieDistortion *distortion, ImBuf *ibuf)
640 {
641         ImBuf *undistibuf;
642
643         if (distortion)
644                 undistibuf = BKE_tracking_distortion_exec(distortion, &clip->tracking, ibuf, ibuf->x, ibuf->y, 0.0f, 1);
645         else
646                 undistibuf = BKE_tracking_undistort_frame(&clip->tracking, ibuf, ibuf->x, ibuf->y, 0.0f);
647
648         IMB_scaleImBuf(undistibuf, ibuf->x, ibuf->y);
649
650         return undistibuf;
651 }
652
653 static int need_undistortion_postprocess(MovieClipUser *user)
654 {
655         int result = 0;
656
657         /* only full undistorted render can be used as on-fly undistorting image */
658         result |= (user->render_size == MCLIP_PROXY_RENDER_SIZE_FULL) &&
659                   (user->render_flag & MCLIP_PROXY_RENDER_UNDISTORT) != 0;
660
661         return result;
662 }
663
664 static int need_postprocessed_frame(MovieClipUser *user, int postprocess_flag)
665 {
666         int result = postprocess_flag;
667
668         result |= need_undistortion_postprocess(user);
669
670         return result;
671 }
672
673 static int check_undistortion_cache_flags(MovieClip *clip)
674 {
675         MovieClipCache *cache = clip->cache;
676         MovieTrackingCamera *camera = &clip->tracking.camera;
677
678         /* check for distortion model changes */
679         if (!equals_v2v2(camera->principal, cache->postprocessed.principal))
680                 return FALSE;
681
682         if (!equals_v3v3(&camera->k1, &cache->postprocessed.k1))
683                 return FALSE;
684
685         return TRUE;
686 }
687
688 static ImBuf *get_postprocessed_cached_frame(MovieClip *clip, MovieClipUser *user, int flag, int postprocess_flag)
689 {
690         MovieClipCache *cache = clip->cache;
691         int framenr = user->framenr;
692         short proxy = IMB_PROXY_NONE;
693         int render_flag = 0;
694
695         if (flag & MCLIP_USE_PROXY) {
696                 proxy = rendersize_to_proxy(user, flag);
697                 render_flag = user->render_flag;
698         }
699
700         /* no cache or no cached postprocessed image */
701         if (!clip->cache || !clip->cache->postprocessed.ibuf)
702                 return NULL;
703
704         /* postprocessing happened for other frame */
705         if (cache->postprocessed.framenr != framenr)
706                 return NULL;
707
708         /* cached ibuf used different proxy settings */
709         if (cache->postprocessed.render_flag != render_flag || cache->postprocessed.proxy != proxy)
710                 return NULL;
711
712         if (cache->postprocessed.flag != postprocess_flag)
713                 return NULL;
714
715         if (need_undistortion_postprocess(user)) {
716                 if (!check_undistortion_cache_flags(clip))
717                         return NULL;
718         }
719         else if (cache->postprocessed.undistortion_used)
720                 return NULL;
721
722         IMB_refImBuf(cache->postprocessed.ibuf);
723
724         return cache->postprocessed.ibuf;
725 }
726
727 static ImBuf *put_postprocessed_frame_to_cache(MovieClip *clip, MovieClipUser *user, ImBuf *ibuf,
728                                                int flag, int postprocess_flag)
729 {
730         MovieClipCache *cache = clip->cache;
731         MovieTrackingCamera *camera = &clip->tracking.camera;
732         ImBuf *postproc_ibuf = NULL;
733
734         cache->postprocessed.framenr = user->framenr;
735         cache->postprocessed.flag = postprocess_flag;
736
737         if (flag & MCLIP_USE_PROXY) {
738                 cache->postprocessed.proxy = rendersize_to_proxy(user, flag);
739                 cache->postprocessed.render_flag = user->render_flag;
740         }
741         else {
742                 cache->postprocessed.proxy = IMB_PROXY_NONE;
743                 cache->postprocessed.render_flag = 0;
744         }
745
746         if (need_undistortion_postprocess(user)) {
747                 copy_v2_v2(cache->postprocessed.principal, camera->principal);
748                 copy_v3_v3(&cache->postprocessed.k1, &camera->k1);
749                 cache->postprocessed.undistortion_used = TRUE;
750                 postproc_ibuf = get_undistorted_ibuf(clip, NULL, ibuf);
751         }
752         else {
753                 cache->postprocessed.undistortion_used = FALSE;
754         }
755
756         if (postprocess_flag) {
757                 int disable_red   = postprocess_flag & MOVIECLIP_DISABLE_RED,
758                     disable_green = postprocess_flag & MOVIECLIP_DISABLE_GREEN,
759                     disable_blue  = postprocess_flag & MOVIECLIP_DISABLE_BLUE,
760                     grayscale     = postprocess_flag & MOVIECLIP_PREVIEW_GRAYSCALE;
761
762                 if (!postproc_ibuf)
763                         postproc_ibuf = IMB_dupImBuf(ibuf);
764
765                 if (disable_red || disable_green || disable_blue || grayscale)
766                         BKE_tracking_disable_channels(postproc_ibuf, disable_red, disable_green, disable_blue, 1);
767         }
768
769         IMB_refImBuf(postproc_ibuf);
770
771         if (cache->postprocessed.ibuf)
772                 IMB_freeImBuf(cache->postprocessed.ibuf);
773
774         cache->postprocessed.ibuf = postproc_ibuf;
775
776         return postproc_ibuf;
777 }
778
779 static ImBuf *movieclip_get_postprocessed_ibuf(MovieClip *clip, MovieClipUser *user, int flag,
780                                                int postprocess_flag, int cache_flag)
781 {
782         ImBuf *ibuf = NULL;
783         int framenr = user->framenr, need_postprocess = FALSE;
784
785         /* cache isn't threadsafe itself and also loading of movies
786          * can't happen from concurent threads that's why we use lock here */
787         BLI_lock_thread(LOCK_MOVIECLIP);
788
789         /* try to obtain cached postprocessed frame first */
790         if (need_postprocessed_frame(user, postprocess_flag)) {
791                 ibuf = get_postprocessed_cached_frame(clip, user, flag, postprocess_flag);
792
793                 if (!ibuf)
794                         need_postprocess = TRUE;
795         }
796
797         if (!ibuf)
798                 ibuf = get_imbuf_cache(clip, user, flag);
799
800         if (!ibuf) {
801                 int use_sequence = FALSE;
802
803                 /* undistorted proxies for movies should be read as image sequence */
804                 use_sequence = (user->render_flag & MCLIP_PROXY_RENDER_UNDISTORT) &&
805                                (user->render_size != MCLIP_PROXY_RENDER_SIZE_FULL);
806
807                 if (clip->source == MCLIP_SRC_SEQUENCE || use_sequence) {
808                         ibuf = movieclip_load_sequence_file(clip, user, framenr, flag);
809                 }
810                 else {
811                         ibuf = movieclip_load_movie_file(clip, user, framenr, flag);
812                 }
813
814                 if (ibuf && (cache_flag & MOVIECLIP_CACHE_SKIP) == 0)
815                         put_imbuf_cache(clip, user, ibuf, flag);
816         }
817
818         if (ibuf) {
819                 clip->lastframe = framenr;
820                 real_ibuf_size(clip, user, ibuf, &clip->lastsize[0], &clip->lastsize[1]);
821
822                 /* postprocess frame and put to cache */
823                 if (need_postprocess) {
824                         ImBuf *tmpibuf = ibuf;
825                         ibuf = put_postprocessed_frame_to_cache(clip, user, tmpibuf, flag, postprocess_flag);
826                         IMB_freeImBuf(tmpibuf);
827                 }
828         }
829
830         BLI_unlock_thread(LOCK_MOVIECLIP);
831
832         return ibuf;
833 }
834
835 ImBuf *BKE_movieclip_get_ibuf(MovieClip *clip, MovieClipUser *user)
836 {
837         return BKE_movieclip_get_ibuf_flag(clip, user, clip->flag, 0);
838 }
839
840 ImBuf *BKE_movieclip_get_ibuf_flag(MovieClip *clip, MovieClipUser *user, int flag, int cache_flag)
841 {
842         return movieclip_get_postprocessed_ibuf(clip, user, flag, 0, cache_flag);
843 }
844
845 ImBuf *BKE_movieclip_get_postprocessed_ibuf(MovieClip *clip, MovieClipUser *user, int postprocess_flag)
846 {
847         return movieclip_get_postprocessed_ibuf(clip, user, clip->flag, postprocess_flag, 0);
848 }
849
850 static ImBuf *get_stable_cached_frame(MovieClip *clip, MovieClipUser *user, ImBuf *reference_ibuf,
851                                       int framenr, int postprocess_flag)
852 {
853         MovieClipCache *cache = clip->cache;
854         MovieTracking *tracking = &clip->tracking;
855         ImBuf *stableibuf;
856         float tloc[2], tscale, tangle;
857         short proxy = IMB_PROXY_NONE;
858         int render_flag = 0;
859         int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, framenr);
860
861         if (clip->flag & MCLIP_USE_PROXY) {
862                 proxy = rendersize_to_proxy(user, clip->flag);
863                 render_flag = user->render_flag;
864         }
865
866         /* there's no cached frame or it was calculated for another frame */
867         if (!cache->stabilized.ibuf || cache->stabilized.framenr != framenr)
868                 return NULL;
869
870         if (cache->stabilized.reference_ibuf != reference_ibuf)
871                 return NULL;
872
873         /* cached ibuf used different proxy settings */
874         if (cache->stabilized.render_flag != render_flag || cache->stabilized.proxy != proxy)
875                 return NULL;
876
877         if (cache->stabilized.postprocess_flag != postprocess_flag)
878                 return NULL;
879
880         /* stabilization also depends on pixel aspect ratio */
881         if (cache->stabilized.aspect != tracking->camera.pixel_aspect)
882                 return NULL;
883
884         if (cache->stabilized.filter != tracking->stabilization.filter)
885                 return NULL;
886
887         stableibuf = cache->stabilized.ibuf;
888
889         BKE_tracking_stabilization_data_get(&clip->tracking, clip_framenr, stableibuf->x, stableibuf->y, tloc, &tscale, &tangle);
890
891         /* check for stabilization parameters */
892         if (tscale != cache->stabilized.scale ||
893             tangle != cache->stabilized.angle ||
894             !equals_v2v2(tloc, cache->stabilized.loc))
895         {
896                 return NULL;
897         }
898
899         IMB_refImBuf(stableibuf);
900
901         return stableibuf;
902 }
903
904 static ImBuf *put_stabilized_frame_to_cache(MovieClip *clip, MovieClipUser *user, ImBuf *ibuf,
905                                             int framenr, int postprocess_flag)
906 {
907         MovieClipCache *cache = clip->cache;
908         MovieTracking *tracking = &clip->tracking;
909         ImBuf *stableibuf;
910         float tloc[2], tscale, tangle;
911         int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, framenr);
912
913         stableibuf = BKE_tracking_stabilize_frame(&clip->tracking, clip_framenr, ibuf, tloc, &tscale, &tangle);
914
915         copy_v2_v2(cache->stabilized.loc, tloc);
916
917         cache->stabilized.scale = tscale;
918         cache->stabilized.angle = tangle;
919         cache->stabilized.framenr = framenr;
920         cache->stabilized.aspect = tracking->camera.pixel_aspect;
921         cache->stabilized.filter = tracking->stabilization.filter;
922
923         if (clip->flag & MCLIP_USE_PROXY) {
924                 cache->stabilized.proxy = rendersize_to_proxy(user, clip->flag);
925                 cache->stabilized.render_flag = user->render_flag;
926         }
927         else {
928                 cache->stabilized.proxy = IMB_PROXY_NONE;
929                 cache->stabilized.render_flag = 0;
930         }
931
932         cache->stabilized.postprocess_flag = postprocess_flag;
933
934         if (cache->stabilized.ibuf)
935                 IMB_freeImBuf(cache->stabilized.ibuf);
936
937         cache->stabilized.ibuf = stableibuf;
938
939         IMB_refImBuf(stableibuf);
940
941         return stableibuf;
942 }
943
944 ImBuf *BKE_movieclip_get_stable_ibuf(MovieClip *clip, MovieClipUser *user, float loc[2], float *scale, float *angle,
945                                      int postprocess_flag)
946 {
947         ImBuf *ibuf, *stableibuf = NULL;
948         int framenr = user->framenr;
949
950         ibuf = BKE_movieclip_get_postprocessed_ibuf(clip, user, postprocess_flag);
951
952         if (!ibuf)
953                 return NULL;
954
955         if (clip->tracking.stabilization.flag & TRACKING_2D_STABILIZATION) {
956                 MovieClipCache *cache = clip->cache;
957
958                 stableibuf = get_stable_cached_frame(clip, user, ibuf, framenr, postprocess_flag);
959
960                 if (!stableibuf)
961                         stableibuf = put_stabilized_frame_to_cache(clip, user, ibuf, framenr, postprocess_flag);
962
963                 if (loc)
964                         copy_v2_v2(loc, cache->stabilized.loc);
965
966                 if (scale)
967                         *scale = cache->stabilized.scale;
968
969                 if (angle)
970                         *angle = cache->stabilized.angle;
971         }
972         else {
973                 if (loc)
974                         zero_v2(loc);
975
976                 if (scale)
977                         *scale = 1.0f;
978
979                 if (angle)
980                         *angle = 0.0f;
981
982                 stableibuf = ibuf;
983         }
984
985         if (stableibuf != ibuf) {
986                 IMB_freeImBuf(ibuf);
987                 ibuf = stableibuf;
988         }
989
990         return ibuf;
991
992 }
993
994 int BKE_movieclip_has_frame(MovieClip *clip, MovieClipUser *user)
995 {
996         ImBuf *ibuf = BKE_movieclip_get_ibuf(clip, user);
997
998         if (ibuf) {
999                 IMB_freeImBuf(ibuf);
1000                 return TRUE;
1001         }
1002
1003         return FALSE;
1004 }
1005
1006 void BKE_movieclip_get_size(MovieClip *clip, MovieClipUser *user, int *width, int *height)
1007 {
1008 #if 0
1009         /* originally was needed to support image sequences with different image dimensions,
1010          * which might be useful for such things as reconstruction of unordered image sequence,
1011          * or painting/rotoscoping of non-equal-sized images, but this ended up in unneeded
1012          * cache lookups and even unwanted non-proxied files loading when doing mask parenting,
1013          * so let's disable this for now and assume image sequence consists of images with
1014          * equal sizes (sergey)
1015          */
1016         if (user->framenr == clip->lastframe) {
1017 #endif
1018         if (clip->lastsize[0] != 0 && clip->lastsize[1] != 0) {
1019                 *width = clip->lastsize[0];
1020                 *height = clip->lastsize[1];
1021         }
1022         else {
1023                 ImBuf *ibuf = BKE_movieclip_get_ibuf(clip, user);
1024
1025                 if (ibuf && ibuf->x && ibuf->y) {
1026                         real_ibuf_size(clip, user, ibuf, width, height);
1027                 }
1028                 else {
1029                         *width = clip->lastsize[0];
1030                         *height = clip->lastsize[1];
1031                 }
1032
1033                 if (ibuf)
1034                         IMB_freeImBuf(ibuf);
1035         }
1036 }
1037 void BKE_movieclip_get_size_fl(MovieClip *clip, MovieClipUser *user, float size[2])
1038 {
1039         int width, height;
1040         BKE_movieclip_get_size(clip, user, &width, &height);
1041
1042         size[0] = (float)width;
1043         size[1] = (float)height;
1044 }
1045
1046 int BKE_movieclip_get_duration(MovieClip *clip)
1047 {
1048         if (!clip->len) {
1049                 movieclip_calc_length(clip);
1050         }
1051
1052         return clip->len;
1053 }
1054
1055 void BKE_movieclip_get_aspect(MovieClip *clip, float *aspx, float *aspy)
1056 {
1057         *aspx = 1.0;
1058
1059         /* x is always 1 */
1060         *aspy = clip->aspy / clip->aspx / clip->tracking.camera.pixel_aspect;
1061 }
1062
1063 /* get segments of cached frames. useful for debugging cache policies */
1064 void BKE_movieclip_get_cache_segments(MovieClip *clip, MovieClipUser *user, int *totseg_r, int **points_r)
1065 {
1066         *totseg_r = 0;
1067         *points_r = NULL;
1068
1069         if (clip->cache) {
1070                 int proxy = rendersize_to_proxy(user, clip->flag);
1071
1072                 IMB_moviecache_get_cache_segments(clip->cache->moviecache, proxy, user->render_flag, totseg_r, points_r);
1073         }
1074 }
1075
1076 void BKE_movieclip_user_set_frame(MovieClipUser *iuser, int framenr)
1077 {
1078         /* TODO: clamp framenr here? */
1079
1080         iuser->framenr = framenr;
1081 }
1082
1083 static void free_buffers(MovieClip *clip)
1084 {
1085         if (clip->cache) {
1086                 IMB_moviecache_free(clip->cache->moviecache);
1087
1088                 if (clip->cache->postprocessed.ibuf)
1089                         IMB_freeImBuf(clip->cache->postprocessed.ibuf);
1090
1091                 if (clip->cache->stabilized.ibuf)
1092                         IMB_freeImBuf(clip->cache->stabilized.ibuf);
1093
1094                 MEM_freeN(clip->cache);
1095                 clip->cache = NULL;
1096         }
1097
1098         if (clip->anim) {
1099                 IMB_free_anim(clip->anim);
1100                 clip->anim = NULL;
1101         }
1102
1103         BKE_free_animdata((ID *) clip);
1104 }
1105
1106 void BKE_movieclip_reload(MovieClip *clip)
1107 {
1108         /* clear cache */
1109         free_buffers(clip);
1110
1111         clip->tracking.stabilization.ok = FALSE;
1112
1113         /* update clip source */
1114         detect_clip_source(clip);
1115
1116         clip->lastsize[0] = clip->lastsize[1] = 0;
1117         movieclip_load_get_szie(clip);
1118
1119         movieclip_calc_length(clip);
1120
1121         /* same as for image update -- don't use notifiers because they are not 100% sure to succeeded
1122          * (node trees which are not currently visible wouldn't be refreshed)
1123          */
1124         {
1125                 Scene *scene;
1126                 for (scene = G.main->scene.first; scene; scene = scene->id.next) {
1127                         if (scene->nodetree) {
1128                                 nodeUpdateID(scene->nodetree, &clip->id);
1129                         }
1130                 }
1131         }
1132 }
1133
1134 void BKE_movieclip_update_scopes(MovieClip *clip, MovieClipUser *user, MovieClipScopes *scopes)
1135 {
1136         if (scopes->ok)
1137                 return;
1138
1139         if (scopes->track_preview) {
1140                 IMB_freeImBuf(scopes->track_preview);
1141                 scopes->track_preview = NULL;
1142         }
1143
1144         if (scopes->track_search) {
1145                 IMB_freeImBuf(scopes->track_search);
1146                 scopes->track_search = NULL;
1147         }
1148
1149         scopes->marker = NULL;
1150         scopes->track = NULL;
1151         scopes->track_locked = TRUE;
1152
1153         if (clip) {
1154                 MovieTrackingTrack *act_track = BKE_tracking_track_get_active(&clip->tracking);
1155
1156                 if (act_track) {
1157                         MovieTrackingTrack *track = act_track;
1158                         int framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, user->framenr);
1159                         MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
1160
1161                         scopes->marker = marker;
1162                         scopes->track = track;
1163
1164                         if (marker->flag & MARKER_DISABLED) {
1165                                 scopes->track_disabled = TRUE;
1166                         }
1167                         else {
1168                                 ImBuf *ibuf = BKE_movieclip_get_ibuf(clip, user);
1169
1170                                 scopes->track_disabled = FALSE;
1171
1172                                 if (ibuf && (ibuf->rect || ibuf->rect_float)) {
1173                                         ImBuf *search_ibuf;
1174                                         MovieTrackingMarker undist_marker = *marker;
1175
1176                                         if (user->render_flag & MCLIP_PROXY_RENDER_UNDISTORT) {
1177                                                 int width, height;
1178                                                 float aspy = 1.0f / clip->tracking.camera.pixel_aspect;
1179
1180                                                 BKE_movieclip_get_size(clip, user, &width, &height);
1181
1182                                                 undist_marker.pos[0] *= width;
1183                                                 undist_marker.pos[1] *= height * aspy;
1184
1185                                                 BKE_tracking_undistort_v2(&clip->tracking, undist_marker.pos, undist_marker.pos);
1186
1187                                                 undist_marker.pos[0] /= width;
1188                                                 undist_marker.pos[1] /= height * aspy;
1189                                         }
1190
1191                                         search_ibuf = BKE_tracking_get_search_imbuf(ibuf, track, &undist_marker, TRUE, TRUE);
1192
1193                                         if (search_ibuf) {
1194                                                 if (!search_ibuf->rect_float) {
1195                                                         /* sampling happens in float buffer */
1196                                                         IMB_float_from_rect(search_ibuf);
1197                                                 }
1198
1199                                                 scopes->track_search = search_ibuf;
1200                                         }
1201
1202                                         scopes->undist_marker = undist_marker;
1203
1204                                         scopes->frame_width = ibuf->x;
1205                                         scopes->frame_height = ibuf->y;
1206
1207                                         scopes->use_track_mask = track->flag & TRACK_PREVIEW_ALPHA;
1208                                 }
1209
1210                                 IMB_freeImBuf(ibuf);
1211                         }
1212
1213                         if ((track->flag & TRACK_LOCKED) == 0) {
1214                                 float pat_min[2], pat_max[2];
1215
1216                                 scopes->track_locked = FALSE;
1217
1218                                 /* XXX: would work fine with non-transformed patterns, but would likely fail
1219                                  *      with transformed patterns, but that would be easier to debug when
1220                                  *      we'll have real pattern sampling (at least to test) */
1221                                 BKE_tracking_marker_pattern_minmax(marker, pat_min, pat_max);
1222
1223                                 scopes->slide_scale[0] = pat_max[0] - pat_min[0];
1224                                 scopes->slide_scale[1] = pat_max[1] - pat_min[1];
1225                         }
1226                 }
1227         }
1228
1229         scopes->framenr = user->framenr;
1230         scopes->ok = TRUE;
1231 }
1232
1233 static void movieclip_build_proxy_ibuf(MovieClip *clip, ImBuf *ibuf, int cfra, int proxy_render_size, int undistorted)
1234 {
1235         char name[FILE_MAX];
1236         int quality, rectx, recty;
1237         int size = rendersize_to_number(proxy_render_size);
1238         ImBuf *scaleibuf;
1239
1240         get_proxy_fname(clip, proxy_render_size, undistorted, cfra, name);
1241
1242         rectx = ibuf->x * size / 100.0f;
1243         recty = ibuf->y * size / 100.0f;
1244
1245         scaleibuf = IMB_dupImBuf(ibuf);
1246
1247         IMB_scaleImBuf(scaleibuf, (short)rectx, (short)recty);
1248
1249         quality = clip->proxy.quality;
1250         scaleibuf->ftype = JPG | quality;
1251
1252         /* unsupported feature only confuses other s/w */
1253         if (scaleibuf->planes == 32)
1254                 scaleibuf->planes = 24;
1255
1256         BLI_lock_thread(LOCK_MOVIECLIP);
1257
1258         BLI_make_existing_file(name);
1259         if (IMB_saveiff(scaleibuf, name, IB_rect) == 0)
1260                 perror(name);
1261
1262         BLI_unlock_thread(LOCK_MOVIECLIP);
1263
1264         IMB_freeImBuf(scaleibuf);
1265 }
1266
1267 void BKE_movieclip_build_proxy_frame(MovieClip *clip, int clip_flag, struct MovieDistortion *distortion,
1268                                      int cfra, int *build_sizes, int build_count, int undistorted)
1269 {
1270         ImBuf *ibuf;
1271         MovieClipUser user;
1272
1273         user.framenr = cfra;
1274         user.render_flag = 0;
1275         user.render_size = MCLIP_PROXY_RENDER_SIZE_FULL;
1276
1277         ibuf = BKE_movieclip_get_ibuf_flag(clip, &user, clip_flag, MOVIECLIP_CACHE_SKIP);
1278
1279         if (ibuf) {
1280                 ImBuf *tmpibuf = ibuf;
1281                 int i;
1282
1283                 if (undistorted)
1284                         tmpibuf = get_undistorted_ibuf(clip, distortion, ibuf);
1285
1286                 for (i = 0; i < build_count; i++)
1287                         movieclip_build_proxy_ibuf(clip, tmpibuf, cfra, build_sizes[i], undistorted);
1288
1289                 IMB_freeImBuf(ibuf);
1290
1291                 if (tmpibuf != ibuf)
1292                         IMB_freeImBuf(tmpibuf);
1293         }
1294 }
1295
1296 void BKE_movieclip_free(MovieClip *clip)
1297 {
1298         BKE_sequencer_clear_movieclip_in_clipboard(clip);
1299
1300         free_buffers(clip);
1301
1302         BKE_tracking_free(&clip->tracking);
1303 }
1304
1305 void BKE_movieclip_unlink(Main *bmain, MovieClip *clip)
1306 {
1307         bScreen *scr;
1308         ScrArea *area;
1309         SpaceLink *sl;
1310         Scene *sce;
1311         Object *ob;
1312
1313         for (scr = bmain->screen.first; scr; scr = scr->id.next) {
1314                 for (area = scr->areabase.first; area; area = area->next) {
1315                         for (sl = area->spacedata.first; sl; sl = sl->next) {
1316                                 if (sl->spacetype == SPACE_CLIP) {
1317                                         SpaceClip *sc = (SpaceClip *) sl;
1318
1319                                         if (sc->clip == clip)
1320                                                 sc->clip = NULL;
1321                                 }
1322                                 else if (sl->spacetype == SPACE_VIEW3D) {
1323                                         View3D *v3d = (View3D *) sl;
1324                                         BGpic *bgpic;
1325
1326                                         for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) {
1327                                                 if (bgpic->clip == clip)
1328                                                         bgpic->clip = NULL;
1329                                         }
1330                                 }
1331                         }
1332                 }
1333         }
1334
1335         for (sce = bmain->scene.first; sce; sce = sce->id.next) {
1336                 if (sce->clip == clip)
1337                         sce->clip = NULL;
1338         }
1339
1340         for (ob = bmain->object.first; ob; ob = ob->id.next) {
1341                 bConstraint *con;
1342
1343                 for (con = ob->constraints.first; con; con = con->next) {
1344                         bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
1345
1346                         if (cti->type == CONSTRAINT_TYPE_FOLLOWTRACK) {
1347                                 bFollowTrackConstraint *data = (bFollowTrackConstraint *) con->data;
1348
1349                                 if (data->clip == clip)
1350                                         data->clip = NULL;
1351                         }
1352                         else if (cti->type == CONSTRAINT_TYPE_CAMERASOLVER) {
1353                                 bCameraSolverConstraint *data = (bCameraSolverConstraint *) con->data;
1354
1355                                 if (data->clip == clip)
1356                                         data->clip = NULL;
1357                         }
1358                         else if (cti->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
1359                                 bObjectSolverConstraint *data = (bObjectSolverConstraint *) con->data;
1360
1361                                 if (data->clip == clip)
1362                                         data->clip = NULL;
1363                         }
1364                 }
1365         }
1366
1367         {
1368                 bNodeTreeType *treetype = ntreeGetType(NTREE_COMPOSIT);
1369                 treetype->foreach_nodetree(bmain, (void *)clip, &BKE_node_tree_unlink_id_cb);
1370         }
1371
1372         clip->id.us = 0;
1373 }
1374
1375 float BKE_movieclip_remap_scene_to_clip_frame(MovieClip *clip, float framenr)
1376 {
1377         return framenr - (float) clip->start_frame + 1.0f;
1378 }
1379
1380 float BKE_movieclip_remap_clip_to_scene_frame(MovieClip *clip, float framenr)
1381 {
1382         return framenr + (float) clip->start_frame - 1.0f;
1383 }