avfilter/curves: support slice threading.
authorClément Bœsch <u@pkh.me>
Thu, 13 Feb 2014 13:34:58 +0000 (14:34 +0100)
committerClément Bœsch <u@pkh.me>
Thu, 13 Feb 2014 13:35:10 +0000 (14:35 +0100)
libavfilter/vf_curves.c

index 5123430..93799b0 100644 (file)
@@ -69,6 +69,10 @@ typedef struct {
     int step;
 } CurvesContext;
 
+typedef struct ThreadData {
+    AVFrame *in, *out;
+} ThreadData;
+
 #define OFFSET(x) offsetof(CurvesContext, x)
 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
 static const AVOption curves_options[] = {
@@ -473,23 +477,46 @@ static int config_input(AVFilterLink *inlink)
     return 0;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
 {
-    int x, y, direct = 0;
-    AVFilterContext *ctx = inlink->dst;
-    CurvesContext *curves = ctx->priv;
-    AVFilterLink *outlink = ctx->outputs[0];
-    AVFrame *out;
-    uint8_t *dst;
-    const uint8_t *src;
+    int x, y;
+    const CurvesContext *curves = ctx->priv;
+    const ThreadData *td = arg;
+    const AVFrame *in  = td->in;
+    const AVFrame *out = td->out;
+    const int direct = out == in;
     const int step = curves->step;
     const uint8_t r = curves->rgba_map[R];
     const uint8_t g = curves->rgba_map[G];
     const uint8_t b = curves->rgba_map[B];
     const uint8_t a = curves->rgba_map[A];
+    const int slice_start = (in->height *  jobnr   ) / nb_jobs;
+    const int slice_end   = (in->height * (jobnr+1)) / nb_jobs;
+    uint8_t       *dst = out->data[0] + slice_start * out->linesize[0];
+    const uint8_t *src =  in->data[0] + slice_start *  in->linesize[0];
+
+    for (y = slice_start; y < slice_end; y++) {
+        for (x = 0; x < in->width * step; x += step) {
+            dst[x + r] = curves->graph[R][src[x + r]];
+            dst[x + g] = curves->graph[G][src[x + g]];
+            dst[x + b] = curves->graph[B][src[x + b]];
+            if (!direct && step == 4)
+                dst[x + a] = src[x + a];
+        }
+        dst += out->linesize[0];
+        src += in ->linesize[0];
+    }
+    return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+    AVFilterContext *ctx = inlink->dst;
+    AVFilterLink *outlink = ctx->outputs[0];
+    AVFrame *out;
+    ThreadData td;
 
     if (av_frame_is_writable(in)) {
-        direct = 1;
         out = in;
     } else {
         out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
@@ -500,22 +527,11 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
         av_frame_copy_props(out, in);
     }
 
-    dst = out->data[0];
-    src = in ->data[0];
-
-    for (y = 0; y < inlink->h; y++) {
-        for (x = 0; x < inlink->w * step; x += step) {
-            dst[x + r] = curves->graph[R][src[x + r]];
-            dst[x + g] = curves->graph[G][src[x + g]];
-            dst[x + b] = curves->graph[B][src[x + b]];
-            if (!direct && step == 4)
-                dst[x + a] = src[x + a];
-        }
-        dst += out->linesize[0];
-        src += in ->linesize[0];
-    }
+    td.in  = in;
+    td.out = out;
+    ctx->internal->execute(ctx, filter_slice, &td, NULL, FFMIN(outlink->h, ctx->graph->nb_threads));
 
-    if (!direct)
+    if (out != in)
         av_frame_free(&in);
 
     return ff_filter_frame(outlink, out);
@@ -548,5 +564,5 @@ AVFilter ff_vf_curves = {
     .inputs        = curves_inputs,
     .outputs       = curves_outputs,
     .priv_class    = &curves_class,
-    .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
+    .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
 };