Refactor of proxies build operators
authorSergey Sharybin <sergey.vfx@gmail.com>
Wed, 29 Feb 2012 12:08:26 +0000 (12:08 +0000)
committerSergey Sharybin <sergey.vfx@gmail.com>
Wed, 29 Feb 2012 12:08:26 +0000 (12:08 +0000)
Split proxy build operator into three parts:
- Prepare context (IMB_anim_index_rebuild_context) which prepares all
  needed data and stores it in an anonymous structure used by specific
  builder lately.
- Build proxies/timecodes into temporary files (IMB_anim_index_rebuild)
  This function will build all selected proxies/timecodes into a temporary
  files so old proxies will be still available during building.
- Finish building proxies (IMB_anim_index_rebuild_finish) which copies
  temporary files over old proxies filed and releases all resources used
  by a context.

Context creation and finishing building happens in a main thread so
it's easy and safe to close all opened handles of proxies files and
refresh cache after rebuilding is finished.

This should finally fix #30315: Temporary proxy files are not erased and old proxys are not updated if the proxy is built more then once (windows)

source/blender/blenkernel/BKE_sequencer.h
source/blender/blenkernel/intern/sequencer.c
source/blender/editors/space_clip/clip_ops.c
source/blender/editors/space_sequencer/sequencer_edit.c
source/blender/imbuf/IMB_imbuf.h
source/blender/imbuf/intern/anim_movie.c
source/blender/imbuf/intern/indexer.c

index 5c6058b14532fac8eff73e6a5a624f114f4823ce..3cb8e91ac005f6ef86fe42e32cbed71d0a509710 100644 (file)
@@ -40,6 +40,8 @@ struct Strip;
 struct StripElem;
 struct bSound;
 
+struct SeqIndexBuildContext;
+
 #define BUILD_SEQAR_COUNT_NOTHING  0
 #define BUILD_SEQAR_COUNT_CURRENT  1
 #define BUILD_SEQAR_COUNT_CHILDREN 2
