Changed frame numbering to only alter hashes if they are in the filename (not the...
[blender-staging.git] / source / blender / src / sequence.c
index 9a94f16712c69c54e21d1cd9247a3dd4d60a3812..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;
@@ -87,21 +92,20 @@ void free_tstripdata(int len, TStripElem *se)
        }
 
        for(a=0; a<len; a++, se++) {
-               if(se->ibuf && se->ok != STRIPELEM_META) {
+               if(se->ibuf) {
                        IMB_freeImBuf(se->ibuf);
                        se->ibuf = 0;
                }
+               if(se->ibuf_comp) {
+                       IMB_freeImBuf(se->ibuf_comp);
+                       se->ibuf_comp = 0;
+               }
        }
 
        MEM_freeN(seo);
 
 }
 
-void seq_proxy_free(StripProxy * proxy)
-{
-       MEM_freeN(proxy);
-}
-
 void free_strip(Strip *strip)
 {
        strip->us--;
@@ -111,20 +115,36 @@ 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);
        }
 
        free_tstripdata(strip->len, strip->tstripdata);
+       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);
 }
@@ -133,7 +153,25 @@ void new_tstripdata(Sequence *seq)
 {
        if(seq->strip) {
                free_tstripdata(seq->strip->len, seq->strip->tstripdata);
+               free_tstripdata(seq->strip->endstill, 
+                               seq->strip->tstripdata_endstill);
+               free_tstripdata(seq->strip->startstill, 
+                               seq->strip->tstripdata_startstill);
+
                seq->strip->tstripdata= 0;
+               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;
        }
 }
@@ -211,6 +249,66 @@ void build_seqar(ListBase *seqbase, Sequence  ***seqar, int *totseq)
        *seqar= tseqar;
 }
 
+static void do_seq_count_cb(ListBase *seqbase, int *totseq,
+                           int (*test_func)(Sequence * seq))
+{
+       Sequence *seq;
+
+       seq= seqbase->first;
+       while(seq) {
+               int test = test_func(seq);
+               if (test & BUILD_SEQAR_COUNT_CURRENT) {
+                       (*totseq)++;
+               }
+               if(seq->seqbase.first && (test & BUILD_SEQAR_COUNT_CHILDREN)) {
+                       do_seq_count_cb(&seq->seqbase, totseq, test_func);
+               }
+               seq= seq->next;
+       }
+}
+
+static void do_build_seqar_cb(ListBase *seqbase, Sequence ***seqar, int depth,
+                             int (*test_func)(Sequence * seq))
+{
+       Sequence *seq;
+
+       seq= seqbase->first;
+       while(seq) {
+               int test = test_func(seq);
+               seq->depth= depth;
+
+               if(seq->seqbase.first && (test & BUILD_SEQAR_COUNT_CHILDREN)) {
+                       do_build_seqar_cb(&seq->seqbase, seqar, depth+1, 
+                                         test_func);
+               }
+               if (test & BUILD_SEQAR_COUNT_CURRENT) {
+                       **seqar= seq;
+                       (*seqar)++;
+               }
+               seq= seq->next;
+       }
+}
+
+void build_seqar_cb(ListBase *seqbase, Sequence  ***seqar, int *totseq,
+                   int (*test_func)(Sequence * seq))
+{
+       Sequence **tseqar;
+
+       *totseq= 0;
+       do_seq_count_cb(seqbase, totseq, test_func);
+
+       if(*totseq==0) {
+               *seqar= 0;
+               return;
+       }
+       *seqar= MEM_mallocN(sizeof(void *)* *totseq, "seqar");
+       tseqar= *seqar;
+
+       do_build_seqar_cb(seqbase, seqar, 0, test_func);
+       *seqar= tseqar;
+}
+
+
 void free_editing(Editing *ed)
 {
        MetaStack *ms;
@@ -300,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);
@@ -312,6 +412,113 @@ void calc_sequence(Sequence *seq)
        }
 }
 
+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_RAM_SOUND ||
+             seq->type == SEQ_SCENE || seq->type == SEQ_META)) {
+               return;
+       }
+
+       new_tstripdata(seq);
+
+       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_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);
+
+               if (!seq->anim) {
+                       return;
+               }
+       
+               seq->len = IMB_anim_get_duration(seq->anim);
+               
+               seq->anim_preseek = IMB_anim_get_preseek(seq->anim);
+
+               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_HD_SOUND) {
+               if(seq->hdaudio) sound_close_hdaudio(seq->hdaudio);
+               seq->hdaudio = sound_open_hdaudio(str);
+
+               if (!seq->hdaudio) {
+                       return;
+               }
+
+               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;
+                while(sce) {
+                        if(nr == seq->scenenr) {
+                                break;
+                        }
+                        nr++;
+                        sce= sce->id.next;
+                }
+
+               if (sce) {
+                       seq->scene = sce;
+               } else {
+                       sce = seq->scene;
+               }
+
+               strncpy(seq->name + 2, sce->id.name + 2, 
+                       sizeof(seq->name) - 2);
+
+               seq->len= seq->scene->r.efra - seq->scene->r.sfra + 1;
+               seq->len -= seq->anim_startofs;
+               seq->len -= seq->anim_endofs;
+               if (seq->len < 0) {
+                       seq->len = 0;
+               }
+               seq->strip->len = seq->len;
+       }
+
+       calc_sequence(seq);
+}
+
 void sort_seq()
 {
        /* all strips together per kind, and in order of y location ("machine") */
@@ -382,6 +589,54 @@ void clear_scene_in_allseqs(Scene *sce)
        }
 }
 
