Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel/intern/sequence.c')
-rw-r--r--source/blender/blenkernel/intern/sequence.c3295
1 files changed, 3295 insertions, 0 deletions
diff --git a/source/blender/blenkernel/intern/sequence.c b/source/blender/blenkernel/intern/sequence.c
new file mode 100644
index 00000000000..121dfce4980
--- /dev/null
+++ b/source/blender/blenkernel/intern/sequence.c
@@ -0,0 +1,3295 @@
+/**
+* $Id: sequence.c 17508 2008-11-20 00:34:24Z campbellbarton $
+ *
+ * ***** 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s):
+ * - Blender Foundation, 2003-2009
+ * - Peter Schlaile <peter [at] schlaile [dot] de> 2005/2006
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+#include "DNA_sequence_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_global.h"
+#include "BKE_image.h"
+#include "BKE_main.h"
+#include "BKE_sequence.h"
+#include "BKE_utildefines.h"
+
+#include "BLI_blenlib.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "BLI_threads.h"
+#include <pthread.h>
+
+#ifdef WIN32
+#define snprintf _snprintf
+#endif
+
+/* **** XXX ******** */
+static int seqrectx= 0; /* bad bad global! */
+static int seqrecty= 0;
+static void waitcursor() {}
+static int blender_test_break() {return 0;}
+
+/* **** XXX ******** */
+
+
+/* **********************************************************************
+ alloc / free functions
+ ********************************************************************** */
+
+static void free_tstripdata(int len, TStripElem *se)
+{
+ TStripElem *seo;
+ int a;
+
+ seo= se;
+ if (!se)
+ return;
+
+ for(a=0; a<len; a++, se++) {
+ 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 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;
+ }
+}
+
+
+/* free */
+
+void seq_free_strip(Strip *strip)
+{
+ strip->us--;
+ if(strip->us>0) return;
+ if(strip->us<0) {
+ printf("error: negative users in strip\n");
+ return;
+ }
+
+ 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->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);
+}
+
+void seq_free_sequence(Editing *ed, Sequence *seq)
+{
+ if(seq->strip) seq_free_strip(seq->strip);
+
+ if(seq->anim) IMB_free_anim(seq->anim);
+ //XXX if(seq->hdaudio) sound_close_hdaudio(seq->hdaudio);
+
+ /* XXX if (seq->type & SEQ_EFFECT) {
+ struct SeqEffectHandle sh = get_sequence_effect(seq);
+
+ sh.free(seq);
+ }*/
+
+ if (ed->act_seq==seq)
+ ed->act_seq= NULL;
+
+ MEM_freeN(seq);
+}
+
+Editing *seq_give_editing(Scene *scene, int alloc)
+{
+ if (scene->ed == NULL && alloc) {
+ Editing *ed;
+
+ ed= scene->ed= MEM_callocN( sizeof(Editing), "addseq");
+ ed->seqbasep= &ed->seqbase;
+ }
+ return scene->ed;
+}
+
+void seq_free_editing(Editing *ed)
+{
+ MetaStack *ms;
+ Sequence *seq;
+
+ if(ed==NULL)
+ return;
+
+ SEQ_BEGIN(ed, seq) {
+ seq_free_sequence(ed, seq);
+ }
+ SEQ_END
+
+ while((ms= ed->metastack.first)) {
+ BLI_remlink(&ed->metastack, ms);
+ MEM_freeN(ms);
+ }
+
+ MEM_freeN(ed);
+}
+
+/* ************************* itterator ************************** */
+/* *************** (replaces old WHILE_SEQ) ********************* */
+/* **************** use now SEQ_BEGIN() SEQ_END ***************** */
+
+/* sequence strip iterator:
+ * - builds a full array, recursively into meta strips */
+
+static void seq_count(ListBase *seqbase, int *tot)
+{
+ Sequence *seq;
+
+ for(seq=seqbase->first; seq; seq=seq->next) {
+ (*tot)++;
+
+ if(seq->seqbase.first)
+ seq_count(&seq->seqbase, tot);
+ }
+}
+
+static void seq_build_array(ListBase *seqbase, Sequence ***array, int depth)
+{
+ Sequence *seq;
+
+ for(seq=seqbase->first; seq; seq=seq->next) {
+ seq->depth= depth;
+
+ if(seq->seqbase.first)
+ seq_build_array(&seq->seqbase, array, depth+1);
+
+ **array= seq;
+ (*array)++;
+ }
+}
+
+void seq_array(Editing *ed, Sequence ***seqarray, int *tot, int use_pointer)
+{
+ Sequence **array;
+
+ *seqarray= NULL;
+ *tot= 0;
+
+ if(ed == NULL)
+ return;
+
+ if(use_pointer)
+ seq_count(ed->seqbasep, tot);
+ else
+ seq_count(&ed->seqbase, tot);
+
+ if(*tot == 0)
+ return;
+
+ *seqarray= array= MEM_mallocN(sizeof(Sequence *)*(*tot), "SeqArray");
+ if(use_pointer)
+ seq_build_array(ed->seqbasep, &array, 0);
+ else
+ seq_build_array(&ed->seqbase, &array, 0);
+}
+
+void seq_begin(Editing *ed, SeqIterator *iter, int use_pointer)
+{
+ memset(iter, 0, sizeof(*iter));
+ seq_array(ed, &iter->array, &iter->tot, use_pointer);
+
+ if(iter->tot) {
+ iter->cur= 0;
+ iter->seq= iter->array[iter->cur];
+ iter->valid= 1;
+ }
+}
+
+void seq_next(SeqIterator *iter)
+{
+ if(++iter->cur < iter->tot)
+ iter->seq= iter->array[iter->cur];
+ else
+ iter->valid= 0;
+}
+
+void seq_end(SeqIterator *iter)
+{
+ if(iter->array)
+ MEM_freeN(iter->array);
+
+ iter->valid= 0;
+}
+
+/*
+ **********************************************************************
+ * build_seqar
+ **********************************************************************
+ * Build a complete array of _all_ sequencies (including those
+ * in metastrips!)
+ **********************************************************************
+*/
+
+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;
+ }
+}
+
+void build_seqar(ListBase *seqbase, Sequence ***seqar, int *totseq)
+{
+ Sequence **tseqar;
+
+ *totseq= 0;
+ do_seq_count(seqbase, totseq);
+
+ if(*totseq==0) {
+ *seqar= 0;
+ return;
+ }
+ *seqar= MEM_mallocN(sizeof(void *)* *totseq, "seqar");
+ tseqar= *seqar;
+
+ do_build_seqar(seqbase, seqar, 0);
+ *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 calc_sequence_disp(Sequence *seq)
+{
+ if(seq->startofs && seq->startstill) seq->startstill= 0;
+ if(seq->endofs && seq->endstill) seq->endstill= 0;
+
+ seq->startdisp= seq->start + seq->startofs - seq->startstill;
+ seq->enddisp= seq->start+seq->len - seq->endofs + seq->endstill;
+
+ seq->handsize= 10.0; /* 10 frames */
+ if( seq->enddisp-seq->startdisp < 10 ) {
+ seq->handsize= (float)(0.5*(seq->enddisp-seq->startdisp));
+ }
+ else if(seq->enddisp-seq->startdisp > 250) {
+ seq->handsize= (float)((seq->enddisp-seq->startdisp)/25);
+ }
+}
+
+void calc_sequence(Sequence *seq)
+{
+ Sequence *seqm;
+ int min, max;
+
+ /* check all metas recursively */
+ seqm= seq->seqbase.first;
+ while(seqm) {
+ if(seqm->seqbase.first) calc_sequence(seqm);
+ seqm= seqm->next;
+ }
+
+ /* effects and meta: automatic start and end */
+
+ if(seq->type & SEQ_EFFECT) {
+ /* pointers */
+ if(seq->seq2==0) seq->seq2= seq->seq1;
+ if(seq->seq3==0) seq->seq3= seq->seq1;
+
+ /* effecten go from seq1 -> seq2: test */
+
+ /* we take the largest start and smallest end */
+
+ // seq->start= seq->startdisp= MAX2(seq->seq1->startdisp, seq->seq2->startdisp);
+ // seq->enddisp= MIN2(seq->seq1->enddisp, seq->seq2->enddisp);
+
+ 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);
+ seq->len= seq->enddisp - seq->startdisp;
+ } else {
+ calc_sequence_disp(seq);
+ }
+
+ if(seq->strip && seq->len!=seq->strip->len) {
+ new_tstripdata(seq);
+ }
+
+ }
+ else {
+ if(seq->type==SEQ_META) {
+ seqm= seq->seqbase.first;
+ if(seqm) {
+ min= 1000000;
+ max= -1000000;
+ while(seqm) {
+ if(seqm->startdisp < min) min= seqm->startdisp;
+ if(seqm->enddisp > max) max= seqm->enddisp;
+ seqm= seqm->next;
+ }
+ 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);
+ }
+ }
+ }
+ calc_sequence_disp(seq);
+ }
+}
+
+void reload_sequence_new_file(Scene *scene, 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) {
+ BLI_join_dirfile(str, seq->strip->dir, seq->strip->stripdata->name);
+ BLI_convertstringcode(str, G.sce);
+ BLI_convertstringframe(str, scene->r.cfra);
+
+ }
+
+ 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 | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0));
+
+ 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) {
+// XXX if(seq->hdaudio) sound_close_hdaudio(seq->hdaudio);
+// seq->hdaudio = sound_open_hdaudio(str);
+
+ if (!seq->hdaudio) {
+ return;
+ }
+
+// XXX 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)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(Scene *scene)
+{
+ /* all strips together per kind, and in order of y location ("machine") */
+ ListBase seqbase, effbase;
+ Editing *ed= seq_give_editing(scene, FALSE);
+ Sequence *seq, *seqt;
+
+
+ if(ed==NULL) return;
+
+ seqbase.first= seqbase.last= 0;
+ effbase.first= effbase.last= 0;
+
+ while( (seq= ed->seqbasep->first) ) {
+ BLI_remlink(ed->seqbasep, seq);
+
+ if(seq->type & SEQ_EFFECT) {
+ seqt= effbase.first;
+ while(seqt) {
+ if(seqt->machine>=seq->machine) {
+ BLI_insertlinkbefore(&effbase, seqt, seq);
+ break;
+ }
+ seqt= seqt->next;
+ }
+ if(seqt==0) BLI_addtail(&effbase, seq);
+ }
+ else {
+ seqt= seqbase.first;
+ while(seqt) {
+ if(seqt->machine>=seq->machine) {
+ BLI_insertlinkbefore(&seqbase, seqt, seq);
+ break;
+ }
+ seqt= seqt->next;
+ }
+ if(seqt==0) BLI_addtail(&seqbase, seq);
+ }
+ }
+
+ addlisttolist(&seqbase, &effbase);
+ *(ed->seqbasep)= seqbase;
+}
+
+
+void clear_scene_in_allseqs(Scene *sce)
+{
+ Scene *sce1;
+ Editing *ed;
+ Sequence *seq;
+
+ /* when a scene is deleted: test all seqs */
+
+ sce1= G.main->scene.first;
+ while(sce1) {
+ if(sce1!=sce && sce1->ed) {
+ ed= sce1->ed;
+
+ SEQ_BEGIN(ed, seq) {
+
+ if(seq->scene==sce) seq->scene= 0;
+
+ }
+ SEQ_END
+ }
+
+ sce1= sce1->id.next;
+ }
+}
+
+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)
+{
+ unsigned int *rect;
+ float *rect_float;
+ int tot;
+
+ if(ibuf==0 || (ibuf->rect==0 && ibuf->rect_float==0)) return;
+
+ tot= ibuf->x*ibuf->y;
+
+ rect= ibuf->rect;
+ rect_float = ibuf->rect_float;
+
+ if (rect) {
+ memset(rect, 0, tot * sizeof(char) * 4);
+ }
+
+ if (rect_float) {
+ memset(rect_float, 0, tot * sizeof(float) * 4);
+ }
+}
+
+static void multibuf(ImBuf *ibuf, float fmul)
+{
+ char *rt;
+ float *rt_float;
+
+ int a, mul, icol;
+
+ mul= (int)(256.0*fmul);
+ rt= (char *)ibuf->rect;
+ rt_float = ibuf->rect_float;
+
+ if (rt) {
+ a= ibuf->x*ibuf->y;
+ while(a--) {
+
+ icol= (mul*rt[0])>>8;
+ if(icol>254) rt[0]= 255; else rt[0]= icol;
+ icol= (mul*rt[1])>>8;
+ if(icol>254) rt[1]= 255; else rt[1]= icol;
+ icol= (mul*rt[2])>>8;
+ if(icol>254) rt[2]= 255; else rt[2]= icol;
+ icol= (mul*rt[3])>>8;
+ if(icol>254) rt[3]= 255; else rt[3]= icol;
+
+ rt+= 4;
+ }
+ }
+ if (rt_float) {
+ a= ibuf->x*ibuf->y;
+ while(a--) {
+ rt_float[0] *= fmul;
+ rt_float[1] *= fmul;
+ rt_float[2] *= fmul;
+ rt_float[3] *= fmul;
+
+ rt_float += 4;
+ }
+ }
+}
+
+static void do_effect(Scene *scene, int cfra, Sequence *seq, TStripElem * se)
+{
+ TStripElem *se1, *se2, *se3;
+ float fac, facf;
+ int x, y;
+ int early_out;
+ struct SeqEffectHandle sh = get_sequence_effect(seq);
+
+ if (!sh.execute) { /* effect not supported in this version... */
+ make_black_ibuf(se->ibuf);
+ return;
+ }
+
+#if 0 // XXX old animation system
+ if(seq->ipo && seq->ipo->curve.first) {
+ do_seq_ipo(scene, seq, cfra);
+ fac= seq->facf0;
+ facf= seq->facf1;
+ } else
+#endif // XXX old animation system
+ {
+ sh.get_default_fac(seq, cfra, &fac, &facf);
+ }
+
+ if( !(scene->r.mode & R_FIELDS) ) facf = fac;
+
+ 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,
+ 0, 0, 0, se->ibuf);
+ return;
+ }
+
+ switch (early_out) {
+ case 0:
+ if (se->se1==0 || se->se2==0 || se->se3==0) {
+ make_black_ibuf(se->ibuf);
+ return;
+ }
+
+ 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)) {
+ make_black_ibuf(se->ibuf);
+ return;
+ }
+
+ break;
+ case 1:
+ if (se->se1 == 0) {
+ make_black_ibuf(se->ibuf);
+ return;
+ }
+
+ se1= se->se1;
+
+ if (se1 == 0 || se1->ibuf == 0) {
+ make_black_ibuf(se->ibuf);
+ return;
+ }
+
+ if (se->ibuf != se1->ibuf) {
+ IMB_freeImBuf(se->ibuf);
+ se->ibuf = se1->ibuf;
+ IMB_refImBuf(se->ibuf);
+ }
+ return;
+ case 2:
+ if (se->se2 == 0) {
+ make_black_ibuf(se->ibuf);
+ return;
+ }
+
+ se2= se->se2;
+
+ if (se2 == 0 || se2->ibuf == 0) {
+ make_black_ibuf(se->ibuf);
+ return;
+ }
+ if (se->ibuf != se2->ibuf) {
+ IMB_freeImBuf(se->ibuf);
+ se->ibuf = se2->ibuf;
+ IMB_refImBuf(se->ibuf);
+ }
+ return;
+ default:
+ make_black_ibuf(se->ibuf);
+ return;
+ }
+
+ x= se2->ibuf->x;
+ y= se2->ibuf->y;
+
+ if (!se1->ibuf->rect_float && se->ibuf->rect_float) {
+ IMB_float_from_rect(se1->ibuf);
+ }
+ if (!se2->ibuf->rect_float && se->ibuf->rect_float) {
+ IMB_float_from_rect(se2->ibuf);
+ }
+ if (!se3->ibuf->rect_float && se->ibuf->rect_float) {
+ IMB_float_from_rect(se3->ibuf);
+ }
+
+ if (!se1->ibuf->rect && !se->ibuf->rect_float) {
+ IMB_rect_from_float(se1->ibuf);
+ }
+ if (!se2->ibuf->rect && !se->ibuf->rect_float) {
+ IMB_rect_from_float(se2->ibuf);
+ }
+ if (!se3->ibuf->rect && !se->ibuf->rect_float) {
+ IMB_rect_from_float(se3->ibuf);
+ }
+
+ sh.execute(seq, cfra, fac, facf, x, y, se1->ibuf, se2->ibuf, se3->ibuf,
+ se->ibuf);
+}
+
+static int give_stripelem_index(Sequence *seq, int cfra)
+{
+ int nr;
+
+ if(seq->startdisp >cfra || seq->enddisp <= cfra) return -1;
+ 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;
+ else nr= (seq->start + seq->len) - cfra;
+ } else {
+ if(cfra <= seq->start) nr= 0;
+ else if(cfra >= seq->start+seq->len-1) nr= seq->len-1;
+ else nr= cfra-seq->start;
+ }
+ if (seq->strobe < 1.0) seq->strobe = 1.0;
+ if (seq->strobe > 1.0) {
+ nr -= (int)fmod((double)nr, (double)seq->strobe);
+ }
+
+ 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;
+ int nr;
+
+ se = seq->strip->tstripdata;
+ if (se == 0 && seq->len > 0) {
+ 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= nr;
+
+ return se;
+}
+
+StripElem *give_stripelem(Sequence *seq, int cfra)
+{
+ StripElem *se;
+ int nr;
+
+ se = seq->strip->stripdata;
+ nr = give_stripelem_index(seq, cfra);
+
+ if (nr == -1) return 0;
+ if (se == 0) return 0;
+
+ se += nr + seq->anim_startofs;
+
+ return se;
+}
+
+static int evaluate_seq_frame_gen(Sequence ** seq_arr, ListBase *seqbase, int cfra)
+{
+ Sequence *seq;
+ int totseq=0;
+
+ memset(seq_arr, 0, sizeof(Sequence*) * (MAXSEQ+1));
+
+ seq= seqbase->first;
+ while(seq) {
+ if(seq->startdisp <=cfra && seq->enddisp > cfra) {
+ seq_arr[seq->machine]= seq;
+ totseq++;
+ }
+ seq= seq->next;
+ }
+
+ return totseq;
+}
+
+int evaluate_seq_frame(Scene *scene, int cfra)
+{
+ Editing *ed= seq_give_editing(scene, FALSE);
+ Sequence *seq_arr[MAXSEQ+1];
+
+ if(ed==NULL) return 0;
+ return evaluate_seq_frame_gen(seq_arr, ed->seqbasep, cfra);
+}
+
+static int video_seq_is_rendered(Sequence * seq)
+{
+ return (seq
+ && !(seq->flag & SEQ_MUTE)
+ && seq->type != SEQ_RAM_SOUND
+ && seq->type != SEQ_HD_SOUND);
+}
+
+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 (b > MAXSEQ) {
+ return 0;
+ }
+
+ if(evaluate_seq_frame_gen(seq_arr, seqbasep, cfra)) {
+ 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;
+ }
+ }
+ }
+ }
+
+ 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;
+}
+
+
+/* **********************************************************************
+ proxy management
+ ********************************************************************** */
+
+#define PROXY_MAXFILE (2*FILE_MAXDIR+FILE_MAXFILE)
+
+static int seq_proxy_get_fname(Scene *scene, 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, 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,
+ 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,
+ scene->r.size);
+ }
+
+ BLI_convertstringcode(name, G.sce);
+ BLI_convertstringframe(name, frameno);
+
+
+ strcat(name, ".jpg");
+
+ return TRUE;
+}
+
+static struct ImBuf * seq_proxy_fetch(Scene *scene, 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 (scene->r.size == 100.0) {
+ return 0;
+ }
+
+ if (!seq_proxy_get_fname(scene, seq, cfra, name)) {
+ return 0;
+ }
+
+ if (BLI_exists(name)) {
+ return IMB_loadiffname(name, IB_rect);
+ } else {
+ return 0;
+ }
+}
+
+static void do_build_seq_ibuf(Scene *scene, Sequence * seq, TStripElem *se, int cfra,
+ int build_proxy_run);
+
+static void seq_proxy_build_frame(Scene *scene, 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 (scene->r.size == 100.0) {
+ return;
+ }
+
+ if (!seq_proxy_get_fname(scene, 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(scene, seq, se, cfra, TRUE);
+
+ if (!se->ibuf) {
+ return;
+ }
+
+ rectx= (scene->r.size*scene->r.xsch)/100;
+ recty= (scene->r.size*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(Scene *scene, Sequence * seq)
+{
+ int cfra;
+
+ waitcursor(1);
+
+ G.afbreek = 0;
+
+ /* flag management tries to account for strobe and
+ other "non-linearities", that might come in the future...
+ better way would be to "touch" the files, so that _really_
+ no one is rebuild twice.
+ */
+
+ for (cfra = seq->startdisp; cfra < seq->enddisp; cfra++) {
+ TStripElem * tse = give_tstripelem(seq, cfra);
+
+ 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(scene, 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(scene, 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 *= gain;
+ v += lift;
+ 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 *= gain;
+ v += lift;
+ 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;
+ }
+}
+
+static void color_balance_byte_float(Sequence * seq, TStripElem* se, float mul)
+{
+ 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;
+
+ imb_addrectfloatImBuf(se->ibuf);
+
+ 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);
+ }
+
+ 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;
+ }
+}
+
+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.gain[c] + cb.lift[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);
+ }
+}
+
+/*
+ input preprocessing for SEQ_IMAGE, SEQ_MOVIE and SEQ_SCENE
+
+ Do all the things you can't really do afterwards using sequence effects
+ (read: before rescaling to render resolution has been done)
+
+ Order is important!
+
+ - Deinterlace
+ - 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(Scene *scene, 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 0 // XXX old animation system
+ if (seq->ipo && seq->ipo->curve.first) {
+ do_seq_ipo(scene, seq, cfra);
+ mul *= seq->facf0;
+ }
+#endif // XXX old animation system
+ mul *= seq->blend_opacity / 100.0;
+ }
+
+ if (mul != 1.0) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void input_preprocess(Scene *scene, Sequence *seq, TStripElem *se, int cfra)
+{
+ float mul;
+
+ seq->strip->orx= se->ibuf->x;
+ seq->strip->ory= se->ibuf->y;
+
+ if((seq->flag & SEQ_FILTERY) && seq->type != SEQ_MOVIE) {
+ IMB_filtery(se->ibuf);
+ }
+
+ if(seq->flag & SEQ_USE_CROP || seq->flag & SEQ_USE_TRANSFORM) {
+ StripCrop c;
+ StripTransform t;
+ int sx,sy,dx,dy;
+
+ memset(&c, 0, sizeof(StripCrop));
+ memset(&t, 0, sizeof(StripTransform));
+
+ if(seq->flag & SEQ_USE_CROP && seq->strip->crop) {
+ c = *seq->strip->crop;
+ }
+ if(seq->flag & SEQ_USE_TRANSFORM && seq->strip->transform) {
+ t = *seq->strip->transform;
+ }
+
+ sx = se->ibuf->x - c.left - c.right;
+ sy = se->ibuf->y - c.top - c.bottom;
+ dx = sx;
+ dy = sy;
+
+ if (seq->flag & SEQ_USE_TRANSFORM) {
+ dx = scene->r.xsch;
+ dy = scene->r.ysch;
+ }
+
+ if (c.top + c.bottom >= se->ibuf->y ||
+ c.left + c.right >= se->ibuf->x ||
+ t.xofs >= dx || t.yofs >= dy) {
+ make_black_ibuf(se->ibuf);
+ } else {
+ ImBuf * i;
+
+ if (se->ibuf->rect_float) {
+ i = IMB_allocImBuf(dx, dy,32, IB_rectfloat, 0);
+ } else {
+ i = IMB_allocImBuf(dx, dy,32, IB_rect, 0);
+ }
+
+ IMB_rectcpy(i, se->ibuf,
+ t.xofs, t.yofs,
+ c.left, c.bottom,
+ sx, sy);
+
+ IMB_freeImBuf(se->ibuf);
+
+ se->ibuf = i;
+ }
+ }
+
+ if(seq->flag & SEQ_FLIPX) {
+ IMB_flipx(se->ibuf);
+ }
+ if(seq->flag & SEQ_FLIPY) {
+ IMB_flipy(se->ibuf);
+ }
+
+ if(seq->mul == 0.0) {
+ seq->mul = 1.0;
+ }
+
+ mul = seq->mul;
+
+ if(seq->blend_mode == SEQ_BLEND_REPLACE) {
+#if 0 // XXX old animation system
+ if (seq->ipo && seq->ipo->curve.first) {
+ do_seq_ipo(scene, seq, cfra);
+ mul *= seq->facf0;
+ }
+#endif // XXX old animation system
+ 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(mul != 1.0) {
+ multibuf(se->ibuf, mul);
+ }
+
+ if(seq->flag & SEQ_MAKE_PREMUL) {
+ if(se->ibuf->depth == 32 && se->ibuf->zbuf == 0) {
+ converttopremul(se->ibuf);
+ }
+ }
+
+
+ if(se->ibuf->x != seqrectx || se->ibuf->y != seqrecty ) {
+ if(scene->r.mode & R_OSA) {
+ IMB_scaleImBuf(se->ibuf,
+ (short)seqrectx, (short)seqrecty);
+ } else {
+ IMB_scalefastImBuf(se->ibuf,
+ (short)seqrectx, (short)seqrecty);
+ }
+ }
+}
+
+/* test if image too small or discarded from cache: reload */
+
+static void test_and_auto_discard_ibuf(TStripElem * se)
+{
+ 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 void free_metastrip_imbufs(ListBase *seqbasep, int cfra, int chanshown)
+{
+ Sequence* seq_arr[MAXSEQ+1];
+ int i;
+ TStripElem* se = 0;
+
+ evaluate_seq_frame_gen(seq_arr, seqbasep, cfra);
+
+ for (i = 0; i < MAXSEQ; i++) {
+ if (!video_seq_is_rendered(seq_arr[i])) {
+ continue;
+ }
+ se = give_tstripelem(seq_arr[i], cfra);
+ if (se) {
+ if (se->ibuf) {
+ IMB_freeImBuf(se->ibuf);
+
+ se->ibuf= 0;
+ se->ok= STRIPELEM_OK;
+ }
+
+ if (se->ibuf_comp) {
+ IMB_freeImBuf(se->ibuf_comp);
+
+ se->ibuf_comp = 0;
+ }
+ }
+ }
+
+}
+
+static TStripElem* do_build_seq_array_recursively(Scene *scene,
+ ListBase *seqbasep, int cfra, int chanshown);
+
+static void do_build_seq_ibuf(Scene *scene, 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) {
+ TStripElem * meta_se = 0;
+ use_limiter = FALSE;
+
+ if (!build_proxy_run && se->ibuf == 0) {
+ se->ibuf = seq_proxy_fetch(scene, seq, cfra);
+ if (se->ibuf) {
+ use_limiter = TRUE;
+ }
+ }
+
+ if(!se->ibuf && seq->seqbase.first) {
+ meta_se = do_build_seq_array_recursively(scene,
+ &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(scene, seq, se, cfra) ||
+ build_proxy_run)) {
+ IMB_refImBuf(se->ibuf);
+ if (build_proxy_run) {
+ IMB_cache_limiter_unref(se->ibuf);
+ }
+ } else if (se->ibuf) {
+ struct ImBuf * i = IMB_dupImBuf(se->ibuf);
+
+ IMB_cache_limiter_unref(se->ibuf);
+
+ se->ibuf = i;
+
+ use_limiter = TRUE;
+ }
+ }
+ if (meta_se) {
+ free_metastrip_imbufs(
+ &seq->seqbase, seq->start + se->nr, 0);
+ }
+
+ if (use_limiter) {
+ input_preprocess(scene, 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(scene, seq, cfra);
+ }
+
+ if(se->ibuf == 0) {
+ /* if any inputs are rectfloat, output is float too */
+ if((se->se1 && se->se1->ibuf && se->se1->ibuf->rect_float) ||
+ (se->se2 && se->se2->ibuf && se->se2->ibuf->rect_float) ||
+ (se->se3 && se->se3->ibuf && se->se3->ibuf->rect_float))
+ se->ibuf= IMB_allocImBuf((short)seqrectx, (short)seqrecty, 32, IB_rectfloat, 0);
+ else
+ se->ibuf= IMB_allocImBuf((short)seqrectx, (short)seqrecty, 32, IB_rect, 0);
+
+ do_effect(scene, cfra, seq, se);
+ }
+ } else if(seq->type == SEQ_IMAGE) {
+ if(se->ok == STRIPELEM_OK && se->ibuf == 0) {
+ StripElem * s_elem = give_stripelem(seq, cfra);
+ BLI_join_dirfile(name, seq->strip->dir, s_elem->name);
+ BLI_convertstringcode(name, G.sce);
+ BLI_convertstringframe(name, scene->r.cfra);
+ if (!build_proxy_run) {
+ se->ibuf = seq_proxy_fetch(scene, seq, cfra);
+ }
+ copy_from_ibuf_still(seq, se);
+
+ 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(scene, seq, se, cfra);
+ }
+ }
+ } else if(seq->type == SEQ_MOVIE) {
+ if(se->ok == STRIPELEM_OK && se->ibuf==0) {
+ if(!build_proxy_run) {
+ se->ibuf = seq_proxy_fetch(scene, seq, cfra);
+ }
+ copy_from_ibuf_still(seq, se);
+
+ if (se->ibuf == 0) {
+ if(seq->anim==0) {
+ BLI_join_dirfile(name, seq->strip->dir, seq->strip->stripdata->name);
+ BLI_convertstringcode(name, G.sce);
+ BLI_convertstringframe(name, scene->r.cfra);
+
+ seq->anim = openanim(
+ name, IB_rect |
+ ((seq->flag & SEQ_FILTERY)
+ ? IB_animdeinterlace : 0));
+ }
+ if(seq->anim) {
+ IMB_anim_set_preseek(seq->anim, seq->anim_preseek);
+ se->ibuf = IMB_anim_absolute(seq->anim, se->nr + seq->anim_startofs);
+ }
+ copy_to_ibuf_still(seq, se);
+ }
+
+ if(se->ibuf == 0) {
+ se->ok = STRIPELEM_FAILED;
+ } else if (!build_proxy_run) {
+ input_preprocess(scene, seq, se, cfra);
+ }
+ }
+ } else if(seq->type == SEQ_SCENE) { // scene can be NULL after deletions
+#if 0
+ /* XXX move entirely to render? */
+ int oldcfra = CFRA;
+ Sequence * oldseq = get_last_seq();
+ Scene *sce= seq->scene, *oldsce= 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(scene, seq, cfra);
+ if (se->ibuf) {
+ input_preprocess(scene, seq, se, cfra);
+ }
+ }
+
+ if (se->ibuf == NULL && sce_valid) {
+ copy_from_ibuf_still(seq, se);
+ if (se->ibuf) {
+ input_preprocess(scene, 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
+ the seq->scene can already have a Render initialized with same name,
+ so we have to use a default name. (compositor uses scene name to
+ find render).
+ However, when called from within the UI (image preview in sequencer)
+ we do want to use scene Render, that way the render result is defined
+ for display in render/imagewindow */
+ if(rendering) {
+ BLI_strncpy(scenename, sce->id.name+2, 64);
+ strcpy(sce->id.name+2, " do_build_seq_ibuf");
+ }
+ re= RE_NewRender(sce->id.name);
+
+ /* prevent eternal loop */
+ doseq= scene->r.scemode & R_DOSEQ;
+ scene->r.scemode &= ~R_DOSEQ;
+
+ BIF_init_render_callbacks(re, 0); /* 0= no display callbacks */
+
+ /* XXX hrms, set_scene still needed? work on that... */
+ if(sce!=oldsce) set_scene_bg(sce);
+ 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 */
+ G.rendering= rendering;
+ if(rendering)
+ BLI_strncpy(sce->id.name+2, scenename, 64);
+
+ RE_GetResultImage(re, &rres);
+
+ if(rres.rectf) {
+ se->ibuf= IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rectfloat, 0);
+ memcpy(se->ibuf->rect_float, rres.rectf, 4*sizeof(float)*rres.rectx*rres.recty);
+ if(rres.rectz) {
+ addzbuffloatImBuf(se->ibuf);
+ memcpy(se->ibuf->zbuf_float, rres.rectz, sizeof(float)*rres.rectx*rres.recty);
+ }
+ } else if (rres.rect32) {
+ se->ibuf= IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rect, 0);
+ memcpy(se->ibuf->rect, rres.rect32, 4*rres.rectx*rres.recty);
+ }
+
+ BIF_end_render_callbacks();
+
+ /* restore */
+ scene->r.scemode |= doseq;
+
+ CFRA = oldcfra;
+ set_last_seq(oldseq);
+
+ copy_to_ibuf_still(seq, se);
+
+ if (!build_proxy_run) {
+ if(se->ibuf == NULL) {
+ se->ok = STRIPELEM_FAILED;
+ } else {
+ input_preprocess(scene, seq, se, cfra);
+ }
+ }
+
+ }
+#endif
+ }
+ 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(Scene *scene, Sequence *seq, int cfra);
+
+static void do_effect_seq_recursively(Scene *scene, Sequence *seq, TStripElem *se, int cfra)
+{
+ float fac, facf;
+ struct SeqEffectHandle sh = get_sequence_effect(seq);
+ int early_out;
+
+ se->se1 = 0;
+ se->se2 = 0;
+ se->se3 = 0;
+
+#if 0 // XXX old animation system
+ if(seq->ipo && seq->ipo->curve.first) {
+ do_seq_ipo(scene, seq, cfra);
+ fac= seq->facf0;
+ facf= seq->facf1;
+ } else
+#endif // XXX old animation system
+ {
+ sh.get_default_fac(seq, cfra, &fac, &facf);
+ }
+
+ if( scene->r.mode & R_FIELDS ); else facf= fac;
+
+ early_out = sh.early_out(seq, fac, facf);
+ switch (early_out) {
+ case -1:
+ /* no input needed */
+ break;
+ case 0:
+ se->se1 = do_build_seq_recursively(scene, seq->seq1, cfra);
+ se->se2 = do_build_seq_recursively(scene, seq->seq2, cfra);
+ if (seq->seq3) {
+ se->se3 = do_build_seq_recursively(scene, seq->seq3, cfra);
+ }
+ break;
+ case 1:
+ se->se1 = do_build_seq_recursively(scene, seq->seq1, cfra);
+ break;
+ case 2:
+ se->se2 = do_build_seq_recursively(scene, seq->seq2, cfra);
+ break;
+ }
+
+
+ do_build_seq_ibuf(scene, seq, se, cfra, FALSE);
+
+ /* children are not needed anymore ... */
+
+ if (se->se1 && se->se1->ibuf) {
+ IMB_cache_limiter_unref(se->se1->ibuf);
+ }
+ if (se->se2 && se->se2->ibuf) {
+ IMB_cache_limiter_unref(se->se2->ibuf);
+ }
+ if (se->se3 && se->se3->ibuf) {
+ IMB_cache_limiter_unref(se->se3->ibuf);
+ }
+}
+
+static TStripElem* do_build_seq_recursively_impl(Scene *scene, Sequence * seq, int cfra)
+{
+ TStripElem *se;
+
+ se = give_tstripelem(seq, cfra);
+
+ if(se) {
+ if (seq->type & SEQ_EFFECT) {
+ do_effect_seq_recursively(scene, seq, se, cfra);
+ } else {
+ do_build_seq_ibuf(scene, seq, se, cfra, FALSE);
+ }
+ }
+ return se;
+}
+
+/* FIXME:
+
+If cfra was float throughout blender (especially in the render
+pipeline) one could even _render_ with subframe precision
+instead of faking using the blend code below...
+
+*/
+
+static TStripElem* do_handle_speed_effect(Scene *scene, Sequence * seq, int cfra)
+{
+ SpeedControlVars * s = (SpeedControlVars *)seq->effectdata;
+ int nr = cfra - seq->start;
+ float f_cfra;
+ int cfra_left;
+ int cfra_right;
+ TStripElem * se = 0;
+ TStripElem * se1 = 0;
+ TStripElem * se2 = 0;
+
+ sequence_effect_speed_rebuild_map(seq, 0);
+
+ f_cfra = seq->start + s->frameMap[nr];
+
+ cfra_left = (int) floor(f_cfra);
+ cfra_right = (int) ceil(f_cfra);
+
+ se = give_tstripelem(seq, cfra);
+
+ if (!se) {
+ return se;
+ }
+
+ if (cfra_left == cfra_right ||
+ (s->flags & SEQ_SPEED_BLEND) == 0) {
+ test_and_auto_discard_ibuf(se);
+
+ if (se->ibuf == NULL) {
+ se1 = do_build_seq_recursively_impl(scene, seq->seq1, cfra_left);
+
+ if((se1 && se1->ibuf && se1->ibuf->rect_float))
+ se->ibuf= IMB_allocImBuf((short)seqrectx, (short)seqrecty, 32, IB_rectfloat, 0);
+ else
+ se->ibuf= IMB_allocImBuf((short)seqrectx, (short)seqrecty, 32, IB_rect, 0);
+
+ if (se1 == 0 || se1->ibuf == 0) {
+ make_black_ibuf(se->ibuf);
+ } else {
+ if (se->ibuf != se1->ibuf) {
+ if (se->ibuf) {
+ IMB_freeImBuf(se->ibuf);
+ }
+
+ se->ibuf = se1->ibuf;
+ IMB_refImBuf(se->ibuf);
+ }
+ }
+ }
+ } else {
+ struct SeqEffectHandle sh;
+
+ 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;
+ }
+ }
+
+ if (se->ibuf == NULL) {
+ se1 = do_build_seq_recursively_impl(scene, seq->seq1, cfra_left);
+ se2 = do_build_seq_recursively_impl(scene, seq->seq1, cfra_right);
+
+ if((se1 && se1->ibuf && se1->ibuf->rect_float))
+ se->ibuf= IMB_allocImBuf((short)seqrectx, (short)seqrecty, 32, IB_rectfloat, 0);
+ else
+ se->ibuf= IMB_allocImBuf((short)seqrectx, (short)seqrecty, 32, IB_rect, 0);
+
+ if (!se1 || !se2) {
+ make_black_ibuf(se->ibuf);
+ } else {
+ sh = get_sequence_effect(seq);
+
+ sh.execute(seq, cfra,
+ f_cfra - (float) cfra_left,
+ f_cfra - (float) cfra_left,
+ se->ibuf->x, se->ibuf->y,
+ se1->ibuf, se2->ibuf, 0, se->ibuf);
+ }
+ }
+
+ }
+
+ /* caller expects this to be referenced, so do it! */
+ if (se->ibuf) {
+ IMB_cache_limiter_insert(se->ibuf);
+ IMB_cache_limiter_ref(se->ibuf);
+ IMB_cache_limiter_touch(se->ibuf);
+ }
+
+ /* children are no longer needed */
+ if (se1 && se1->ibuf)
+ IMB_cache_limiter_unref(se1->ibuf);
+ if (se2 && se2->ibuf)
+ IMB_cache_limiter_unref(se2->ibuf);
+
+ return se;
+}
+
+/*
+ * build all ibufs recursively
+ *
+ * if successfull, the returned TStripElem contains the (referenced!) imbuf
+ * that means: you _must_ call
+ *
+ * IMB_cache_limiter_unref(rval);
+ *
+ * if rval != 0
+ *
+ */
+
+static TStripElem* do_build_seq_recursively(Scene *scene, Sequence * seq, int cfra)
+{
+ if (seq->type == SEQ_SPEED) {
+ return do_handle_speed_effect(scene, seq, cfra);
+ } else {
+ return do_build_seq_recursively_impl(scene, seq, cfra);
+ }
+}
+
+/* Bug: 18209
+ * when dragging the mouse over a metastrip, on mouse-up for some unknown
+ * reason in some cases the metastrips TStripElem->ibuf->rect is NULL,
+ * This should be fixed but I had a look and couldnt work out why its
+ * happening so for now workaround with a NULL check - campbell */
+
+#define SEQ_SPECIAL_SEQ_UPDATE_WORKAROUND
+
+static TStripElem* do_build_seq_array_recursively(Scene *scene,
+ 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(scene, 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(scene, 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 0 // XXX old animation system
+ if(seq->ipo && seq->ipo->curve.first) {
+ do_seq_ipo(scene, seq, cfra);
+ }
+#endif
+
+ if( 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(scene, 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(scene, 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);
+ }
+
+#ifdef SEQ_SPECIAL_SEQ_UPDATE_WORKAROUND
+ if (se2->ibuf->rect==NULL && se2->ibuf->rect_float==NULL) {
+ printf("ERROR: sequencer se2->ibuf missing buffer\n");
+ } else if (se1->ibuf && se1->ibuf->rect==NULL && se1->ibuf->rect_float==NULL) {
+ printf("ERROR: sequencer se1->ibuf missing buffer\n");
+ } else {
+#endif
+ /* 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);
+ }
+
+#ifdef SEQ_SPECIAL_SEQ_UPDATE_WORKAROUND
+ }
+#endif
+
+ 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!
+ */
+
+static ImBuf *give_ibuf_seq_impl(Scene *scene, int rectx, int recty, int cfra, int chanshown)
+{
+ Editing *ed= seq_give_editing(scene, FALSE);
+ int count;
+ ListBase *seqbasep;
+ TStripElem *se;
+
+
+ if(ed==NULL) return NULL;
+
+ count = BLI_countlist(&ed->metastack);
+ if((chanshown < 0) && (count > 0)) {
+ count = MAX2(count + chanshown, 0);
+ seqbasep= ((MetaStack*)BLI_findlink(&ed->metastack, count))->oldbasep;
+ } else {
+ seqbasep= ed->seqbasep;
+ }
+
+ seqrectx= rectx; /* bad bad global! */
+ seqrecty= recty;
+
+ se = do_build_seq_array_recursively(scene, seqbasep, cfra, chanshown);
+
+ if(!se) {
+ return 0;
+ }
+
+ return se->ibuf_comp;
+}
+
+ImBuf *give_ibuf_seq_direct(Scene *scene, int rectx, int recty, int cfra, Sequence *seq)
+{
+ TStripElem* se;
+
+ seqrectx= rectx; /* bad bad global! */
+ seqrecty= recty;
+
+ se = do_build_seq_recursively(scene, seq, cfra);
+
+ if(!se) {
+ return 0;
+ }
+
+ if (se->ibuf) {
+ IMB_cache_limiter_unref(se->ibuf);
+ }
+
+ return se->ibuf;
+}
+
+ImBuf *give_ibuf_seq(Scene *scene, int rectx, int recty, int cfra, int chanshown)
+{
+ ImBuf* i = give_ibuf_seq_impl(scene, rectx, recty, cfra, chanshown);
+
+ if (i) {
+ IMB_cache_limiter_unref(i);
+ }
+ return i;
+}
+
+/* check used when we need to change seq->blend_mode but not to effect or audio strips */
+int seq_can_blend(Sequence *seq)
+{
+ if (ELEM4(seq->type, SEQ_IMAGE, SEQ_META, SEQ_SCENE, SEQ_MOVIE)) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+/* *********************** threading api ******************* */
+
+static ListBase running_threads;
+static ListBase prefetch_wait;
+static ListBase prefetch_done;
+
+static pthread_mutex_t queue_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t wakeup_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t wakeup_cond = PTHREAD_COND_INITIALIZER;
+
+static pthread_mutex_t prefetch_ready_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t prefetch_ready_cond = PTHREAD_COND_INITIALIZER;
+
+static pthread_mutex_t frame_done_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t frame_done_cond = PTHREAD_COND_INITIALIZER;
+
+static volatile int seq_thread_shutdown = FALSE;
+static volatile int seq_last_given_monoton_cfra = 0;
+static int monoton_cfra = 0;
+
+typedef struct PrefetchThread {
+ struct PrefetchThread *next, *prev;
+
+ Scene *scene;
+ struct PrefetchQueueElem *current;
+ pthread_t pthread;
+ int running;
+
+} PrefetchThread;
+
+typedef struct PrefetchQueueElem {
+ struct PrefetchQueueElem *next, *prev;
+
+ int rectx;
+ int recty;
+ int cfra;
+ int chanshown;
+
+ int monoton_cfra;
+
+ struct ImBuf * ibuf;
+} PrefetchQueueElem;
+
+static void *seq_prefetch_thread(void * This_)
+{
+ PrefetchThread * This = This_;
+
+ while (!seq_thread_shutdown) {
+ PrefetchQueueElem *e;
+ int s_last;
+
+ pthread_mutex_lock(&queue_lock);
+ e = prefetch_wait.first;
+ if (e) {
+ BLI_remlink(&prefetch_wait, e);
+ }
+ s_last = seq_last_given_monoton_cfra;
+
+ This->current = e;
+
+ pthread_mutex_unlock(&queue_lock);
+
+ if (!e) {
+ pthread_mutex_lock(&prefetch_ready_lock);
+
+ This->running = FALSE;
+
+ pthread_cond_signal(&prefetch_ready_cond);
+ pthread_mutex_unlock(&prefetch_ready_lock);
+
+ pthread_mutex_lock(&wakeup_lock);
+ if (!seq_thread_shutdown) {
+ pthread_cond_wait(&wakeup_cond, &wakeup_lock);
+ }
+ pthread_mutex_unlock(&wakeup_lock);
+ continue;
+ }
+
+ This->running = TRUE;
+
+ if (e->cfra >= s_last) {
+ e->ibuf = give_ibuf_seq_impl(This->scene,
+ e->rectx, e->recty, e->cfra, e->chanshown);
+ }
+
+ pthread_mutex_lock(&queue_lock);
+
+ BLI_addtail(&prefetch_done, e);
+
+ for (e = prefetch_wait.first; e; e = e->next) {
+ if (s_last > e->monoton_cfra) {
+ BLI_remlink(&prefetch_wait, e);
+ MEM_freeN(e);
+ }
+ }
+
+ for (e = prefetch_done.first; e; e = e->next) {
+ if (s_last > e->monoton_cfra) {
+ if (e->ibuf) {
+ IMB_cache_limiter_unref(e->ibuf);
+ }
+ BLI_remlink(&prefetch_done, e);
+ MEM_freeN(e);
+ }
+ }
+
+ pthread_mutex_unlock(&queue_lock);
+
+ pthread_mutex_lock(&frame_done_lock);
+ pthread_cond_signal(&frame_done_cond);
+ pthread_mutex_unlock(&frame_done_lock);
+ }
+ return 0;
+}
+
+void seq_start_threads(Scene *scene)
+{
+ int i;
+
+ running_threads.first = running_threads.last = NULL;
+ prefetch_wait.first = prefetch_wait.last = NULL;
+ prefetch_done.first = prefetch_done.last = NULL;
+
+ seq_thread_shutdown = FALSE;
+ seq_last_given_monoton_cfra = monoton_cfra = 0;
+
+ /* since global structures are modified during the processing
+ of one frame, only one render thread is currently possible...
+
+ (but we code, in the hope, that we can remove this restriction
+ soon...)
+ */
+
+ fprintf(stderr, "SEQ-THREAD: seq_start_threads\n");
+
+ for (i = 0; i < 1; i++) {
+ PrefetchThread *t = MEM_callocN(sizeof(PrefetchThread), "prefetch_thread");
+ t->scene= scene;
+ t->running = TRUE;
+ BLI_addtail(&running_threads, t);
+
+ pthread_create(&t->pthread, NULL, seq_prefetch_thread, t);
+ }
+
+ /* init malloc mutex */
+ BLI_init_threads(0, 0, 0);
+}
+
+void seq_stop_threads()
+{
+ PrefetchThread *tslot;
+ PrefetchQueueElem *e;
+
+ fprintf(stderr, "SEQ-THREAD: seq_stop_threads()\n");
+
+ if (seq_thread_shutdown) {
+ fprintf(stderr, "SEQ-THREAD: ... already stopped\n");
+ return;
+ }
+
+ pthread_mutex_lock(&wakeup_lock);
+
+ seq_thread_shutdown = TRUE;
+
+ pthread_cond_broadcast(&wakeup_cond);
+ pthread_mutex_unlock(&wakeup_lock);
+
+ for(tslot = running_threads.first; tslot; tslot= tslot->next) {
+ pthread_join(tslot->pthread, NULL);
+ }
+
+
+ for (e = prefetch_wait.first; e; e = e->next) {
+ BLI_remlink(&prefetch_wait, e);
+ MEM_freeN(e);
+ }
+
+ for (e = prefetch_done.first; e; e = e->next) {
+ if (e->ibuf) {
+ IMB_cache_limiter_unref(e->ibuf);
+ }
+ BLI_remlink(&prefetch_done, e);
+ MEM_freeN(e);
+ }
+
+ BLI_freelistN(&running_threads);
+
+ /* deinit malloc mutex */
+ BLI_end_threads(0);
+}
+
+void give_ibuf_prefetch_request(int rectx, int recty, int cfra, int chanshown)
+{
+ PrefetchQueueElem *e;
+ if (seq_thread_shutdown) {
+ return;
+ }
+
+ e = MEM_callocN(sizeof(PrefetchQueueElem), "prefetch_queue_elem");
+ e->rectx = rectx;
+ e->recty = recty;
+ e->cfra = cfra;
+ e->chanshown = chanshown;
+ e->monoton_cfra = monoton_cfra++;
+
+ pthread_mutex_lock(&queue_lock);
+ BLI_addtail(&prefetch_wait, e);
+ pthread_mutex_unlock(&queue_lock);
+
+ pthread_mutex_lock(&wakeup_lock);
+ pthread_cond_signal(&wakeup_cond);
+ pthread_mutex_unlock(&wakeup_lock);
+}
+
+void seq_wait_for_prefetch_ready()
+{
+ PrefetchThread *tslot;
+
+ if (seq_thread_shutdown) {
+ return;
+ }
+
+ fprintf(stderr, "SEQ-THREAD: rendering prefetch frames...\n");
+
+ pthread_mutex_lock(&prefetch_ready_lock);
+
+ for(;;) {
+ for(tslot = running_threads.first; tslot; tslot= tslot->next) {
+ if (tslot->running) {
+ break;
+ }
+ }
+ if (!tslot) {
+ break;
+ }
+ pthread_cond_wait(&prefetch_ready_cond, &prefetch_ready_lock);
+ }
+
+ pthread_mutex_unlock(&prefetch_ready_lock);
+
+ fprintf(stderr, "SEQ-THREAD: prefetch done\n");
+}
+
+ImBuf *give_ibuf_seq_threaded(Scene *scene, int rectx, int recty, int cfra, int chanshown)
+{
+ PrefetchQueueElem *e = NULL;
+ int found_something = FALSE;
+
+ if (seq_thread_shutdown) {
+ return give_ibuf_seq(scene, rectx, recty, cfra, chanshown);
+ }
+
+ while (!e) {
+ int success = FALSE;
+ pthread_mutex_lock(&queue_lock);
+
+ for (e = prefetch_done.first; e; e = e->next) {
+ if (cfra == e->cfra &&
+ chanshown == e->chanshown &&
+ rectx == e->rectx &&
+ recty == e->recty) {
+ success = TRUE;
+ found_something = TRUE;
+ break;
+ }
+ }
+
+ if (!e) {
+ for (e = prefetch_wait.first; e; e = e->next) {
+ if (cfra == e->cfra &&
+ chanshown == e->chanshown &&
+ rectx == e->rectx &&
+ recty == e->recty) {
+ found_something = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (!e) {
+ PrefetchThread *tslot;
+
+ for(tslot = running_threads.first;
+ tslot; tslot= tslot->next) {
+ if (tslot->current &&
+ cfra == tslot->current->cfra &&
+ chanshown == tslot->current->chanshown &&
+ rectx == tslot->current->rectx &&
+ recty == tslot->current->recty) {
+ found_something = TRUE;
+ break;
+ }
+ }
+ }
+
+ /* e->ibuf is unrefed by render thread on next round. */
+
+ if (e) {
+ seq_last_given_monoton_cfra = e->monoton_cfra;
+ }
+
+ pthread_mutex_unlock(&queue_lock);
+
+ if (!success) {
+ e = NULL;
+
+ if (!found_something) {
+ fprintf(stderr,
+ "SEQ-THREAD: Requested frame "
+ "not in queue ???\n");
+ break;
+ }
+ pthread_mutex_lock(&frame_done_lock);
+ pthread_cond_wait(&frame_done_cond, &frame_done_lock);
+ pthread_mutex_unlock(&frame_done_lock);
+ }
+ }
+
+ return e ? e->ibuf : 0;
+}
+
+/* Functions to free imbuf and anim data on changes */
+
+static void free_imbuf_strip_elem(TStripElem *se)
+{
+ 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)
+{
+ if(seq->anim) {
+ IMB_free_anim(seq->anim);
+ seq->anim = 0;
+ }
+}
+
+void free_imbuf_seq_except(Scene *scene, int cfra)
+{
+ Editing *ed= seq_give_editing(scene, FALSE);
+ Sequence *seq;
+ TStripElem *se;
+ int a;
+
+ if(ed==NULL) return;
+
+ SEQ_BEGIN(ed, seq) {
+ if(seq->strip) {
+ TStripElem * curelem = give_tstripelem(seq, cfra);
+
+ 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)
+ free_anim_seq(seq);
+ }
+ }
+ SEQ_END
+}
+
+void free_imbuf_seq(ListBase * seqbase)
+{
+ Sequence *seq;
+ TStripElem *se;
+ int a;
+
+ for(seq= seqbase->first; seq; seq= seq->next) {
+ if(seq->strip) {
+ 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)
+ free_anim_seq(seq);
+ if(seq->type==SEQ_SPEED) {
+ sequence_effect_speed_rebuild_map(seq, 1);
+ }
+ }
+ if(seq->type==SEQ_META) {
+ free_imbuf_seq(&seq->seqbase);
+ }
+ }
+
+}
+
+static int update_changed_seq_recurs(Scene *scene, Sequence *seq, Sequence *changed_seq, int len_change, int ibuf_change)
+{
+ Sequence *subseq;
+ int a, free_imbuf = 0;
+ TStripElem *se;
+
+ /* recurs downwards to see if this seq depends on the changed seq */
+
+ if(seq == NULL)
+ return 0;
+
+ if(seq == changed_seq)
+ free_imbuf = 1;
+
+ for(subseq=seq->seqbase.first; subseq; subseq=subseq->next)
+ if(update_changed_seq_recurs(scene, subseq, changed_seq, len_change, ibuf_change))
+ free_imbuf = TRUE;
+
+ if(seq->seq1)
+ if(update_changed_seq_recurs(scene, seq->seq1, changed_seq, len_change, ibuf_change))
+ free_imbuf = TRUE;
+ if(seq->seq2 && (seq->seq2 != seq->seq1))
+ if(update_changed_seq_recurs(scene, seq->seq2, changed_seq, len_change, ibuf_change))
+ free_imbuf = TRUE;
+ if(seq->seq3 && (seq->seq3 != seq->seq1) && (seq->seq3 != seq->seq2))
+ if(update_changed_seq_recurs(scene, seq->seq3, changed_seq, len_change, ibuf_change))
+ free_imbuf = TRUE;
+
+ if(free_imbuf) {
+ if(ibuf_change) {
+ se= seq->strip->tstripdata;
+ if (se) {
+ for(a=0; a<seq->len; a++, se++)
+ free_imbuf_strip_elem(se);
+ }
+
+ if(seq->type == SEQ_MOVIE)
+ free_anim_seq(seq);
+ if(seq->type == SEQ_SPEED) {
+ sequence_effect_speed_rebuild_map(seq, 1);
+ }
+ }
+
+ if(len_change)
+ calc_sequence(seq);
+ }
+
+ return free_imbuf;
+}
+
+void update_changed_seq_and_deps(Scene *scene, Sequence *changed_seq, int len_change, int ibuf_change)
+{
+ Editing *ed= seq_give_editing(scene, FALSE);
+ Sequence *seq;
+
+ if (ed==NULL) return;
+
+ for (seq=ed->seqbase.first; seq; seq=seq->next)
+ update_changed_seq_recurs(scene, seq, changed_seq, len_change, ibuf_change);
+}
+
+void free_imbuf_seq_with_ipo(Scene *scene, struct Ipo *ipo)
+{
+ /* force update of all sequences with this ipo, on ipo changes */
+ Editing *ed= seq_give_editing(scene, FALSE);
+ Sequence *seq;
+
+ if(ed==NULL) return;
+
+ SEQ_BEGIN(ed, seq) {
+ if(seq->ipo == ipo) {
+ update_changed_seq_and_deps(scene, seq, 0, 1);
+ if(seq->type == SEQ_SPEED) {
+ sequence_effect_speed_rebuild_map(seq, 1);
+ }
+ }
+ }
+ SEQ_END
+}
+
+#if 0
+/* bad levell call... */
+void do_render_seq(RenderResult *rr, int cfra)
+{
+ ImBuf *ibuf;
+
+ ibuf= give_ibuf_seq(scene, rr->rectx, rr->recty, cfra, 0);
+
+ if(ibuf) {
+ if(ibuf->rect_float) {
+ if (!rr->rectf)
+ rr->rectf= MEM_mallocN(4*sizeof(float)*rr->rectx*rr->recty, "render_seq rectf");
+
+ memcpy(rr->rectf, ibuf->rect_float, 4*sizeof(float)*rr->rectx*rr->recty);
+
+ /* TSK! Since sequence render doesn't free the *rr render result, the old rect32
+ can hang around when sequence render has rendered a 32 bits one before */
+ if(rr->rect32) {
+ MEM_freeN(rr->rect32);
+ rr->rect32= NULL;
+ }
+ }
+ else if(ibuf->rect) {
+ if (!rr->rect32)
+ rr->rect32= MEM_mallocN(sizeof(int)*rr->rectx*rr->recty, "render_seq rect");
+
+ memcpy(rr->rect32, ibuf->rect, 4*rr->rectx*rr->recty);
+
+ /* if (ibuf->zbuf) { */
+ /* if (R.rectz) freeN(R.rectz); */
+ /* R.rectz = BLI_dupallocN(ibuf->zbuf); */
+ /* } */
+ }
+
+ /* Let the cache limitor take care of this (schlaile) */
+ /* While render let's keep all memory available for render
+ (ton)
+ At least if free memory is tight...
+ This can make a big difference in encoding speed
+ (it is around 4 times(!) faster, if we do not waste time
+ on freeing _all_ buffers every time on long timelines...)
+ (schlaile)
+ */
+ {
+ uintptr_t mem_in_use;
+ uintptr_t mmap_in_use;
+ uintptr_t max;
+
+ mem_in_use= MEM_get_memory_in_use();
+ mmap_in_use= MEM_get_mapped_memory_in_use();
+ max = MEM_CacheLimiter_get_maximum();
+
+ if (max != 0 && mem_in_use + mmap_in_use > max) {
+ fprintf(stderr, "Memory in use > maximum memory\n");
+ fprintf(stderr, "Cleaning up, please wait...\n"
+ "If this happens very often,\n"
+ "consider "
+ "raising the memcache limit in the "
+ "user preferences.\n");
+ free_imbuf_seq();
+ }
+ }
+ }
+ else {
+ /* render result is delivered empty in most cases, nevertheless we handle all cases */
+ if (rr->rectf)
+ memset(rr->rectf, 0, 4*sizeof(float)*rr->rectx*rr->recty);
+ else if (rr->rect32)
+ memset(rr->rect32, 0, 4*rr->rectx*rr->recty);
+ else
+ rr->rect32= MEM_callocN(sizeof(int)*rr->rectx*rr->recty, "render_seq rect");
+ }
+}
+
+#endif
+
+/* seq funcs's for transforming internally
+ notice the difference between start/end and left/right.
+
+ 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) {
+ return seq->start;
+}
+int seq_tx_get_end(Sequence *seq)
+{
+ return seq->start+seq->len;
+}
+
+int seq_tx_get_final_left(Sequence *seq, int metaclip)
+{
+ if (metaclip && seq->tmp) {
+ /* return the range clipped by the parents range */
+ return MAX2( seq_tx_get_final_left(seq, 0), seq_tx_get_final_left((Sequence *)seq->tmp, 1) );
+ } else {
+ return (seq->start - seq->startstill) + seq->startofs;
+ }
+
+}
+int seq_tx_get_final_right(Sequence *seq, int metaclip)
+{
+ if (metaclip && seq->tmp) {
+ /* return the range clipped by the parents range */
+ return MIN2( seq_tx_get_final_right(seq, 0), seq_tx_get_final_right((Sequence *)seq->tmp, 1) );
+ } else {
+ return ((seq->start+seq->len) + seq->endstill) - seq->endofs;
+ }
+}
+
+void seq_tx_set_final_left(Sequence *seq, int val)
+{
+ if (val < (seq)->start) {
+ seq->startstill = abs(val - (seq)->start);
+ (seq)->startofs = 0;
+ } else {
+ seq->startofs = abs(val - (seq)->start);
+ seq->startstill = 0;
+ }
+}
+
+void seq_tx_set_final_right(Sequence *seq, int val)
+{
+ if (val > (seq)->start + (seq)->len) {
+ seq->endstill = abs(val - (seq->start + (seq)->len));
+ (seq)->endofs = 0;
+ } else {
+ seq->endofs = abs(val - ((seq)->start + (seq)->len));
+ seq->endstill = 0;
+ }
+}
+
+/* used so we can do a quick check for single image seq
+ since they work a bit differently to normal image seq's (during transform) */
+int check_single_seq(Sequence *seq)
+{
+ if ( seq->len==1 && (seq->type == SEQ_IMAGE || seq->type == SEQ_COLOR))
+ return 1;
+ else
+ return 0;
+}
+
+/* use to impose limits when dragging/extending - so impossible situations dont happen
+ * Cant use the SEQ_LEFTSEL and SEQ_LEFTSEL directly because the strip may be in a metastrip */
+void seq_tx_handle_xlimits(Sequence *seq, int leftflag, int rightflag)
+{
+ if(leftflag) {
+ if (seq_tx_get_final_left(seq, 0) >= seq_tx_get_final_right(seq, 0)) {
+ seq_tx_set_final_left(seq, seq_tx_get_final_right(seq, 0)-1);
+ }
+
+ if (check_single_seq(seq)==0) {
+ if (seq_tx_get_final_left(seq, 0) >= seq_tx_get_end(seq)) {
+ seq_tx_set_final_left(seq, seq_tx_get_end(seq)-1);
+ }
+
+ /* dosnt work now - TODO */
+ /*
+ if (seq_tx_get_start(seq) >= seq_tx_get_final_right(seq, 0)) {
+ int ofs;
+ ofs = seq_tx_get_start(seq) - seq_tx_get_final_right(seq, 0);
+ seq->start -= ofs;
+ seq_tx_set_final_left(seq, seq_tx_get_final_left(seq, 0) + ofs );
+ }*/
+
+ }
+ }
+
+ if(rightflag) {
+ if (seq_tx_get_final_right(seq, 0) <= seq_tx_get_final_left(seq, 0)) {
+ seq_tx_set_final_right(seq, seq_tx_get_final_left(seq, 0)+1);
+ }
+
+ if (check_single_seq(seq)==0) {
+ if (seq_tx_get_final_right(seq, 0) <= seq_tx_get_start(seq)) {
+ seq_tx_set_final_right(seq, seq_tx_get_start(seq)+1);
+ }
+ }
+ }
+
+ /* sounds cannot be extended past their endpoints */
+ if (seq->type == SEQ_RAM_SOUND || seq->type == SEQ_HD_SOUND) {
+ seq->startstill= 0;
+ seq->endstill= 0;
+ }
+}
+
+void fix_single_seq(Sequence *seq)
+{
+ int left, start, offset;
+ if (!check_single_seq(seq))
+ return;
+
+ /* make sure the image is always at the start since there is only one,
+ adjusting its start should be ok */
+ left = seq_tx_get_final_left(seq, 0);
+ start = seq->start;
+ if (start != left) {
+ offset = left - start;
+ seq_tx_set_final_left( seq, seq_tx_get_final_left(seq, 0) - offset );
+ seq_tx_set_final_right( seq, seq_tx_get_final_right(seq, 0) - offset );
+ seq->start += offset;
+ }
+}
+
+int seq_tx_test(Sequence * seq)
+{
+ return (seq->type < SEQ_EFFECT) || (get_sequence_effect_num_inputs(seq->type) == 0);
+}
+
+int seq_test_overlap(ListBase * seqbasep, Sequence *test)
+{
+ Sequence *seq;
+
+ seq= seqbasep->first;
+ while(seq) {
+ if(seq!=test) {
+ if(test->machine==seq->machine) {
+ if( (test->enddisp <= seq->startdisp) || (test->startdisp >= seq->enddisp) );
+ else return 1;
+ }
+ }
+ seq= seq->next;
+ }
+ return 0;
+}
+
+
+static void seq_translate(Sequence *seq, int delta)
+{
+ seq->start += delta;
+ if(seq->type==SEQ_META) {
+ Sequence *seq_child;
+ for(seq_child= seq->seqbase.first; seq_child; seq_child= seq_child->next) {
+ seq_translate(seq_child, delta);
+ }
+ }
+
+ calc_sequence_disp(seq);
+}
+
+/* return 0 if there werent enough space */
+int shuffle_seq(ListBase * seqbasep, Sequence *test)
+{
+ int orig_machine= test->machine;
+ test->machine++;
+ calc_sequence(test);
+ while( seq_test_overlap(seqbasep, test) ) {
+ if(test->machine >= MAXSEQ) {
+ break;
+ }
+ test->machine++;
+ calc_sequence(test); // XXX - I dont think this is needed since were only moving vertically, Campbell.
+ }
+
+
+ if(test->machine >= MAXSEQ) {
+ /* Blender 2.4x would remove the strip.
+ * nicer to move it to the end */
+
+ Sequence *seq;
+ int new_frame= test->enddisp;
+
+ for(seq= seqbasep->first; seq; seq= seq->next) {
+ if (seq->machine == orig_machine)
+ new_frame = MAX2(new_frame, seq->enddisp);
+ }
+
+ test->machine= orig_machine;
+ new_frame = new_frame + (test->start-test->startdisp); /* adjust by the startdisp */
+ seq_translate(test, new_frame - test->start);
+
+ calc_sequence(test);
+ return 0;
+ } else {
+ return 1;
+ }
+}