Unified · Split
| @@ -16,6 +16,7 @@ version <next>: · 15 unmodified lines | |||
| 16 | - atilt audio filter | 16 | - atilt audio filter |
| 17 | - grayworld video filter | 17 | - grayworld video filter |
| 18 | - AV1 Low overhead bitstream format muxer | 18 | - AV1 Low overhead bitstream format muxer |
| 19 | - swscale slice threading | ||
| 19 | 20 | ||
| 20 | 21 | ||
| 21 | version 4.4: | 22 | version 4.4: |
| @@ -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 | ||
| @@ -1113,6 +1113,9 @@ int sws_send_slice(struct SwsContext *c, unsigned int slice_start, · 1112 unmodified lines | |||
| 1113 | 1113 | ||
| 1114 | unsigned int sws_receive_slice_alignment(const struct SwsContext *c) | 1114 | unsigned 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 | |||
| 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 | } | ||
| @@ -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 long | 39 | #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 the | 314 | * 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 | ||
| 1096 | void ff_sws_slice_worker(void *priv, int jobnr, int threadnr, | ||
| 1097 | int nb_jobs, int nb_threads); | ||
| 1098 | |||
| 1085 | //number of extra lines to process | 1099 | //number of extra lines to process |
| 1086 | #define MAX_LINES_AHEAD 4 | 1100 | #define MAX_LINES_AHEAD 4 |
| 1087 | 1101 | ||
| @@ -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 | ||
| 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 | |||
| 1173 | av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter, | 1244 | av_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 | ||