+char *give_seqname_by_type(int type)
+{
+       switch(type) {
+       case SEQ_META:       return "Meta";
+       case SEQ_IMAGE:      return "Image";
+       case SEQ_SCENE:      return "Scene";
+       case SEQ_MOVIE:      return "Movie";
+       case SEQ_RAM_SOUND:  return "Audio (RAM)";
+       case SEQ_HD_SOUND:   return "Audio (HD)";
+       case SEQ_CROSS:      return "Cross";
+       case SEQ_GAMCROSS:   return "Gamma Cross";
+       case SEQ_ADD:        return "Add";
+       case SEQ_SUB:        return "Sub";
+       case SEQ_MUL:        return "Mul";
+       case SEQ_ALPHAOVER:  return "Alpha Over";
+       case SEQ_ALPHAUNDER: return "Alpha Under";
+       case SEQ_OVERDROP:   return "Over Drop";
+       case SEQ_WIPE:       return "Wipe";
+       case SEQ_GLOW:       return "Glow";
+       case SEQ_TRANSFORM:  return "Transform";
+       case SEQ_COLOR:      return "Color";
+       case SEQ_SPEED:      return "Speed";
+       default:
+               return 0;
+       }
+}
+
+char *give_seqname(Sequence *seq)
+{
+       char * name = give_seqname_by_type(seq->type);
+
+       if (!name) {
+               if(seq->type<SEQ_EFFECT) {
+                       return seq->strip->dir;
+               } else if(seq->type==SEQ_PLUGIN) {
+                       if(!(seq->flag & SEQ_EFFECT_NOT_LOADED) &&
+                          seq->plugin && seq->plugin->doit) {
+                               return seq->plugin->pname;
+                       } else {
+                               return "Plugin";
+                       }
+               } else {
+                       return "Effect";
+               }
+       }
+       return name;
+}
+
 /* ***************** DO THE SEQUENCE ***************** */
 
 static void make_black_ibuf(ImBuf *ibuf)
@@ -414,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;
@@ -435,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;
@@ -446,7 +701,7 @@ static void multibuf(ImBuf *ibuf, float fmul)
        }
 }
 
-static void do_effect(int cfra, Sequence *seq, TStripElem *se)
+static void do_effect(int cfra, Sequence *seq, TStripElem * se)
 {
        TStripElem *se1, *se2, *se3;
        float fac, facf;
@@ -472,7 +727,8 @@ static void do_effect(int cfra, Sequence *seq, TStripElem *se)
        early_out = sh.early_out(seq, fac, facf);
 
        if (early_out == -1) { /* no input needed */
-               sh.execute(seq, cfra, fac, facf, se->ibuf->x, se->ibuf->y, 
+               sh.execute(seq, cfra, fac, facf, 
+                          se->ibuf->x, se->ibuf->y, 
                           0, 0, 0, se->ibuf);
                return;
        }
@@ -484,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)) {
@@ -506,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);
@@ -526,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);
@@ -570,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;
@@ -589,6 +838,16 @@ static int give_stripelem_index(Sequence *seq, int cfra)
        return nr;
 }
 
