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 <libavformat/avformat.h>
#include <libavutil/opt.h>
#include <libswscale/swscale.h>
#include "BLI_threads.h"
/* Check if our ffmpeg is new enough, avoids user complaints.
* Minimum supported version is currently 3.2.0 which mean the following library versions:
* libavutil > 55.30
@ -47,11 +50,6 @@
# define FFMPEG_USE_OLD_CHANNEL_VARS
#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
* upstream commit
* github.com/FFmpeg/FFmpeg/commit/7d09579190def3ef7562399489e628f3b65714ce
@ -141,6 +139,51 @@ int64_t av_get_frame_duration_in_pts_units(const AVFrame *picture)
#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
*

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. */
if (context->img_convert_frame != nullptr) {
BLI_assert(context->img_convert_ctx != NULL);
# if defined(FFMPEG_SWSCALE_THREADING)
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
sws_scale_frame_threaded(context->img_convert_ctx, context->current_frame, rgb_frame);
}
return context->current_frame;
@ -677,47 +667,6 @@ static const AVCodec *get_av1_encoder(
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 */
static AVStream *alloc_video_stream(FFMpegContext *context,
@ -955,8 +904,8 @@ static AVStream *alloc_video_stream(FFMpegContext *context,
else {
/* 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_ctx = get_threaded_sws_context(
c->width, c->height, AV_PIX_FMT_RGBA, c->pix_fmt);
context->img_convert_ctx = sws_getContext_threaded(
c->width, c->height, AV_PIX_FMT_RGBA, c->pix_fmt, SWS_BICUBIC);
}
avcodec_parameters_from_context(st->codecpar, c);

View File

@ -694,16 +694,12 @@ static int startffmpeg(anim *anim)
1);
}
anim->img_convert_ctx = sws_getContext(anim->x,
anim->y,
anim->pCodecCtx->pix_fmt,
anim->x,
anim->y,
AV_PIX_FMT_RGBA,
SWS_BILINEAR | SWS_PRINT_INFO | SWS_FULL_CHR_H_INT,
nullptr,
nullptr,
nullptr);
anim->img_convert_ctx = sws_getContext_threaded(anim->x,
anim->y,
anim->pCodecCtx->pix_fmt,
AV_PIX_FMT_RGBA,
SWS_BILINEAR | SWS_PRINT_INFO |
SWS_FULL_CHR_H_INT);
if (!anim->img_convert_ctx) {
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,
(const uint8_t *const *)input->data,
input->linesize,
0,
anim->y,
anim->pFrameRGB->data,
anim->pFrameRGB->linesize);
sws_scale_frame_threaded(anim->img_convert_ctx, anim->pFrameRGB, input);
/* Copy the valid bytes from the aligned buffer vertically flipped into ImBuf */
int aligned_stride = anim->pFrameRGB->linesize[0];