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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/imbuf/intern/indexer.c')
-rw-r--r--source/blender/imbuf/intern/indexer.c133
1 files changed, 127 insertions, 6 deletions
diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c
index 7aeee2740c0..a85ba65d014 100644
--- a/source/blender/imbuf/intern/indexer.c
+++ b/source/blender/imbuf/intern/indexer.c
@@ -37,6 +37,8 @@
# include "BLI_winstuff.h"
#endif
+#include "PIL_time.h"
+
#include "IMB_anim.h"
#include "IMB_indexer.h"
#include "imbuf.h"
@@ -814,12 +816,16 @@ typedef struct FFmpegIndexBuilderContext {
double pts_time_base;
int frameno, frameno_gapless;
int start_pts_set;
+
+ bool build_only_on_bad_performance;
+ bool building_cancelled;
} FFmpegIndexBuilderContext;
static IndexBuildContext *index_ffmpeg_create_context(struct anim *anim,
IMB_Timecode_Type tcs_in_use,
IMB_Proxy_Size proxy_sizes_in_use,
- int quality)
+ int quality,
+ bool build_only_on_bad_performance)
{
FFmpegIndexBuilderContext *context = MEM_callocN(sizeof(FFmpegIndexBuilderContext),
"FFmpeg index builder context");
@@ -831,6 +837,7 @@ static IndexBuildContext *index_ffmpeg_create_context(struct anim *anim,
context->proxy_sizes_in_use = proxy_sizes_in_use;
context->num_proxy_sizes = IMB_PROXY_MAX_SLOT;
context->num_indexers = IMB_TC_MAX_SLOT;
+ context->build_only_on_bad_performance = build_only_on_bad_performance;
memset(context->proxy_ctx, 0, sizeof(context->proxy_ctx));
memset(context->indexer, 0, sizeof(context->indexer));
@@ -936,15 +943,17 @@ static void index_rebuild_ffmpeg_finish(FFmpegIndexBuilderContext *context, int
{
int i;
+ const bool do_rollback = stop || context->building_cancelled;
+
for (i = 0; i < context->num_indexers; i++) {
if (context->tcs_in_use & tc_types[i]) {
- IMB_index_builder_finish(context->indexer[i], stop);
+ IMB_index_builder_finish(context->indexer[i], do_rollback);
}
}
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);
+ free_proxy_output_ffmpeg(context->proxy_ctx[i], do_rollback);
}
}
@@ -1095,6 +1104,111 @@ static int index_rebuild_ffmpeg(FFmpegIndexBuilderContext *context,
return 1;
}
+/* Get number of frames, that can be decoded in specified time period. */
+static int indexer_performance_get_decode_rate(FFmpegIndexBuilderContext *context,
+ const double time_period)
+{
+ AVFrame *in_frame = av_frame_alloc();
+ AVPacket *packet = av_packet_alloc();
+
+ const double start = PIL_check_seconds_timer();
+ int frames_decoded = 0;
+
+ while (av_read_frame(context->iFormatCtx, packet) >= 0) {
+ if (packet->stream_index != context->videoStream) {
+ continue;
+ }
+
+ int ret = avcodec_send_packet(context->iCodecCtx, packet);
+ while (ret >= 0) {
+ ret = avcodec_receive_frame(context->iCodecCtx, in_frame);
+
+ if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
+ break;
+ }
+
+ if (ret < 0) {
+ fprintf(stderr, "Error decoding proxy frame: %s\n", av_err2str(ret));
+ break;
+ }
+ frames_decoded++;
+ }
+
+ const double end = PIL_check_seconds_timer();
+
+ if (end > start + time_period) {
+ break;
+ }
+ }
+
+ avcodec_flush_buffers(context->iCodecCtx);
+ av_seek_frame(context->iFormatCtx, -1, 0, AVSEEK_FLAG_BACKWARD);
+ return frames_decoded;
+}
+
+/* Read up to 10k movie packets and return max GOP size detected.
+ * Number of packets is arbitrary. It should be as large as possible, but processed within
+ * reasonable time period, so detected GOP size is as close to real as possible. */
+static int indexer_performance_get_max_gop_size(FFmpegIndexBuilderContext *context)
+{
+ AVPacket *packet = av_packet_alloc();
+
+ const int packets_max = 10000;
+ int packet_index = 0;
+ int max_gop = 0;
+ int cur_gop = 0;
+
+ while (av_read_frame(context->iFormatCtx, packet) >= 0) {
+ if (packet->stream_index != context->videoStream) {
+ continue;
+ }
+ packet_index++;
+ cur_gop++;
+
+ if (packet->flags & AV_PKT_FLAG_KEY) {
+ max_gop = max_ii(max_gop, cur_gop);
+ cur_gop = 0;
+ }
+
+ if (packet_index > packets_max) {
+ break;
+ }
+ }
+
+ av_seek_frame(context->iFormatCtx, -1, 0, AVSEEK_FLAG_BACKWARD);
+ return max_gop;
+}
+
+/* Assess scrubbing performance of provided file. This function is not meant to be very exact.
+ * It compares number number of frames decoded in reasonable time with largest detected GOP size.
+ * Because seeking happens in single GOP, it means, that maximum seek time can be detected this
+ * way.
+ * Since proxies use GOP size of 10 frames, skip building if detected GOP size is less or
+ * equal.
+ */
+static bool indexer_need_to_build_proxy(FFmpegIndexBuilderContext *context)
+{
+ if (!context->build_only_on_bad_performance) {
+ return true;
+ }
+
+ /* Make sure, that file is not cold read. */
+ indexer_performance_get_decode_rate(context, 0.1);
+ /* Get decode rate per 100ms. This is arbitrary, but seems to be good baseline cadence of
+ * seeking. */
+ const int decode_rate = indexer_performance_get_decode_rate(context, 0.1);
+ const int max_gop_size = indexer_performance_get_max_gop_size(context);
+
+ if (max_gop_size <= 10 || max_gop_size < decode_rate) {
+ printf("Skipping proxy building for %s: Decoding performance is already good.\n",
+ context->iFormatCtx->url);
+ context->building_cancelled = true;
+ return false;
+ }
+
+ return true;
+}
+
#endif
/* ----------------------------------------------------------------------
@@ -1274,7 +1388,8 @@ IndexBuildContext *IMB_anim_index_rebuild_context(struct anim *anim,
IMB_Proxy_Size proxy_sizes_in_use,
int quality,
const bool overwrite,
- GSet *file_list)
+ GSet *file_list,
+ bool build_only_on_bad_performance)
{
IndexBuildContext *context = NULL;
IMB_Proxy_Size proxy_sizes_to_build = proxy_sizes_in_use;
@@ -1328,9 +1443,13 @@ IndexBuildContext *IMB_anim_index_rebuild_context(struct anim *anim,
switch (anim->curtype) {
#ifdef WITH_FFMPEG
case ANIM_FFMPEG:
- context = index_ffmpeg_create_context(anim, tcs_in_use, proxy_sizes_to_build, quality);
+ context = index_ffmpeg_create_context(
+ anim, tcs_in_use, proxy_sizes_to_build, quality, build_only_on_bad_performance);
break;
+#else
+ UNUSED_VARS(build_only_on_bad_performance);
#endif
+
#ifdef WITH_AVI
default:
context = index_fallback_create_context(anim, tcs_in_use, proxy_sizes_to_build, quality);
@@ -1358,7 +1477,9 @@ void IMB_anim_index_rebuild(struct IndexBuildContext *context,
switch (context->anim_type) {
#ifdef WITH_FFMPEG
case ANIM_FFMPEG:
- index_rebuild_ffmpeg((FFmpegIndexBuilderContext *)context, stop, do_update, progress);
+ if (indexer_need_to_build_proxy((FFmpegIndexBuilderContext *)context)) {
+ index_rebuild_ffmpeg((FFmpegIndexBuilderContext *)context, stop, do_update, progress);
+ }
break;
#endif
#ifdef WITH_AVI