+static TStripElem* alloc_tstripdata(int len, const char * name)
+{
+       int i;
+       TStripElem *se = MEM_callocN(len * sizeof(TStripElem), name);
+       for (i = 0; i < len; i++) {
+               se[i].ok = STRIPELEM_OK;
+       }
+       return se;
+}
+
 TStripElem *give_tstripelem(Sequence *seq, int cfra)
 {
        TStripElem *se;
@@ -596,21 +855,67 @@ TStripElem *give_tstripelem(Sequence *seq, int cfra)
 
        se = seq->strip->tstripdata;
        if (se == 0 && seq->len > 0) {
-               int i;
-               se = seq->strip->tstripdata = MEM_callocN(
-                       seq->len*sizeof(TStripElem), "tstripelems");
-               for (i = 0; i < seq->len; i++) {
-                       se[i].ok = STRIPELEM_OK;
-               }
+               se = seq->strip->tstripdata = alloc_tstripdata(seq->len,
+                                                              "tstripelems");
        }
        nr = give_stripelem_index(seq, cfra);
 
        if (nr == -1) return 0;
        if (se == 0) return 0;
+
+       se += nr; 
+
+       /* if there are IPOs with blend modes active, one has to watch out
+          for startstill + endstill area: we can't use the same tstripelem
+          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... or want to use your strip as a watermark in
+          alpha over mode...
+       */
+       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;
+                       if (seq->startstill > s->startstill) {
+                               free_tstripdata(s->startstill, 
+                                               s->tstripdata_startstill);
+                               se = 0;
+                       }
+
+                       if (se == 0) {
+                               s->startstill = seq->startstill;
+                               se = seq->strip->tstripdata_startstill
+                                       = alloc_tstripdata(
+                                               s->startstill,
+                                               "tstripelems_startstill");
+                       }
+                       se += seq->start - cfra - 1;
+
+               } else if (cfra > seq->start + seq->len-1) {
+                       se = s->tstripdata_endstill;
+                       if (seq->endstill > s->endstill) {
+                               free_tstripdata(s->endstill, 
+                                               s->tstripdata_endstill);
+                               se = 0;
+                       }
+
+                       if (se == 0) {
+                               s->endstill = seq->endstill;
+                               se = seq->strip->tstripdata_endstill
+                                       = alloc_tstripdata(
+                                               s->endstill,
+                                               "tstripelems_endstill");
+                       }
+                       se += cfra - (seq->start + seq->len-1) - 1;
+               }
+       }
+
        
-       se+= nr; 
        se->nr= nr;
-       
+
        return se;
 }
 
@@ -625,7 +930,7 @@ StripElem *give_stripelem(Sequence *seq, int cfra)
        if (nr == -1) return 0;
        if (se == 0) return 0;
 
-       se += nr; 
+       se += nr + seq->anim_startofs
        
        return se;
 }
@@ -636,7 +941,7 @@ static int evaluate_seq_frame_gen(
        Sequence *seq;
        int totseq=0;
 
-       memset(seq_arr, 0, sizeof(Sequence*) * MAXSEQ);
+       memset(seq_arr, 0, sizeof(Sequence*) * (MAXSEQ+1));
 
        seq= seqbase->first;
        while(seq) {
@@ -662,83 +967,425 @@ int evaluate_seq_frame(int cfra)
 
 }
 
-Sequence *get_shown_sequence(ListBase * seqbasep, int cfra, int chanshown)
+static int video_seq_is_rendered(Sequence * seq)
 {
-       Sequence *seq, *seqim, *seqeff;
-       Sequence *seq_arr[MAXSEQ+1];
-       int b;
+       return (seq 
+               && !(seq->flag & SEQ_MUTE) 
+               && seq->type != SEQ_RAM_SOUND 
+               && seq->type != SEQ_HD_SOUND);
+}
 
-       seq = 0;
+static int get_shown_sequences(
+       ListBase * seqbasep, int cfra, int chanshown, Sequence ** seq_arr_out)
+{
+       Sequence *seq_arr[MAXSEQ+1];
+       int b = chanshown;
+       int cnt = 0;
 
-       if (chanshown > MAXSEQ) {
+       if (b > MAXSEQ) {
                return 0;
        }
 
        if(evaluate_seq_frame_gen(seq_arr, seqbasep, cfra)) {
-               if (chanshown > 0) {
-                       return seq_arr[chanshown];
-               }
-
-               /* we take the upper effect strip or 
-                  the lowest imagestrip/metastrip */
-               seqim= seqeff= 0;
-
-               for(b=1; b<MAXSEQ; b++) {
-                       if(seq_arr[b]) {
-                               seq= seq_arr[b];
-                               if(seq->flag & SEQ_MUTE) {
-                                       /* skip */
-                               } else if(seq->type & SEQ_EFFECT) {
-                                       if(seqeff==0) seqeff= seq;
-                                       else if(seqeff->machine < seq->machine)
-                                               seqeff= seq;
-                               } else if (seq->type != SEQ_RAM_SOUND && seq->type != SEQ_HD_SOUND) {
-                                       if(seqim==0) seqim= seq;
-                                       else if(seqim->machine > seq->machine)
-                                               seqim= seq;
+               if (b > 0) {
+                       if (seq_arr[b] == 0) {
+                               return 0;
+                       }
+               } else {
+                       for (b = MAXSEQ; b > 0; b--) {
+                               if (video_seq_is_rendered(seq_arr[b])) {
+                                       break;
                                }
                        }
                }
-               if(seqeff) seq= seqeff;
-               else if(seqim) seq= seqim;
-               else seq= 0;
        }
        
-       return seq;
+       chanshown = b;
+
+       for (;b > 0; b--) {
+               if (video_seq_is_rendered(seq_arr[b])) {
+                       if (seq_arr[b]->blend_mode == SEQ_BLEND_REPLACE) {
+                               break;
+                       }
+               }
+       }
+
+       for (;b <= chanshown; b++) {
+               if (video_seq_is_rendered(seq_arr[b])) {
+                       seq_arr_out[cnt++] = seq_arr[b];
+               }
+       }
+
+       return cnt;
 }
  
-static Sequence * get_shown_seq_from_metastrip(Sequence * seqm, int cfra)
+
+/* **********************************************************************
+   proxy management
+   ********************************************************************** */
+
+#define PROXY_MAXFILE (2*FILE_MAXDIR+FILE_MAXFILE)
+
+static int seq_proxy_get_fname(Sequence * seq, int cfra, char * name)
+{
+       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;
+}
+
+static struct ImBuf * seq_proxy_fetch(Sequence * seq, int cfra)
+{
+       char name[PROXY_MAXFILE];
+
+       if (!(seq->flag & SEQ_USE_PROXY)) {
+               return 0;
+       }
+
+       /* 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);
+       }
+
+       IMB_freeImBuf(ibuf);
+       se->ibuf = 0;
+}
+
+void seq_proxy_rebuild(Sequence * seq)
 {
-       return get_shown_sequence(&seqm->seqbase, cfra, 0);
+       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);
+
+               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);
+
+                       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_;
+       int c;
+
+       if (cb.flag & SEQ_COLOR_BALANCE_INVERSE_LIFT) {
+               for (c = 0; c < 3; c++) {
+                       cb.lift[c] = 1.0 - cb.lift[c];
+               }
+       } else {
+               for (c = 0; c < 3; c++) {
+                       cb.lift[c] = -(1.0 - cb.lift[c]);
+               }
+       }
+       if (cb.flag & SEQ_COLOR_BALANCE_INVERSE_GAIN) {
+               for (c = 0; c < 3; c++) {
+                       if (cb.gain[c] != 0.0) {
+                               cb.gain[c] = 1.0/cb.gain[c];
+                       } else {
+                               cb.gain[c] = 1000000; /* should be enough :) */
+                       }
+               }
+       }
+
+       if (!(cb.flag & SEQ_COLOR_BALANCE_INVERSE_GAMMA)) {
+               for (c = 0; c < 3; c++) {
+                       if (cb.gamma[c] != 0.0) {
+                               cb.gamma[c] = 1.0/cb.gamma[c];
+                       } else {
+                               cb.gamma[c] = 1000000; /* should be enough :) */
+                       }
+               }
+       }
+
+       return cb;
+}
+
+static void make_cb_table_byte(float lift, float gain, float gamma,
+                              unsigned char * table, float mul)
+{
+       int y;
+
+       for (y = 0; y < 256; y++) {
+               float v = 1.0 * y / 255;
+               v += lift; 
+               v *= gain;
+               v = pow(v, gamma);
+               v *= mul;
+               if ( v > 1.0) {
+                       v = 1.0;
+               } else if (v < 0.0) {
+                       v = 0.0;
+               }
+               table[y] = v * 255;
+       }
+
+}
+
+static void make_cb_table_float(float lift, float gain, float gamma,
+                               float * table, float mul)
+{
+       int y;
+
+       for (y = 0; y < 256; y++) {
+               float v = (float) y * 1.0 / 255.0;
+               v += lift;
+               v *= gain;
+               v = pow(v, gamma);
+               v *= mul;
+               table[y] = v;
+       }
+}
+
+static void color_balance_byte_byte(Sequence * seq, TStripElem* se,
+                                   float mul)
+{
+       unsigned char cb_tab[3][256];
+       int c;
+       unsigned char * p = (unsigned char*) se->ibuf->rect;
+       unsigned char * e = p + se->ibuf->x * 4 * se->ibuf->y;
+
+       StripColorBalance cb = calc_cb(seq->strip->color_balance);
+
+       for (c = 0; c < 3; c++) {
+               make_cb_table_byte(cb.lift[c], cb.gain[c], cb.gamma[c],
+                                  cb_tab[c], mul);
+       }
+
+       while (p < e) {
+               p[0] = cb_tab[0][p[0]];
+               p[1] = cb_tab[1][p[1]];
+               p[2] = cb_tab[2][p[2]];
+               
+               p += 4;
+       }
 }
 
-void set_meta_stripdata(Sequence *seqm)
+static void color_balance_byte_float(Sequence * seq, TStripElem* se,
+                                    float mul)
 {
-       Sequence *seq;
-       TStripElem *se;
-       int a, cfra;
+       float cb_tab[4][256];
+       int c,i;
+       unsigned char * p = (unsigned char*) se->ibuf->rect;
+       unsigned char * e = p + se->ibuf->x * 4 * se->ibuf->y;
+       float * o;
+       StripColorBalance cb;
 
-       se= seqm->strip->tstripdata;
+       imb_addrectfloatImBuf(se->ibuf);
 
-       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;
-               }
+       o = se->ibuf->rect_float;
+
+       cb = calc_cb(seq->strip->color_balance);
+
+       for (c = 0; c < 3; c++) {
+               make_cb_table_float(cb.lift[c], cb.gain[c], cb.gamma[c],
+                                   cb_tab[c], mul);
+       }
+
+       for (i = 0; i < 256; i++) {
+               cb_tab[3][i] = ((float)i)*(1.0f/255.0f);
        }
 
-       /* sets all ->se1 pointers in stripdata, to read the ibuf from it */
+       while (p < e) {
+               o[0] = cb_tab[0][p[0]];
+               o[1] = cb_tab[1][p[1]];
+               o[2] = cb_tab[2][p[2]];
+               o[3] = cb_tab[3][p[3]];
+
+               p += 4; o += 4;
+       }
+}
 
-       for(a=0; a<seqm->len; a++, se++) {
-               cfra= a+seqm->start;
-               seq = get_shown_seq_from_metastrip(seqm, cfra);
-               if (seq) {
-                       se->se1= give_tstripelem(seq, cfra);
-               } else { 
-                       se->se1= 0;
+static void color_balance_float_float(Sequence * seq, TStripElem* se,
+                                     float mul)
+{
+       float * p = se->ibuf->rect_float;
+       float * e = se->ibuf->rect_float + se->ibuf->x * 4* se->ibuf->y;
+       StripColorBalance cb = calc_cb(seq->strip->color_balance);
+
+       while (p < e) {
+               int c;
+               for (c = 0; c < 3; c++) {
+                       p[c] = pow((p[c] + cb.lift[c]) * cb.gain[c], 
+                                  cb.gamma[c]) * mul;
                }
+               p += 4;
+       }
+}
+
+static void color_balance(Sequence * seq, TStripElem* se, float mul)
+{
+       if (se->ibuf->rect_float) {
+               color_balance_float_float(seq, se, mul);
+       } else if(seq->flag & SEQ_MAKE_FLOAT) {
+               color_balance_byte_float(seq, se, mul);
+       } else {
+               color_balance_byte_byte(seq, se, mul);
        }
 }
 
@@ -754,12 +1401,49 @@ void set_meta_stripdata(Sequence *seqm)
   - Crop and transform in image source coordinate space
   - Flip X + Flip Y (could be done afterwards, backward compatibility)
   - Promote image to float data (affects pipeline operations afterwards)
+  - Color balance (is most efficient in the byte -> float 
+    (future: half -> float should also work fine!)
+    case, if done on load, since we can use lookup tables)
   - Premultiply
 
 */
 
+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;
+
        seq->strip->orx= se->ibuf->x;
        seq->strip->ory= se->ibuf->y;
 
@@ -822,17 +1506,36 @@ static void input_preprocess(Sequence * seq, TStripElem* se, int cfra)
                IMB_flipy(se->ibuf);
        }
 
+       if(seq->mul == 0.0) {
+               seq->mul = 1.0;
+       }
+
+       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(seq->flag & SEQ_USE_COLOR_BALANCE && seq->strip->color_balance) {
+               color_balance(seq, se, mul);
+               mul = 1.0;
+       }
+
        if(seq->flag & SEQ_MAKE_FLOAT) {
                if (!se->ibuf->rect_float) {
                        IMB_float_from_rect(se->ibuf);
                }
+               if (se->ibuf->rect) {
+                       imb_freerectImBuf(se->ibuf);
+               }
        }
 
-       if(seq->mul == 0.0) {
-               seq->mul = 1.0;
-       }
-       if(seq->mul != 1.0) {
-               multibuf(se->ibuf, seq->mul);
+       if(mul != 1.0) {
+               multibuf(se->ibuf, mul);
        }
 
        if(seq->flag & SEQ_MAKE_PREMUL) {
@@ -853,44 +1556,144 @@ static void input_preprocess(Sequence * seq, TStripElem* se, int cfra)
        }
 }
 
-static TStripElem* do_build_seq_recursively(Sequence * seq, int cfra);
+/* test if image too small or discarded from cache: reload */
 
-static void do_build_seq_ibuf(Sequence * seq, TStripElem *se, int cfra)
+static void test_and_auto_discard_ibuf(TStripElem * se)
 {
-       char name[FILE_MAXDIR+FILE_MAXFILE];
-
-       if (seq->type != SEQ_META && se->ibuf) {
-               /* test if image too small 
-                  or discarded from cache: reload */
+       if (se->ibuf) {
                if(se->ibuf->x != seqrectx || se->ibuf->y != seqrecty 
                   || !(se->ibuf->rect || se->ibuf->rect_float)) {
                        IMB_freeImBuf(se->ibuf);
+
                        se->ibuf= 0;
                        se->ok= STRIPELEM_OK;
                }
        }
+       if (se->ibuf_comp) {
+               if(se->ibuf_comp->x != seqrectx || se->ibuf_comp->y != seqrecty 
+                  || !(se->ibuf_comp->rect || se->ibuf_comp->rect_float)) {
+                       IMB_freeImBuf(se->ibuf_comp);
+
+                       se->ibuf_comp = 0;
+               }
+       }
+}
+
+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,
+                             int build_proxy_run)
+{
+       char name[FILE_MAXDIR+FILE_MAXFILE];
+       int use_limiter = TRUE;
+
+       test_and_auto_discard_ibuf(se);
+       test_and_auto_discard_ibuf_stills(seq->strip);
 
        if(seq->type == SEQ_META) {
-               if(seq->seqbase.first) {
-                       Sequence * seqmshown= 
-                               get_shown_seq_from_metastrip(seq, cfra);
-                       if (seqmshown) {
-                               if(cfra< seq->start) 
-                                       do_build_seq_recursively(seqmshown, seq->start);
-                               else if(cfra> seq->start+seq->len-1) 
-                                       do_build_seq_recursively(seqmshown, seq->start + seq->len-1);
-                               else do_build_seq_recursively(seqmshown, cfra);
+               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;
+                       }
+               }
+
+               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;
                        }
                }
 
-               se->ok = STRIPELEM_META;
-               if(se->se1 == 0) set_meta_stripdata(seq);
-               if(se->se1) {
-                       se->ibuf= se->se1->ibuf;
+               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) ||
@@ -901,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);
-                               }
-                               
-                               if(se->ibuf == 0) {
-                                       se->ok = STRIPELEM_FAILED;
-                               } else {
-                                       input_preprocess(seq, se, cfra);
+                                       se->ibuf = IMB_anim_absolute(seq->anim, se->nr + seq->anim_startofs);
                                }
