summaryrefslogtreecommitdiff
path: root/libswscale/utils.c
diff options
context:
space:
mode:
authorAnton Khirnov <anton@khirnov.net>2021-07-12 12:31:14 +0200
committerAnton Khirnov <anton@khirnov.net>2021-09-06 09:17:53 +0200
commitd6fdc78e9164c8e6bf7bfc7766932c467b874aa2 (patch)
treedd3ba9ef975f1838ede89d9c693f86d079878600 /libswscale/utils.c
parent22c6fbc8475f99b67ded526ace496cdd5362074b (diff)
downloadffmpeg-d6fdc78e9164c8e6bf7bfc7766932c467b874aa2.tar.gz
sws: implement slice threading
Diffstat (limited to 'libswscale/utils.c')
-rw-r--r--libswscale/utils.c85
1 files changed, 85 insertions, 0 deletions
diff --git a/libswscale/utils.c b/libswscale/utils.c
index 235a846809..25051ead72 100644
--- a/libswscale/utils.c
+++ b/libswscale/utils.c
@@ -49,6 +49,7 @@
#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
#include "libavutil/pixdesc.h"
+#include "libavutil/slicethread.h"
#include "libavutil/thread.h"
#include "libavutil/aarch64/cpu.h"
#include "libavutil/ppc/cpu.h"
@@ -871,6 +872,18 @@ int sws_setColorspaceDetails(struct SwsContext *c, const int inv_table[4],
const AVPixFmtDescriptor *desc_src;
int need_reinit = 0;
+ if (c->nb_slice_ctx) {
+ for (int i = 0; i < c->nb_slice_ctx; i++) {
+ int ret = sws_setColorspaceDetails(c->slice_ctx[i], inv_table,
+ srcRange, table, dstRange,
+ brightness, contrast, saturation);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+ }
+
handle_formats(c);
desc_dst = av_pix_fmt_desc_get(c->dstFormat);
desc_src = av_pix_fmt_desc_get(c->srcFormat);
@@ -1005,6 +1018,12 @@ int sws_getColorspaceDetails(struct SwsContext *c, int **inv_table,
if (!c )
return -1;
+ if (c->nb_slice_ctx) {
+ return sws_getColorspaceDetails(c->slice_ctx[0], inv_table, srcRange,
+ table, dstRange, brightness, contrast,
+ saturation);
+ }
+
*inv_table = c->srcColorspaceTable;
*table = c->dstColorspaceTable;
*srcRange = range_override_needed(c->srcFormat) ? 1 : c->srcRange;
@@ -1170,6 +1189,58 @@ static enum AVPixelFormat alphaless_fmt(enum AVPixelFormat fmt)
}
}
+static int context_init_threaded(SwsContext *c,
+ SwsFilter *src_filter, SwsFilter *dst_filter)
+{
+ int ret;
+
+ ret = avpriv_slicethread_create(&c->slicethread, (void*)c,
+ ff_sws_slice_worker, NULL, c->nb_threads);
+ if (ret == AVERROR(ENOSYS)) {
+ c->nb_threads = 1;
+ return 0;
+ } else if (ret < 0)
+ return ret;
+
+ c->nb_threads = ret;
+
+ c->slice_ctx = av_mallocz_array(c->nb_threads, sizeof(*c->slice_ctx));
+ c->slice_err = av_mallocz_array(c->nb_threads, sizeof(*c->slice_err));
+ if (!c->slice_ctx || !c->slice_err)
+ return AVERROR(ENOMEM);
+
+ for (int i = 0; i < c->nb_threads; i++) {
+ c->slice_ctx[i] = sws_alloc_context();
+ if (!c->slice_ctx[i])
+ return AVERROR(ENOMEM);
+
+ ret = av_opt_copy((void*)c->slice_ctx[i], (void*)c);
+ if (ret < 0)
+ return ret;
+
+ c->slice_ctx[i]->nb_threads = 1;
+
+ ret = sws_init_context(c->slice_ctx[i], src_filter, dst_filter);
+ if (ret < 0)
+ return ret;
+
+ c->nb_slice_ctx++;
+
+ if (c->slice_ctx[i]->dither == SWS_DITHER_ED) {
+ av_log(c, AV_LOG_VERBOSE,
+ "Error-diffusion dither is in use, scaling will be single-threaded.");
+ break;
+ }
+ }
+
+ c->frame_src = av_frame_alloc();
+ c->frame_dst = av_frame_alloc();
+ if (!c->frame_src || !c->frame_dst)
+ return AVERROR(ENOMEM);
+
+ return 0;
+}
+
av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter,
SwsFilter *dstFilter)
{
@@ -1192,6 +1263,13 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter,
static const float float_mult = 1.0f / 255.0f;
static AVOnce rgb2rgb_once = AV_ONCE_INIT;
+ if (c->nb_threads != 1) {
+ ret = context_init_threaded(c, srcFilter, dstFilter);
+ if (ret < 0 || c->nb_threads > 1)
+ return ret;
+ // threading disabled in this build, init as single-threaded
+ }
+
cpu_flags = av_get_cpu_flags();
flags = c->flags;
emms_c();
@@ -2254,6 +2332,13 @@ void sws_freeContext(SwsContext *c)
if (!c)
return;
+ for (i = 0; i < c->nb_slice_ctx; i++)
+ sws_freeContext(c->slice_ctx[i]);
+ av_freep(&c->slice_ctx);
+ av_freep(&c->slice_err);
+
+ avpriv_slicethread_free(&c->slicethread);
+
for (i = 0; i < 4; i++)
av_freep(&c->dither_error[i]);