Some small fixes and changes:
[blender.git] / source / blender / blenkernel / intern / sequencer.c
index a4d11c9..3dcbe03 100644 (file)
@@ -1,6 +1,4 @@
 /*
-* $Id$
- *
  * ***** BEGIN GPL LICENSE BLOCK *****
  *
  * This program is free software; you can redistribute it and/or
 #include "BKE_sequencer.h"
 #include "BKE_fcurve.h"
 #include "BKE_scene.h"
-#include "RNA_access.h"
 #include "BKE_utildefines.h"
 
+#include "RNA_access.h"
+
 #include "RE_pipeline.h"
 
 #include <pthread.h>
 
 #include "BKE_context.h"
 #include "BKE_sound.h"
-#include "AUD_C-API.h"
 
-#ifdef WIN32
-#define snprintf _snprintf
+#ifdef WITH_AUDASPACE
+#  include "AUD_C-API.h"
 #endif
 
-/* **** XXX ******** */
-//static void waitcursor(int val) {}
-//static int blender_test_break() {return 0;}
+static ImBuf* seq_render_strip_stack( 
+       SeqRenderData context, ListBase *seqbasep, float cfra, int chanshown);
+
+static ImBuf * seq_render_strip(
+       SeqRenderData context, Sequence * seq, float cfra);
+
+static void seq_free_animdata(Scene *scene, Sequence *seq);
+
 
 /* **** XXX ******** */
 #define SELECT 1
@@ -177,8 +180,6 @@ void seq_free_strip(Strip *strip)
        MEM_freeN(strip);
 }
 
-static void seq_free_animdata(Scene *scene, Sequence *seq);
-
 void seq_free_sequence(Scene *scene, Sequence *seq)
 {
        if(seq->strip) seq_free_strip(seq->strip);
@@ -191,6 +192,10 @@ void seq_free_sequence(Scene *scene, Sequence *seq)
                sh.free(seq);
        }
 
+       if(seq->sound) {
+               ((ID *)seq->sound)->us--; 
+       }
+
        /* clipboard has no scene and will never have a sound handle or be active */
        if(scene) {
                Editing *ed = scene->ed;
@@ -207,6 +212,18 @@ void seq_free_sequence(Scene *scene, Sequence *seq)
        MEM_freeN(seq);
 }
 
+void seq_free_sequence_recurse(Scene *scene, Sequence *seq)
+{
+       Sequence *iseq;
+
+       for(iseq= seq->seqbase.first; iseq; iseq= iseq->next) {
+               seq_free_sequence_recurse(scene, iseq);
+       }
+
+       seq_free_sequence(scene, seq);
+}
+
+
 Editing *seq_give_editing(Scene *scene, int alloc)
 {
        if (scene->ed == NULL && alloc) {
@@ -446,51 +463,6 @@ void seq_end(SeqIterator *iter)
   * in metastrips!)
   **********************************************************************
 */
-#if 0 /* UNUSED */
-static void do_seq_count(ListBase *seqbase, int *totseq)
-{
-       Sequence *seq;
-
-       seq= seqbase->first;
-       while(seq) {
-               (*totseq)++;
-               if(seq->seqbase.first) do_seq_count(&seq->seqbase, totseq);
-               seq= seq->next;
-       }
-}
-
-static void do_build_seqar(ListBase *seqbase, Sequence ***seqar, int depth)
-{
-       Sequence *seq;
-
-       seq= seqbase->first;
-       while(seq) {
-               seq->depth= depth;
-               if(seq->seqbase.first) do_build_seqar(&seq->seqbase, seqar, depth+1);
-               **seqar= seq;
-               (*seqar)++;
-               seq= seq->next;
-       }
-}
-
-static void build_seqar(ListBase *seqbase, Sequence  ***seqar, int *totseq)
-{
-       Sequence **tseqar;
-
-       *totseq= 0;
-       do_seq_count(seqbase, totseq);
-
-       if(*totseq==0) {
-               *seqar= NULL;
-               return;
-       }
-       *seqar= MEM_mallocN(sizeof(void *)* *totseq, "seqar");
-       tseqar= *seqar;
-
-       do_build_seqar(seqbase, seqar, 0);
-       *seqar= tseqar;
-}
-#endif /* UNUSED */
 
 static void do_seq_count_cb(ListBase *seqbase, int *totseq,
                                int (*test_func)(Sequence * seq))
@@ -567,7 +539,7 @@ void calc_sequence_disp(Scene *scene, Sequence *seq)
                seq->handsize= (float)((seq->enddisp-seq->startdisp)/25);
        }
 
-       seq_update_sound(scene, seq);
+       seq_update_sound_bounds(scene, seq);
 }
 
 static void seq_update_sound_bounds_recursive(Scene *scene, Sequence *metaseq)
@@ -624,8 +596,22 @@ void calc_sequence(Scene *scene, Sequence *seq)
                if (seq->seq1) {
                        seq->start= seq->startdisp= MAX3(seq->seq1->startdisp, seq->seq2->startdisp, seq->seq3->startdisp);
                        seq->enddisp= MIN3(seq->seq1->enddisp, seq->seq2->enddisp, seq->seq3->enddisp);
+                       /* we cant help if strips don't overlap, it wont give useful results.
+                        * but at least ensure 'len' is never negative which causes bad bugs elsewhere. */
+                       if(seq->enddisp < seq->startdisp) {
+                               /* simple start/end swap */
+                               seq->start= seq->enddisp;
+                               seq->enddisp = seq->startdisp;
+                               seq->startdisp= seq->start;
+                               seq->flag |= SEQ_INVALID_EFFECT;
+                       }
+                       else {
+                               seq->flag &= ~SEQ_INVALID_EFFECT;
+                       }
+
                        seq->len= seq->enddisp - seq->startdisp;
-               } else {
+               }
+               else {
                        calc_sequence_disp(scene, seq);
                }
 