+                               copy_to_ibuf_still(seq, se);
                        }
-               } 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];
                        
+                       if(se->ibuf == 0) {
+                               se->ok = STRIPELEM_FAILED;
+                       } else if (!build_proxy_run) {
+                               input_preprocess(seq, se, cfra);
+                       }
+               }
+       } 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
@@ -971,7 +1807,8 @@ static void do_build_seq_ibuf(Sequence * seq, TStripElem *se, int cfra)
                        
                        /* hrms, set_scene still needed? work on that... */
                        if(sce!=oldsce) set_scene_bg(sce);
-                       RE_BlenderFrame(re, sce, seq->sfra + se->nr);
+                       RE_BlenderFrame(re, sce,
+                                       seq->sfra+se->nr+seq->anim_startofs);
                        if(sce!=oldsce) set_scene_bg(oldsce);
                        
                        /* UGLY WARNING, it is set to zero in  RE_BlenderFrame */
@@ -1002,16 +1839,29 @@ 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);
+               }
        }
 }
 
+static TStripElem* do_build_seq_recursively(Sequence * seq, int cfra);
+
 static void do_effect_seq_recursively(Sequence * seq, TStripElem *se, int cfra)
 {
        float fac, facf;
@@ -1053,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 ... */
 
@@ -1078,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;
@@ -1114,13 +1964,7 @@ static TStripElem* do_handle_speed_effect(Sequence * seq, int cfra)
 
        if (cfra_left == cfra_right || 
            (s->flags & SEQ_SPEED_BLEND) == 0) {
-               if(se->ibuf) {
-                       if(se->ibuf->x < seqrectx || se->ibuf->y < seqrecty 
-                          || !(se->ibuf->rect || se->ibuf->rect_float)) {
-                               IMB_freeImBuf(se->ibuf);
-                               se->ibuf= 0;
-                       }
-               }
+               test_and_auto_discard_ibuf(se);
 
                if (se->ibuf == NULL) {
                        se1 = do_build_seq_recursively_impl(
@@ -1218,6 +2062,216 @@ static TStripElem* do_build_seq_recursively(Sequence * seq, int cfra)
        }
 }
 
+static TStripElem* do_build_seq_array_recursively(
+       ListBase *seqbasep, int cfra, int chanshown)
+{
+       Sequence* seq_arr[MAXSEQ+1];
+       int count;
+       int i;
+       TStripElem* se = 0;
+
+       count = get_shown_sequences(seqbasep, cfra, chanshown, (Sequence **)&seq_arr);
+
+       if (!count) {
+               return 0;
+       }
+
+       se = give_tstripelem(seq_arr[count - 1], cfra);
+
+       if (!se) {
+               return 0;
+       }
+
+       test_and_auto_discard_ibuf(se);
+
+       if (se->ibuf_comp != 0) {
+               IMB_cache_limiter_insert(se->ibuf_comp);
+               IMB_cache_limiter_ref(se->ibuf_comp);
+               IMB_cache_limiter_touch(se->ibuf_comp);
+               return se;
+       }
+
+       
+       if(count == 1) {
+               se = do_build_seq_recursively(seq_arr[0], cfra);
+               if (se->ibuf) {
+                       se->ibuf_comp = se->ibuf;
+                       IMB_refImBuf(se->ibuf_comp);
+               }
+               return se;
+       }
+
+
+       for (i = count - 1; i >= 0; i--) {
+               int early_out;
+               Sequence * seq = seq_arr[i];
+               struct SeqEffectHandle sh;
+
+               se = give_tstripelem(seq, cfra);
+
+               test_and_auto_discard_ibuf(se);
+
+               if (se->ibuf_comp != 0) {
+                       break;
+               }
+               if (seq->blend_mode == SEQ_BLEND_REPLACE) {
+                       do_build_seq_recursively(seq, cfra);
+                       if (se->ibuf) {
+                               se->ibuf_comp = se->ibuf;
+                               IMB_refImBuf(se->ibuf);
+                       } else {
+                               se->ibuf_comp = IMB_allocImBuf(
+                                       (short)seqrectx, (short)seqrecty, 
+                                       32, IB_rect, 0);
+                       }
+                       break;
+               }
+
+               sh = get_sequence_blend(seq);
+
+               seq->facf0 = seq->facf1 = 1.0;
+
+               if(seq->ipo && seq->ipo->curve.first) {
+                       do_seq_ipo(seq, cfra);
+               } 
+
+               if( G.scene->r.mode & R_FIELDS ); else seq->facf0 = seq->facf1;
+
+               seq->facf0 *= seq->blend_opacity / 100.0;
+               seq->facf1 *= seq->blend_opacity / 100.0;
+
+               early_out = sh.early_out(seq, seq->facf0, seq->facf1);
+
+               switch (early_out) {
+               case -1:
+               case 2:
+                       do_build_seq_recursively(seq, cfra);
+                       if (se->ibuf) {
+                               se->ibuf_comp = se->ibuf;
+                               IMB_refImBuf(se->ibuf_comp);
+                       } else {
+                               se->ibuf_comp = IMB_allocImBuf(
+                                       (short)seqrectx, (short)seqrecty, 
+                                       32, IB_rect, 0);
+                       }
+                       break;
+               case 1:
+                       if (i == 0) {
+                               se->ibuf_comp = IMB_allocImBuf(
+                                       (short)seqrectx, (short)seqrecty, 
+                                       32, IB_rect, 0);
+                               IMB_cache_limiter_insert(se->ibuf_comp);
+                               IMB_cache_limiter_ref(se->ibuf_comp);
+                               IMB_cache_limiter_touch(se->ibuf_comp);
+                       }
+                       break;
+               case 0:
+                       do_build_seq_recursively(seq, cfra);
+                       if (!se->ibuf) {
+                               se->ibuf = IMB_allocImBuf(
+                                       (short)seqrectx, (short)seqrecty, 
+                                       32, IB_rect, 0);
+                       }
+                       if (i == 0) {
+                               se->ibuf_comp = se->ibuf;
+                               IMB_refImBuf(se->ibuf_comp);
+                       }
+                       break;
+               }
+       
+               if (se->ibuf_comp) {
+                       break;
+               }
+       }
+
+       i++;
+
+       for (; i < count; i++) {
+               Sequence * seq = seq_arr[i];
+               struct SeqEffectHandle sh = get_sequence_blend(seq);
+               TStripElem* se1 = give_tstripelem(seq_arr[i-1], cfra);
+               TStripElem* se2 = give_tstripelem(seq_arr[i], cfra);
+       
+               int early_out = sh.early_out(seq, seq->facf0, seq->facf1);
+               switch (early_out) {
+               case 0: {
+                       int x= se2->ibuf->x;
+                       int y= se2->ibuf->y;
+                       int swap_input = FALSE;
+
+                       if (se1->ibuf_comp->rect_float ||
+                           se2->ibuf->rect_float) {
+                               se2->ibuf_comp = IMB_allocImBuf(
+                                       (short)seqrectx, (short)seqrecty, 
+                                       32, IB_rectfloat, 0);
+                       } else {
+                               se2->ibuf_comp = IMB_allocImBuf(
+                                       (short)seqrectx, (short)seqrecty, 
+                                       32, IB_rect, 0);
+                       }
+
+
+                       if (!se1->ibuf_comp->rect_float && 
+                           se2->ibuf_comp->rect_float) {
+                               IMB_float_from_rect(se1->ibuf_comp);
+                       }
+                       if (!se2->ibuf->rect_float && 
+                           se2->ibuf_comp->rect_float) {
+                               IMB_float_from_rect(se2->ibuf);
+                       }
+
+                       if (!se1->ibuf_comp->rect && 
+                           !se2->ibuf_comp->rect_float) {
+                               IMB_rect_from_float(se1->ibuf_comp);
+                       }
+                       if (!se2->ibuf->rect && 
+                           !se2->ibuf_comp->rect_float) {
+                               IMB_rect_from_float(se2->ibuf);
+                       }
+
+                       /* bad hack, to fix crazy input ordering of 
+                          those two effects */
+
+                       if (seq->blend_mode == SEQ_ALPHAOVER ||
+                           seq->blend_mode == SEQ_ALPHAUNDER ||
+                           seq->blend_mode == SEQ_OVERDROP) {
+                               swap_input = TRUE;
+                       }
+
+                       if (swap_input) {
+                               sh.execute(seq, cfra, 
+                                          seq->facf0, seq->facf1, x, y, 
+                                          se2->ibuf, se1->ibuf_comp, 0,
+                                          se2->ibuf_comp);
+                       } else {
+                               sh.execute(seq, cfra, 
+                                          seq->facf0, seq->facf1, x, y, 
+                                          se1->ibuf_comp, se2->ibuf, 0,
+                                          se2->ibuf_comp);
+                       }
+                       
+                       IMB_cache_limiter_insert(se2->ibuf_comp);
+                       IMB_cache_limiter_ref(se2->ibuf_comp);
+                       IMB_cache_limiter_touch(se2->ibuf_comp);
+
+                       IMB_cache_limiter_unref(se1->ibuf_comp);
+                       IMB_cache_limiter_unref(se2->ibuf);
+
+                       break;
+               }
+               case 1: {
+                       se2->ibuf_comp = se1->ibuf;
+                       IMB_refImBuf(se2->ibuf_comp);
+
+                       break;
+               }
+               }
+               se = se2;
+       }
+
+       return se;
+}
+
 /*
  * returned ImBuf is refed!
  * you have to unref after usage!
@@ -1225,7 +2279,6 @@ static TStripElem* do_build_seq_recursively(Sequence * seq, int cfra)
 
 static ImBuf *give_ibuf_seq_impl(int rectx, int recty, int cfra, int chanshown)
 {
-       Sequence *seqfirst=0;
        Editing *ed;
        int count;
        ListBase *seqbasep;
@@ -1245,19 +2298,13 @@ static ImBuf *give_ibuf_seq_impl(int rectx, int recty, int cfra, int chanshown)
        seqrectx= rectx;        /* bad bad global! */
        seqrecty= recty;
 
-       seqfirst = get_shown_sequence(seqbasep, cfra, chanshown);
-
-       if (!seqfirst) {
-               return 0;
-       }
-
-       se = do_build_seq_recursively(seqfirst, cfra);
+       se = do_build_seq_array_recursively(seqbasep, cfra, chanshown);
 
        if(!se) { 
                return 0;
        }
 
-       return se->ibuf;
+       return se->ibuf_comp;
 }
 
 ImBuf *give_ibuf_seq_direct(int rectx, int recty, int cfra,
@@ -1613,13 +2660,16 @@ ImBuf * give_ibuf_seq_threaded(int rectx, int recty, int cfra, int chanshown)
 
 static void free_imbuf_strip_elem(TStripElem *se)
 {
-       if (se->ibuf) {
-               if (se->ok != STRIPELEM_META && se->ibuf != 0)
-                       IMB_freeImBuf(se->ibuf);
-               se->ibuf= 0;
-               se->ok= STRIPELEM_OK;
-               se->se1= se->se2= se->se3= 0;
+       if(se->ibuf) {
+               IMB_freeImBuf(se->ibuf);
        }
+       if(se->ibuf_comp) {
+               IMB_freeImBuf(se->ibuf_comp);
+       }
+       se->ibuf_comp = 0;
+       se->ibuf= 0;
+       se->ok= STRIPELEM_OK;
+       se->se1= se->se2= se->se3= 0;
 }
 
 static void free_anim_seq(Sequence *seq)
@@ -1643,9 +2693,33 @@ void free_imbuf_seq_except(int cfra)
                if(seq->strip) {
                        TStripElem * curelem = give_tstripelem(seq, cfra);
 
-                       for(a=0, se= seq->strip->tstripdata; a<seq->len; a++, se++)
-                               if(se != curelem)
+                       for(a = 0, se = seq->strip->tstripdata; 
+                           a < seq->strip->len && se; a++, se++) {
+                               if(se != curelem) {
+                                       free_imbuf_strip_elem(se);
+                               }
+                       }
+                       for(a = 0, se = seq->strip->tstripdata_startstill;
+                           a < seq->strip->startstill && se; a++, se++) {
+                               if(se != curelem) {
+                                       free_imbuf_strip_elem(se);
+                               }
+                       }
+                       for(a = 0, se = seq->strip->tstripdata_endstill;
+                           a < seq->strip->endstill && se; a++, se++) {
+                               if(se != curelem) {
                                        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)
@@ -1666,9 +2740,26 @@ void free_imbuf_seq()
 
        WHILE_SEQ(&ed->seqbase) {
                if(seq->strip) {
-                       if (seq->strip->tstripdata) {
-                               for(a=0, se= seq->strip->tstripdata; a<seq->len; a++, se++)
-                                       free_imbuf_strip_elem(se);
+                       for(a = 0, se = seq->strip->tstripdata; 
+                           a < seq->strip->len && se; a++, se++) {
+                               free_imbuf_strip_elem(se);
+                       }
+                       for(a = 0, se = seq->strip->tstripdata_startstill; 
+                           a < seq->strip->startstill && se; a++, se++) {
+                               free_imbuf_strip_elem(se);
+                       }
+                       for(a = 0, se = seq->strip->tstripdata_endstill; 
+                           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)