diff options
author | Sergey Sharybin <sergey.vfx@gmail.com> | 2012-02-29 16:08:26 +0400 |
---|---|---|
committer | Sergey Sharybin <sergey.vfx@gmail.com> | 2012-02-29 16:08:26 +0400 |
commit | d8bdd4497eec824a522062c4a8b597ef25395d63 (patch) | |
tree | c797600b9e618ff184cdf16c36d59a9196d9cc7d /source/blender/imbuf/intern/indexer.c | |
parent | 31cd0521ae64e95982bd4bd4f8685b7cf96d4248 (diff) |
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)
Diffstat (limited to 'source/blender/imbuf/intern/indexer.c')
-rw-r--r-- | source/blender/imbuf/intern/indexer.c | 360 |
1 files changed, 225 insertions, 135 deletions
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; - - 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; |