Refactor of proxies build operators

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)
This commit is contained in:
Sergey Sharybin 2012-02-29 12:08:26 +00:00
parent 31cd0521ae
commit d8bdd4497e
7 changed files with 380 additions and 226 deletions

@ -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);
/* **********************************************************************

@ -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

@ -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);

@ -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;
}

@ -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);
/**

@ -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)
{

@ -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;