Browse code

avfilter/signalstats: add slice threading for subfilters

Clément Bœsch authored on 2014/11/17 05:12:55
Showing 1 changed files
... ...
@@ -45,8 +45,15 @@ typedef struct {
45 45
     AVFrame *frame_prev;
46 46
     uint8_t rgba_color[4];
47 47
     int yuv_color[3];
48
+    int nb_jobs;
49
+    int *jobs_rets;
48 50
 } SignalstatsContext;
49 51
 
52
+typedef struct ThreadData {
53
+    const AVFrame *in;
54
+    AVFrame *out;
55
+} ThreadData;
56
+
50 57
 #define OFFSET(x) offsetof(SignalstatsContext, x)
51 58
 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
52 59
 
... ...
@@ -87,6 +94,7 @@ static av_cold void uninit(AVFilterContext *ctx)
87 87
 {
88 88
     SignalstatsContext *s = ctx->priv;
89 89
     av_frame_free(&s->frame_prev);
90
+    av_freep(&s->jobs_rets);
90 91
 }
91 92
 
92 93
 static int query_formats(AVFilterContext *ctx)
... ...
@@ -122,10 +130,14 @@ static int config_props(AVFilterLink *outlink)
122 122
     s->fs = inlink->w * inlink->h;
123 123
     s->cfs = s->chromaw * s->chromah;
124 124
 
125
+    s->nb_jobs   = FFMAX(1, FFMIN(inlink->h, ctx->graph->nb_threads));
126
+    s->jobs_rets = av_malloc_array(s->nb_jobs, sizeof(*s->jobs_rets));
127
+    if (!s->jobs_rets)
128
+        return AVERROR(ENOMEM);
125 129
     return 0;
126 130
 }
127 131
 
128
-static void burn_frame(SignalstatsContext *s, AVFrame *f, int x, int y)
132
+static void burn_frame(const SignalstatsContext *s, AVFrame *f, int x, int y)
129 133
 {
130 134
     const int chromax = x >> s->hsub;
131 135
     const int chromay = y >> s->vsub;
... ...
@@ -134,11 +146,19 @@ static void burn_frame(SignalstatsContext *s, AVFrame *f, int x, int y)
134 134
     f->data[2][chromay * f->linesize[2] + chromax] = s->yuv_color[2];
135 135
 }
136 136
 
