Browse code

avfilter: add (a)graphmonitor filter(s)

Paul B Mahol authored on 2018/10/28 02:17:08
Showing 6 changed files
... ...
@@ -41,6 +41,7 @@ version <next>:
41 41
 - decoding S12M timecode in h264
42 42
 - xstack filter
43 43
 - pcm vidc decoder and encoder
44
+- (a)graphmonitor filter
44 45
 
45 46
 
46 47
 version 4.0:
... ...
@@ -10300,6 +10300,63 @@ gradfun=radius=8
10300 10300
 
10301 10301
 @end itemize
10302 10302
 
10303
+@section graphmonitor, agraphmonitor
10304
+Show various filtergraph stats.
10305
+
10306
+With this filter one can debug complete filtergraph.
10307
+Especially issues with links filling with queued frames.
10308
+
10309
+The filter accepts the following options:
10310
+
10311
+@table @option
10312
+@item size, s
10313
+Set video output size. Default is @var{hd720}.
10314
+
10315
+@item opacity, o
10316
+Set video opacity. Default is @var{0.9}. Allowed range is from @var{0} to @var{1}.
10317
+
10318
+@item mode, m
10319
+Set output mode, can be @var{fulll} or @var{compact}.
10320
+In @var{compact} mode only filters with some queued frames have displayed stats.
10321
+
10322
+@item flags, f
10323
+Set flags which enable which stats are shown in video.
10324
+
10325
+Available values for flags are:
10326
+@table @samp
10327
+@item queue
10328
+Display number of queued frames in each link.
10329
+
10330
+@item frame_count_in
10331
+Display number of frames taken from filter.
10332
+
10333
+@item frame_count_out
10334
+Display number of frames given out from filter.
10335
+
10336
+@item pts
10337
+Display current filtered frame pts.
10338
+
10339
+@item time
10340
+Display current filtered frame time.
10341
+
10342
+@item timebase
10343
+Display time base for filter link.
10344
+
10345
+@item format
10346
+Display used format for filter link.
10347
+
10348
+@item size
10349
+Display video size or number of audio channels in case of audio used by filter link.
10350
+
10351
+@item rate
10352
+Display video frame rate or sample rate in case of audio used by filter link.
10353
+@end table
10354
+
10355
+@item rate, r
10356
+Set upper limit for video rate of output stream, Default value is @var{25}.
10357
+This guarantee that output video frame rate will not be higher than this value.
10358
+@end table
10359
+
10303 10360
 @section greyedge
10304 10361
 A color constancy variation filter which estimates scene illumination via grey edge algorithm
10305 10362
 and corrects the scene colors accordingly.
... ...
@@ -240,6 +240,7 @@ OBJS-$(CONFIG_FSPP_FILTER)                   += vf_fspp.o
240 240
 OBJS-$(CONFIG_GBLUR_FILTER)                  += vf_gblur.o
241 241
 OBJS-$(CONFIG_GEQ_FILTER)                    += vf_geq.o
242 242
 OBJS-$(CONFIG_GRADFUN_FILTER)                += vf_gradfun.o
243
+OBJS-$(CONFIG_GRAPHMONITOR_FILTER)           += f_graphmonitor.o
243 244
 OBJS-$(CONFIG_GREYEDGE_FILTER)               += vf_colorconstancy.o
244 245
 OBJS-$(CONFIG_HALDCLUT_FILTER)               += vf_lut3d.o framesync.o
245 246
 OBJS-$(CONFIG_HFLIP_FILTER)                  += vf_hflip.o
... ...
@@ -437,6 +438,7 @@ OBJS-$(CONFIG_NULLSINK_FILTER)               += vsink_nullsink.o
437 437
 # multimedia filters
438 438
 OBJS-$(CONFIG_ABITSCOPE_FILTER)              += avf_abitscope.o
439 439
 OBJS-$(CONFIG_ADRAWGRAPH_FILTER)             += f_drawgraph.o
440
+OBJS-$(CONFIG_AGRAPHMONITOR_FILTER)          += f_graphmonitor.o
440 441
 OBJS-$(CONFIG_AHISTOGRAM_FILTER)             += avf_ahistogram.o
