ffmpeg: optimize ffmpeg_postprocess #116309
|
@ -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
|
||||||
*
|
*
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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];
|
||||||
|
|
Loading…
Reference in New Issue