137
-static int filter_brng(SignalstatsContext *s, const AVFrame *in, AVFrame *out, int w, int h)
137
+static int filter_brng(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
138 138
 {
139
+    ThreadData *td = arg;
140
+    const SignalstatsContext *s = ctx->priv;
141
+    const AVFrame *in = td->in;
142
+    AVFrame *out = td->out;
143
+    const int w = in->width;
144
+    const int h = in->height;
145
+    const int slice_start = (h *  jobnr   ) / nb_jobs;
146
+    const int slice_end   = (h * (jobnr+1)) / nb_jobs;
139 147
     int x, y, score = 0;
140 148
 
141
-    for (y = 0; y < h; y++) {
149
+    for (y = slice_start; y < slice_end; y++) {
142 150
         const int yc = y >> s->vsub;
143 151
         const uint8_t *pluma    = &in->data[0][y  * in->linesize[0]];
144 152
         const uint8_t *pchromau = &in->data[1][yc * in->linesize[1]];
... ...
@@ -165,13 +185,21 @@ static int filter_tout_outlier(uint8_t x, uint8_t y, uint8_t z)
165 165
     return ((abs(x - y) + abs (z - y)) / 2) - abs(z - x) > 4; // make 4 configurable?
166 166
 }
167 167
 
168
-static int filter_tout(SignalstatsContext *s, const AVFrame *in, AVFrame *out, int w, int h)
168
+static int filter_tout(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
169 169
 {
170
+    ThreadData *td = arg;
171
+    const SignalstatsContext *s = ctx->priv;
172
+    const AVFrame *in = td->in;
173
+    AVFrame *out = td->out;
174
+    const int w = in->width;
175
+    const int h = in->height;
176
+    const int slice_start = (h *  jobnr   ) / nb_jobs;
177
+    const int slice_end   = (h * (jobnr+1)) / nb_jobs;
170 178
     const uint8_t *p = in->data[0];
171 179
     int lw = in->linesize[0];
172 180
     int x, y, score = 0, filt;
173 181
 
174
-    for (y = 0; y < h; y++) {
182
+    for (y = slice_start; y < slice_end; y++) {
175 183
 
176 184
         if (y - 1 < 0 || y + 1 >= h)
177 185
             continue;
... ...
@@ -207,17 +235,28 @@ static int filter_tout(SignalstatsContext *s, const AVFrame *in, AVFrame *out, i
207 207
 
208 208
 #define VREP_START 4
209 209
 
210
-static int filter_vrep(SignalstatsContext *s, const AVFrame *in, AVFrame *out, int w, int h)
210
+static int filter_vrep(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
211 211
 {
212
+    ThreadData *td = arg;
213
+    const SignalstatsContext *s = ctx->priv;
214
+    const AVFrame *in = td->in;
215
+    AVFrame *out = td->out;
216
+    const int w = in->width;
217
+    const int h = in->height;
218
+    const int slice_start = (h *  jobnr   ) / nb_jobs;
219
+    const int slice_end   = (h * (jobnr+1)) / nb_jobs;
212 220
     const uint8_t *p = in->data[0];
213 221
     const int lw = in->linesize[0];
214 222
     int x, y, score = 0;
215 223
 
216
-    for (y = VREP_START; y < h; y++) {
224
+    for (y = slice_start; y < slice_end; y++) {
217 225
         const int y2lw = (y - VREP_START) * lw;
218 226
         const int ylw  =  y               * lw;
219 227
         int filt, totdiff = 0;
220 228
 
229
+        if (y < VREP_START)
230
+            continue;
231
+
221 232
         for (x = 0; x < w; x++)
222 233
             totdiff += abs(p[y2lw + x] - p[ylw + x]);
223 234
         filt = totdiff < w;
... ...
@@ -232,7 +271,7 @@ static int filter_vrep(SignalstatsContext *s, const AVFrame *in, AVFrame *out, i
232 232
 
233 233
 static const struct {
234 234
     const char *name;
235
-    int (*process)(SignalstatsContext *s, const AVFrame *in, AVFrame *out, int w, int h);
235
+    int (*process)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs);
236 236
 } filters_def[] = {
237 237
     {"TOUT", filter_tout},
238 238
     {"VREP", filter_vrep},
... ...
@@ -244,8 +283,9 @@ static const struct {
244 244
 
245 245
 static int filter_frame(AVFilterLink *link, AVFrame *in)
246 246
 {
247
-    SignalstatsContext *s = link->dst->priv;
248
-    AVFilterLink *outlink = link->dst->outputs[0];
247
+    AVFilterContext *ctx = link->dst;
248
+    SignalstatsContext *s = ctx->priv;
249
+    AVFilterLink *outlink = ctx->outputs[0];
249 250
     AVFrame *out = in;
250 251
     int i, j;
251 252
     int  w = 0,  cw = 0, // in
... ...
@@ -319,8 +359,15 @@ static int filter_frame(AVFilterLink *link, AVFrame *in)
319 319
 
320 320
     for (fil = 0; fil < FILT_NUMB; fil ++) {
321 321
         if (s->filters & 1<<fil) {
322
-            AVFrame *dbg = out != in && s->outfilter == fil ? out : NULL;
323
-            filtot[fil] = filters_def[fil].process(s, in, dbg, link->w, link->h);
322
+            ThreadData td = {
323
+                .in = in,
324
+                .out = out != in && s->outfilter == fil ? out : NULL,
325
+            };
326
+            memset(s->jobs_rets, 0, s->nb_jobs * sizeof(*s->jobs_rets));
327
+            ctx->internal->execute(ctx, filters_def[fil].process,
328
+                                   &td, s->jobs_rets, s->nb_jobs);
329
+            for (i = 0; i < s->nb_jobs; i++)
330
+                filtot[fil] += s->jobs_rets[i];
324 331
         }
325 332
     }
326 333
 
... ...
@@ -459,4 +506,5 @@ AVFilter ff_vf_signalstats = {
459 459
     .inputs        = signalstats_inputs,
460 460
     .outputs       = signalstats_outputs,
461 461
     .priv_class    = &signalstats_class,
462
+    .flags         = AVFILTER_FLAG_SLICE_THREADS,
462 463
 };