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
1616 - atilt audio filter
1717 - grayworld video filter
1818 - AV1 Low overhead bitstream format muxer
19+- swscale slice threading
1920
2021
2122 version 4.4:
libswscale/options.c+3−0
@@ -81,6 +81,9 @@ static const AVOption swscale_options[] = { · 80 unmodified lines
8181 { "uniform_color", "blend onto a uniform color", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_ALPHA_BLEND_UNIFORM},INT_MIN, INT_MAX, VE, "alphablend" },
8282 { "checkerboard", "blend onto a checkerboard", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_ALPHA_BLEND_CHECKERBOARD},INT_MIN, INT_MAX, VE, "alphablend" },
8383
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+
8487 { NULL }
8588 };
8689
libswscale/swscale.c+59−0
@@ -1113,6 +1113,9 @@ int sws_send_slice(struct SwsContext *c, unsigned int slice_start, · 1112 unmodified lines
11131113
11141114 unsigned int sws_receive_slice_alignment(const struct SwsContext *c)
11151115 {
1116+ if (c->slice_ctx)
1117+ return c->slice_ctx[0]->dst_slice_align;
1118+
11161119 return c->dst_slice_align;
11171120 }
11181121
@@ -1136,6 +1139,27 @@ int sws_receive_slice(struct SwsContext *c, unsigned int slice_start, · 17 unmodified lines
11361139 return AVERROR(EINVAL);
11371140 }
11381141
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+
11391163 for (int i = 0; i < FF_ARRAY_ELEMS(dst) && c->frame_dst->data[i]; i++) {
11401164 dst[i] = c->frame_dst->data[i] +
11411165 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
11731197 int srcSliceH, uint8_t *const dst[],
11741198 const int dstStride[])
11751199 {
1200+ if (c->nb_slice_ctx)
1201+ c = c->slice_ctx[0];
1202+
11761203 return scale_internal(c, srcSlice, srcStride, srcSliceY, srcSliceH,
11771204 dst, dstStride, 0, c->dstH);
11781205 }
1206+
1207+void 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
3333 #include "libavutil/mem_internal.h"
3434 #include "libavutil/pixfmt.h"
3535 #include "libavutil/pixdesc.h"
36+#include "libavutil/slicethread.h"
3637 #include "libavutil/ppc/util_altivec.h"
3738
3839 #define STR(s) AV_TOSTRING(s) // AV_STRINGIFY is too long
@@ -300,6 +301,15 @@ typedef struct SwsContext { · 261 unmodified lines
300301 */
301302 const AVClass *av_class;
302303
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+
303313 /**
304314 * Note that src, dst, srcStride, dstStride will be copied in the
305315 * sws_scale() wrapper so they can be freely modified here.
@@ -325,6 +335,7 @@ typedef struct SwsContext { · 19 unmodified lines
325335 int chrDstVSubSample; ///< Binary logarithm of vertical subsampling factor between luma/alpha and chroma planes in destination image.
326336 int vChrDrop; ///< Binary logarithm of extra vertical subsampling factor in source image chroma planes specified by user.
327337 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
328339 double param[2]; ///< Input parameters for scaling algorithms that need them.
329340
330341 AVFrame *frame_src;
@@ -1082,6 +1093,9 @@ void ff_init_vscale_pfn(SwsContext *c, yuv2planar1_fn yuv2plane1, yuv2planarX_fn · 751 unmodified lines
10821093 yuv2interleavedX_fn yuv2nv12cX, yuv2packed1_fn yuv2packed1, yuv2packed2_fn yuv2packed2,
10831094 yuv2packedX_fn yuv2packedX, yuv2anyX_fn yuv2anyX, int use_mmx);
10841095
1096+void ff_sws_slice_worker(void *priv, int jobnr, int threadnr,
1097+ int nb_jobs, int nb_threads);
1098+
10851099 //number of extra lines to process
10861100 #define MAX_LINES_AHEAD 4
10871101
libswscale/utils.c+85−0
@@ -49,6 +49,7 @@ · 48 unmodified lines
4949 #include "libavutil/mathematics.h"
5050 #include "libavutil/opt.h"
5151 #include "libavutil/pixdesc.h"
52+#include "libavutil/slicethread.h"
5253 #include "libavutil/thread.h"
5354 #include "libavutil/aarch64/cpu.h"
5455 #include "libavutil/ppc/cpu.h"
@@ -871,6 +872,18 @@ int sws_setColorspaceDetails(struct SwsContext *c, const int inv_table[4], · 816 unmodified lines
871872 const AVPixFmtDescriptor *desc_src;
872873 int need_reinit = 0;
873874
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+
874887 handle_formats(c);
875888 desc_dst = av_pix_fmt_desc_get(c->dstFormat);
876889 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
10051018 if (!c )
10061019 return -1;
10071020
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+
10081027 *inv_table = c->srcColorspaceTable;
10091028 *table = c->dstColorspaceTable;
10101029 *srcRange = range_override_needed(c->srcFormat) ? 1 : c->srcRange;
@@ -1170,6 +1189,58 @@ static enum AVPixelFormat alphaless_fmt(enum AVPixelFormat fmt) · 159 unmodified lines
11701189 }
11711190 }
11721191
1192+static 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+
11731244 av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter,
11741245 SwsFilter *dstFilter)
11751246 {
@@ -1192,6 +1263,13 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter, · 16 unmodified lines
11921263 static const float float_mult = 1.0f / 255.0f;
11931264 static AVOnce rgb2rgb_once = AV_ONCE_INIT;
11941265
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+
11951273 cpu_flags = av_get_cpu_flags();
11961274 flags = c->flags;
11971275 emms_c();
@@ -2254,6 +2332,13 @@ void sws_freeContext(SwsContext *c) · 1056 unmodified lines
22542332 if (!c)
22552333 return;
22562334
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+
22572342 for (i = 0; i < 4; i++)
22582343 av_freep(&c->dither_error[i]);
22592344

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