Changed frame numbering to only alter hashes if they are in the filename (not the...
[blender-staging.git] / source / blender / src / sequence.c
index 6ddb68ef6447c4d7d3d75501cf9e3a1661998aaf..9f3be52af1bd7a7323b1eee2ed7b1d151591b72d 100644 (file)
@@ -1,15 +1,12 @@
 /**
  * $Id$
  *
- * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ * ***** BEGIN GPL LICENSE BLOCK *****
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version. The Blender
- * Foundation also sells licenses for use in proprietary software under
- * the Blender License.  See http://www.blender.org/BL/ for information
- * about this.
+ * of the License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -25,7 +22,7 @@
  *
  * Contributor(s): Peter Schlaile <peter [at] schlaile [dot] de> 2005/2006
  *
- * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * ***** END GPL LICENSE BLOCK *****
  */
 
 #include <string.h>
 #include "BLI_threads.h"
 #include <pthread.h>
 
+#ifdef WIN32
+#define snprintf _snprintf
+#endif
+
 int seqrectx, seqrecty;
 
+/* **********************************************************************
+   alloc / free functions
+   ********************************************************************** */
+
 void free_tstripdata(int len, TStripElem *se)
 {
        TStripElem *seo;
@@ -101,11 +106,6 @@ void free_tstripdata(int len, TStripElem *se)
 
 }
 
-void seq_proxy_free(StripProxy * proxy)
-{
-       MEM_freeN(proxy);
-}
-
 void free_strip(Strip *strip)
 {
        strip->us--;
@@ -115,18 +115,19 @@ void free_strip(Strip *strip)
                return;
        }
 
-       if(strip->stripdata) {
+       if (strip->stripdata) {
                MEM_freeN(strip->stripdata);
        }
+
+       if (strip->proxy) {
+               MEM_freeN(strip->proxy);
+       }
        if (strip->crop) {
                MEM_freeN(strip->crop);
        }
        if (strip->transform) {
                MEM_freeN(strip->transform);
        }
-       if (strip->proxy) {
-               seq_proxy_free(strip->proxy);
-       }
        if (strip->color_balance) {
                MEM_freeN(strip->color_balance);
        }
@@ -135,6 +136,16 @@ void free_strip(Strip *strip)
        free_tstripdata(strip->endstill, strip->tstripdata_endstill);
        free_tstripdata(strip->startstill, strip->tstripdata_startstill);
 
+       if(strip->ibuf_startstill) {
+               IMB_freeImBuf(strip->ibuf_startstill);
+               strip->ibuf_startstill = 0;
+       }
+
+       if(strip->ibuf_endstill) {
+               IMB_freeImBuf(strip->ibuf_endstill);
+               strip->ibuf_endstill = 0;
+       }
+
        MEM_freeN(strip);
 }
 
@@ -151,6 +162,16 @@ void new_tstripdata(Sequence *seq)
                seq->strip->tstripdata_endstill= 0;
                seq->strip->tstripdata_startstill= 0;
 
+               if(seq->strip->ibuf_startstill) {
+                       IMB_freeImBuf(seq->strip->ibuf_startstill);
+                       seq->strip->ibuf_startstill = 0;
+               }
+
+               if(seq->strip->ibuf_endstill) {
+                       IMB_freeImBuf(seq->strip->ibuf_endstill);
+                       seq->strip->ibuf_endstill = 0;
+               }
+
                seq->strip->len= seq->len;
        }
 }
@@ -377,8 +398,10 @@ void calc_sequence(Sequence *seq)
                                        if(seqm->enddisp > max) max= seqm->enddisp;
                                        seqm= seqm->next;
                                }
-                               seq->start= min;
-                               seq->len= max-min;
+                               seq->start= min + seq->anim_startofs;
+                               seq->len = max-min;
+                               seq->len -= seq->anim_startofs;
+                               seq->len -= seq->anim_endofs;
 
                                if(seq->strip && seq->len!=seq->strip->len) {
                                        new_tstripdata(seq);
@@ -394,22 +417,35 @@ void reload_sequence_new_file(Sequence * seq)
        char str[FILE_MAXDIR+FILE_MAXFILE];
 
        if (!(seq->type == SEQ_MOVIE || seq->type == SEQ_IMAGE ||
-             seq->type == SEQ_HD_SOUND || seq->type == SEQ_SCENE)) {
+             seq->type == SEQ_HD_SOUND || seq->type == SEQ_RAM_SOUND ||
+             seq->type == SEQ_SCENE || seq->type == SEQ_META)) {
                return;
        }
 
        new_tstripdata(seq);
 
