+struct thread_data {
+ const uint8_t *srcrow;
+ uint8_t *dstrow;
+ int dst_linesize;
+ int src_linesize;
+
+ double coeff;
+ uint8_t offset;
+
+ int h;
+
+ int imin;
+ int omin;
+};
+
+#define LOAD_COMMON\
+ ColorLevelsContext *s = ctx->priv;\
+ const struct thread_data *td = arg;\
+\
+ int process_h = td->h;\
+ const int slice_start = (process_h * jobnr ) / nb_jobs;\
+ const int slice_end = (process_h * (jobnr+1)) / nb_jobs;\
+ int x, y;\
+ const uint8_t *srcrow = td->srcrow;\
+ uint8_t *dstrow = td->dstrow;\
+ const int step = s->step;\
+ const uint8_t offset = td->offset;\
+\
+ int imin = td->imin;\
+ int omin = td->omin;\
+ double coeff = td->coeff;\
+
+static int colorlevel_slice_8(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
+{
+ LOAD_COMMON
+
+ for (y = slice_start; y < slice_end; y++) {
+ const uint8_t *src = srcrow + y * td->src_linesize;
+ uint8_t *dst = dstrow + y * td->dst_linesize;
+
+ for (x = 0; x < s->linesize; x += step)
+ dst[x + offset] = av_clip_uint8((src[x + offset] - imin) * coeff + omin);
+ }
+
+ return 0;
+}
+
+static int colorlevel_slice_16(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
+{
+ LOAD_COMMON
+
+ for (y = slice_start; y < slice_end; y++) {
+ const uint16_t *src = (const uint16_t *)(srcrow + y * td->src_linesize);
+ uint16_t *dst = (uint16_t *)(dstrow + y * td->dst_linesize);
+
+ for (x = 0; x < s->linesize; x += step)
+ dst[x + offset] = av_clip_uint16((src[x + offset] - imin) * coeff + omin);
+ }
+
+ return 0;
+}
+