@@ -194,9 +196,10 @@ void update_changed_seq_and_deps(struct Scene *scene, struct Sequence *changed_s
 int input_have_to_preprocess(
        SeqRenderData context, struct Sequence * seq, float cfra);
 
-void seq_proxy_rebuild(struct Main * bmain, 
-                       struct Scene *scene, struct Sequence * seq,
+struct SeqIndexBuildContext *seq_proxy_rebuild_context(struct Main *bmain, struct Scene *scene, struct Sequence *seq);
+void seq_proxy_rebuild(struct SeqIndexBuildContext *context,
                        short *stop, short *do_update, float *progress);
+void seq_proxy_rebuild_finish(struct SeqIndexBuildContext *context, short stop);
 
 
 /* **********************************************************************
index 1c3cc44c585d212a44010d12b9e1af0abd35f102..92199eadf5b449ef38bcb32c9f84b63f19576061 100644 (file)
@@ -1140,6 +1140,18 @@ static int get_shown_sequences(  ListBase * seqbasep, int cfra, int chanshown, Se
    proxy management
    ********************************************************************** */
 
+typedef struct SeqIndexBuildContext {
+       struct IndexBuildContext *index_context;
+
+       int tc_flags;
+       int size_flags;
+       int quality;
+
+       Main *bmain;
+       Scene *scene;
+       Sequence *seq, *orig_seq;
+} SeqIndexBuildContext;
+
 #define PROXY_MAXFILE (2*FILE_MAXDIR+FILE_MAXFILE)
 
 static IMB_Proxy_Size seq_rendersize_to_proxysize(int size)
@@ -1345,35 +1357,56 @@ static void seq_proxy_build_frame(SeqRenderData context,
        IMB_freeImBuf(ibuf);
 }
 
-void seq_proxy_rebuild(struct Main * bmain, Scene *scene, Sequence * seq,
-                      short *stop, short *do_update, float *progress)
+struct SeqIndexBuildContext *seq_proxy_rebuild_context(Main *bmain, Scene *scene, Sequence *seq)
 {
-       SeqRenderData context;
-       int cfra;
-       int tc_flags;
-       int size_flags;
-       int quality;
+       SeqIndexBuildContext *context;
+       Sequence *nseq;
 
        if (!seq->strip || !seq->strip->proxy) {
-               return;
+               return NULL;
        }
 
        if (!(seq->flag & SEQ_USE_PROXY)) {
-               return;
+               return NULL;
        }
 
-       tc_flags   = seq->strip->proxy->build_tc_flags;
-       size_flags = seq->strip->proxy->build_size_flags;
-       quality    = seq->strip->proxy->quality;
+       context = MEM_callocN(sizeof(SeqIndexBuildContext), "seq proxy rebuild context");
 
-       if (seq->type == SEQ_MOVIE) {
-               seq_open_anim_file(seq);
+       nseq = seq_dupli_recursive(scene, scene, seq, 0);
 
-               if (seq->anim) {
-                       IMB_anim_index_rebuild(
-                               seq->anim, tc_flags, size_flags, quality,
-                               stop, do_update, progress);
+       context->tc_flags   = nseq->strip->proxy->build_tc_flags;
+       context->size_flags = nseq->strip->proxy->build_size_flags;
+       context->quality    = nseq->strip->proxy->quality;
+
+       context->bmain = bmain;
+       context->scene = scene;
+       context->orig_seq = seq;
+       context->seq = nseq;
+
+       if (nseq->type == SEQ_MOVIE) {
+               seq_open_anim_file(nseq);
+
+               if (nseq->anim) {
+                       context->index_context = IMB_anim_index_rebuild_context(nseq->anim,
+                               context->tc_flags, context->size_flags, context->quality);
+               }
+       }
+
+       return context;
+}
+
+void seq_proxy_rebuild(SeqIndexBuildContext *context, short *stop, short *do_update, float *progress)
+{
+       SeqRenderData render_context;
+       Sequence *seq = context->seq;
+       Scene *scene = context->scene;
+       int cfra;
+
+       if (seq->type == SEQ_MOVIE) {
+               if (context->index_context) {
+                       IMB_anim_index_rebuild(context->index_context, stop, do_update, progress);
                }
+
                return;
        }
 
@@ -1388,25 +1421,25 @@ void seq_proxy_rebuild(struct Main * bmain, Scene *scene, Sequence * seq,
 
        /* fail safe code */
 
-       context = seq_new_render_data(
-               bmain, scene, 
+       render_context = seq_new_render_data(
+               context->bmain, context->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);
+               if (context->size_flags & IMB_PROXY_25) {
+                       seq_proxy_build_frame(render_context, seq, cfra, 25);
                }
-               if (size_flags & IMB_PROXY_50) {
-                       seq_proxy_build_frame(context, seq, cfra, 50);
+               if (context->size_flags & IMB_PROXY_50) {
+                       seq_proxy_build_frame(render_context, seq, cfra, 50);
                }
-               if (size_flags & IMB_PROXY_75) {
-                       seq_proxy_build_frame(context, seq, cfra, 75);
+               if (context->size_flags & IMB_PROXY_75) {
+                       seq_proxy_build_frame(render_context, seq, cfra, 75);
                }
-               if (size_flags & IMB_PROXY_100) {
-                       seq_proxy_build_frame(context, seq, cfra, 100);
+               if (context->size_flags & IMB_PROXY_100) {
+                       seq_proxy_build_frame(render_context, seq, cfra, 100);
                }
 
                *progress= (float)cfra/(seq->enddisp - seq->endstill 
@@ -1418,6 +1451,18 @@ void seq_proxy_rebuild(struct Main * bmain, Scene *scene, Sequence * seq,
        }
 }
 
+void seq_proxy_rebuild_finish(SeqIndexBuildContext *context, short stop)
+{
+       if (context->index_context) {
+               IMB_close_anim_proxies(context->seq->anim);
+               IMB_close_anim_proxies(context->orig_seq->anim);
+               IMB_anim_index_rebuild_finish(context->index_context, stop);
+       }
+
+       seq_free_sequence_recurse(context->scene, context->seq);
+
+       MEM_freeN(context);
+}
 
 /* **********************************************************************
    color balance 
index 459f40c64a586102f0611da58b6f306b715fcc37..99ee4974659c890d238f6e19a87a979c5a9c2b44 100644 (file)
@@ -845,7 +845,8 @@ typedef struct ProxyBuildJob {
        Scene *scene;
        struct Main *main;
        MovieClip *clip;
-       int clip_flag;
+       int clip_flag, stop;
+       struct IndexBuildContext *index_context;
 } ProxyJob;
 
 static void proxy_freejob(void *pjv)
@@ -896,11 +897,13 @@ static void proxy_startjob(void *pjv, short *stop, short *do_update, float *prog
        build_undistort_count= proxy_bitflag_to_array(size_flag, build_undistort_sizes, 1);
 
        if(clip->source == MCLIP_SRC_MOVIE) {
-               if(clip->anim)
-                       IMB_anim_index_rebuild(clip->anim, tc_flag, size_flag, quality, stop, do_update, progress);
+               if (pj->index_context)
+                       IMB_anim_index_rebuild(pj->index_context, stop, do_update, progress);
 
                if(!build_undistort_count) {
-                       BKE_movieclip_reload(clip);
+                       if (*stop)
+                               pj->stop = 1;
+
                        return;
                }
                else {
@@ -928,7 +931,23 @@ static void proxy_startjob(void *pjv, short *stop, short *do_update, float *prog
        if(distortion)
                BKE_tracking_distortion_destroy(distortion);
 
-       BKE_movieclip_reload(clip);
+       if (*stop)
+               pj->stop = 1;
+}
+
+static void proxy_endjob(void *pjv)
+{
+       ProxyJob *pj = pjv;
+
+       if (pj->clip->anim)
+               IMB_close_anim_proxies(pj->clip->anim);
+
+       if (pj->index_context)
+               IMB_anim_index_rebuild_finish(pj->index_context, pj->stop);
+
+       BKE_movieclip_reload(pj->clip);
+
+       WM_main_add_notifier(NC_MOVIECLIP|ND_DISPLAY, pj->clip);
 }
 
 static int clip_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op))
@@ -951,9 +970,14 @@ static int clip_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op))
        pj->clip= clip;
        pj->clip_flag= clip->flag&MCLIP_TIMECODE_FLAGS;
 
+       if (clip->anim) {
+               pj->index_context = IMB_anim_index_rebuild_context(clip->anim, clip->proxy.build_tc_flag,
+                                       clip->proxy.build_size_flag, clip->proxy.quality);
+       }
+
        WM_jobs_customdata(steve, pj, proxy_freejob);
        WM_jobs_timer(steve, 0.2, NC_MOVIECLIP|ND_DISPLAY, 0);
-       WM_jobs_callbacks(steve, proxy_startjob, NULL, NULL, NULL);
+       WM_jobs_callbacks(steve, proxy_startjob, NULL, NULL, proxy_endjob);
 
        G.afbreek= 0;
        WM_jobs_start(CTX_wm_manager(C), steve);
index 222be03b2fe26efe90736d23cd651b065d28c3fe..fad402a678768b76225afb3774ef793b3cf767da 100644 (file)
@@ -56,6 +56,8 @@
 #include "BKE_report.h"
 #include "BKE_sound.h"
 
+#include "IMB_imbuf.h"
+
 #include "WM_api.h"
 #include "WM_types.h"
 
@@ -131,20 +133,14 @@ typedef struct ProxyBuildJob {
        Scene *scene; 
        struct Main * main;
        ListBase queue;
-       ThreadMutex queue_lock;
+       int stop;
 } ProxyJob;
 
 static void proxy_freejob(void *pjv)
 {
        ProxyJob *pj= pjv;
-       Sequence * seq;
-
-       for (seq = pj->queue.first; seq; seq = seq->next) {
-               BLI_remlink(&pj->queue, seq);
-               seq_free_sequence_recurse(pj->scene, seq);
-       }
 
-       BLI_mutex_end(&pj->queue_lock);
+       BLI_freelistN(&pj->queue);
 
        MEM_freeN(pj);
 }
@@ -153,30 +149,17 @@ static void proxy_freejob(void *pjv)
 static void proxy_startjob(void *pjv, short *stop, short *do_update, float *progress)
 {
        ProxyJob *pj = pjv;
+       LinkData *link;
 
-       while (!*stop) {
-               Sequence * seq;
-
-               BLI_mutex_lock(&pj->queue_lock);
-               
-               if (!pj->queue.first) {
-                       BLI_mutex_unlock(&pj->queue_lock);
-                       break;
-               }
+       for (link = pj->queue.first; link; link = link->next) {
+               struct SeqIndexBuildContext *context = link->data;
 
-               seq = pj->queue.first;
-
-               BLI_remlink(&pj->queue, seq);
-               BLI_mutex_unlock(&pj->queue_lock);
-
-               seq_proxy_rebuild(pj->main, pj->scene, seq, 
-                                 stop, do_update, progress);
-               seq_free_sequence_recurse(pj->scene, seq);
+               seq_proxy_rebuild(context, stop, do_update, progress);
        }
 
        if (*stop) {
-               fprintf(stderr, 
-                       "Canceling proxy rebuild on users request...\n");
+               pj->stop = 1;
+               fprintf(stderr,  "Canceling proxy rebuild on users request...\n");
        }
 }
 
@@ -184,23 +167,29 @@ static void proxy_endjob(void *pjv)
 {
        ProxyJob *pj = pjv;
        Editing *ed = seq_give_editing(pj->scene, FALSE);
+       LinkData *link;
+
+       for (link = pj->queue.first; link; link = link->next) {
+               seq_proxy_rebuild_finish(link->data, pj->stop);
+       }
 
        free_imbuf_seq(pj->scene, &ed->seqbase, FALSE, FALSE);
 
        WM_main_add_notifier(NC_SCENE|ND_SEQUENCER, pj->scene);
 }
 
-static void seq_proxy_build_job(const bContext *C, Sequence * seq)
+static void seq_proxy_build_job(const bContext *C)
 {
        wmJob * steve;
        ProxyJob *pj;
        Scene *scene= CTX_data_scene(C);
+       Editing *ed = seq_give_editing(scene, FALSE);
        ScrArea * sa= CTX_wm_area(C);
+       struct SeqIndexBuildContext *context;
+       LinkData *link;
+       Sequence * seq;
 
-       seq = seq_dupli_recursive(scene, scene, seq, 0);
-
-       steve = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), 
-                           sa, "Building Proxies", WM_JOB_PROGRESS);
+       steve = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa, "Building Proxies", WM_JOB_PROGRESS);
 
        pj = WM_jobs_get_customdata(steve);
 
@@ -210,18 +199,19 @@ static void seq_proxy_build_job(const bContext *C, Sequence * seq)
                pj->scene= scene;
                pj->main = CTX_data_main(C);
 
-               BLI_mutex_init(&pj->queue_lock);
-
                WM_jobs_customdata(steve, pj, proxy_freejob);
-               WM_jobs_timer(steve, 0.1, NC_SCENE|ND_SEQUENCER,
-                             NC_SCENE|ND_SEQUENCER);
-               WM_jobs_callbacks(steve, proxy_startjob, NULL, NULL,
-                                 proxy_endjob);
+               WM_jobs_timer(steve, 0.1, NC_SCENE|ND_SEQUENCER, NC_SCENE|ND_SEQUENCER);
+               WM_jobs_callbacks(steve, proxy_startjob, NULL, NULL, proxy_endjob);
        }
 
-       BLI_mutex_lock(&pj->queue_lock);
-       BLI_addtail(&pj->queue, seq);
-       BLI_mutex_unlock(&pj->queue_lock);
+       SEQP_BEGIN(ed, seq) {
+               if ((seq->flag & SELECT)) {
+                       context = seq_proxy_rebuild_context(pj->main, pj->scene, seq);
+                       link = BLI_genericNodeN(context);
+                       BLI_addtail(&pj->queue, link);
+               }
+       }
+       SEQ_END
 
        if (!WM_jobs_is_running(steve)) {
                G.afbreek = 0;
@@ -2822,17 +2812,8 @@ void SEQUENCER_OT_view_ghost_border(wmOperatorType *ot)
 /* rebuild_proxy operator */
 static int sequencer_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op))
 {
-       Scene *scene = CTX_data_scene(C);
-       Editing *ed = seq_give_editing(scene, FALSE);
-       Sequence * seq;
+       seq_proxy_build_job(C);
 
-       SEQP_BEGIN(ed, seq) {
-               if ((seq->flag & SELECT)) {
-                       seq_proxy_build_job(C, seq);
-               }
-       }
-       SEQ_END
-               
        return OPERATOR_FINISHED;
 }
 
index 5f38142726f8459f3d3fc1647687f1495467f614..dfd53a145f6f48c4d94a3a03a1d506e7f45ec718 100644 (file)
@@ -217,13 +217,19 @@ void IMB_anim_set_index_dir(struct anim * anim, const char * dir);
 int IMB_anim_index_get_frame_index(struct anim * anim, IMB_Timecode_Type tc,
                                    int position);
 
+struct IndexBuildContext;
+
+/* prepare context for proxies/imecodes builder */
+struct IndexBuildContext *IMB_anim_index_rebuild_context(struct anim *anim, IMB_Timecode_Type tcs_in_use,
+                                                         IMB_Proxy_Size proxy_sizes_in_use, int quality);
+
 /* will rebuild all used indices and proxies at once */
-void IMB_anim_index_rebuild(struct anim * anim, 
-                            IMB_Timecode_Type build_tcs,
-                            IMB_Proxy_Size build_preview_sizes,
-                            int build_quality,
+void IMB_anim_index_rebuild(struct IndexBuildContext *context,
                             short *stop, short *do_update, float *progress);
 
+/* finish rebuilding proxises/timecodes and free temporary contexts used */
+void IMB_anim_index_rebuild_finish(struct IndexBuildContext *context, short stop);
+
 /**
  * Return the length (in frames) of the given @a anim.
  */
@@ -243,6 +249,7 @@ int IMB_anim_get_fps(struct anim * anim,
  */
 struct anim *IMB_open_anim(const char *name, int ib_flags, int streamindex);
 void IMB_close_anim(struct anim *anim);
+void IMB_close_anim_proxies(struct anim *anim);
 
 
 /**
index a09033795285aa2dd88833ebad666ab80794833d..8722ca8e90afb507686ce0d8e0e3e141bca995ae 100644 (file)
@@ -241,6 +241,10 @@ void IMB_close_anim(struct anim * anim)
        IMB_free_anim(anim);
 }
 
+void IMB_close_anim_proxies(struct anim *anim)
+{
+       IMB_free_indices(anim);
+}
 
 struct anim * IMB_open_anim( const char * name, int ib_flags, int streamindex)
 {
index ca2c4719917d5471f5ca5d79d129d3dc5232eeda..cc95cc0fbbeb99545adfbc56d361d935b8a3db8f 100644 (file)
@@ -695,102 +695,112 @@ static void free_proxy_output_ffmpeg(struct proxy_output_ctx * ctx,
        MEM_freeN(ctx);
 }
 
+typedef struct IndexBuildContext {
+       int anim_type;
+} IndexBuildContext;
 
-static int index_rebuild_ffmpeg(struct anim * anim, 
-                               IMB_Timecode_Type tcs_in_use,
-                               IMB_Proxy_Size proxy_sizes_in_use,
-                               int quality,
-                               short *stop, short *do_update, 
-                               float *progress)
-{
-       int i, videoStream;
-       unsigned long long seek_pos = 0;
-       unsigned long long last_seek_pos = 0;
-       unsigned long long seek_pos_dts = 0;
-       unsigned long long seek_pos_pts = 0;
-       unsigned long long last_seek_pos_dts = 0;
-       unsigned long long start_pts = 0;
-       double frame_rate;
-       double pts_time_base;
-       int frameno = 0, frameno_gapless = 0;
-       int start_pts_set = FALSE;
+typedef struct FFmpegIndexBuilderContext {
+       int anim_type;
 
        AVFormatContext *iFormatCtx;
        AVCodecContext *iCodecCtx;
        AVCodec *iCodec;
        AVStream *iStream;
-       AVFrame* in_frame = 0;
-       AVPacket next_packet;
-       int streamcount;
+       int videoStream;
+
+       int num_proxy_sizes;
+       int num_indexers;
 
        struct proxy_output_ctx * proxy_ctx[IMB_PROXY_MAX_SLOT];
        anim_index_builder * indexer [IMB_TC_MAX_SLOT];
 
+       IMB_Timecode_Type tcs_in_use;
+       IMB_Proxy_Size proxy_sizes_in_use;
+} FFmpegIndexBuilderContext;
+
+typedef struct FallbackIndexBuilderContext {
+       int anim_type;
+
+       struct anim *anim;
+       AviMovie *proxy_ctx[IMB_PROXY_MAX_SLOT];
+       IMB_Proxy_Size proxy_sizes_in_use;
+} FallbackIndexBuilderContext;
+
+static IndexBuildContext *index_ffmpeg_create_context(struct anim *anim, IMB_Timecode_Type tcs_in_use,
+                                                      IMB_Proxy_Size proxy_sizes_in_use, int quality)
+{
+       FFmpegIndexBuilderContext *context = MEM_callocN(sizeof(FFmpegIndexBuilderContext), "FFmpeg index builder context");
        int num_proxy_sizes = IMB_PROXY_MAX_SLOT;
        int num_indexers = IMB_TC_MAX_SLOT;
-       uint64_t stream_size;
+       int i, streamcount;
 
-       memset(proxy_ctx, 0, sizeof(proxy_ctx));
-       memset(indexer, 0, sizeof(indexer));
+       context->tcs_in_use = tcs_in_use;
+       context->proxy_sizes_in_use = proxy_sizes_in_use;
+       context->num_proxy_sizes = IMB_PROXY_MAX_SLOT;
+       context->num_indexers = IMB_TC_MAX_SLOT;
 
-       if(av_open_input_file(&iFormatCtx, anim->name, NULL, 0, NULL) != 0) {
-               return 0;
+       memset(context->proxy_ctx, 0, sizeof(context->proxy_ctx));
+       memset(context->indexer, 0, sizeof(context->indexer));
+
+       if(av_open_input_file(&context->iFormatCtx, anim->name, NULL, 0, NULL) != 0) {
+               MEM_freeN(context);
+               return NULL;
        }
 
-       if (av_find_stream_info(iFormatCtx) < 0) {
-               av_close_input_file(iFormatCtx);
-               return 0;
+       if (av_find_stream_info(context->iFormatCtx) < 0) {
+               av_close_input_file(context->iFormatCtx);
+               MEM_freeN(context);
+               return NULL;
        }
 
        streamcount = anim->streamindex;
 
        /* Find the video stream */
-       videoStream = -1;
-       for (i = 0; i < iFormatCtx->nb_streams; i++)
-               if(iFormatCtx->streams[i]->codec->codec_type
+       context->videoStream = -1;
+       for (i = 0; i < context->iFormatCtx->nb_streams; i++)
+               if(context->iFormatCtx->streams[i]->codec->codec_type
                   == AVMEDIA_TYPE_VIDEO) {
                        if (streamcount > 0) {
                                streamcount--;
                                continue;
                        }
-                       videoStream = i;
+                       context->videoStream = i;
                        break;
                }
 
-       if (videoStream == -1) {
-               av_close_input_file(iFormatCtx);
-               return 0;
+       if (context->videoStream == -1) {
+               av_close_input_file(context->iFormatCtx);
+               MEM_freeN(context);
+               return NULL;
        }
 
-       iStream = iFormatCtx->streams[videoStream];
-       iCodecCtx = iStream->codec;
-
-       iCodec = avcodec_find_decoder(iCodecCtx->codec_id);
-       
-       if (iCodec == NULL) {
-               av_close_input_file(iFormatCtx);
-               return 0;
-       }
+       context->iStream = context->iFormatCtx->streams[context->videoStream];
+       context->iCodecCtx = context->iStream->codec;
 
-       iCodecCtx->workaround_bugs = 1;
+       context->iCodec = avcodec_find_decoder(context->iCodecCtx->codec_id);
 
-       if (avcodec_open(iCodecCtx, iCodec) < 0) {
-               av_close_input_file(iFormatCtx);
-               return 0;
+       if (context->iCodec == NULL) {
+               av_close_input_file(context->iFormatCtx);
+               MEM_freeN(context);
+               return NULL;
        }
 
-       in_frame = avcodec_alloc_frame();
+       context->iCodecCtx->workaround_bugs = 1;
 
-       stream_size = avio_size(iFormatCtx->pb);
+       if (avcodec_open(context->iCodecCtx, context->iCodec) < 0) {
+               av_close_input_file(context->iFormatCtx);
+               MEM_freeN(context);
+               return NULL;
+       }
 
        for (i = 0; i < num_proxy_sizes; i++) {
                if (proxy_sizes_in_use & proxy_sizes[i]) {
-                       proxy_ctx[i] = alloc_proxy_output_ffmpeg(
-                               anim, iStream, proxy_sizes[i],
-                               iCodecCtx->width * proxy_fac[i],
-                               iCodecCtx->height * proxy_fac[i],
+                       context->proxy_ctx[i] = alloc_proxy_output_ffmpeg(
+                               anim, context->iStream, proxy_sizes[i],
+                               context->iCodecCtx->width * proxy_fac[i],
+                               context->iCodecCtx->height * proxy_fac[i],
                                quality);
-                       if (!proxy_ctx[i]) {
+                       if (!context->proxy_ctx[i]) {
                                proxy_sizes_in_use &= ~proxy_sizes[i];
                        }
                }
@@ -802,17 +812,61 @@ static int index_rebuild_ffmpeg(struct anim * anim,
 
                        get_tc_filename(anim, tc_types[i], fname);
 
-                       indexer[i] = IMB_index_builder_create(fname);
-                       if (!indexer[i]) {
+                       context->indexer[i] = IMB_index_builder_create(fname);
+                       if (!context->indexer[i]) {
                                tcs_in_use &= ~tc_types[i];
                        }
                }
        }
 
-       frame_rate = av_q2d(iStream->r_frame_rate);
-       pts_time_base = av_q2d(iStream->time_base);
+       return (IndexBuildContext *)context;
+}
+
+static void index_rebuild_ffmpeg_finish(FFmpegIndexBuilderContext *context, int stop)
+{
+       int i;
+
+       for (i = 0; i < context->num_indexers; i++) {
+               if (context->tcs_in_use & tc_types[i]) {
+                       IMB_index_builder_finish(context->indexer[i], stop);
+               }
+       }
+
+       for (i = 0; i < context->num_proxy_sizes; i++) {
+               if (context->proxy_sizes_in_use & proxy_sizes[i]) {
+                       free_proxy_output_ffmpeg(context->proxy_ctx[i], stop);
+               }
+       }
+
+       MEM_freeN(context);
+}
 
-       while(av_read_frame(iFormatCtx, &next_packet) >= 0) {
+static int index_rebuild_ffmpeg(FFmpegIndexBuilderContext *context,
+                                short *stop, short *do_update, float *progress)
+{
+       int i;
+       unsigned long long seek_pos = 0;
+       unsigned long long last_seek_pos = 0;
+       unsigned long long seek_pos_dts = 0;
+       unsigned long long seek_pos_pts = 0;
+       unsigned long long last_seek_pos_dts = 0;
+       unsigned long long start_pts = 0;
+       double frame_rate;
+       double pts_time_base;
+       int frameno = 0, frameno_gapless = 0;
+       int start_pts_set = FALSE;
+       AVFrame* in_frame = 0;
+       AVPacket next_packet;
+       uint64_t stream_size;
+
+       in_frame = avcodec_alloc_frame();
+
+       stream_size = avio_size(context->iFormatCtx->pb);
+
+       frame_rate = av_q2d(context->iStream->r_frame_rate);
+       pts_time_base = av_q2d(context->iStream->time_base);
+
+       while(av_read_frame(context->iFormatCtx, &next_packet) >= 0) {
                int frame_finished = 0;
                float next_progress =  (float)((int)floor(((double) next_packet.pos) * 100 /
                                                   ((double) stream_size)+0.5)) / 100;
@@ -827,7 +881,7 @@ static int index_rebuild_ffmpeg(struct anim * anim,
                        break;
                }
 
-               if (next_packet.stream_index == videoStream) {
+               if (next_packet.stream_index == context->videoStream) {
                        if (next_packet.flags & AV_PKT_FLAG_KEY) {
                                last_seek_pos = seek_pos;
                                last_seek_pos_dts = seek_pos_dts;
@@ -837,7 +891,7 @@ static int index_rebuild_ffmpeg(struct anim * anim,
                        }
 
                        avcodec_decode_video2(
-                               iCodecCtx, in_frame, &frame_finished, 
+                               context->iCodecCtx, in_frame, &frame_finished,
                                &next_packet);
                }
 
@@ -845,11 +899,11 @@ static int index_rebuild_ffmpeg(struct anim * anim,
                        unsigned long long s_pos = seek_pos;
                        unsigned long long s_dts = seek_pos_dts;
                        unsigned long long pts 
-                               = av_get_pts_from_frame(iFormatCtx, in_frame);
+                               = av_get_pts_from_frame(context->iFormatCtx, in_frame);
 
-                       for (i = 0; i < num_proxy_sizes; i++) {
+                       for (i = 0; i < context->num_proxy_sizes; i++) {
                                add_to_proxy_output_ffmpeg(
-                                       proxy_ctx[i], in_frame);
+                                       context->proxy_ctx[i], in_frame);
                        }
 
                        if (!start_pts_set) {
@@ -872,15 +926,15 @@ static int index_rebuild_ffmpeg(struct anim * anim,
                                s_dts = last_seek_pos_dts;
                        }
 
-                       for (i = 0; i < num_indexers; i++) {
-                               if (tcs_in_use & tc_types[i]) {
+                       for (i = 0; i < context->num_indexers; i++) {
+                               if (context->tcs_in_use & tc_types[i]) {
                                        int tc_frameno = frameno;
 
                                        if(tc_types[i] == IMB_TC_RECORD_RUN_NO_GAPS)
                                                tc_frameno = frameno_gapless;
 
                                        IMB_index_builder_proc_frame(
-                                               indexer[i], 
+                                               context->indexer[i],
                                                next_packet.data, 
                                                next_packet.size,
                                                tc_frameno,
@@ -893,18 +947,6 @@ static int index_rebuild_ffmpeg(struct anim * anim,
                av_free_packet(&next_packet);
        }
 
-       for (i = 0; i < num_indexers; i++) {
-               if (tcs_in_use & tc_types[i]) {
-                       IMB_index_builder_finish(indexer[i], *stop);
-               }
-       }
-
-       for (i = 0; i < num_proxy_sizes; i++) {
-               if (proxy_sizes_in_use & proxy_sizes[i]) {
-                       free_proxy_output_ffmpeg(proxy_ctx[i], *stop);
-               }
-       }
-
        av_free(in_frame);
 
        return 1;
@@ -955,20 +997,11 @@ static AviMovie * alloc_proxy_output_avi(
        return avi;
 }
 
-static void index_rebuild_fallback(struct anim * anim,
-                                  IMB_Timecode_Type UNUSED(tcs_in_use),
-                                  IMB_Proxy_Size proxy_sizes_in_use,
-                                  int quality,
-                                  short *stop, short *do_update, 
-                                  float *progress)
+static IndexBuildContext *index_fallback_create_context(struct anim *anim, IMB_Timecode_Type UNUSED(tcs_in_use),
+                                                        IMB_Proxy_Size proxy_sizes_in_use, int quality)
 {
-       int cnt = IMB_anim_get_duration(anim, IMB_TC_NONE);
-       int i, pos;
-       AviMovie * proxy_ctx[IMB_PROXY_MAX_SLOT];
-       char fname[FILE_MAX];
-       char fname_tmp[FILE_MAX];
-       
-       memset(proxy_ctx, 0, sizeof(proxy_ctx));
+       FallbackIndexBuilderContext *context;
+       int i;
 
        /* since timecode indices only work with ffmpeg right now,
           don't know a sensible fallback here...
@@ -976,28 +1009,67 @@ static void index_rebuild_fallback(struct anim * anim,
           so no proxies, no game to play...
        */
        if (proxy_sizes_in_use == IMB_PROXY_NONE) {
-               return;
+               return NULL;
        }
 
+       context = MEM_callocN(sizeof(FallbackIndexBuilderContext), "fallback index builder context");
+
+       context->anim = anim;
+       context->proxy_sizes_in_use = proxy_sizes_in_use;
+
+       memset(context->proxy_ctx, 0, sizeof(context->proxy_ctx));
+
        for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) {
-               if (proxy_sizes_in_use & proxy_sizes[i]) {
+               if (context->proxy_sizes_in_use & proxy_sizes[i]) {
                        char fname[FILE_MAX];
 
                        get_proxy_filename(anim, proxy_sizes[i], fname, TRUE);
                        BLI_make_existing_file(fname);
 
-                       proxy_ctx[i] = alloc_proxy_output_avi(
-                               anim, fname,
-                               anim->x * proxy_fac[i],
-                               anim->y * proxy_fac[i],
-                               quality);
+                       context->proxy_ctx[i] = alloc_proxy_output_avi(anim, fname,
+                               anim->x * proxy_fac[i], anim->y * proxy_fac[i], quality);
                }
        }
 
+       return (IndexBuildContext *)context;
+}
+
+static void index_rebuild_fallback_finish(FallbackIndexBuilderContext *context, int stop)
+{
+       struct anim *anim = context->anim;
+       char fname[FILE_MAX];
+       char fname_tmp[FILE_MAX];
+       int i;
+
+       for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) {
+               if (context->proxy_sizes_in_use & proxy_sizes[i]) {
+                       AVI_close_compress(context->proxy_ctx[i]);
+                       MEM_freeN(context->proxy_ctx[i]);
+
+                       get_proxy_filename(anim, proxy_sizes[i], fname_tmp, TRUE);
+                       get_proxy_filename(anim, proxy_sizes[i], fname, FALSE);
+
+                       if (stop) {
+                               unlink(fname_tmp);
+                       } else {
+                               unlink(fname);
+                               rename(fname_tmp, fname);
+                       }
+               }
+       }
+}
+
+static void index_rebuild_fallback(FallbackIndexBuilderContext *context,
+                                   short *stop, short *do_update, float *progress)
+{
+       int cnt = IMB_anim_get_duration(context->anim, IMB_TC_NONE);
+       int i, pos;
+       struct anim *anim = context->anim;
+
        for (pos = 0; pos < cnt; pos++) {
-               struct ImBuf * ibuf = IMB_anim_absolute(
-                       anim, pos, IMB_TC_NONE, IMB_PROXY_NONE);
-               int next_progress = (int) ((double) pos / (double) cnt);
+               struct ImBuf *ibuf = IMB_anim_absolute(anim, pos, IMB_TC_NONE, IMB_PROXY_NONE);
+               struct ImBuf *tmp_ibuf = IMB_dupImBuf(ibuf);
+               float next_progress = (float) pos / (float) cnt;
 
                if (*progress != next_progress) {
                        *progress = next_progress;
@@ -1008,19 +1080,20 @@ static void index_rebuild_fallback(struct anim * anim,
                        break;
                }
 
-               IMB_flipy(ibuf);
+               IMB_flipy(tmp_ibuf);
 
                for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) {
-                       if (proxy_sizes_in_use & proxy_sizes[i]) {
+                       if (context->proxy_sizes_in_use & proxy_sizes[i]) {
                                int x = anim->x * proxy_fac[i];
                                int y = anim->y * proxy_fac[i];
 
-                               struct ImBuf * s_ibuf = IMB_scalefastImBuf(
-                                       ibuf, x, y);
+                               struct ImBuf * s_ibuf = IMB_dupImBuf(tmp_ibuf);
+
+                               IMB_scalefastImBuf(s_ibuf, x, y);
 
                                IMB_convert_rgba_to_abgr(s_ibuf);
        
-                               AVI_write_frame (proxy_ctx[i], pos, 
+                               AVI_write_frame (context->proxy_ctx[i], pos, 
                                                 AVI_FORMAT_RGB32, 
                                                 s_ibuf->rect, x * y * 4);
 
@@ -1030,25 +1103,9 @@ static void index_rebuild_fallback(struct anim * anim,
                                IMB_freeImBuf(s_ibuf);
                        }
                }
-       }
-
-       for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) {
-               if (proxy_sizes_in_use & proxy_sizes[i]) {
-                       AVI_close_compress (proxy_ctx[i]);
-                       MEM_freeN (proxy_ctx[i]);
 
-                       get_proxy_filename(anim, proxy_sizes[i], 
-                                          fname_tmp, TRUE);
-                       get_proxy_filename(anim, proxy_sizes[i], 
-                                          fname, FALSE);
-
-                       if (*stop) {
-                               unlink(fname_tmp);
-                       } else {
-                               unlink(fname);
-                               rename(fname_tmp, fname);
-                       }
-               }
+               IMB_freeImBuf(tmp_ibuf);
+               IMB_freeImBuf(ibuf);
        }
 }
 
@@ -1056,25 +1113,58 @@ static void index_rebuild_fallback(struct anim * anim,
    - public API
    ---------------------------------------------------------------------- */
 
-void IMB_anim_index_rebuild(struct anim * anim, IMB_Timecode_Type tcs_in_use,
-                           IMB_Proxy_Size proxy_sizes_in_use,
-                           int quality,
-                           short *stop, short *do_update, float *progress)
+IndexBuildContext *IMB_anim_index_rebuild_context(struct anim *anim, IMB_Timecode_Type tcs_in_use,
+                                                         IMB_Proxy_Size proxy_sizes_in_use, int quality)
 {
+       IndexBuildContext *context = NULL;
+
        switch (anim->curtype) {
 #ifdef WITH_FFMPEG
        case ANIM_FFMPEG:
-               index_rebuild_ffmpeg(anim, tcs_in_use, proxy_sizes_in_use,
-                                    quality, stop, do_update, progress);
+               context = index_ffmpeg_create_context(anim, tcs_in_use, proxy_sizes_in_use, quality);
+               break;
+#endif
+       default:
+               context = index_fallback_create_context(anim, tcs_in_use, proxy_sizes_in_use, quality);
+               break;
+       }
+
+       if (context)
+               context->anim_type = anim->curtype;
+
+       return context;
+}
+
+void IMB_anim_index_rebuild(struct IndexBuildContext *context,
+                            short *stop, short *do_update, float *progress)
+{
+       switch (context->anim_type) {
+#ifdef WITH_FFMPEG
+       case ANIM_FFMPEG:
+               index_rebuild_ffmpeg((FFmpegIndexBuilderContext*)context, stop, do_update, progress);
+               break;
+#endif
+       default:
+               index_rebuild_fallback((FallbackIndexBuilderContext*)context, stop, do_update, progress);
+               break;
+       }
+}
+
+void IMB_anim_index_rebuild_finish(IndexBuildContext *context, short stop)
+{
+       switch (context->anim_type) {
+#ifdef WITH_FFMPEG
+       case ANIM_FFMPEG:
+               index_rebuild_ffmpeg_finish((FFmpegIndexBuilderContext*)context, stop);
                break;
 #endif
        default:
-               index_rebuild_fallback(anim, tcs_in_use, proxy_sizes_in_use,
-                                      quality, stop, do_update, progress);
+               index_rebuild_fallback_finish((FallbackIndexBuilderContext*)context, stop);
                break;
        }
 }
 
+
 void IMB_free_indices(struct anim * anim)
 {
        int i;