ffmpeg: optimize ffmpeg_postprocess #116309

Merged
Aras Pranckevicius merged 4 commits from aras_p/blender:ffmpeg-threaded-decode-conv into main 2023-12-19 18:29:01 +01:00
3 changed files with 58 additions and 76 deletions
Showing only changes of commit 4647c80f52 - Show all commits

View File

@ -16,8 +16,11 @@
#include <libavcodec/avcodec.h> #include <libavcodec/avcodec.h>
#include <libavformat/avformat.h> #include <libavformat/avformat.h>
#include <libavutil/opt.h>
#include <libswscale/swscale.h> #include <libswscale/swscale.h>
#include "BLI_threads.h"
/* Check if our ffmpeg is new enough, avoids user complaints. /* Check if our ffmpeg is new enough, avoids user complaints.
* Minimum supported version is currently 3.2.0 which mean the following library versions: * Minimum supported version is currently 3.2.0 which mean the following library versions:
* libavutil > 55.30 * libavutil > 55.30
@ -47,11 +50,6 @@
# define FFMPEG_USE_OLD_CHANNEL_VARS # define FFMPEG_USE_OLD_CHANNEL_VARS
#endif #endif
/* Threaded sws_scale_frame was added in ffmpeg 5.0 (swscale version 6.1). */
#if (LIBSWSCALE_VERSION_INT >= AV_VERSION_INT(6, 1, 100))
# define FFMPEG_SWSCALE_THREADING
#endif
/* AV_CODEC_CAP_AUTO_THREADS was renamed to AV_CODEC_CAP_OTHER_THREADS with /* AV_CODEC_CAP_AUTO_THREADS was renamed to AV_CODEC_CAP_OTHER_THREADS with
* upstream commit * upstream commit
* github.com/FFmpeg/FFmpeg/commit/7d09579190def3ef7562399489e628f3b65714ce * github.com/FFmpeg/FFmpeg/commit/7d09579190def3ef7562399489e628f3b65714ce
@ -141,6 +139,51 @@ int64_t av_get_frame_duration_in_pts_units(const AVFrame *picture)
#endif #endif
} }
/* Threaded sws_scale_frame was added in ffmpeg 5.0 (swscale version 6.1). */
#if (LIBSWSCALE_VERSION_INT >= AV_VERSION_INT(6, 1, 100))
# define FFMPEG_SWSCALE_THREADING
#endif
FFMPEG_INLINE SwsContext *sws_getContext_threaded(
int width, int height, AVPixelFormat src_format, AVPixelFormat dst_format, int sws_flags)
{
#if defined(FFMPEG_SWSCALE_THREADING)
/* sws_getContext does not allow passing flags that ask for multi-threaded
* scaling context, so do it the hard way. */
SwsContext *c = sws_alloc_context();
if (c == nullptr) {
return nullptr;
}
av_opt_set_int(c, "srcw", width, 0);
av_opt_set_int(c, "srch", height, 0);
av_opt_set_int(c, "src_format", src_format, 0);
av_opt_set_int(c, "dstw", width, 0);
av_opt_set_int(c, "dsth", height, 0);
av_opt_set_int(c, "dst_format", dst_format, 0);
av_opt_set_int(c, "sws_flags", sws_flags, 0);
av_opt_set_int(c, "threads", BLI_system_thread_count(), 0);
if (sws_init_context(c, nullptr, nullptr) < 0) {
sws_freeContext(c);
return nullptr;
}
#else
SwsContext *c = sws_getContext(
width, height, src_format, width, height, dst_format, sws_flags, nullptr, nullptr, nullptr);
#endif
return c;
}
FFMPEG_INLINE void sws_scale_frame_threaded(SwsContext *ctx, AVFrame *dst, const AVFrame *src)
{
#if defined(FFMPEG_SWSCALE_THREADING)
sws_scale_frame(ctx, dst, src);
#else
sws_scale(ctx, src->data, src->linesize, 0, src->height, dst->data, dst->linesize);
#endif
}
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
/** \name Deinterlace code block /** \name Deinterlace code block
* *

View File

@ -420,17 +420,7 @@ static AVFrame *generate_video_frame(FFMpegContext *context, const uint8_t *pixe
/* Convert to the output pixel format, if it's different that Blender's internal one. */ /* Convert to the output pixel format, if it's different that Blender's internal one. */
if (context->img_convert_frame != nullptr) { if (context->img_convert_frame != nullptr) {
BLI_assert(context->img_convert_ctx != NULL); BLI_assert(context->img_convert_ctx != NULL);
# if defined(FFMPEG_SWSCALE_THREADING) sws_scale_frame_threaded(context->img_convert_ctx, context->current_frame, rgb_frame);
sws_scale_frame(context->img_convert_ctx, context->current_frame, rgb_frame);
# else
sws_scale(context->img_convert_ctx,
(const uint8_t *const *)rgb_frame->data,
rgb_frame->linesize,
0,
codec->height,
context->current_frame->data,
context->current_frame->linesize);
# endif
} }
return context->current_frame; return context->current_frame;
@ -677,47 +667,6 @@ static const AVCodec *get_av1_encoder(
return codec; return codec;
} }
static SwsContext *get_threaded_sws_context(int width,
int height,
AVPixelFormat src_format,
AVPixelFormat dst_format)
{
# if defined(FFMPEG_SWSCALE_THREADING)
/* sws_getContext does not allow passing flags that ask for multi-threaded
* scaling context, so do it the hard way. */
SwsContext *c = sws_alloc_context();
if (c == nullptr) {
return nullptr;
}
av_opt_set_int(c, "srcw", width, 0);
av_opt_set_int(c, "srch", height, 0);
av_opt_set_int(c, "src_format", src_format, 0);
av_opt_set_int(c, "dstw", width, 0);
av_opt_set_int(c, "dsth", height, 0);
av_opt_set_int(c, "dst_format", dst_format, 0);
av_opt_set_int(c, "sws_flags", SWS_BICUBIC, 0);
av_opt_set_int(c, "threads", BLI_system_thread_count(), 0);
if (sws_init_context(c, nullptr, nullptr) < 0) {
sws_freeContext(c);
return nullptr;
}
# else
SwsContext *c = sws_getContext(width,
height,
src_format,
width,
height,
dst_format,
SWS_BICUBIC,
nullptr,
nullptr,
nullptr);
# endif
return c;
}
/* prepare a video stream for the output file */ /* prepare a video stream for the output file */
static AVStream *alloc_video_stream(FFMpegContext *context, static AVStream *alloc_video_stream(FFMpegContext *context,
@ -955,8 +904,8 @@ static AVStream *alloc_video_stream(FFMpegContext *context,
else { else {
/* Output pixel format is different, allocate frame for conversion. */ /* Output pixel format is different, allocate frame for conversion. */
context->img_convert_frame = alloc_picture(AV_PIX_FMT_RGBA, c->width, c->height); context->img_convert_frame = alloc_picture(AV_PIX_FMT_RGBA, c->width, c->height);
context->img_convert_ctx = get_threaded_sws_context( context->img_convert_ctx = sws_getContext_threaded(
c->width, c->height, AV_PIX_FMT_RGBA, c->pix_fmt); c->width, c->height, AV_PIX_FMT_RGBA, c->pix_fmt, SWS_BICUBIC);
} }
avcodec_parameters_from_context(st->codecpar, c); avcodec_parameters_from_context(st->codecpar, c);

View File

@ -694,16 +694,12 @@ static int startffmpeg(anim *anim)
1); 1);
} }
anim->img_convert_ctx = sws_getContext(anim->x, anim->img_convert_ctx = sws_getContext_threaded(anim->x,
anim->y, anim->y,
anim->pCodecCtx->pix_fmt, anim->pCodecCtx->pix_fmt,
anim->x, AV_PIX_FMT_RGBA,
anim->y, SWS_BILINEAR | SWS_PRINT_INFO |
AV_PIX_FMT_RGBA, SWS_FULL_CHR_H_INT);
SWS_BILINEAR | SWS_PRINT_INFO | SWS_FULL_CHR_H_INT,
nullptr,
nullptr,
nullptr);
if (!anim->img_convert_ctx) { if (!anim->img_convert_ctx) {
fprintf(stderr, "Can't transform color space??? Bailing out...\n"); fprintf(stderr, "Can't transform color space??? Bailing out...\n");
@ -846,13 +842,7 @@ static void ffmpeg_postprocess(anim *anim, AVFrame *input, ImBuf *ibuf)
} }
} }
sws_scale(anim->img_convert_ctx, sws_scale_frame_threaded(anim->img_convert_ctx, anim->pFrameRGB, input);
(const uint8_t *const *)input->data,
input->linesize,
0,
anim->y,
anim->pFrameRGB->data,
anim->pFrameRGB->linesize);
/* Copy the valid bytes from the aligned buffer vertically flipped into ImBuf */ /* Copy the valid bytes from the aligned buffer vertically flipped into ImBuf */
int aligned_stride = anim->pFrameRGB->linesize[0]; int aligned_stride = anim->pFrameRGB->linesize[0];