diff mbox

[FFmpeg-devel,PATCHv2,2/3] avfilter/vf_geq: use per-thread state for expression evaluation

Message ID 20191230222504.5942-1-cus@passwd.hu
State New
Headers show

Commit Message

Marton Balint Dec. 30, 2019, 10:25 p.m. UTC
Fixes ticket #7528.

Signed-off-by: Marton Balint <cus@passwd.hu>
---
 doc/filters.texi     |  5 +++++
 libavfilter/vf_geq.c | 19 ++++++++++++++++---
 2 files changed, 21 insertions(+), 3 deletions(-)
diff mbox

Patch

diff --git a/doc/filters.texi b/doc/filters.texi
index ba00989987..9572fa36fc 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -11386,6 +11386,11 @@  Default is bilinear.
 For functions, if @var{x} and @var{y} are outside the area, the value will be
 automatically clipped to the closer edge.
 
+Please note that this filter can use multiple threads in which case each slice
+will have its own expression state. If you want to use only a single expression
+state because your expressions depend on previous state then you should limit
+the number of filter threads to 1.
+
 @subsection Examples
 
 @itemize
diff --git a/libavfilter/vf_geq.c b/libavfilter/vf_geq.c
index 2905efae24..ae5724b69e 100644
--- a/libavfilter/vf_geq.c
+++ b/libavfilter/vf_geq.c
@@ -33,6 +33,7 @@ 
 #include "libavutil/pixdesc.h"
 #include "internal.h"
 
+#define MAX_NB_THREADS 32
 #define NB_PLANES 4
 
 enum InterpolationMethods {
@@ -57,6 +58,7 @@  typedef struct GEQContext {
     int interpolation;
     int is_rgb;
     int bps;
+    AVExprState *states[MAX_NB_THREADS]; ///< expression states per thread (job)
 
     double *pixel_sums[NB_PLANES];
     int needs_sum[NB_PLANES];
@@ -297,6 +299,14 @@  static av_cold int geq_init(AVFilterContext *ctx)
         geq->needs_sum[plane] = counter[5] + counter[6] + counter[7] + counter[8] + counter[9];
     }
 
+    for (int i = 0; i < MAX_NB_THREADS; i++) {
+        geq->states[i] = av_expr_state_alloc();
+        if (!geq->states[i]) {
+            ret = AVERROR(ENOMEM);
+            break;
+        }
+    }
+
 end:
     return ret;
 }
@@ -377,6 +387,7 @@  static int slice_geq_filter(AVFilterContext *ctx, void *arg, int jobnr, int nb_j
     int x, y;
     uint8_t *ptr;
     uint16_t *ptr16;
+    AVExprState *state = geq->states[jobnr];
 
     double values[VAR_VARS_NB];
     values[VAR_W] = geq->values[VAR_W];
@@ -393,7 +404,7 @@  static int slice_geq_filter(AVFilterContext *ctx, void *arg, int jobnr, int nb_j
 
             for (x = 0; x < width; x++) {
                 values[VAR_X] = x;
-                ptr[x] = av_expr_eval(geq->e[plane], values, geq);
+                ptr[x] = av_expr_eval2(geq->e[plane], state, values, geq);
             }
             ptr += linesize;
         }
@@ -404,7 +415,7 @@  static int slice_geq_filter(AVFilterContext *ctx, void *arg, int jobnr, int nb_j
             values[VAR_Y] = y;
             for (x = 0; x < width; x++) {
                 values[VAR_X] = x;
-                ptr16[x] = av_expr_eval(geq->e[plane], values, geq);
+                ptr16[x] = av_expr_eval2(geq->e[plane], state, values, geq);
             }
         }
     }
@@ -416,7 +427,7 @@  static int geq_filter_frame(AVFilterLink *inlink, AVFrame *in)
 {
     int plane;
     AVFilterContext *ctx = inlink->dst;
-    const int nb_threads = ff_filter_get_nb_threads(ctx);
+    const int nb_threads = FFMIN(MAX_NB_THREADS, ff_filter_get_nb_threads(ctx));
     GEQContext *geq = ctx->priv;
     AVFilterLink *outlink = inlink->dst->outputs[0];
     AVFrame *out;
@@ -470,6 +481,8 @@  static av_cold void geq_uninit(AVFilterContext *ctx)
         av_expr_free(geq->e[i]);
     for (i = 0; i < NB_PLANES; i++)
         av_freep(&geq->pixel_sums);
+    for (i = 0; i < MAX_NB_THREADS; i++)
+        av_expr_state_free(&geq->states[i]);
 }
 
 static const AVFilterPad geq_inputs[] = {