diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h index 5c6058b1453..3cb8e91ac00 100644 --- a/source/blender/blenkernel/BKE_sequencer.h +++ b/source/blender/blenkernel/BKE_sequencer.h @@ -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); /* ********************************************************************** diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index 1c3cc44c585..92199eadf5b 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -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"); + + nseq = seq_dupli_recursive(scene, scene, seq, 0); + + 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) { - seq_open_anim_file(seq); - - if (seq->anim) { - IMB_anim_index_rebuild( - seq->anim, tc_flags, size_flags, quality, - stop, do_update, progress); + 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 diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c index 459f40c64a5..99ee4974659 100644 --- a/source/blender/editors/space_clip/clip_ops.c +++ b/source/blender/editors/space_clip/clip_ops.c @@ -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); diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 222be03b2fe..fad402a6787 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -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; + for (link = pj->queue.first; link; link = link->next) { + struct SeqIndexBuildContext *context = link->data; - BLI_mutex_lock(&pj->queue_lock); - - if (!pj->queue.first) { - BLI_mutex_unlock(&pj->queue_lock); - break; - } - - 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; } diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h index 5f38142726f..dfd53a145f6 100644 --- a/source/blender/imbuf/IMB_imbuf.h +++ b/source/blender/imbuf/IMB_imbuf.h @@ -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); /** diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c index a0903379528..8722ca8e90a 100644 --- a/source/blender/imbuf/intern/anim_movie.c +++ b/source/blender/imbuf/intern/anim_movie.c @@ -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) { diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c index ca2c4719917..cc95cc0fbbe 100644 --- a/source/blender/imbuf/intern/indexer.c +++ b/source/blender/imbuf/intern/indexer.c @@ -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; + context->iStream = context->iFormatCtx->streams[context->videoStream]; + context->iCodecCtx = context->iStream->codec; - iCodec = avcodec_find_decoder(iCodecCtx->codec_id); - - if (iCodec == NULL) { - av_close_input_file(iFormatCtx); - return 0; + context->iCodec = avcodec_find_decoder(context->iCodecCtx->codec_id); + + if (context->iCodec == NULL) { + av_close_input_file(context->iFormatCtx); + MEM_freeN(context); + return NULL; } - iCodecCtx->workaround_bugs = 1; + context->iCodecCtx->workaround_bugs = 1; - if (avcodec_open(iCodecCtx, iCodec) < 0) { - av_close_input_file(iFormatCtx); - return 0; + if (avcodec_open(context->iCodecCtx, context->iCodec) < 0) { + av_close_input_file(context->iFormatCtx); + MEM_freeN(context); + return NULL; } - in_frame = avcodec_alloc_frame(); - - stream_size = avio_size(iFormatCtx->pb); - 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; +} - while(av_read_frame(iFormatCtx, &next_packet) >= 0) { +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); +} + +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: - index_rebuild_fallback(anim, tcs_in_use, proxy_sizes_in_use, - quality, stop, do_update, progress); + 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_finish((FallbackIndexBuilderContext*)context, stop); + break; + } +} + + void IMB_free_indices(struct anim * anim) { int i;