@@ -703,13 +689,16 @@ void reload_sequence_new_file(Scene *scene, Sequence * seq, int lock_range)
        }
        case SEQ_MOVIE:
                if(seq->anim) IMB_free_anim(seq->anim);
-               seq->anim = openanim(str, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0));
+               seq->anim = openanim(str, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0), seq->streamindex);
 
                if (!seq->anim) {
                        return;
                }
        
-               seq->len = IMB_anim_get_duration(seq->anim);
+               seq->len = IMB_anim_get_duration(seq->anim,
+                                                seq->strip->proxy ?
+                                                seq->strip->proxy->tc :
+                                                IMB_TC_RECORD_RUN);
                
                seq->anim_preseek = IMB_anim_get_preseek(seq->anim);
 
@@ -719,7 +708,9 @@ void reload_sequence_new_file(Scene *scene, Sequence * seq, int lock_range)
                        seq->len = 0;
                }
                seq->strip->len = seq->len;
+               break;
        case SEQ_SOUND:
+#ifdef WITH_AUDASPACE
                if(!seq->sound)
                        return;
                seq->len = ceil(AUD_getInfo(seq->sound->playback_handle).length * FPS);
@@ -729,6 +720,9 @@ void reload_sequence_new_file(Scene *scene, Sequence * seq, int lock_range)
                        seq->len = 0;
                }
                seq->strip->len = seq->len;
+#else
+               return;
+#endif
                break;
        case SEQ_SCENE:
        {
@@ -871,8 +865,8 @@ void seqbase_unique_name_recursive(ListBase *seqbasep, struct Sequence *seq)
        SeqUniqueInfo sui;
        char *dot;
        sui.seq= seq;
-       strcpy(sui.name_src, seq->name+2);
-       strcpy(sui.name_dest, seq->name+2);
+       BLI_strncpy(sui.name_src, seq->name+2, sizeof(sui.name_src));
+       BLI_strncpy(sui.name_dest, seq->name+2, sizeof(sui.name_dest));
 
        sui.count= 1;
        sui.match= 1; /* assume the worst to start the loop */
@@ -892,7 +886,7 @@ void seqbase_unique_name_recursive(ListBase *seqbasep, struct Sequence *seq)
                seqbase_recursive_apply(seqbasep, seqbase_unique_name_recursive_cb, &sui);
        }
 
-       strcpy(seq->name+2, sui.name_dest);
+       BLI_strncpy(seq->name+2, sui.name_dest, sizeof(seq->name)-2);
 }
 
 static const char *give_seqname_by_type(int type)
@@ -916,6 +910,7 @@ static const char *give_seqname_by_type(int type)
        case SEQ_TRANSFORM:  return "Transform";
        case SEQ_COLOR:      return "Color";
        case SEQ_MULTICAM:   return "Multicam";
+       case SEQ_ADJUSTMENT: return "Adjustment";
        case SEQ_SPEED:      return "Speed";
        default:
                return NULL;
@@ -1013,16 +1008,22 @@ static float give_stripelem_index(Sequence *seq, float cfra)
        int sta = seq->start;
        int end = seq->start+seq->len-1;
 
-       if(seq->len == 0) return -1;
+       if (seq->type & SEQ_EFFECT) {
+               end = seq->enddisp;
+       } 
+
+       if(end < sta) {
+               return -1;
+       }
 
        if(seq->flag&SEQ_REVERSE_FRAMES) {      
                /*reverse frame in this sequence */
-               if(cfra <= sta) nr= seq->len-1;
+               if(cfra <= sta) nr= end - sta;
                else if(cfra >= end) nr= 0;
                else nr= end - cfra;
        } else {
                if(cfra <= sta) nr= 0;
-               else if(cfra >= end) nr= seq->len-1;
+               else if(cfra >= end) nr= end - sta;
                else nr= cfra - sta;
        }
        
