From e4f347783320d83e43bc650020013e19b2f22c7f Mon Sep 17 00:00:00 2001 From: Richard Antalik Date: Tue, 16 Mar 2021 18:37:23 +0100 Subject: FFmpeg: Improve proxy building performance Use h264 codec for output. This codec produces smaller files, can be multithreaded and decodes even faster than MJPEG. Quality setting 0-100 corresponds to "Lowest Quality" to "Perceptually Lossless" in Blender's h264 encoding presets. All available cores are used for decoding. Same goes for decoding but only for codecs that supports this (h264, vp9 seems to support this option out of th box as well). Other decoders can probably be optimized in similar way, but threaded encoding provides significant boost already. I have tested variety of codecs, and all were transcoded properly. Reviewed By: sergey, fsiddi Differential Revision: https://developer.blender.org/D10731 --- source/blender/imbuf/intern/indexer.c | 37 ++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c index c9581c108c0..edaa1b973d0 100644 --- a/source/blender/imbuf/intern/indexer.c +++ b/source/blender/imbuf/intern/indexer.c @@ -27,6 +27,7 @@ #include "BLI_endian_switch.h" #include "BLI_fileops.h" #include "BLI_ghash.h" +#include "BLI_math.h" #include "BLI_path_util.h" #include "BLI_string.h" #include "BLI_threads.h" @@ -477,7 +478,6 @@ static struct proxy_output_ctx *alloc_proxy_output_ffmpeg( struct proxy_output_ctx *rv = MEM_callocN(sizeof(struct proxy_output_ctx), "alloc_proxy_output"); char fname[FILE_MAX]; - int ffmpeg_quality; rv->proxy_size = proxy_size; rv->anim = anim; @@ -496,12 +496,15 @@ static struct proxy_output_ctx *alloc_proxy_output_ffmpeg( rv->st->id = 0; rv->c = rv->st->codec; - rv->c->thread_count = BLI_system_thread_count(); - rv->c->thread_type = FF_THREAD_SLICE; rv->c->codec_type = AVMEDIA_TYPE_VIDEO; - rv->c->codec_id = AV_CODEC_ID_MJPEG; + rv->c->codec_id = AV_CODEC_ID_H264; rv->c->width = width; rv->c->height = height; + rv->c->gop_size = 2; + rv->c->max_b_frames = 0; + /* Correct wrong default ffmpeg param which crash x264. */ + rv->c->qmin = 10; + rv->c->qmax = 51; rv->of->oformat->video_codec = rv->c->codec_id; rv->codec = avcodec_find_encoder(rv->c->codec_id); @@ -527,11 +530,19 @@ static struct proxy_output_ctx *alloc_proxy_output_ffmpeg( rv->c->time_base.num = 1; rv->st->time_base = rv->c->time_base; - /* there's no way to set JPEG quality in the same way as in AVI JPEG and image sequence, - * but this seems to be giving expected quality result */ - ffmpeg_quality = (int)(1.0f + 30.0f * (1.0f - (float)quality / 100.0f) + 0.5f); - av_opt_set_int(rv->c, "qmin", ffmpeg_quality, 0); - av_opt_set_int(rv->c, "qmax", ffmpeg_quality, 0); + /* This range matches eFFMpegCrf. Crf_range_min corresponds to lowest quality, crf_range_max to + * highest quality. */ + const int crf_range_min = 32; + const int crf_range_max = 17; + int crf = round_fl_to_int((quality / 100.0f) * (crf_range_max - crf_range_min) + crf_range_min); + + AVDictionary *codec_opts = NULL; + /* High quality preset value. */ + av_dict_set_int(&codec_opts, "crf", crf, 0); + /* Prefer smaller filesize. */ + av_dict_set(&codec_opts, "preset", "slow", 0); + /* Thread count. */ + av_dict_set_int(&codec_opts, "threads", BLI_system_thread_count(), 0); if (rv->of->flags & AVFMT_GLOBALHEADER) { rv->c->flags |= CODEC_FLAG_GLOBAL_HEADER; @@ -545,7 +556,7 @@ static struct proxy_output_ctx *alloc_proxy_output_ffmpeg( return 0; } - avcodec_open2(rv->c, rv->codec, NULL); + avcodec_open2(rv->c, rv->codec, &codec_opts); rv->orig_height = av_get_cropped_height_from_codec(st->codec); @@ -783,7 +794,11 @@ static IndexBuildContext *index_ffmpeg_create_context(struct anim *anim, context->iCodecCtx->workaround_bugs = 1; - if (avcodec_open2(context->iCodecCtx, context->iCodec, NULL) < 0) { + AVDictionary *codec_opts = NULL; + /* Thread count. */ + av_dict_set_int(&codec_opts, "threads", BLI_system_thread_count(), 0); + + if (avcodec_open2(context->iCodecCtx, context->iCodec, &codec_opts) < 0) { avformat_close_input(&context->iFormatCtx); MEM_freeN(context); return NULL; -- cgit v1.2.3