-       if (seq->type == SEQ_IMAGE) {
-               return;
-       }
-
-       if (seq->type != SEQ_SCENE) {
+       if (seq->type != SEQ_SCENE && seq->type != SEQ_META &&
+           seq->type != SEQ_IMAGE) {
                strncpy(str, seq->strip->dir, FILE_MAXDIR-1);
                strncat(str, seq->strip->stripdata->name, FILE_MAXFILE-1);
+
+               BLI_convertstringcode(str, G.sce);
+               BLI_convertstringframe(str, G.scene->r.cfra); /* TODO - is this needed? */
+               
        }
 
-       if (seq->type == SEQ_MOVIE) {
+       if (seq->type == SEQ_IMAGE) {
+               /* Hack? */
+               int olen = MEM_allocN_len(seq->strip->stripdata) 
+                       / sizeof(struct StripElem);
+               seq->len = olen;
+               seq->len -= seq->anim_startofs;
+               seq->len -= seq->anim_endofs;
+               if (seq->len < 0) {
+                       seq->len = 0;
+               }
+               seq->strip->len = seq->len;
+       } else if (seq->type == SEQ_MOVIE) {
                if(seq->anim) IMB_free_anim(seq->anim);
                seq->anim = openanim(str, IB_rect);
 
@@ -435,8 +471,22 @@ void reload_sequence_new_file(Sequence * seq)
                        return;
                }
 
-               seq->strip->len = seq->len 
-                       = sound_hdaudio_get_duration(seq->hdaudio, FPS);
+               seq->len = sound_hdaudio_get_duration(seq->hdaudio, FPS)
+                       - seq->anim_startofs - seq->anim_endofs;
+               if (seq->len < 0) {
+                       seq->len = 0;
+               }
+               seq->strip->len = seq->len;
+       } else if (seq->type == SEQ_RAM_SOUND) {
+               seq->len = (int) ( ((float)(seq->sound->streamlen-1)/
+                                   ((float)G.scene->audio.mixrate*4.0 ))
+                                  * FPS);
+               seq->len -= seq->anim_startofs;
+               seq->len -= seq->anim_endofs;
+               if (seq->len < 0) {
+                       seq->len = 0;
+               }
+               seq->strip->len = seq->len;
        } else if (seq->type == SEQ_SCENE) {
                Scene * sce = G.main->scene.first;
                 int nr = 1;
@@ -450,6 +500,8 @@ void reload_sequence_new_file(Sequence * seq)
 
                if (sce) {
                        seq->scene = sce;
+               } else {
+                       sce = seq->scene;
                }
 
                strncpy(seq->name + 2, sce->id.name + 2, 
@@ -464,7 +516,6 @@ void reload_sequence_new_file(Sequence * seq)
                seq->strip->len = seq->len;
        }
 
-
        calc_sequence(seq);
 }
 
@@ -618,12 +669,11 @@ static void multibuf(ImBuf *ibuf, float fmul)
        int a, mul, icol;
 
        mul= (int)(256.0*fmul);
-
-       a= ibuf->x*ibuf->y;
        rt= (char *)ibuf->rect;
        rt_float = ibuf->rect_float;
 
        if (rt) {
+               a= ibuf->x*ibuf->y;
                while(a--) {
 
                        icol= (mul*rt[0])>>8;
@@ -639,6 +689,7 @@ static void multibuf(ImBuf *ibuf, float fmul)
                }
        }
        if (rt_float) {
+               a= ibuf->x*ibuf->y;
                while(a--) {
                        rt_float[0] *= fmul;
                        rt_float[1] *= fmul;
@@ -689,14 +740,9 @@ static void do_effect(int cfra, Sequence *seq, TStripElem * se)
                        return;
                }
 
-               if(se->se1->ok == STRIPELEM_META) se1= se->se1->se1;
-               else se1= se->se1;
-               
-               if(se->se2->ok == STRIPELEM_META) se2= se->se2->se1;
-               else se2= se->se2;
-               
-               if(se->se3->ok == STRIPELEM_META) se3= se->se3->se1;
-               else se3= se->se3;
+               se1= se->se1;
+               se2= se->se2;
+               se3= se->se3;
 
                if (   (se1==0 || se2==0 || se3==0)
                    || (se1->ibuf==0 || se2->ibuf==0 || se3->ibuf==0)) {
@@ -711,8 +757,7 @@ static void do_effect(int cfra, Sequence *seq, TStripElem * se)
                        return;
                }
 
-               if(se->se1->ok == STRIPELEM_META) se1= se->se1->se1;
-               else se1= se->se1;
+               se1= se->se1;
 
                if (se1 == 0 || se1->ibuf == 0) {
                        make_black_ibuf(se->ibuf);
@@ -731,8 +776,7 @@ static void do_effect(int cfra, Sequence *seq, TStripElem * se)
                        return;
                }
 
-               if(se->se2->ok == STRIPELEM_META) se2= se->se2->se1;
-               else se2= se->se2;
+               se2= se->se2;
 
                if (se2 == 0 || se2->ibuf == 0) {
                        make_black_ibuf(se->ibuf);
@@ -775,8 +819,8 @@ static int give_stripelem_index(Sequence *seq, int cfra)
        int nr;
 
        if(seq->startdisp >cfra || seq->enddisp <= cfra) return -1;
-
-       if(seq->flag&SEQ_REVERSE_FRAMES)        {       
+       if(seq->len == 0) return -1;
+       if(seq->flag&SEQ_REVERSE_FRAMES) {      
                /*reverse frame in this sequence */
                if(cfra <= seq->start) nr= seq->len-1;
                else if(cfra >= seq->start+seq->len-1) nr= 0;
@@ -826,12 +870,12 @@ TStripElem *give_tstripelem(Sequence *seq, int cfra)
           here for all ibufs, since then, blending with IPOs won't work!
           
           Rather common case, if you use a single image and try to fade
-          it in and out...
-
-          Performance TODO: seperate give_tstripelem for ibuf from
-          give_tstripelem for ibuf_comp, so that caching works here again...
+          it in and out... or want to use your strip as a watermark in
+          alpha over mode...
        */
-       if (seq->ipo && seq->ipo->curve.first && !(seq->type & SEQ_EFFECT)) {
+       if (seq->blend_mode != SEQ_BLEND_REPLACE ||
+           (seq->ipo && seq->ipo->curve.first && (
+                   !(seq->type & SEQ_EFFECT) || !seq->seq1))) {
                Strip * s = seq->strip;
                if (cfra < seq->start) {
                        se = s->tstripdata_startstill;
@@ -975,44 +1019,216 @@ static int get_shown_sequences(
        return cnt;
 }
  
-static int get_shown_seq_from_metastrip(Sequence * seqm, int cfra,
-                                       Sequence ** seq_arr_out)
+
+/* **********************************************************************
+   proxy management
+   ********************************************************************** */
+
+#define PROXY_MAXFILE (2*FILE_MAXDIR+FILE_MAXFILE)
+
+static int seq_proxy_get_fname(Sequence * seq, int cfra, char * name)
 {
-       return get_shown_sequences(&seqm->seqbase, cfra, 0, seq_arr_out);
+       int frameno;
+       char dir[FILE_MAXDIR];
+
+       if (!seq->strip->proxy) {
+               return FALSE;
+       }
+
+       if (seq->flag & SEQ_USE_PROXY_CUSTOM_DIR) {
+               strcpy(dir, seq->strip->proxy->dir);
+       } else {
+               if (seq->type == SEQ_IMAGE || seq->type == SEQ_MOVIE) {
+                       snprintf(dir, FILE_MAXDIR, "%s/BL_proxy", 
+                                seq->strip->dir);
+               } else {
+                       return FALSE;
+               }
+       }
+
+       /* generate a seperate proxy directory for each preview size */
+
+       if (seq->type == SEQ_IMAGE) {
+               StripElem * se = give_stripelem(seq, cfra);
+               snprintf(name, PROXY_MAXFILE, "%s/images/%d/%s_proxy",
+                        dir, G.scene->r.size, se->name);
+               frameno = 1;
+       } else if (seq->type == SEQ_MOVIE) {
+               TStripElem * tse = give_tstripelem(seq, cfra);
+
+               frameno = tse->nr + seq->anim_startofs;
+
+               snprintf(name, PROXY_MAXFILE, "%s/%s/%d/####", dir,
+                        seq->strip->stripdata->name,
+                        G.scene->r.size);
+       } else {
+               TStripElem * tse = give_tstripelem(seq, cfra);
+
+               frameno = tse->nr + seq->anim_startofs;
+
+               snprintf(name, PROXY_MAXFILE, "%s/proxy_misc/%d/####", dir,
+                        G.scene->r.size);
+       }
+
+       BLI_convertstringcode(name, G.sce);
+       BLI_convertstringframe(name, frameno);
+       
+
+       strcat(name, ".jpg");
+
+       return TRUE;
 }
 
-void set_meta_stripdata(Sequence *seqm)
+static struct ImBuf * seq_proxy_fetch(Sequence * seq, int cfra)
 {
-       TStripElem *se;
-       int a, cfra;
+       char name[PROXY_MAXFILE];
 
-       se= seqm->strip->tstripdata;
+       if (!(seq->flag & SEQ_USE_PROXY)) {
+               return 0;
+       }
 
-       if (se == 0 && seqm->len > 0) {
-               int i;
-               se = seqm->strip->tstripdata = MEM_callocN(
-                       seqm->len*sizeof(TStripElem), "tstripelems");
-               for (i = 0; i < seqm->len; i++) {
-                       se[i].ok = STRIPELEM_META;
-               }
+       /* rendering at 100% ? No real sense in proxy-ing, right? */
+       if (G.scene->r.size == 100.0) {
+               return 0;
+       }
+
+       if (!seq_proxy_get_fname(seq, cfra, name)) {
+               return 0;
+       }
+
+       if (BLI_exists(name)) {
+               return IMB_loadiffname(name, IB_rect);
+       } else {
+               return 0;
+       }
+}
+
+static void do_build_seq_ibuf(Sequence * seq, TStripElem *se, int cfra,
+                             int build_proxy_run);
+
+static void seq_proxy_build_frame(Sequence * seq, int cfra)
+{
+       char name[PROXY_MAXFILE];
+       int quality;
+       TStripElem * se;
+       int ok;
+       int rectx, recty;
+       struct ImBuf * ibuf;
+
+       if (!(seq->flag & SEQ_USE_PROXY)) {
+               return;
+       }
+
+       /* rendering at 100% ? No real sense in proxy-ing, right? */
+       if (G.scene->r.size == 100.0) {
+               return;
+       }
+
+       if (!seq_proxy_get_fname(seq, cfra, name)) {
+               return;
+       }
+
+       se = give_tstripelem(seq, cfra);
+       if (!se) {
+               return;
+       }
+
+       if(se->ibuf) {
+               IMB_freeImBuf(se->ibuf);
+               se->ibuf = 0;
+       }
+       
+       do_build_seq_ibuf(seq, se, cfra, TRUE);
+
+       if (!se->ibuf) {
+               return;
+       }
+
+       rectx= (G.scene->r.size*G.scene->r.xsch)/100;
+       recty= (G.scene->r.size*G.scene->r.ysch)/100;
+
+       ibuf = se->ibuf;
+
+       if (ibuf->x != rectx || ibuf->y != recty) {
+               IMB_scalefastImBuf(ibuf, (short)rectx, (short)recty);
+       }
+
+       /* quality is fixed, otherwise one has to generate seperate
+          directories for every quality...
+
+          depth = 32 is intentionally left in, otherwise ALPHA channels
+          won't work... */
+       quality = 90;
+       ibuf->ftype= JPG | quality;
+
+       BLI_make_existing_file(name);
+       
+       ok = IMB_saveiff(ibuf, name, IB_rect | IB_zbuf | IB_zbuffloat);
+       if (ok == 0) {
+               perror(name);
        }
 
-       /* sets all ->se1 pointers in stripdata, to read the ibuf from it */
+       IMB_freeImBuf(ibuf);
+       se->ibuf = 0;
+}
+
+void seq_proxy_rebuild(Sequence * seq)
+{
+       int cfra;
+
+       waitcursor(1);
+
+       G.afbreek = 0;
+
+       /* flag management tries to account for strobe and 
+          other "non-linearities", that might come in the future...
+          better way would be to "touch" the files, so that _really_
+          no one is rebuild twice.
+        */
+
+       for (cfra = seq->startdisp; cfra < seq->enddisp; cfra++) {
+               TStripElem * tse = give_tstripelem(seq, cfra);
 
-       for(a=0; a<seqm->len; a++, se++) {
-               int cnt;
-               Sequence *seq_arr[MAXSEQ+1];
+               tse->flag &= ~STRIPELEM_PREVIEW_DONE;
+       }
+
+       /* a _lot_ faster for movie files, if we read frames in
+          sequential order */
+       if (seq->flag & SEQ_REVERSE_FRAMES) {
+               for (cfra = seq->enddisp-seq->endstill-1; 
+                    cfra >= seq->startdisp + seq->startstill; cfra--) {
+                       TStripElem * tse = give_tstripelem(seq, cfra);
 
-               cfra= a+seqm->start;
-               cnt = get_shown_seq_from_metastrip(seqm, cfra, seq_arr);
-               if (cnt) {
-                       se->se1= give_tstripelem(seq_arr[cnt-1], cfra);
-               } else { 
-                       se->se1= 0;
+                       if (!(tse->flag & STRIPELEM_PREVIEW_DONE)) {
+                               seq_proxy_build_frame(seq, cfra);
+                               tse->flag |= STRIPELEM_PREVIEW_DONE;
+                       }
+                       if (blender_test_break()) {
+                               break;
+                       }
+               }
+       } else {
+               for (cfra = seq->startdisp + seq->startstill; 
+                    cfra < seq->enddisp - seq->endstill; cfra++) {
+                       TStripElem * tse = give_tstripelem(seq, cfra);
+
+                       if (!(tse->flag & STRIPELEM_PREVIEW_DONE)) {
+                               seq_proxy_build_frame(seq, cfra);
+                               tse->flag |= STRIPELEM_PREVIEW_DONE;
+                       }
+                       if (blender_test_break()) {
+                               break;
+                       }
                }
        }
+       waitcursor(0);
 }
 
+
+/* **********************************************************************
+   color balance 
+   ********************************************************************** */
+
 static StripColorBalance calc_cb(StripColorBalance * cb_)
 {
        StripColorBalance cb = *cb_;
@@ -1039,7 +1255,7 @@ static StripColorBalance calc_cb(StripColorBalance * cb_)
 
        if (!(cb.flag & SEQ_COLOR_BALANCE_INVERSE_GAMMA)) {
                for (c = 0; c < 3; c++) {
-                       if (cb.gain[c] != 0.0) {
+                       if (cb.gamma[c] != 0.0) {
                                cb.gamma[c] = 1.0/cb.gamma[c];
                        } else {
                                cb.gamma[c] = 1000000; /* should be enough :) */
@@ -1158,6 +1374,7 @@ static void color_balance_float_float(Sequence * seq, TStripElem* se,
                        p[c] = pow((p[c] + cb.lift[c]) * cb.gain[c], 
                                   cb.gamma[c]) * mul;
                }
+               p += 4;
        }
 }
 
@@ -1191,6 +1408,38 @@ static void color_balance(Sequence * seq, TStripElem* se, float mul)
 
 */
 
+static int input_have_to_preprocess(Sequence * seq, TStripElem* se, int cfra)
+{
+       float mul;
+
+       if ((seq->flag & SEQ_FILTERY) || 
+           (seq->flag & SEQ_USE_CROP) ||
+           (seq->flag & SEQ_USE_TRANSFORM) ||
+           (seq->flag & SEQ_FLIPX) ||
+           (seq->flag & SEQ_FLIPY) ||
+           (seq->flag & SEQ_USE_COLOR_BALANCE) ||
+           (seq->flag & SEQ_MAKE_PREMUL) ||
+           (se->ibuf->x != seqrectx || se->ibuf->y != seqrecty)) {
+               return TRUE;
+       }
+
+       mul = seq->mul;
+
+       if(seq->blend_mode == SEQ_BLEND_REPLACE) {
+               if (seq->ipo && seq->ipo->curve.first) {
+                       do_seq_ipo(seq, cfra);
+                       mul *= seq->facf0;
+               }
+               mul *= seq->blend_opacity / 100.0;
+       }
+
+       if (mul != 1.0) {
+               return TRUE;
+       }
+               
+       return FALSE;
+}
+
 static void input_preprocess(Sequence * seq, TStripElem* se, int cfra)
 {
        float mul;
@@ -1330,49 +1579,121 @@ static void test_and_auto_discard_ibuf(TStripElem * se)
        }
 }
 
+static void test_and_auto_discard_ibuf_stills(Strip * strip)
+{
+       if (strip->ibuf_startstill) {
+               if (!strip->ibuf_startstill->rect &&
+                   !strip->ibuf_startstill->rect_float) {
+                       IMB_freeImBuf(strip->ibuf_startstill);
+                       strip->ibuf_startstill = 0;
+               }
+       }
+       if (strip->ibuf_endstill) {
+               if (!strip->ibuf_endstill->rect &&
+                   !strip->ibuf_endstill->rect_float) {
+                       IMB_freeImBuf(strip->ibuf_endstill);
+                       strip->ibuf_endstill = 0;
+               }
+       }
+}
+
+static void copy_from_ibuf_still(Sequence * seq, TStripElem * se)
+{
+       if (!se->ibuf) {
+               if (se->nr == 0 && seq->strip->ibuf_startstill) {
+                       IMB_cache_limiter_touch(seq->strip->ibuf_startstill);
+
+                       se->ibuf = IMB_dupImBuf(seq->strip->ibuf_startstill);
+               }
+               if (se->nr == seq->len - 1 
+                   && (seq->len != 1)
+                   && seq->strip->ibuf_endstill) {
+                       IMB_cache_limiter_touch(seq->strip->ibuf_endstill);
+
+                       se->ibuf = IMB_dupImBuf(seq->strip->ibuf_endstill);
+               }
+       }
+}
+
+static void copy_to_ibuf_still(Sequence * seq, TStripElem * se)
+{
+       if (se->ibuf) {
+               if (se->nr == 0) {
+                       seq->strip->ibuf_startstill = IMB_dupImBuf(se->ibuf);
+
+                       IMB_cache_limiter_insert(seq->strip->ibuf_startstill);
+                       IMB_cache_limiter_touch(seq->strip->ibuf_startstill);
+               }
+               if (se->nr == seq->len - 1 && seq->len != 1) {
+                       seq->strip->ibuf_endstill = IMB_dupImBuf(se->ibuf);
+
+                       IMB_cache_limiter_insert(seq->strip->ibuf_endstill);
+                       IMB_cache_limiter_touch(seq->strip->ibuf_endstill);
+               }
+       }
+}
+
+
 static TStripElem* do_build_seq_array_recursively(
        ListBase *seqbasep, int cfra, int chanshown);
 
-static void do_build_seq_ibuf(Sequence * seq, TStripElem *se, int cfra)
+static void do_build_seq_ibuf(Sequence * seq, TStripElem *se, int cfra,
+                             int build_proxy_run)
 {
        char name[FILE_MAXDIR+FILE_MAXFILE];
+       int use_limiter = TRUE;
 
-
-       if (seq->type != SEQ_META) {
-               test_and_auto_discard_ibuf(se);
-       }
+       test_and_auto_discard_ibuf(se);
+       test_and_auto_discard_ibuf_stills(seq->strip);
 
        if(seq->type == SEQ_META) {
-               if(seq->seqbase.first) {
-                       if(cfra < seq->start) {
-                               do_build_seq_array_recursively(
-                                       &seq->seqbase, 
-                                       seq->start, 0);
-                       } else if(cfra > seq->start + seq->len - 1) {
-                               do_build_seq_array_recursively(
-                                       &seq->seqbase, 
-                                       seq->start + seq->len - 1, 0);
-                       } else {
-                               do_build_seq_array_recursively(
-                                       &seq->seqbase, 
-                                       cfra, 0);
+               TStripElem * meta_se = 0;
+               use_limiter = FALSE;
+
+               if (!build_proxy_run && se->ibuf == 0) {
+                       se->ibuf = seq_proxy_fetch(seq, cfra);
+                       if (se->ibuf) {
+                               use_limiter = TRUE;
                        }
                }
 
-               se->ok = STRIPELEM_META;
-               if(se->se1 == 0) set_meta_stripdata(seq);
-               if(se->se1) {
-                       if(se->ibuf) {
-                               IMB_freeImBuf(se->ibuf);
-                       }
-                       se->ibuf = se->se1->ibuf_comp;
-                       if(se->ibuf) {
+               if(!se->ibuf && seq->seqbase.first) {
+                       meta_se = do_build_seq_array_recursively(
+                               &seq->seqbase, seq->start + se->nr, 0);
+               }
+
+               se->ok = STRIPELEM_OK;
+
+               if(!se->ibuf && meta_se) {
+                       se->ibuf = meta_se->ibuf_comp;
+                       if(se->ibuf &&
+                          (!input_have_to_preprocess(seq, se, cfra) ||
+                           build_proxy_run)) {
                                IMB_refImBuf(se->ibuf);
+                               if (build_proxy_run) {
+                                       IMB_cache_limiter_unref(se->ibuf);
+                               }
+                       } else if (se->ibuf) {
+                               struct ImBuf * i = IMB_dupImBuf(se->ibuf);
+
+                               IMB_cache_limiter_unref(se->ibuf);
+
+                               se->ibuf = i;
+
+                               use_limiter = TRUE;
                        }
                }
+
+               if (use_limiter) {
+                       input_preprocess(seq, se, cfra);
+               }
        } else if(seq->type & SEQ_EFFECT) {
                /* should the effect be recalculated? */
                
+               if (!build_proxy_run && se->ibuf == 0) {
+                       se->ibuf = seq_proxy_fetch(seq, cfra);
+               }
+
                if(se->ibuf == 0) {
                        /* if one of two first inputs are rectfloat, output is float too */
                        if((se->se1 && se->se1->ibuf && se->se1->ibuf->rect_float) ||
@@ -1383,53 +1704,86 @@ static void do_build_seq_ibuf(Sequence * seq, TStripElem *se, int cfra)
                        
                        do_effect(cfra, seq, se);
                }
+       } else if(seq->type == SEQ_IMAGE) {
+               if(se->ok == STRIPELEM_OK && se->ibuf == 0) {
+                       StripElem * s_elem = give_stripelem(seq, cfra);
+                       
+                       strncpy(name, seq->strip->dir, FILE_MAXDIR-1);
+                       strncat(name, s_elem->name, FILE_MAXFILE);
+                       BLI_convertstringcode(name, G.sce);
+                       BLI_convertstringframe(name, G.scene->r.cfra);
+                       if (!build_proxy_run) {
+                               se->ibuf = seq_proxy_fetch(seq, cfra);
+                       }
+                       copy_from_ibuf_still(seq, se);
 
-       } else if(seq->type < SEQ_EFFECT) {
-               
-               if(seq->type==SEQ_IMAGE) {
-                       if(se->ok == STRIPELEM_OK && se->ibuf==0) {
-                               StripElem * s_elem = give_stripelem(seq, cfra);
-
-                               strncpy(name, seq->strip->dir, FILE_MAXDIR-1);
-                               strncat(name, s_elem->name, FILE_MAXFILE);
-                               BLI_convertstringcode(name, G.sce, G.scene->r.cfra);
-                               se->ibuf= IMB_loadiffname(name, IB_rect);
-                               
-                               if(se->ibuf == 0) {
-                                       se->ok = STRIPELEM_FAILED;
-                               } else {
-                                       input_preprocess(seq, se, cfra);
-                               }
+                       if (!se->ibuf) {
+                               se->ibuf= IMB_loadiffname(
+                                       name, IB_rect);
+                               copy_to_ibuf_still(seq, se);
+                       }
+                       
+                       if(se->ibuf == 0) {
+                               se->ok = STRIPELEM_FAILED;
+                       } else if (!build_proxy_run) {
+                               input_preprocess(seq, se, cfra);
                        }
                }
-               else if(seq->type==SEQ_MOVIE) {
-                       if(se->ok == STRIPELEM_OK && se->ibuf==0) {
+       } else if(seq->type == SEQ_MOVIE) {
+               if(se->ok == STRIPELEM_OK && se->ibuf==0) {
+                       if(!build_proxy_run) {
+                               se->ibuf = seq_proxy_fetch(seq, cfra);
+                       }
+                       copy_from_ibuf_still(seq, se);
+
+                       if (se->ibuf == 0) {
                                if(seq->anim==0) {
                                        strncpy(name, seq->strip->dir, FILE_MAXDIR-1);
                                        strncat(name, seq->strip->stripdata->name, FILE_MAXFILE-1);
-                                       BLI_convertstringcode(name, G.sce, G.scene->r.cfra);
-                                       
+                                       BLI_convertstringcode(name, G.sce);
+                                       BLI_convertstringframe(name, G.scene->r.cfra);
+                               
                                        seq->anim = openanim(name, IB_rect);
                                }
                                if(seq->anim) {
                                        IMB_anim_set_preseek(seq->anim, seq->anim_preseek);
                                        se->ibuf = IMB_anim_absolute(seq->anim, se->nr + seq->anim_startofs);
                                }
-                               
-                               if(se->ibuf == 0) {
-                                       se->ok = STRIPELEM_FAILED;
-                               } else {
-                                       input_preprocess(seq, se, cfra);
-                               }
+                               copy_to_ibuf_still(seq, se);
+                       }
+                       
+                       if(se->ibuf == 0) {
+                               se->ok = STRIPELEM_FAILED;
+                       } else if (!build_proxy_run) {
+                               input_preprocess(seq, se, cfra);
                        }
-               } else if(seq->type==SEQ_SCENE && se->ibuf==NULL && seq->scene) {       // scene can be NULL after deletions
-                       int oldcfra = CFRA;
-                       Scene *sce= seq->scene, *oldsce= G.scene;
-                       Render *re;
-                       RenderResult rres;
-                       int doseq, rendering= G.rendering;
-                       char scenename[64];
+               }
+       } else if(seq->type == SEQ_SCENE) {     // scene can be NULL after deletions
+               int oldcfra = CFRA;
+               Scene *sce= seq->scene, *oldsce= G.scene;
+               Render *re;
+               RenderResult rres;
+               int doseq, rendering= G.rendering;
+               char scenename[64];
+               int sce_valid =sce&& (sce->camera || sce->r.scemode & R_DOSEQ);
                        
+               if (se->ibuf == NULL && sce_valid && !build_proxy_run) {
+                       se->ibuf = seq_proxy_fetch(seq, cfra);
+                       if (se->ibuf) {
+                               input_preprocess(seq, se, cfra);
+                       }
+               }
+
+               if (se->ibuf == NULL && sce_valid) {
+                       copy_from_ibuf_still(seq, se);
+                       if (se->ibuf) {
+                               input_preprocess(seq, se, cfra);
+                       }
+               }
+               
+               if (!sce_valid) {
+                       se->ok = STRIPELEM_FAILED;
+               } else if (se->ibuf==NULL && sce_valid) {
                        waitcursor(1);
                        
                        /* Hack! This function can be called from do_render_seq(), in that case
@@ -1485,13 +1839,24 @@ static void do_build_seq_ibuf(Sequence * seq, TStripElem *se, int cfra)
                                waitcursor(0);
                        CFRA = oldcfra;
 
-                       input_preprocess(seq, se, cfra);
+                       copy_to_ibuf_still(seq, se);
+
+                       if (!build_proxy_run) {
+                               if(se->ibuf == NULL) {
+                                       se->ok = STRIPELEM_FAILED;
+                               } else {
+                                       input_preprocess(seq, se, cfra);
+                               }
+                       }
+
                }       
        }
-       if (se->ibuf && seq->type != SEQ_META) {
-               IMB_cache_limiter_insert(se->ibuf);
-               IMB_cache_limiter_ref(se->ibuf);
-               IMB_cache_limiter_touch(se->ibuf);
+       if (!build_proxy_run) {
+               if (se->ibuf && use_limiter) {
+                       IMB_cache_limiter_insert(se->ibuf);
+                       IMB_cache_limiter_ref(se->ibuf);
+                       IMB_cache_limiter_touch(se->ibuf);
+               }
        }
 }
 
@@ -1538,7 +1903,7 @@ static void do_effect_seq_recursively(Sequence * seq, TStripElem *se, int cfra)
        }
 
 
-       do_build_seq_ibuf(seq, se, cfra);
+       do_build_seq_ibuf(seq, se, cfra, FALSE);
 
        /* children are not needed anymore ... */
 
@@ -1563,7 +1928,7 @@ static TStripElem* do_build_seq_recursively_impl(Sequence * seq, int cfra)
                if (seq->type & SEQ_EFFECT) {
                        do_effect_seq_recursively(seq, se, cfra);
                } else {
-                       do_build_seq_ibuf(seq, se, cfra);
+                       do_build_seq_ibuf(seq, se, cfra, FALSE);
                }
        }
        return se;
@@ -1713,6 +2078,10 @@ static TStripElem* do_build_seq_array_recursively(
 
        se = give_tstripelem(seq_arr[count - 1], cfra);
 
+       if (!se) {
+               return 0;
+       }
+
        test_and_auto_discard_ibuf(se);
 
        if (se->ibuf_comp != 0) {
@@ -2342,6 +2711,15 @@ void free_imbuf_seq_except(int cfra)
                                        free_imbuf_strip_elem(se);
                                }
                        }
+                       if(seq->strip->ibuf_startstill) {
+                               IMB_freeImBuf(seq->strip->ibuf_startstill);
+                               seq->strip->ibuf_startstill = 0;
+                       }
+
+                       if(seq->strip->ibuf_endstill) {
+                               IMB_freeImBuf(seq->strip->ibuf_endstill);
+                               seq->strip->ibuf_endstill = 0;
+                       }
 
                        if(seq->type==SEQ_MOVIE)
                                if(seq->startdisp > cfra || seq->enddisp < cfra)
@@ -2374,6 +2752,15 @@ void free_imbuf_seq()
                            a < seq->strip->endstill && se; a++, se++) {
                                free_imbuf_strip_elem(se);
                        }
+                       if(seq->strip->ibuf_startstill) {
+                               IMB_freeImBuf(seq->strip->ibuf_startstill);
+                               seq->strip->ibuf_startstill = 0;
+                       }
+
+                       if(seq->strip->ibuf_endstill) {
+                               IMB_freeImBuf(seq->strip->ibuf_endstill);
+                               seq->strip->ibuf_endstill = 0;
+                       }
 
                        if(seq->type==SEQ_MOVIE)
                                free_anim_seq(seq);