441 442
 OBJS-$(CONFIG_APHASEMETER_FILTER)            += avf_aphasemeter.o
442 443
 OBJS-$(CONFIG_AVECTORSCOPE_FILTER)           += avf_avectorscope.o
... ...
@@ -227,6 +227,7 @@ extern AVFilter ff_vf_fspp;
227 227
 extern AVFilter ff_vf_gblur;
228 228
 extern AVFilter ff_vf_geq;
229 229
 extern AVFilter ff_vf_gradfun;
230
+extern AVFilter ff_vf_graphmonitor;
230 231
 extern AVFilter ff_vf_greyedge;
231 232
 extern AVFilter ff_vf_haldclut;
232 233
 extern AVFilter ff_vf_hflip;
... ...
@@ -418,6 +419,7 @@ extern AVFilter ff_vsink_nullsink;
418 418
 /* multimedia filters */
419 419
 extern AVFilter ff_avf_abitscope;
420 420
 extern AVFilter ff_avf_adrawgraph;
421
+extern AVFilter ff_avf_agraphmonitor;
421 422
 extern AVFilter ff_avf_ahistogram;
422 423
 extern AVFilter ff_avf_aphasemeter;
423 424
 extern AVFilter ff_avf_avectorscope;
424 425
new file mode 100644
... ...
@@ -0,0 +1,425 @@
0
+/*
1
+ * Copyright (c) 2018 Paul B Mahol
2
+ *
3
+ * This file is part of FFmpeg.
4
+ *
5
+ * FFmpeg is free software; you can redistribute it and/or
6
+ * modify it under the terms of the GNU Lesser General Public
7
+ * License as published by the Free Software Foundation; either
8
+ * version 2.1 of the License, or (at your option) any later version.
9
+ *
10
+ * FFmpeg is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
+ * Lesser General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU Lesser General Public
16
+ * License along with FFmpeg; if not, write to the Free Software
17
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
+ */
19
+
20
+#include "float.h"
21
+
22
+#include "libavutil/pixdesc.h"
23
+#include "libavutil/eval.h"
24
+#include "libavutil/intreadwrite.h"
25
+#include "libavutil/opt.h"
26
+#include "libavutil/timestamp.h"
27
+#include "libavutil/xga_font_data.h"
28
+#include "avfilter.h"
29
+#include "filters.h"
30
+#include "formats.h"
31
+#include "internal.h"
32
+#include "video.h"
33
+
34
+typedef struct GraphMonitorContext {
35
+    const AVClass *class;
36
+
37
+    int w, h;
38
+    float opacity;
39
+    int mode;
40
+    int flags;
41
+    AVRational frame_rate;
42
+
43
+    int64_t pts;
44
+    uint8_t white[4];
45
+    uint8_t yellow[4];
46
+    uint8_t red[4];
47
+    uint8_t green[4];
48
+    uint8_t bg[4];
49
+} GraphMonitorContext;
50
+
51
+enum {
52
+    MODE_QUEUE = 1 << 0,
53
+    MODE_FCIN  = 1 << 1,
54
+    MODE_FCOUT = 1 << 2,
55
+    MODE_PTS   = 1 << 3,
56
+    MODE_TIME  = 1 << 4,
57
+    MODE_TB    = 1 << 5,
58
+    MODE_FMT   = 1 << 6,
59
+    MODE_SIZE  = 1 << 7,
60
+    MODE_RATE  = 1 << 8,
61
+};
62
+
63
+#define OFFSET(x) offsetof(GraphMonitorContext, x)
64
+#define VF AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
65
+
66
+static const AVOption graphmonitor_options[] = {
67
+    { "size", "set monitor size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str="hd720"}, 0, 0, VF },
68
+    { "s",    "set monitor size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str="hd720"}, 0, 0, VF },
69
+    { "opacity", "set video opacity", OFFSET(opacity), AV_OPT_TYPE_FLOAT, {.dbl=.9}, 0, 1, VF },
70
+    { "o",       "set video opacity", OFFSET(opacity), AV_OPT_TYPE_FLOAT, {.dbl=.9}, 0, 1, VF },
71
+    { "mode", "set mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, VF, "mode" },
72
+    { "m",    "set mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, VF, "mode" },
73
+        { "full",     NULL, 0, AV_OPT_TYPE_CONST, {.i64=0},   0, 0, VF, "mode" },
74
+        { "compact",  NULL, 0, AV_OPT_TYPE_CONST, {.i64=1},   0, 0, VF, "mode" },
75
+    { "flags", "set flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64=MODE_QUEUE}, 0, INT_MAX, VF, "flags" },
76
+    { "f",     "set flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64=MODE_QUEUE}, 0, INT_MAX, VF, "flags" },
77
+        { "queue",            NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_QUEUE},   0, 0, VF, "flags" },
78
+        { "frame_count_in",   NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_FCOUT},   0, 0, VF, "flags" },
79
+        { "frame_count_out",  NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_FCIN},    0, 0, VF, "flags" },
80
+        { "pts",              NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_PTS},     0, 0, VF, "flags" },
81
+        { "time",             NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_TIME},    0, 0, VF, "flags" },
82
+        { "timebase",         NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_TB},      0, 0, VF, "flags" },
83
+        { "format",           NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_FMT},     0, 0, VF, "flags" },
84
+        { "size",             NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_SIZE},    0, 0, VF, "flags" },
85
+        { "rate",             NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_RATE},    0, 0, VF, "flags" },
86
+    { "rate", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, INT_MAX, VF },
87
+    { "r",    "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, INT_MAX, VF },
88
+    { NULL }
89
+};
90
+
91
+static int query_formats(AVFilterContext *ctx)
92
+{
93
+    AVFilterLink *outlink = ctx->outputs[0];
94
+    static const enum AVPixelFormat pix_fmts[] = {
95
+        AV_PIX_FMT_RGBA,
96
+        AV_PIX_FMT_NONE
97
+    };
98
+    int ret;
99
+
100
+    AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
101
+    if ((ret = ff_formats_ref(fmts_list, &outlink->in_formats)) < 0)
102
+        return ret;
103
+
104
+    return 0;
105
+}
106
+
107
+static void clear_image(GraphMonitorContext *s, AVFrame *out, AVFilterLink *outlink)
108
+{
109
+    int bg = AV_RN32(s->bg);
110
+
111
+    for (int i = 0; i < out->height; i++)
112
+        for (int j = 0; j < out->width; j++)
113
+            AV_WN32(out->data[0] + i * out->linesize[0] + j * 4, bg);
114
+}
115
+
116
+static void drawtext(AVFrame *pic, int x, int y, const char *txt, uint8_t *color)
117
+{
118
+    const uint8_t *font;
119
+    int font_height;
120
+    int i;
121
+
122
+    font = avpriv_cga_font,   font_height =  8;
123
+
124
+    if (y + 8 >= pic->height ||
125
+        x + strlen(txt) * 8 >= pic->width)
126
+        return;
127
+
128
+    for (i = 0; txt[i]; i++) {
129
+        int char_y, mask;
130
+
131
+        uint8_t *p = pic->data[0] + y*pic->linesize[0] + (x + i*8)*4;
132
+        for (char_y = 0; char_y < font_height; char_y++) {
133
+            for (mask = 0x80; mask; mask >>= 1) {
134
+                if (font[txt[i] * font_height + char_y] & mask) {
135
+                    p[0] = color[0];
136
+                    p[1] = color[1];
137
+                    p[2] = color[2];
138
+                }
139
+                p += 4;
140
+            }
141
+            p += pic->linesize[0] - 8 * 4;
142
+        }
143
+    }
144
+}
145
+
146
+static int filter_have_queued(AVFilterContext *filter)
147
+{
148
+    for (int j = 0; j < filter->nb_inputs; j++) {
149
+        AVFilterLink *l = filter->inputs[j];
150
+        size_t frames = ff_inlink_queued_frames(l);
151
+
152
+        if (frames)
153
+            return 1;
154
+    }
155
+
156
+    for (int j = 0; j < filter->nb_outputs; j++) {
157
+        AVFilterLink *l = filter->outputs[j];
158
+        size_t frames = ff_inlink_queued_frames(l);
159
+
160
+        if (frames)
161
+            return 1;
162
+    }
163
+
164
+    return 0;
165
+}
166
+
167
+static void draw_items(AVFilterContext *ctx, AVFrame *out,
168
+                       int xpos, int ypos,
169
+                       AVFilterLink *l,
170
+                       size_t frames)
171
+{
172
+    GraphMonitorContext *s = ctx->priv;
173
+    char buffer[1024] = { 0 };
174
+
175
+    if (s->flags & MODE_FMT) {
176
+        if (l->type == AVMEDIA_TYPE_VIDEO) {
177
+            snprintf(buffer, sizeof(buffer)-1, " | format: %s",
178
+                     av_get_pix_fmt_name(l->format));
179
+        } else if (l->type == AVMEDIA_TYPE_AUDIO) {
180
+            snprintf(buffer, sizeof(buffer)-1, " | format: %s",
181
+                     av_get_sample_fmt_name(l->format));
182
+        }
183
+        drawtext(out, xpos, ypos, buffer, s->white);
184
+        xpos += strlen(buffer) * 8;
185
+    }
186
+    if (s->flags & MODE_SIZE) {
187
+        if (l->type == AVMEDIA_TYPE_VIDEO) {
188
+            snprintf(buffer, sizeof(buffer)-1, " | size: %dx%d", l->w, l->h);
189
+        } else if (l->type == AVMEDIA_TYPE_AUDIO) {
190
+            snprintf(buffer, sizeof(buffer)-1, " | channels: %d", l->channels);
191
+        }
192
+        drawtext(out, xpos, ypos, buffer, s->white);
193
+        xpos += strlen(buffer) * 8;
194
+    }
195
+    if (s->flags & MODE_RATE) {
196
+        if (l->type == AVMEDIA_TYPE_VIDEO) {
197
+            snprintf(buffer, sizeof(buffer)-1, " | fps: %d/%d", l->frame_rate.num, l->frame_rate.den);
198
+        } else if (l->type == AVMEDIA_TYPE_AUDIO) {
199
+            snprintf(buffer, sizeof(buffer)-1, " | samplerate: %d", l->sample_rate);
200
+        }
201
+        drawtext(out, xpos, ypos, buffer, s->white);
202
+        xpos += strlen(buffer) * 8;
203
+    }
204
+    if (s->flags & MODE_TB) {
205
+        snprintf(buffer, sizeof(buffer)-1, " | tb: %d/%d", l->time_base.num, l->time_base.den);
206
+        drawtext(out, xpos, ypos, buffer, s->white);
207
+        xpos += strlen(buffer) * 8;
208
+    }
209
+    if (s->flags & MODE_QUEUE) {
210
+        snprintf(buffer, sizeof(buffer)-1, " | queue: ");
211
+        drawtext(out, xpos, ypos, buffer, s->white);
212
+        xpos += strlen(buffer) * 8;
213
+        snprintf(buffer, sizeof(buffer)-1, "%"PRId64, frames);
214
+        drawtext(out, xpos, ypos, buffer, frames > 0 ? frames >= 10 ? frames >= 50 ? s->red : s->yellow : s->green : s->white);
215
+        xpos += strlen(buffer) * 8;
216
+    }
217
+    if (s->flags & MODE_FCIN) {
218
+        snprintf(buffer, sizeof(buffer)-1, " | in: %"PRId64, l->frame_count_in);
219
+        drawtext(out, xpos, ypos, buffer, s->white);
220
+        xpos += strlen(buffer) * 8;
221
+    }
222
+    if (s->flags & MODE_FCOUT) {
223
+        snprintf(buffer, sizeof(buffer)-1, " | out: %"PRId64, l->frame_count_out);
224
+        drawtext(out, xpos, ypos, buffer, s->white);
225
+        xpos += strlen(buffer) * 8;
226
+    }
227
+    if (s->flags & MODE_PTS) {
228
+        snprintf(buffer, sizeof(buffer)-1, " | pts: %s", av_ts2str(l->current_pts_us));
229
+        drawtext(out, xpos, ypos, buffer, s->white);
230
+        xpos += strlen(buffer) * 8;
231
+    }
232
+    if (s->flags & MODE_TIME) {
233
+        snprintf(buffer, sizeof(buffer)-1, " | time: %s", av_ts2timestr(l->current_pts_us, &AV_TIME_BASE_Q));
234
+        drawtext(out, xpos, ypos, buffer, s->white);
235
+        xpos += strlen(buffer) * 8;
236
+    }
237
+}
238
+
239
+static int create_frame(AVFilterContext *ctx, int64_t pts)
240
+{
241
+    GraphMonitorContext *s = ctx->priv;
242
+    AVFilterLink *outlink = ctx->outputs[0];
243
+    AVFrame *out;
244
+    int xpos, ypos = 0;
245
+
246
+    out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
247
+    if (!out)
248
+        return AVERROR(ENOMEM);
249
+
250
+    clear_image(s, out, outlink);
251
+
252
+    for (int i = 0; i < ctx->graph->nb_filters; i++) {
253
+        AVFilterContext *filter = ctx->graph->filters[i];
254
+        char buffer[1024] = { 0 };
255
+
256
+        if (s->mode && !filter_have_queued(filter))
257
+            continue;
258
+
259
+        xpos = 0;
260
+        drawtext(out, xpos, ypos, filter->name, s->white);
261
+        xpos += strlen(filter->name) * 8 + 10;
262
+        drawtext(out, xpos, ypos, filter->filter->name, s->white);
263
+        ypos += 10;
264
+        for (int j = 0; j < filter->nb_inputs; j++) {
265
+            AVFilterLink *l = filter->inputs[j];
266
+            size_t frames = ff_inlink_queued_frames(l);
267
+
268
+            if (s->mode && !frames)
269
+                continue;
270
+
271
+            xpos = 10;
272
+            snprintf(buffer, sizeof(buffer)-1, "in%d: ", j);
273
+            drawtext(out, xpos, ypos, buffer, s->white);
274
+            xpos += strlen(buffer) * 8;
275
+            drawtext(out, xpos, ypos, l->src->name, s->white);
276
+            xpos += strlen(l->src->name) * 8 + 10;
277
+            draw_items(ctx, out, xpos, ypos, l, frames);
278
+            ypos += 10;
279
+        }
280
+
281
+        ypos += 2;
282
+        for (int j = 0; j < filter->nb_outputs; j++) {
283
+            AVFilterLink *l = filter->outputs[j];
284
+            size_t frames = ff_inlink_queued_frames(l);
285
+
286
+            if (s->mode && !frames)
287
+                continue;
288
+
289
+            xpos = 10;
290
+            snprintf(buffer, sizeof(buffer)-1, "out%d: ", j);
291
+            drawtext(out, xpos, ypos, buffer, s->white);
292
+            xpos += strlen(buffer) * 8;
293
+            drawtext(out, xpos, ypos, l->dst->name, s->white);
294
+            xpos += strlen(l->dst->name) * 8 + 10;
295
+            draw_items(ctx, out, xpos, ypos, l, frames);
296
+            ypos += 10;
297
+        }
298
+        ypos += 5;
299
+    }
300
+
301
+    out->pts = pts;
302
+    s->pts = pts;
303
+    return ff_filter_frame(outlink, out);
304
+}
305
+
306
+static int activate(AVFilterContext *ctx)
307
+{
308
+    GraphMonitorContext *s = ctx->priv;
309
+    AVFilterLink *inlink = ctx->inputs[0];
310
+    AVFilterLink *outlink = ctx->outputs[0];
311
+    int64_t pts = AV_NOPTS_VALUE;
312
+
313
+    FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink);
314
+
315
+    if (ff_inlink_queued_frames(inlink)) {
316
+        AVFrame *frame = NULL;
317
+        int ret;
318
+
319
+        ret = ff_inlink_consume_frame(inlink, &frame);
320
+        if (ret < 0)
321
+            return ret;
322
+        if (ret > 0) {
323
+            pts = frame->pts;
324
+            av_frame_free(&frame);
325
+        }
326
+    }
327
+
328
+    if (pts != AV_NOPTS_VALUE) {
329
+        pts = av_rescale_q(pts, inlink->time_base, outlink->time_base);
330
+        if (s->pts < pts && ff_outlink_frame_wanted(outlink))
331
+            return create_frame(ctx, pts);
332
+    }
333
+
334
+    FF_FILTER_FORWARD_STATUS(inlink, outlink);
335
+    FF_FILTER_FORWARD_WANTED(outlink, inlink);
336
+
337
+    return FFERROR_NOT_READY;
338
+}
339
+
340
+static int config_output(AVFilterLink *outlink)
341
+{
342
+    GraphMonitorContext *s = outlink->src->priv;
343
+
344
+    s->bg[3] = 255 * s->opacity;
345
+    s->white[0] = s->white[1] = s->white[2] = 255;
346
+    s->yellow[0] = s->yellow[1] = 255;
347
+    s->red[0] = 255;
348
+    s->green[1] = 255;
349
+    outlink->w = s->w;
350
+    outlink->h = s->h;
351
+    outlink->sample_aspect_ratio = (AVRational){1,1};
352
+    outlink->frame_rate = s->frame_rate;
353
+    outlink->time_base = av_inv_q(s->frame_rate);
354
+
355
+    return 0;
356
+}
357
+
358
+#if CONFIG_GRAPHMONITOR_FILTER
359
+
360
+AVFILTER_DEFINE_CLASS(graphmonitor);
361
+
362
+static const AVFilterPad graphmonitor_inputs[] = {
363
+    {
364
+        .name = "default",
365
+        .type = AVMEDIA_TYPE_VIDEO,
366
+    },
367
+    { NULL }
368
+};
369
+
370
+static const AVFilterPad graphmonitor_outputs[] = {
371
+    {
372
+        .name         = "default",
373
+        .type         = AVMEDIA_TYPE_VIDEO,
374
+        .config_props = config_output,
375
+    },
376
+    { NULL }
377
+};
378
+
379
+AVFilter ff_vf_graphmonitor = {
380
+    .name          = "graphmonitor",
381
+    .description   = NULL_IF_CONFIG_SMALL("Show various filtergraph stats."),
382
+    .priv_size     = sizeof(GraphMonitorContext),
383
+    .priv_class    = &graphmonitor_class,
384
+    .query_formats = query_formats,
385
+    .activate      = activate,
386
+    .inputs        = graphmonitor_inputs,
387
+    .outputs       = graphmonitor_outputs,
388
+};
389
+
390
+#endif // CONFIG_GRAPHMONITOR_FILTER
391
+
392
+#if CONFIG_AGRAPHMONITOR_FILTER
393
+
394
+#define agraphmonitor_options graphmonitor_options
395
+AVFILTER_DEFINE_CLASS(agraphmonitor);
396
+
397
+static const AVFilterPad agraphmonitor_inputs[] = {
398
+    {
399
+        .name = "default",
400
+        .type = AVMEDIA_TYPE_AUDIO,
401
+    },
402
+    { NULL }
403
+};
404
+
405
+static const AVFilterPad agraphmonitor_outputs[] = {
406
+    {
407
+        .name         = "default",
408
+        .type         = AVMEDIA_TYPE_VIDEO,
409
+        .config_props = config_output,
410
+    },
411
+    { NULL }
412
+};
413
+
414
+AVFilter ff_avf_agraphmonitor = {
415
+    .name          = "agraphmonitor",
416
+    .description   = NULL_IF_CONFIG_SMALL("Show various filtergraph stats."),
417
+    .priv_size     = sizeof(GraphMonitorContext),
418
+    .priv_class    = &agraphmonitor_class,
419
+    .query_formats = query_formats,
420
+    .activate      = activate,
421
+    .inputs        = agraphmonitor_inputs,
422
+    .outputs       = agraphmonitor_outputs,
423
+};
424
+#endif // CONFIG_AGRAPHMONITOR_FILTER
... ...
@@ -30,7 +30,7 @@
30 30
 #include "libavutil/version.h"
31 31
 
32 32
 #define LIBAVFILTER_VERSION_MAJOR   7
33
-#define LIBAVFILTER_VERSION_MINOR  38
33
+#define LIBAVFILTER_VERSION_MINOR  39
34 34
 #define LIBAVFILTER_VERSION_MICRO 100
35 35
 
36 36
 #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \