History

sws: implement slice threading

Anton Khirnov committed 5 years ago

Commit d6fdc781 parent 22c6fbc5 files · +162 −0Browse files

Unified · Split

5 files
  1. Changelog +1 −0
  2. libswscale/options.c +3 −0
  3. libswscale/swscale.c +59 −0
  4. libswscale/swscale_internal.h +14 −0
  5. libswscale/utils.c +85 −0
Changelog+1−0
@@ -16,6 +16,7 @@ version <next>: · 15 unmodified lines
16- atilt audio filter16- atilt audio filter
17- grayworld video filter17- grayworld video filter
18- AV1 Low overhead bitstream format muxer18- AV1 Low overhead bitstream format muxer
19- swscale slice threading
19 20
20 21
21version 4.4:22version 4.4:
libswscale/options.c+3−0
@@ -81,6 +81,9 @@ static const AVOption swscale_options[] = { · 80 unmodified lines
81 { "uniform_color", "blend onto a uniform color", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_ALPHA_BLEND_UNIFORM},INT_MIN, INT_MAX, VE, "alphablend" },81 { "uniform_color", "blend onto a uniform color", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_ALPHA_BLEND_UNIFORM},INT_MIN, INT_MAX, VE, "alphablend" },
82 { "checkerboard", "blend onto a checkerboard", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_ALPHA_BLEND_CHECKERBOARD},INT_MIN, INT_MAX, VE, "alphablend" },82 { "checkerboard", "blend onto a checkerboard", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_ALPHA_BLEND_CHECKERBOARD},INT_MIN, INT_MAX, VE, "alphablend" },
83 83
84 { "threads", "number of threads", OFFSET(nb_threads), AV_OPT_TYPE_INT, {.i64 = 1 }, 0, INT_MAX, VE, "threads" },
85 { "auto", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, .flags = VE, "threads" },
86
84 { NULL }87 { NULL }
85};88};
86 89
libswscale/swscale.c+59−0
@@ -1113,6 +1113,9 @@ int sws_send_slice(struct SwsContext *c, unsigned int slice_start, · 1112 unmodified lines
1113 1113
1114unsigned int sws_receive_slice_alignment(const struct SwsContext *c)1114unsigned int sws_receive_slice_alignment(const struct SwsContext *c)
1115{1115{
1116 if (c->slice_ctx)
1117 return c->slice_ctx[0]->dst_slice_align;
1118
1116 return c->dst_slice_align;1119 return c->dst_slice_align;
1117}1120}
1118 1121
@@ -1136,6 +1139,27 @@ int sws_receive_slice(struct SwsContext *c, unsigned int slice_start, · 17 unmodified lines
1136 return AVERROR(EINVAL);1139 return AVERROR(EINVAL);
1137 }1140 }
1138 1141
1142 if (c->slicethread) {
1143 int nb_jobs = c->slice_ctx[0]->dither == SWS_DITHER_ED ? 1 : c->nb_slice_ctx;
1144 int ret = 0;
1145
1146 c->dst_slice_start = slice_start;
1147 c->dst_slice_height = slice_height;
1148
1149 avpriv_slicethread_execute(c->slicethread, nb_jobs, 0);
1150
1151 for (int i = 0; i < c->nb_slice_ctx; i++) {
1152 if (c->slice_err[i] < 0) {
1153 ret = c->slice_err[i];
1154 break;
1155 }
1156 }
1157
1158 memset(c->slice_err, 0, c->nb_slice_ctx * sizeof(*c->slice_err));
1159
1160 return ret;
1161 }
1162
1139 for (int i = 0; i < FF_ARRAY_ELEMS(dst) && c->frame_dst->data[i]; i++) {1163 for (int i = 0; i < FF_ARRAY_ELEMS(dst) && c->frame_dst->data[i]; i++) {
1140 dst[i] = c->frame_dst->data[i] +1164 dst[i] = c->frame_dst->data[i] +
1141 c->frame_dst->linesize[i] * (slice_start >> c->chrDstVSubSample);1165 c->frame_dst->linesize[i] * (slice_start >> c->chrDstVSubSample);
@@ -1173,6 +1197,41 @@ int attribute_align_arg sws_scale(struct SwsContext *c, · 31 unmodified lines
1173 int srcSliceH, uint8_t *const dst[],1197 int srcSliceH, uint8_t *const dst[],
1174 const int dstStride[])1198 const int dstStride[])
1175{1199{
1200 if (c->nb_slice_ctx)
1201 c = c->slice_ctx[0];
1202
1176 return scale_internal(c, srcSlice, srcStride, srcSliceY, srcSliceH,1203 return scale_internal(c, srcSlice, srcStride, srcSliceY, srcSliceH,
1177 dst, dstStride, 0, c->dstH);1204 dst, dstStride, 0, c->dstH);
1178}1205}
1206
1207void ff_sws_slice_worker(void *priv, int jobnr, int threadnr,
1208 int nb_jobs, int nb_threads)
1209{
1210 SwsContext *parent = priv;
1211 SwsContext *c = parent->slice_ctx[threadnr];
1212
1213 const int slice_height = FFALIGN(FFMAX((parent->dst_slice_height + nb_jobs - 1) / nb_jobs, 1),
1214 c->dst_slice_align);
1215 const int slice_start = jobnr * slice_height;
1216 const int slice_end = FFMIN((jobnr + 1) * slice_height, parent->dst_slice_height);
1217 int err = 0;
1218
1219 if (slice_end > slice_start) {
1220 uint8_t *dst[4] = { NULL };
1221
1222 for (int i = 0; i < FF_ARRAY_ELEMS(dst) && parent->frame_dst->data[i]; i++) {
1223 const int vshift = (i == 1 || i == 2) ? c->chrDstVSubSample : 0;
1224 const ptrdiff_t offset = parent->frame_dst->linesize[i] *
1225 ((slice_start + parent->dst_slice_start) >> vshift);
1226
1227 dst[i] = parent->frame_dst->data[i] + offset;
1228 }
1229
1230 err = scale_internal(c, (const uint8_t * const *)parent->frame_src->data,
1231 parent->frame_src->linesize, 0, c->srcH,
1232 dst, parent->frame_dst->linesize,
1233 parent->dst_slice_start + slice_start, slice_end - slice_start);
1234 }
1235
1236 parent->slice_err[threadnr] = err;
1237}
libswscale/swscale_internal.h+14−0
@@ -33,6 +33,7 @@ · 32 unmodified lines
33#include "libavutil/mem_internal.h"33#include "libavutil/mem_internal.h"
34#include "libavutil/pixfmt.h"34#include "libavutil/pixfmt.h"
35#include "libavutil/pixdesc.h"35#include "libavutil/pixdesc.h"
36#include "libavutil/slicethread.h"
36#include "libavutil/ppc/util_altivec.h"37#include "libavutil/ppc/util_altivec.h"
37 38
38#define STR(s) AV_TOSTRING(s) // AV_STRINGIFY is too long39#define STR(s) AV_TOSTRING(s) // AV_STRINGIFY is too long
@@ -300,6 +301,15 @@ typedef struct SwsContext { · 261 unmodified lines
300 */301 */
301 const AVClass *av_class;302 const AVClass *av_class;
302 303
304 AVSliceThread *slicethread;
305 struct SwsContext **slice_ctx;
306 int *slice_err;
307 int nb_slice_ctx;
308
309 // values passed to current sws_receive_slice() call
310 unsigned int dst_slice_start;
311 unsigned int dst_slice_height;
312
303 /**313 /**
304 * Note that src, dst, srcStride, dstStride will be copied in the314 * Note that src, dst, srcStride, dstStride will be copied in the
305 * sws_scale() wrapper so they can be freely modified here.315 * sws_scale() wrapper so they can be freely modified here.
@@ -325,6 +335,7 @@ typedef struct SwsContext { · 19 unmodified lines
325 int chrDstVSubSample; ///< Binary logarithm of vertical subsampling factor between luma/alpha and chroma planes in destination image.335 int chrDstVSubSample; ///< Binary logarithm of vertical subsampling factor between luma/alpha and chroma planes in destination image.
326 int vChrDrop; ///< Binary logarithm of extra vertical subsampling factor in source image chroma planes specified by user.336 int vChrDrop; ///< Binary logarithm of extra vertical subsampling factor in source image chroma planes specified by user.
327 int sliceDir; ///< Direction that slices are fed to the scaler (1 = top-to-bottom, -1 = bottom-to-top).337 int sliceDir; ///< Direction that slices are fed to the scaler (1 = top-to-bottom, -1 = bottom-to-top).
338 int nb_threads; ///< Number of threads used for scaling
328 double param[2]; ///< Input parameters for scaling algorithms that need them.339 double param[2]; ///< Input parameters for scaling algorithms that need them.
329 340
330 AVFrame *frame_src;341 AVFrame *frame_src;
@@ -1082,6 +1093,9 @@ void ff_init_vscale_pfn(SwsContext *c, yuv2planar1_fn yuv2plane1, yuv2planarX_fn · 751 unmodified lines
1082 yuv2interleavedX_fn yuv2nv12cX, yuv2packed1_fn yuv2packed1, yuv2packed2_fn yuv2packed2,1093 yuv2interleavedX_fn yuv2nv12cX, yuv2packed1_fn yuv2packed1, yuv2packed2_fn yuv2packed2,
1083 yuv2packedX_fn yuv2packedX, yuv2anyX_fn yuv2anyX, int use_mmx);1094 yuv2packedX_fn yuv2packedX, yuv2anyX_fn yuv2anyX, int use_mmx);
1084 1095
1096void ff_sws_slice_worker(void *priv, int jobnr, int threadnr,
1097 int nb_jobs, int nb_threads);
1098
1085//number of extra lines to process1099//number of extra lines to process
1086#define MAX_LINES_AHEAD 41100#define MAX_LINES_AHEAD 4
1087 1101
libswscale/utils.c+85−0
@@ -49,6 +49,7 @@ · 48 unmodified lines
49#include "libavutil/mathematics.h"49#include "libavutil/mathematics.h"
50#include "libavutil/opt.h"50#include "libavutil/opt.h"
51#include "libavutil/pixdesc.h"51#include "libavutil/pixdesc.h"
52#include "libavutil/slicethread.h"
52#include "libavutil/thread.h"53#include "libavutil/thread.h"
53#include "libavutil/aarch64/cpu.h"54#include "libavutil/aarch64/cpu.h"
54#include "libavutil/ppc/cpu.h"55#include "libavutil/ppc/cpu.h"
@@ -871,6 +872,18 @@ int sws_setColorspaceDetails(struct SwsContext *c, const int inv_table[4], · 816 unmodified lines
871 const AVPixFmtDescriptor *desc_src;872 const AVPixFmtDescriptor *desc_src;
872 int need_reinit = 0;873 int need_reinit = 0;
873 874
875 if (c->nb_slice_ctx) {
876 for (int i = 0; i < c->nb_slice_ctx; i++) {
877 int ret = sws_setColorspaceDetails(c->slice_ctx[i], inv_table,
878 srcRange, table, dstRange,
879 brightness, contrast, saturation);
880 if (ret < 0)
881 return ret;
882 }
883
884 return 0;
885 }
886
874 handle_formats(c);887 handle_formats(c);
875 desc_dst = av_pix_fmt_desc_get(c->dstFormat);888 desc_dst = av_pix_fmt_desc_get(c->dstFormat);
876 desc_src = av_pix_fmt_desc_get(c->srcFormat);889 desc_src = av_pix_fmt_desc_get(c->srcFormat);
@@ -1005,6 +1018,12 @@ int sws_getColorspaceDetails(struct SwsContext *c, int **inv_table, · 128 unmodified lines
1005 if (!c )1018 if (!c )
1006 return -1;1019 return -1;
1007 1020
1021 if (c->nb_slice_ctx) {
1022 return sws_getColorspaceDetails(c->slice_ctx[0], inv_table, srcRange,
1023 table, dstRange, brightness, contrast,
1024 saturation);
1025 }
1026
1008 *inv_table = c->srcColorspaceTable;1027 *inv_table = c->srcColorspaceTable;
1009 *table = c->dstColorspaceTable;1028 *table = c->dstColorspaceTable;
1010 *srcRange = range_override_needed(c->srcFormat) ? 1 : c->srcRange;1029 *srcRange = range_override_needed(c->srcFormat) ? 1 : c->srcRange;
@@ -1170,6 +1189,58 @@ static enum AVPixelFormat alphaless_fmt(enum AVPixelFormat fmt) · 159 unmodified lines
1170 }1189 }
1171}1190}
1172 1191
1192static int context_init_threaded(SwsContext *c,
1193 SwsFilter *src_filter, SwsFilter *dst_filter)
1194{
1195 int ret;
1196
1197 ret = avpriv_slicethread_create(&c->slicethread, (void*)c,
1198 ff_sws_slice_worker, NULL, c->nb_threads);
1199 if (ret == AVERROR(ENOSYS)) {
1200 c->nb_threads = 1;
1201 return 0;
1202 } else if (ret < 0)
1203 return ret;
1204
1205 c->nb_threads = ret;
1206
1207 c->slice_ctx = av_mallocz_array(c->nb_threads, sizeof(*c->slice_ctx));
1208 c->slice_err = av_mallocz_array(c->nb_threads, sizeof(*c->slice_err));
1209 if (!c->slice_ctx || !c->slice_err)
1210 return AVERROR(ENOMEM);
1211
1212 for (int i = 0; i < c->nb_threads; i++) {
1213 c->slice_ctx[i] = sws_alloc_context();
1214 if (!c->slice_ctx[i])
1215 return AVERROR(ENOMEM);
1216
1217 ret = av_opt_copy((void*)c->slice_ctx[i], (void*)c);
1218 if (ret < 0)
1219 return ret;
1220
1221 c->slice_ctx[i]->nb_threads = 1;
1222
1223 ret = sws_init_context(c->slice_ctx[i], src_filter, dst_filter);
1224 if (ret < 0)
1225 return ret;
1226
1227 c->nb_slice_ctx++;
1228
1229 if (c->slice_ctx[i]->dither == SWS_DITHER_ED) {
1230 av_log(c, AV_LOG_VERBOSE,
1231 "Error-diffusion dither is in use, scaling will be single-threaded.");
1232 break;
1233 }
1234 }
1235
1236 c->frame_src = av_frame_alloc();
1237 c->frame_dst = av_frame_alloc();
1238 if (!c->frame_src || !c->frame_dst)
1239 return AVERROR(ENOMEM);
1240
1241 return 0;
1242}
1243
1173av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter,1244av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter,
1174 SwsFilter *dstFilter)1245 SwsFilter *dstFilter)
1175{1246{
@@ -1192,6 +1263,13 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter, · 16 unmodified lines
1192 static const float float_mult = 1.0f / 255.0f;1263 static const float float_mult = 1.0f / 255.0f;
1193 static AVOnce rgb2rgb_once = AV_ONCE_INIT;1264 static AVOnce rgb2rgb_once = AV_ONCE_INIT;
1194 1265
1266 if (c->nb_threads != 1) {
1267 ret = context_init_threaded(c, srcFilter, dstFilter);
1268 if (ret < 0 || c->nb_threads > 1)
1269 return ret;
1270 // threading disabled in this build, init as single-threaded
1271 }
1272
1195 cpu_flags = av_get_cpu_flags();1273 cpu_flags = av_get_cpu_flags();
1196 flags = c->flags;1274 flags = c->flags;
1197 emms_c();1275 emms_c();
@@ -2254,6 +2332,13 @@ void sws_freeContext(SwsContext *c) · 1056 unmodified lines
2254 if (!c)2332 if (!c)
2255 return;2333 return;
2256 2334
2335 for (i = 0; i < c->nb_slice_ctx; i++)
2336 sws_freeContext(c->slice_ctx[i]);
2337 av_freep(&c->slice_ctx);
2338 av_freep(&c->slice_err);
2339
2340 avpriv_slicethread_free(&c->slicethread);
2341
2257 for (i = 0; i < 4; i++)2342 for (i = 0; i < 4; i++)
2258 av_freep(&c->dither_error[i]);2343 av_freep(&c->dither_error[i]);
2259 2344

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t