@@ -1039,7 +1040,11 @@ StripElem *give_stripelem(Sequence *seq, int cfra)
 {
        StripElem *se= seq->strip->stripdata;
 
-       if(seq->type != SEQ_MOVIE) { /* movie use the first */
+       if(seq->type == SEQ_IMAGE) { /* only 
+                                       IMAGE strips use the whole array,
+                                       MOVIE strips use only 
+                                       the first element, all other strips
+                                       don't use this... */
                int nr = (int) give_stripelem_index(seq, cfra);
 
                if (nr == -1 || se == NULL) return NULL;
@@ -1093,15 +1098,12 @@ static int get_shown_sequences( ListBase * seqbasep, int cfra, int chanshown, Se
        }
 
        if(evaluate_seq_frame_gen(seq_arr, seqbasep, cfra)) {
-               if (b > 0) {
-                       if (seq_arr[b] == NULL) {
-                               return 0;
-                       }
-               } else {
-                       for (b = MAXSEQ; b > 0; b--) {
-                               if (video_seq_is_rendered(seq_arr[b])) {
-                                       break;
-                               }
+               if (b == 0) {
+                       b = MAXSEQ;
+               }
+               for (; b > 0; b--) {
+                       if (video_seq_is_rendered(seq_arr[b])) {
+                               break;
                        }
                }
        }
@@ -1124,7 +1126,7 @@ static int get_shown_sequences(   ListBase * seqbasep, int cfra, int chanshown, Se
 
        return cnt;
 }
+
 
 /* **********************************************************************
    proxy management
@@ -1132,49 +1134,106 @@ static int get_shown_sequences(        ListBase * seqbasep, int cfra, int chanshown, Se
 
 #define PROXY_MAXFILE (2*FILE_MAXDIR+FILE_MAXFILE)
 
+static IMB_Proxy_Size seq_rendersize_to_proxysize(int size)
+{
+       if (size >= 100) {
+               return IMB_PROXY_NONE;
+       }
+       if (size >= 99) {
+               return IMB_PROXY_100;
+       }
+       if (size >= 75) {
+               return IMB_PROXY_75;
+       }
+       if (size >= 50) {
+               return IMB_PROXY_50;
+       }
+       return IMB_PROXY_25;
+}
+
+static void seq_open_anim_file(Sequence * seq)
+{
+       char name[FILE_MAXDIR+FILE_MAXFILE];
+       StripProxy * proxy;
+
+       if(seq->anim != NULL) {
+               return;
+       }
+
+       BLI_join_dirfile(name, sizeof(name), 
+                        seq->strip->dir, seq->strip->stripdata->name);
+       BLI_path_abs(name, G.main->name);
+       
+       seq->anim = openanim(name, IB_rect |
+                            ((seq->flag & SEQ_FILTERY) ? 
+                             IB_animdeinterlace : 0), seq->streamindex);
+
+       if (seq->anim == NULL) {
+               return;
+       }
+
+       proxy = seq->strip->proxy;
+
+       if (proxy == NULL) {
+               return;
+       }
+
+       if (seq->flag & SEQ_USE_PROXY_CUSTOM_DIR) {
+               IMB_anim_set_index_dir(seq->anim, seq->strip->proxy->dir);
+       }
+}
+
+
 static int seq_proxy_get_fname(SeqRenderData context, Sequence * seq, int cfra, char * name)
 {
        int frameno;
-       char dir[FILE_MAXDIR];
+       char dir[PROXY_MAXFILE];
+       int render_size = context.preview_render_size;
 
        if (!seq->strip->proxy) {
                return FALSE;
        }
 
+       /* MOVIE tracks (only exception: custom files) are now handled 
+          internally by ImBuf module for various reasons: proper time code 
+          support, quicker index build, using one file instead 
+          of a full directory of jpeg files, etc. Trying to support old
+          and new method at once could lead to funny effects, if people
+          have both, a directory full of jpeg files and proxy avis, so
+          sorry folks, please rebuild your proxies... */
+
        if (seq->flag & (SEQ_USE_PROXY_CUSTOM_DIR|SEQ_USE_PROXY_CUSTOM_FILE)) {
-               strcpy(dir, seq->strip->proxy->dir);
+               BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir));
+       } else if (seq->type == SEQ_IMAGE) {
+               BLI_snprintf(dir, PROXY_MAXFILE, "%s/BL_proxy", seq->strip->dir);
        } else {
-               if (ELEM(seq->type, SEQ_IMAGE, SEQ_MOVIE)) {
-                       snprintf(dir, FILE_MAXDIR, "%s/BL_proxy", seq->strip->dir);
-               } else {
-                       return FALSE;
-               }
+               return FALSE;
        }
 
        if (seq->flag & SEQ_USE_PROXY_CUSTOM_FILE) {
-               BLI_join_dirfile(name, FILE_MAX, dir, seq->strip->proxy->file); /* XXX, not real length */
+               BLI_join_dirfile(name, PROXY_MAXFILE, 
+                                dir, seq->strip->proxy->file);
                BLI_path_abs(name, G.main->name);
 
                return TRUE;
        }
 
+       /* dirty hack to distinguish 100% render size from PROXY_100 */
+       if (render_size == 99) {
+               render_size = 100;
+       }
+
        /* generate a separate proxy directory for each preview size */
 
-       switch(seq->type) {
-       case SEQ_IMAGE:
-               snprintf(name, PROXY_MAXFILE, "%s/images/%d/%s_proxy", dir,
+       if (seq->type == SEQ_IMAGE) {
+               BLI_snprintf(name, PROXY_MAXFILE, "%s/images/%d/%s_proxy", dir,
                         context.preview_render_size, 
                         give_stripelem(seq, cfra)->name);
                frameno = 1;
-               break;
-       case SEQ_MOVIE:
-               frameno = (int) give_stripelem_index(seq, cfra) + seq->anim_startofs;
-               snprintf(name, PROXY_MAXFILE, "%s/%s/%d/####", dir,
-                        seq->strip->stripdata->name, context.preview_render_size);
-               break;
-       default:
-               frameno = (int) give_stripelem_index(seq, cfra) + seq->anim_startofs;
-               snprintf(name, PROXY_MAXFILE, "%s/proxy_misc/%d/####", dir, 
+       } else {
+               frameno = (int) give_stripelem_index(seq, cfra) 
+                       + seq->anim_startofs;
+               BLI_snprintf(name, PROXY_MAXFILE, "%s/proxy_misc/%d/####", dir, 
                         context.preview_render_size);
        }
 
@@ -1189,13 +1248,18 @@ static int seq_proxy_get_fname(SeqRenderData context, Sequence * seq, int cfra,
 static struct ImBuf * seq_proxy_fetch(SeqRenderData context, Sequence * seq, int cfra)
 {
        char name[PROXY_MAXFILE];
+       IMB_Proxy_Size psize = seq_rendersize_to_proxysize(
+               context.preview_render_size);
+       int size_flags;
 
        if (!(seq->flag & SEQ_USE_PROXY)) {
                return NULL;
        }
 
-       /* rendering at 100% ? No real sense in proxy-ing, right? */
-       if (context.preview_render_size == 100) {
+       size_flags = seq->strip->proxy->build_size_flags;
+
+       /* only use proxies, if they are enabled (even if present!) */
+       if (psize == IMB_PROXY_NONE || ((size_flags & psize) != psize)) {
                return NULL;
        }
 
@@ -1206,13 +1270,19 @@ static struct ImBuf * seq_proxy_fetch(SeqRenderData context, Sequence * seq, int
                                return NULL;
                        }
  
-                       seq->strip->proxy->anim = openanim(name, IB_rect);
+                       seq->strip->proxy->anim = openanim(name, IB_rect, 0);
                }
                if (seq->strip->proxy->anim==NULL) {
                        return NULL;
                }
  
-               return IMB_anim_absolute(seq->strip->proxy->anim, frameno);
+               seq_open_anim_file(seq);
+
+               frameno = IMB_anim_index_get_frame_index(
+                       seq->anim, seq->strip->proxy->tc, frameno);
+
+               return IMB_anim_absolute(seq->strip->proxy->anim, frameno,
+                                        IMB_TC_NONE, IMB_PROXY_NONE);
        }
  
        if (seq_proxy_get_fname(context, seq, cfra, name) == 0) {
@@ -1226,71 +1296,38 @@ static struct ImBuf * seq_proxy_fetch(SeqRenderData context, Sequence * seq, int
        }
 }
 
-#if 0
-static void do_build_seq_ibuf(Scene *scene, Sequence * seq, TStripElem *se, int cfra,
-                                 int build_proxy_run, int preview_render_size);
-
-static void seq_proxy_build_frame(Scene *scene, Sequence * seq, int cfra, int preview_render_size, int seqrectx, int seqrecty)
+static void seq_proxy_build_frame(SeqRenderData context,
+                                 Sequence* seq, int cfra,
+                                 int proxy_render_size)
 {
        char name[PROXY_MAXFILE];
        int quality;
-       TStripElem * se;
-       int ok;
        int rectx, recty;
+       int ok;
        struct ImBuf * ibuf;
 
-       if (!(seq->flag & SEQ_USE_PROXY)) {
-               return;
-       }
-
-       /* rendering at 100% ? No real sense in proxy-ing, right? */
-       if (preview_render_size == 100) {
+       if (!seq_proxy_get_fname(context, seq, cfra, name)) {
                return;
        }
 
-       /* that's why it is called custom... */
-       if (seq->flag & SEQ_USE_PROXY_CUSTOM_FILE) {
-               return;
-       }
+       ibuf = seq_render_strip(context, seq, cfra);
 
-       if (!seq_proxy_get_fname(scene, seq, cfra, name, preview_render_size)) {
-               return;
-       }
-
-       se = give_tstripelem(seq, cfra);
-       if (!se) {
-               return;
-       }
-
-       if(se->ibuf) {
-               IMB_freeImBuf(se->ibuf);
-               se->ibuf = 0;
-       }
-       
-       do_build_seq_ibuf(scene, seq, se, cfra, TRUE, preview_render_size,
-                         seqrectx, seqrecty);
-
-       if (!se->ibuf) {
-               return;
-       }
-
-       rectx= (preview_render_size*scene->r.xsch)/100;
-       recty= (preview_render_size*scene->r.ysch)/100;
-
-       ibuf = se->ibuf;
+       rectx = (proxy_render_size * context.scene->r.xsch) / 100;
+       recty = (proxy_render_size * context.scene->r.ysch) / 100;
 
        if (ibuf->x != rectx || ibuf->y != recty) {
                IMB_scalefastImBuf(ibuf, (short)rectx, (short)recty);
        }
 
-       /* quality is fixed, otherwise one has to generate separate
-          directories for every quality...
-
-          depth = 32 is intentionally left in, otherwise ALPHA channels
+       /* depth = 32 is intentionally left in, otherwise ALPHA channels
           won't work... */
        quality = seq->strip->proxy->quality;
        ibuf->ftype= JPG | quality;
 
+       /* unsupported feature only confuses other s/w */
+       if(ibuf->depth==32)
+               ibuf->depth= 24;
+
        BLI_make_existing_file(name);
        
        ok = IMB_saveiff(ibuf, name, IB_rect | IB_zbuf | IB_zbuffloat);
@@ -1299,69 +1336,80 @@ static void seq_proxy_build_frame(Scene *scene, Sequence * seq, int cfra, int pr
        }
 
        IMB_freeImBuf(ibuf);
-       se->ibuf = 0;
 }
 
-static void seq_proxy_rebuild(Scene *scene, Sequence * seq, int seqrectx,
-                             int seqrecty)
+void seq_proxy_rebuild(struct Main * bmain, Scene *scene, Sequence * seq,
+                      short *stop, short *do_update, float *progress)
 {
+       SeqRenderData context;
        int cfra;
-       float rsize = seq->strip->proxy->size;
+       int tc_flags;
+       int size_flags;
+       int quality;
 
-       waitcursor(1);
+       if (!seq->strip || !seq->strip->proxy) {
+               return;
+       }
 
-       G.afbreek = 0;
+       if (!(seq->flag & SEQ_USE_PROXY)) {
+               return;
+       }
 
-       /* 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.
-        */
+       tc_flags   = seq->strip->proxy->build_tc_flags;
+       size_flags = seq->strip->proxy->build_size_flags;
+       quality    = seq->strip->proxy->quality;
 
-       for (cfra = seq->startdisp; cfra < seq->enddisp; cfra++) {
-               TStripElem * tse = give_tstripelem(seq, cfra);
+       if (seq->type == SEQ_MOVIE) {
+               seq_open_anim_file(seq);
 
-               tse->flag &= ~STRIPELEM_PREVIEW_DONE;
+               if (seq->anim) {
+                       IMB_anim_index_rebuild(
+                               seq->anim, tc_flags, size_flags, quality,
+                               stop, do_update, progress);
+               }
+               return;
        }
 
-       
+       if (!(seq->flag & SEQ_USE_PROXY)) {
+               return;
+       }
 
-       /* 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)) {
-//XXX                          set_timecursor(cfra);
-                               seq_proxy_build_frame(scene, seq, cfra, rsize,
-                                                     seqrectx, seqrecty);
-                               tse->flag |= STRIPELEM_PREVIEW_DONE;
-                       }
-                       if (blender_test_break()) {
-                               break;
-                       }
+       /* that's why it is called custom... */
+       if (seq->flag & SEQ_USE_PROXY_CUSTOM_FILE) {
+               return;
+       }
+
+       /* fail safe code */
+
+       context = seq_new_render_data(
+               bmain, scene, 
+               (scene->r.size * (float) scene->r.xsch) / 100.0f + 0.5f, 
+               (scene->r.size * (float) scene->r.ysch) / 100.0f + 0.5f, 
+               100);
+
+       for (cfra = seq->startdisp + seq->startstill; 
+            cfra < seq->enddisp - seq->endstill; cfra++) {
+               if (size_flags & IMB_PROXY_25) {
+                       seq_proxy_build_frame(context, seq, cfra, 25);
                }
-       } 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)) {
-//XXX                          set_timecursor(cfra);
-                               seq_proxy_build_frame(scene, seq, cfra, rsize,
-                                                     seqrectx, seqrecty);
-                               tse->flag |= STRIPELEM_PREVIEW_DONE;
-                       }
-                       if (blender_test_break()) {
-                               break;
-                       }
+               if (size_flags & IMB_PROXY_50) {
+                       seq_proxy_build_frame(context, seq, cfra, 50);
                }
+               if (size_flags & IMB_PROXY_75) {
+                       seq_proxy_build_frame(context, seq, cfra, 75);
+               }
+               if (size_flags & IMB_PROXY_100) {
+                       seq_proxy_build_frame(context, seq, cfra, 100);
+               }
+
+               *progress= (float)cfra/(seq->enddisp - seq->endstill 
+                                       - seq->startdisp + seq->startstill);
+               *do_update= 1;
+
+               if(*stop || G.afbreek)
+                       break;
        }
-       waitcursor(0);
 }
-#endif
 
 
 /* **********************************************************************
@@ -1578,6 +1626,8 @@ static ImBuf * input_preprocess(
 {
        float mul;
 
+       ibuf = IMB_makeSingleUser(ibuf);
+
        if((seq->flag & SEQ_FILTERY) && seq->type != SEQ_MOVIE) {
                IMB_filtery(ibuf);
        }
@@ -1782,7 +1832,7 @@ static ImBuf* seq_render_effect_strip_impl(
                        facf= fac;
        }
        else {
-               fcu = id_data_find_fcurve(&context.scene->id, seq, &RNA_Sequence, "effect_fader", 0);
+               fcu = id_data_find_fcurve(&context.scene->id, seq, &RNA_Sequence, "effect_fader", 0, NULL);
                if (fcu) {
                        fac = facf = evaluate_fcurve(fcu, cfra);
                        if( context.scene->r.mode & R_FIELDS ) {
@@ -1858,7 +1908,7 @@ static ImBuf * seq_render_scene_strip_impl(
        ImBuf * ibuf = NULL;
        float frame= seq->sfra + nr + seq->anim_startofs;
        float oldcfra;
-       Object *oldcamera;
+       Object *camera;
        ListBase oldmarkers;
        
        /* Old info:
@@ -1896,59 +1946,65 @@ static ImBuf * seq_render_scene_strip_impl(
        int doseq;
        int doseq_gl= G.rendering ? /*(scene->r.seq_flag & R_SEQ_GL_REND)*/ 0 : /*(scene->r.seq_flag & R_SEQ_GL_PREV)*/ 1;
        int have_seq= FALSE;
-       Scene *sce= seq->scene; /* dont refer to seq->scene above this point!, it can be NULL */
-       int sce_valid= FALSE;
+       Scene *scene;
 
-       if(sce) {
-               have_seq= (sce->r.scemode & R_DOSEQ) && sce->ed && sce->ed->seqbase.first;
-               sce_valid= (sce->camera || have_seq);
+       /* dont refer to seq->scene above this point!, it can be NULL */
+       if(seq->scene == NULL) {
+               return NULL;
        }
 
-       if (!sce_valid)
-               return NULL;
+       scene= seq->scene;
+
+       have_seq= (scene->r.scemode & R_DOSEQ) && scene->ed && scene->ed->seqbase.first;
+
+       oldcfra= scene->r.cfra; 
+       scene->r.cfra= frame;
+
+       if(seq->scene_camera)   
+               camera= seq->scene_camera;
+       else {  
+               scene_camera_switch_update(scene);
+               camera= scene->camera;
+       }
 
-       oldcfra= seq->scene->r.cfra;
-       oldcamera= seq->scene->camera;
+       if(have_seq==FALSE && camera==NULL) {
+               scene->r.cfra= oldcfra;
+               return NULL;
+       }
 
        /* prevent eternal loop */
        doseq= context.scene->r.scemode & R_DOSEQ;
        context.scene->r.scemode &= ~R_DOSEQ;
        
-       seq->scene->r.cfra= frame;
-       if(seq->scene_camera)   
-               seq->scene->camera= seq->scene_camera;
-       else    
-               scene_camera_switch_update(seq->scene);
-       
 #ifdef DURIAN_CAMERA_SWITCH
        /* stooping to new low's in hackyness :( */
-       oldmarkers= seq->scene->markers;
-       seq->scene->markers.first= seq->scene->markers.last= NULL;
+       oldmarkers= scene->markers;
+       scene->markers.first= scene->markers.last= NULL;
 #endif
        
-       if(sequencer_view3d_cb && BLI_thread_is_main() && doseq_gl && (seq->scene == context.scene || have_seq==0) && seq->scene->camera) {
+       if(sequencer_view3d_cb && BLI_thread_is_main() && doseq_gl && (scene == context.scene || have_seq==0) && camera) {
                char err_out[256]= "unknown";
                /* for old scened this can be uninitialized, should probably be added to do_versions at some point if the functionality stays */
                if(context.scene->r.seq_prev_type==0)
                        context.scene->r.seq_prev_type = 3 /* ==OB_SOLID */; 
 
                /* opengl offscreen render */
-               scene_update_for_newframe(context.bmain, seq->scene, seq->scene->lay);
-               ibuf= sequencer_view3d_cb(seq->scene, context.rectx, context.recty, IB_rect, context.scene->r.seq_prev_type, err_out);
+               scene_update_for_newframe(context.bmain, scene, scene->lay);
+               ibuf= sequencer_view3d_cb(scene, camera, context.rectx, context.recty, IB_rect, context.scene->r.seq_prev_type, err_out);
                if(ibuf == NULL) {
                        fprintf(stderr, "seq_render_scene_strip_impl failed to get opengl buffer: %s\n", err_out);
                }
        }
        else {
-               Render *re = RE_GetRender(sce->id.name);
+               Render *re = RE_GetRender(scene->id.name);
                RenderResult rres;
 
                /* XXX: this if can be removed when sequence preview rendering uses the job system */
-               if(rendering || context.scene != sce) {
+               if(rendering || context.scene != scene) {
                        if(re==NULL)
-                               re= RE_NewRender(sce->id.name);
+                               re= RE_NewRender(scene->id.name);
                        
-                       RE_BlenderFrame(re, context.bmain, sce, NULL, NULL, sce->lay, frame, FALSE);
+                       RE_BlenderFrame(re, context.bmain, scene, NULL, camera, scene->lay, frame, FALSE);
 
                        /* restore previous state after it was toggled on & off by RE_BlenderFrame */
                        G.rendering = rendering;
@@ -1981,14 +2037,14 @@ static ImBuf * seq_render_scene_strip_impl(
        /* restore */
        context.scene->r.scemode |= doseq;
        
-       seq->scene->r.cfra = oldcfra;
-       seq->scene->camera= oldcamera;
+       scene->r.cfra = oldcfra;
+
        if(frame != oldcfra)
-               scene_update_for_newframe(context.bmain, seq->scene, seq->scene->lay);
+               scene_update_for_newframe(context.bmain, scene, scene->lay);
        
 #ifdef DURIAN_CAMERA_SWITCH
        /* stooping to new low's in hackyness :( */
-       seq->scene->markers= oldmarkers;
+       scene->markers= oldmarkers;
 #endif
 
        return ibuf;
@@ -2065,8 +2121,9 @@ static ImBuf * seq_render_strip(SeqRenderData context, Sequence * seq, float cfr
                        break;
                }
                case SEQ_EFFECT:
-               {       
-                       ibuf = seq_render_effect_strip_impl(context, seq, cfra);
+               {
+                       ibuf = seq_render_effect_strip_impl(
+                               context, seq, seq->start + nr);
                        break;
                }
                case SEQ_IMAGE:
@@ -2096,17 +2153,20 @@ static ImBuf * seq_render_strip(SeqRenderData context, Sequence * seq, float cfr
                }
                case SEQ_MOVIE:
                {
-                       if(seq->anim==NULL) {
-                               BLI_join_dirfile(name, sizeof(name), seq->strip->dir, seq->strip->stripdata->name);
-                               BLI_path_abs(name, G.main->name);
-                                       
-                               seq->anim = openanim(name, IB_rect |
-                                                    ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0));
-                       }
+                       seq_open_anim_file(seq);
 
                        if(seq->anim) {
-                               IMB_anim_set_preseek(seq->anim, seq->anim_preseek);
-                               ibuf = IMB_anim_absolute(seq->anim, nr + seq->anim_startofs);
+                               IMB_anim_set_preseek(seq->anim,
+                                                    seq->anim_preseek);
+
+                               ibuf = IMB_anim_absolute(
+                                       seq->anim, nr + seq->anim_startofs, 
+                                       seq->strip->proxy ? 
+                                       seq->strip->proxy->tc
+                                       : IMB_TC_RECORD_RUN, 
+                                       seq_rendersize_to_proxysize(
+                                               context.preview_render_size));
+
                                /* we don't need both (speed reasons)! */
                                if (ibuf && ibuf->rect_float && ibuf->rect)
                                        imb_freerectImBuf(ibuf);
@@ -2123,7 +2183,7 @@ static ImBuf * seq_render_strip(SeqRenderData context, Sequence * seq, float cfr
                        ibuf = seq_render_scene_strip_impl(context, seq, nr);
 
                        /* Scene strips update all animation, so we need to restore original state.*/
-                       BKE_animsys_evaluate_all_animation(context.bmain, cfra);
+                       BKE_animsys_evaluate_all_animation(context.bmain, context.scene, cfra);
 
                        copy_to_ibuf_still(context, seq, nr, ibuf);
                        break;
@@ -2200,7 +2260,7 @@ static ImBuf* seq_render_strip_stack(
        if(scene->r.cfra != cfra) {
                // XXX for prefetch and overlay offset!..., very bad!!!
                AnimData *adt= BKE_animdata_from_id(&scene->id);
-               BKE_animsys_evaluate_animdata(&scene->id, adt, cfra, ADT_RECALC_ANIM);
+               BKE_animsys_evaluate_animdata(scene, &scene->id, adt, cfra, ADT_RECALC_ANIM);
        }
 #endif
 
@@ -2795,7 +2855,8 @@ void update_changed_seq_and_deps(Scene *scene, Sequence *changed_seq, int len_ch
  left and right are the bounds at which the sequence is rendered,
 start and end are from the start and fixed length of the sequence.
 */
-int seq_tx_get_start(Sequence *seq) {
+int seq_tx_get_start(Sequence *seq)
+{
        return seq->start;
 }
 int seq_tx_get_end(Sequence *seq)
@@ -2849,7 +2910,10 @@ void seq_tx_set_final_right(Sequence *seq, int val)
    since they work a bit differently to normal image seq's (during transform) */
 int seq_single_check(Sequence *seq)
 {
-       return (seq->len==1 && ELEM3(seq->type, SEQ_IMAGE, SEQ_COLOR, SEQ_MULTICAM));
+       return (seq->len==1 && (
+                       seq->type == SEQ_IMAGE 
+                       || ((seq->type & SEQ_EFFECT) && 
+                           get_sequence_effect_num_inputs(seq->type) == 0)));
 }
 
 /* check if the selected seq's reference unselected seq's */
@@ -3142,16 +3206,33 @@ int shuffle_seq_time(ListBase * seqbasep, Scene *evil_scene)
        return offset? 0:1;
 }
 
-void seq_update_sound(Scene* scene, Sequence *seq)
+void seq_update_sound_bounds_all(Scene *scene)
 {
-       if(seq->scene_sound)
-       {
+       Editing *ed = scene->ed;
+
+       if(ed) {
+               Sequence *seq;
+
+               for(seq = ed->seqbase.first; seq; seq = seq->next) {
+                       if(seq->type == SEQ_META) {
+                               seq_update_sound_bounds_recursive(scene, seq);
+                       }
+                       else if(ELEM(seq->type, SEQ_SOUND, SEQ_SCENE)) {
+                               seq_update_sound_bounds(scene, seq);
+                       }
+               }
+       }
+}
+
+void seq_update_sound_bounds(Scene* scene, Sequence *seq)
+{
+       if(seq->scene_sound) {
                sound_move_scene_sound(scene, seq->scene_sound, seq->startdisp, seq->enddisp, seq->startofs + seq->anim_startofs);
                /* mute is set in seq_update_muting_recursive */
        }
 }
 
-static void seq_update_muting_recursive(Scene *scene, ListBase *seqbasep, Sequence *metaseq, int mute)
+static void seq_update_muting_recursive(ListBase *seqbasep, Sequence *metaseq, int mute)
 {
        Sequence *seq;
        int seqmute;
@@ -3167,26 +3248,49 @@ static void seq_update_muting_recursive(Scene *scene, ListBase *seqbasep, Sequen
                        if(seq == metaseq)
                                seqmute= 0;
 
-                       seq_update_muting_recursive(scene, &seq->seqbase, metaseq, seqmute);
+                       seq_update_muting_recursive(&seq->seqbase, metaseq, seqmute);
                }
                else if(ELEM(seq->type, SEQ_SOUND, SEQ_SCENE)) {
                        if(seq->scene_sound) {
-                               sound_mute_scene_sound(scene, seq->scene_sound, seqmute);
+                               sound_mute_scene_sound(seq->scene_sound, seqmute);
                        }
                }
        }
 }
 
-void seq_update_muting(Scene *scene, Editing *ed)
+void seq_update_muting(Editing *ed)
 {
        if(ed) {
                /* mute all sounds up to current metastack list */
                MetaStack *ms= ed->metastack.last;
 
                if(ms)
-                       seq_update_muting_recursive(scene, &ed->seqbase, ms->parseq, 1);
+                       seq_update_muting_recursive(&ed->seqbase, ms->parseq, 1);
                else
-                       seq_update_muting_recursive(scene, &ed->seqbase, NULL, 0);
+                       seq_update_muting_recursive(&ed->seqbase, NULL, 0);
+       }
+}
+
+static void seq_update_sound_recursive(Scene *scene, ListBase *seqbasep, bSound *sound)
+{
+       Sequence *seq;
+
+       for(seq=seqbasep->first; seq; seq=seq->next) {
+               if(seq->type == SEQ_META) {
+                       seq_update_sound_recursive(scene, &seq->seqbase, sound);
+               }
+               else if(seq->type == SEQ_SOUND) {
+                       if(seq->scene_sound && sound == seq->sound) {
+                               sound_update_scene_sound(seq->scene_sound, sound);
+                       }
+               }
+       }
+}
+
+void seq_update_sound(struct Scene *scene, struct bSound *sound)
+{
+       if(scene->ed) {
+               seq_update_sound_recursive(scene, &scene->ed->seqbase, sound);
        }
 }
 
@@ -3208,26 +3312,49 @@ ListBase *seq_seqbase(ListBase *seqbase, Sequence *seq)
        return NULL;
 }
 
-int seq_swap(Sequence *seq_a, Sequence *seq_b)
+Sequence *seq_metastrip(ListBase * seqbase, Sequence * meta, Sequence *seq)
+{
+       Sequence * iseq;
+
+       for(iseq = seqbase->first; iseq; iseq = iseq->next) {
+               Sequence * rval;
+
+               if (seq == iseq) {
+                       return meta;
+               } else if(iseq->seqbase.first && 
+                       (rval = seq_metastrip(&iseq->seqbase, iseq, seq))) {
+                       return rval;
+               }
+       }
+
+       return NULL;
+}
+
+int seq_swap(Sequence *seq_a, Sequence *seq_b, const char **error_str)
 {
        char name[sizeof(seq_a->name)];
 
-       if(seq_a->len != seq_b->len)
+       if(seq_a->len != seq_b->len) {
+               *error_str= "Strips must be the same length";
                return 0;
+       }
 
        /* type checking, could be more advanced but disalow sound vs non-sound copy */
        if(seq_a->type != seq_b->type) {
                if(seq_a->type == SEQ_SOUND || seq_b->type == SEQ_SOUND) {
+                       *error_str= "Strips were not compatible";
                        return 0;
                }
 
                /* disallow effects to swap with non-effects strips */
                if((seq_a->type & SEQ_EFFECT) != (seq_b->type & SEQ_EFFECT)) {
+                       *error_str= "Strips were not compatible";
                        return 0;
                }
 
                if((seq_a->type & SEQ_EFFECT) && (seq_b->type & SEQ_EFFECT)) {
                        if(get_sequence_effect_num_inputs(seq_a->type) != get_sequence_effect_num_inputs(seq_b->type)) {
+                               *error_str= "Strips must have the same number of inputs";
                                return 0;
                        }
                }
@@ -3236,9 +3363,9 @@ int seq_swap(Sequence *seq_a, Sequence *seq_b)
        SWAP(Sequence, *seq_a, *seq_b);
 
        /* swap back names so animation fcurves dont get swapped */
-       strcpy(name, seq_a->name+2);
-       strcpy(seq_a->name+2, seq_b->name+2);
-       strcpy(seq_b->name+2, name);
+       BLI_strncpy(name, seq_a->name+2, sizeof(name));
+       BLI_strncpy(seq_a->name+2, seq_b->name+2, sizeof(seq_b->name)-2);
+       BLI_strncpy(seq_b->name+2, name, sizeof(seq_b->name)-2);
 
        /* swap back opacity, and overlay mode */
        SWAP(int, seq_a->blend_mode, seq_b->blend_mode);
@@ -3420,7 +3547,7 @@ void seq_load_apply(Scene *scene, Sequence *seq, SeqLoadInfo *seq_load)
 
                if(seq_load->flag & SEQ_LOAD_SOUND_CACHE) {
                        if(seq->sound)
-                               sound_cache(seq->sound, 0);
+                               sound_cache(seq->sound);
                }
 
                seq_load->tot_success++;
@@ -3447,6 +3574,7 @@ Sequence *alloc_sequence(ListBase *lb, int cfra, int machine)
        seq->mul= 1.0;
        seq->blend_opacity = 100.0;
        seq->volume = 1.0f;
+       seq->pitch = 1.0f;
        seq->scene_sound = NULL;
 
        return seq;
@@ -3476,8 +3604,10 @@ Sequence *sequencer_add_image_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo
        return seq;
 }
 
+#ifdef WITH_AUDASPACE
 Sequence *sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_load)
 {
+       Main *bmain= CTX_data_main(C);
        Scene *scene= CTX_data_scene(C); /* only for sound */
        Editing *ed= seq_give_editing(scene, TRUE);
        bSound *sound;
@@ -3499,7 +3629,7 @@ Sequence *sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo
        info = AUD_getInfo(sound->playback_handle);
 
        if (info.specs.channels == AUD_CHANNELS_INVALID) {
-               sound_delete(C, sound);
+               sound_delete(bmain, sound);
                //if(op)
                //      BKE_report(op->reports, RPT_ERROR, "Unsupported audio format");
                return NULL;
@@ -3517,21 +3647,31 @@ Sequence *sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo
        strip->len = seq->len = ceil(info.length * FPS);
        strip->us= 1;
 
-       strip->stripdata= se= MEM_callocN(seq->len*sizeof(StripElem), "stripelem");
+       /* we only need 1 element to store the filename */
+       strip->stripdata= se= MEM_callocN(sizeof(StripElem), "stripelem");
 
-       BLI_split_dirfile(seq_load->path, strip->dir, se->name);
+       BLI_split_dirfile(seq_load->path, strip->dir, se->name, sizeof(strip->dir), sizeof(se->name));
 
        seq->scene_sound = sound_add_scene_sound(scene, seq, seq_load->start_frame, seq_load->start_frame + strip->len, 0);
 
        calc_sequence_disp(scene, seq);
 
        /* last active name */
-       strncpy(ed->act_sounddir, strip->dir, FILE_MAXDIR-1);
+       BLI_strncpy(ed->act_sounddir, strip->dir, FILE_MAXDIR);
 
        seq_load_apply(scene, seq, seq_load);
 
        return seq;
 }
+#else // WITH_AUDASPACE
+Sequence *sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_load)
+{
+       (void)C;
+       (void)seqbasep;
+       (void)seq_load;
+       return NULL;
+}
+#endif // WITH_AUDASPACE
 
 Sequence *sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_load)
 {
@@ -3547,7 +3687,7 @@ Sequence *sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo
        BLI_strncpy(path, seq_load->path, sizeof(path));
        BLI_path_abs(path, G.main->name);
 
-       an = openanim(path, IB_rect);
+       an = openanim(path, IB_rect, 0);
 
        if(an==NULL)
                return NULL;
@@ -3563,12 +3703,13 @@ Sequence *sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo
 
        /* basic defaults */
        seq->strip= strip= MEM_callocN(sizeof(Strip), "strip");
-       strip->len = seq->len = IMB_anim_get_duration( an );
+       strip->len = seq->len = IMB_anim_get_duration( an, IMB_TC_RECORD_RUN );
        strip->us= 1;
 
-       strip->stripdata= se= MEM_callocN(seq->len*sizeof(StripElem), "stripelem");
+       /* we only need 1 element for MOVIE strips */
+       strip->stripdata= se= MEM_callocN(sizeof(StripElem), "stripelem");
 
-       BLI_split_dirfile(seq_load->path, strip->dir, se->name);
+       BLI_split_dirfile(seq_load->path, strip->dir, se->name, sizeof(strip->dir), sizeof(se->name));
 
        calc_sequence_disp(scene, seq);