[FFmpeg-devel] [PATCH v1] avfilter: add colorstats, colorrgbstats, coloryuvstats video filter
lance.lmwang at gmail.com
lance.lmwang at gmail.com
Fri Dec 27 13:11:14 EET 2019
From: Limin Wang <lance.lmwang at gmail.com>
Signed-off-by: Limin Wang <lance.lmwang at gmail.com>
---
doc/filters.texi | 74 ++++++
libavfilter/Makefile | 1 +
libavfilter/allfilters.c | 3 +
libavfilter/vf_colorstats.c | 461 ++++++++++++++++++++++++++++++++++++
4 files changed, 539 insertions(+)
create mode 100644 libavfilter/vf_colorstats.c
diff --git a/doc/filters.texi b/doc/filters.texi
index 8c5d3a5760..81968b2c17 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -7695,6 +7695,80 @@ For example to convert the input to SMPTE-240M, use the command:
colorspace=smpte240m
@end example
+ at section colorstats, colorrgbstats, coloryuvstats
+The filter provides statistical video measurements such as mean, minimum, maximum and
+standard deviation for each frame. The user can check for unexpected/accidental errors
+very quickly with them.
+
+ at var{colorrgbstats} report the color stats for RGB input video, @var{coloryuvstats}
+to an YUV input video.
+
+These filters accept the following parameters:
+ at table @option
+ at item planes
+Set which planes to filter. Default is only the first plane.
+ at end table
+
+By default the filter will report these metadata values if the planes
+are processed:
+
+ at table @option
+ at item min.y, min.u, min.v, min.r, min.g, min.b, min.a
+Display the minimal Y/U/V/R/G/B/A plane value contained within the input frame.
+Expressed in range of [0, 1<<bitdepth-1]
+
+ at item pmin.y, pmin.u, pmin.v, pmin.r, pmin.g, pmin.b, min.a
+Display the minimal Y/U/V/R/G/B/A plane percentage of maximum contained within
+the input frame. Expressed in range of [0, 1]
+
+ at item max.y, max.u, max.v, max.r, max.g, max.b, max.a
+Display the maximum Y/U/V/R/G/B/A plane value contained within the input frame.
+Expressed in range of [0, 1<<bitdepth-1]
+
+ at item pmax.y, pmax.u, pmax.v, pmax.r, pmax.g, pmax.b, pmax.a
+Display the maximum Y/U/V/R/G/B/A plane percentage of maximum contained within
+the input frame. Expressed in range of [0, 1]
+
+ at item mean.y, mean.u, mean.v, mean.r, mean.g, mean.b, mean.a
+Display the Y/U/V/R/G/B/A plane mean value contained within the input frame.
+Expressed in range of [0, 1<<bitdepth-1]
+
+ at item pmean.y, pmean.u, pmean.v, pmean.r, pmean.g, pmean.b, pmean.a
+Display the Y/U/V/R/G/B/A plane mean value percentage of maximum contained within
+the input frame. Expressed in range of [0, 1]
+
+ at item stdev.y, stdev.u, stdev.v, stdev.r, stdev.g, stdev.b, stdev.a
+Display the Y/U/V/R/G/B/A plane standard deviation value contained within the
+input frame. Expressed in range of [0, 1<<bitdepth-1]
+
+ at item pstdev.y, pstdev.u, pstdev.v, pstdev.r, pstdev.g, pstdev.b, pstdev.a
+Display the Y/U/V/R/G/B/A plane standard deviation value percentage of maximum contained
+within the input frame. Expressed in range of [0, 1]
+ at end table
+
+ at subsection Examples
+
+ at itemize
+ at item
+Show all YUV color stats for each frame:
+ at example
+ffprobe -f lavfi movie=example.mov,coloryuvstats=planes=0xf -show_frames
+ at end example
+
+ at item
+Draw graph for the pmean and pstdev value of the Y plane per frame:
+ at example
+ffplay -i example.mov -vf coloryuvstats,drawgraph=m1=lavf.colorstats.pmean.y:m2=lavf.colorstats.pstdev.y:min=0:max=1
+ at end example
+
+ at item
+Print all RGB color stats for each frame:
+ at example
+ffplay -i example.mov -vf colorrgbstats=planes=0xf,metadata=mode=print
+ at end example
+
+ at end itemize
+
@section convolution
Apply convolution of 3x3, 5x5, 7x7 or horizontal/vertical up to 49 elements.
diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index 37d4eee858..a007bd32d1 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -182,6 +182,7 @@ OBJS-$(CONFIG_CIESCOPE_FILTER) += vf_ciescope.o
OBJS-$(CONFIG_CODECVIEW_FILTER) += vf_codecview.o
OBJS-$(CONFIG_COLORBALANCE_FILTER) += vf_colorbalance.o
OBJS-$(CONFIG_COLORCHANNELMIXER_FILTER) += vf_colorchannelmixer.o
+OBJS-$(CONFIG_COLORSTATS_FILTER) += vf_colorstats.o
OBJS-$(CONFIG_COLORKEY_FILTER) += vf_colorkey.o
OBJS-$(CONFIG_COLORKEY_OPENCL_FILTER) += vf_colorkey_opencl.o opencl.o \
opencl/colorkey.o
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index c295f8e403..6b84a45452 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -172,6 +172,9 @@ extern AVFilter ff_vf_ciescope;
extern AVFilter ff_vf_codecview;
extern AVFilter ff_vf_colorbalance;
extern AVFilter ff_vf_colorchannelmixer;
+extern AVFilter ff_vf_colorstats;
+extern AVFilter ff_vf_colorrgbstats;
+extern AVFilter ff_vf_coloryuvstats;
extern AVFilter ff_vf_colorkey;
extern AVFilter ff_vf_colorkey_opencl;
extern AVFilter ff_vf_colorhold;
diff --git a/libavfilter/vf_colorstats.c b/libavfilter/vf_colorstats.c
new file mode 100644
index 0000000000..7e94c572f9
--- /dev/null
+++ b/libavfilter/vf_colorstats.c
@@ -0,0 +1,461 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/imgutils.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+
+#include "avfilter.h"
+#include "drawutils.h"
+#include "filters.h"
+
+#define R 0
+#define G 1
+#define B 2
+#define A 3
+
+typedef struct ThreadData {
+ AVFrame *in;
+} ThreadData;
+
+typedef struct ColorStatsContext {
+ const AVClass *class;
+
+ ptrdiff_t width[4];
+ ptrdiff_t height[4];
+
+ int planes;
+ int step;
+ int bitdepth;
+ int nb_components;
+ int thread_count;
+ int is_16bit;
+ int is_rgb;
+ int force_fmt; /* 0: all, 1: rgb, 2: yuv */
+ uint8_t rgba_map[4];
+ char comps[4];
+
+ double *mean[4];
+ double *stdev[4];
+
+ int max;
+ double *min_value[4];
+ double *max_value[4];
+
+ int (*stats_slice)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs);
+} ColorStatsContext;
+
+#define OFFSET(x) offsetof(ColorStatsContext, x)
+#define V AV_OPT_FLAG_VIDEO_PARAM
+#define F AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption options[] = {
+ { "planes", "set planes to filter", OFFSET(planes), AV_OPT_TYPE_INT, {.i64=1}, 1, 0xf, V|F},
+ {NULL}
+};
+
+#define YUV_FORMATS \
+ AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P, \
+ AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV440P, \
+ AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ422P, \
+ AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ440P, \
+ AV_PIX_FMT_YUV444P9, AV_PIX_FMT_YUV422P9, \
+ AV_PIX_FMT_YUV420P9, \
+ AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV422P10, \
+ AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV440P10, \
+ AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV422P12, \
+ AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV440P12, \
+ AV_PIX_FMT_YUV444P14, AV_PIX_FMT_YUV422P14, \
+ AV_PIX_FMT_YUV420P14, AV_PIX_FMT_YUV444P16, \
+ AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV420P16, \
+ AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVA422P, \
+ AV_PIX_FMT_YUVA444P16,AV_PIX_FMT_YUVA422P16, \
+ AV_PIX_FMT_YUVA420P16,AV_PIX_FMT_YUVA422P12, \
+ AV_PIX_FMT_YUVA444P12,AV_PIX_FMT_YUVA444P, \
+ AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, \
+ AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16
+
+#define RGB_FORMATS \
+ AV_PIX_FMT_0RGB, AV_PIX_FMT_0BGR, \
+ AV_PIX_FMT_RGB0, AV_PIX_FMT_BGR0, \
+ AV_PIX_FMT_ARGB, AV_PIX_FMT_RGBA, AV_PIX_FMT_ABGR, \
+ AV_PIX_FMT_BGRA, AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24, \
+ AV_PIX_FMT_RGB48, AV_PIX_FMT_RGBA64, AV_PIX_FMT_GBRP, \
+ AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, \
+ AV_PIX_FMT_GBRAP10, AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, \
+ AV_PIX_FMT_GBRP16, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_GBRAP16
+
+static const enum AVPixelFormat yuv_pix_fmts[] = { YUV_FORMATS, AV_PIX_FMT_NONE };
+static const enum AVPixelFormat rgb_pix_fmts[] = { RGB_FORMATS, AV_PIX_FMT_NONE };
+static const enum AVPixelFormat all_pix_fmts[] = { RGB_FORMATS, YUV_FORMATS, AV_PIX_FMT_NONE };
+
+static int query_formats(AVFilterContext *ctx)
+{
+ const ColorStatsContext *s = ctx->priv;
+ const enum AVPixelFormat *pix_fmts = s->force_fmt == 1 ? rgb_pix_fmts :
+ s->force_fmt == 2 ? yuv_pix_fmts :
+ all_pix_fmts;
+
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+#define DECLARE_STATS_PLANAR_FUNC(nbits, div) \
+static int stats_slice_planar_##nbits(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) \
+{ \
+ const ColorStatsContext *s = ctx->priv; \
+ ThreadData *td = arg; \
+ const AVFrame *in = td->in; \
+ int64_t sum[4] = { 0 }, sum2[4] = { 0 }; \
+ int32_t count[4] = { 0 }; \
+ double min_value[4] = { s->max }; \
+ double max_value[4] = { 0 }; \
+ \
+ for (int i = 0; i < s->nb_components; i++) { \
+ const int width = s->width[i]; \
+ const int height = s->height[i]; \
+ const int slice_start = (height * jobnr ) / nb_jobs; \
+ const int slice_end = (height * (jobnr + 1)) / nb_jobs; \
+ int linesize = in->linesize[i] / div; \
+ uint##nbits##_t *src = (uint##nbits##_t*)in->data[i] + slice_start * linesize; \
+ \
+ if (!(s->planes & (1 << i))) \
+ continue; \
+ for (int j = slice_start; j < slice_end; j++) { \
+ for (int x = 0; x < width; x++) { \
+ sum[i] += src[x]; \
+ sum2[i] += src[x] * src[x]; \
+ if (src[i] > max_value[i]) max_value[i] = src[i]; \
+ if (src[i] < min_value[i]) min_value[i] = src[i]; \
+ } \
+ count[i] += width; \
+ src += linesize; \
+ } \
+ \
+ s->mean[i][jobnr] = (double)(sum[i] + count[i] / 2) / count[i]; \
+ s->stdev[i][jobnr] = sqrt((sum2[i] - sum[i] * (double)sum[i] / count[i]) / count[i]); \
+ s->min_value[i][jobnr] = min_value[i]; \
+ s->max_value[i][jobnr] = max_value[i]; \
+ } \
+ \
+ return 0; \
+}
+DECLARE_STATS_PLANAR_FUNC(8, 1)
+DECLARE_STATS_PLANAR_FUNC(16, 2)
+
+#define DECLARE_STATS_PACKED_FUNC(nbits, div) \
+static int stats_slice_packed_##nbits(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) \
+{ \
+ const ColorStatsContext *s = ctx->priv; \
+ ThreadData *td = arg; \
+ const AVFrame *in = td->in; \
+ int64_t sum[4] = { 0 }, sum2[4] = { 0 }; \
+ double min_value[4] = { s->max }; \
+ double max_value[4] = { 0 }; \
+ int32_t count[4] = { 0 }; \
+ const int width = in->width; \
+ const int height = in->height; \
+ const int slice_start = (height * jobnr ) / nb_jobs; \
+ const int slice_end = (height * (jobnr + 1)) / nb_jobs; \
+ int linesize = in->linesize[0] / div; \
+ uint##nbits##_t *src = (uint##nbits##_t*)in->data[0] + slice_start * linesize; \
+ const uint8_t ro = s->rgba_map[R]; \
+ const uint8_t go = s->rgba_map[G]; \
+ const uint8_t bo = s->rgba_map[B]; \
+ const uint8_t ao = s->rgba_map[A]; \
+ \
+ for (int y = slice_start; y < slice_end; y++) { \
+ for (int x = 0; x < width * s->step; x += s->step) { \
+ const int r = src[x + ro]; \
+ const int g = src[x + go]; \
+ const int b = src[x + bo]; \
+ const int a = src[x + ao]; \
+ \
+ sum[ro] += r; \
+ sum[go] += g; \
+ sum[bo] += b; \
+ sum2[ro] += r * r; \
+ sum2[go] += g * g; \
+ sum2[bo] += b * b; \
+ \
+ if (r > max_value[ro]) max_value[ro] = r; \
+ if (r < min_value[ro]) min_value[ro] = r; \
+ if (g > max_value[go]) max_value[go] = g; \
+ if (g < min_value[go]) min_value[go] = g; \
+ if (b > max_value[bo]) max_value[bo] = b; \
+ if (b < min_value[bo]) min_value[bo] = b; \
+ if (s->step == 4) { \
+ sum2[ao] += a * a; \
+ sum[ao] += a; \
+ if (a > max_value[ao]) max_value[ao] = a; \
+ if (a < min_value[ao]) min_value[ao] = a; \
+ } \
+ } \
+ count[ro] += width; \
+ count[go] += width; \
+ count[bo] += width; \
+ if (s->step == 4) \
+ count[ao] += width; \
+ src += linesize; \
+ } \
+ \
+ for (int p = 0; p < s->nb_components; p++) { \
+ int ci = s->is_rgb ? s->rgba_map[p] : p; \
+ double variance; \
+ \
+ s->mean[ci][jobnr] = (double)(sum[ci] + count[ci] / 2) / count[ci]; \
+ variance = (sum2[ci] - sum[ci] * (double)sum[ci] / count[ci]) / count[ci]; \
+ s->stdev[ci][jobnr] = sqrt(variance); \
+ s->min_value[ci][jobnr] = min_value[ci]; \
+ s->max_value[ci][jobnr] = max_value[ci]; \
+ } \
+ \
+ return 0; \
+}
+DECLARE_STATS_PACKED_FUNC(8, 1)
+DECLARE_STATS_PACKED_FUNC(16, 2)
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ ColorStatsContext *s = ctx->priv;
+
+ for (int i = 0; i < s->nb_components; i++) {
+ av_freep(&s->mean[i]);
+ av_freep(&s->stdev[i]);
+ av_freep(&s->min_value[i]);
+ av_freep(&s->max_value[i]);
+ }
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+ AVFilterContext *ctx = inlink->dst;
+ ColorStatsContext *s = ctx->priv;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
+
+ s->nb_components = desc->nb_components;
+ s->bitdepth = desc->comp[0].depth;
+ s->is_16bit = s->bitdepth > 8;
+ s->step = av_get_padded_bits_per_pixel(desc) >> (3 + s->is_16bit);
+ s->max = 1 << s->bitdepth - 1;
+
+ s->is_rgb = ff_fill_rgba_map(s->rgba_map, inlink->format) >= 0;
+ s->comps[0] = s->is_rgb ? 'r' : 'y' ;
+ s->comps[1] = s->is_rgb ? 'g' : 'u' ;
+ s->comps[2] = s->is_rgb ? 'b' : 'v' ;
+ s->comps[3] = 'a';
+
+ s->thread_count = FFMAX(1, FFMIN(inlink->h, ff_filter_get_nb_threads(ctx)));
+ for (int i = 0; i < s->nb_components; i++) {
+ ptrdiff_t line_size = av_image_get_linesize(inlink->format, inlink->w, i);
+
+ s->width[i] = line_size >> (s->bitdepth > 8);
+ s->height[i] = inlink->h >> ((i == 1 || i == 2) ? desc->log2_chroma_h : 0);
+
+ s->mean[i] = av_mallocz_array(s->thread_count, sizeof(*s->mean[i]));
+ s->stdev[i] = av_mallocz_array(s->thread_count, sizeof(*s->stdev[i]));
+ s->max_value[i] = av_mallocz_array(s->thread_count, sizeof(*s->max_value[i]));
+ s->min_value[i] = av_mallocz_array(s->thread_count, sizeof(*s->min_value[i]));
+ if (!s->mean[i] || !s->stdev[i] || !s->max_value[i] || !s->min_value[i])
+ return AVERROR(ENOMEM);
+ for (int j = 0; j < s->thread_count; j++) {
+ s->min_value[i][j] = (1 << s->bitdepth);
+ s->max_value[i][j] = 0;
+ }
+ }
+
+ if (desc->flags & AV_PIX_FMT_FLAG_PLANAR)
+ s->stats_slice = s->bitdepth <= 8 ? stats_slice_planar_8 : stats_slice_planar_16;
+ else
+ s->stats_slice = s->bitdepth <= 8 ? stats_slice_packed_8 : stats_slice_packed_16;
+
+ return 0;
+}
+
+static void set_meta_float(AVDictionary **metadata, const char *key, char c, float d)
+{
+ char value[128];
+ char key2[128];
+
+ snprintf(value, sizeof(value), "%.2f", d);
+ if (c)
+ snprintf(key2, sizeof(key2), "lavf.colorstats.%s.%c", key, c);
+ else
+ snprintf(key2, sizeof(key2), "lavf.colorstats.%s", key);
+ av_dict_set(metadata, key2, value, 0);
+}
+
+static void set_meta_int(AVDictionary **metadata, const char *key, char c, int d)
+{
+ char value[128];
+ char key2[128];
+
+ snprintf(value, sizeof(value), "%d", d);
+ if (c)
+ snprintf(key2, sizeof(key2), "lavf.colorstats.%s.%c", key, c);
+ else
+ snprintf(key2, sizeof(key2), "lavf.colorstats.%s", key);
+ av_dict_set(metadata, key2, value, 0);
+}
+
+static void report_detect_result(AVFilterContext *ctx, AVFrame *in)
+{
+ const ColorStatsContext *s = ctx->priv;
+ double mean[4] = { 0 };
+ double stdev[4] = { 0 };
+ double min_value[4] = { s->max };
+ double max_value[4] = { 0 };
+ int cidx;
+
+ for (int p = 0; p < s->nb_components; p++) {
+ cidx = s->is_rgb ? s->rgba_map[p] : p;
+
+ if (!(s->planes & (1 << p)))
+ continue;
+
+ for (int j = 0; j < s->thread_count; j++) {
+ mean[cidx] += s->mean[cidx][j];
+ stdev[cidx] += s->stdev[cidx][j];
+ if (s->min_value[cidx][j] < min_value[cidx])
+ min_value[cidx] = s->min_value[cidx][j];
+ if (s->max_value[cidx][j] > max_value[cidx])
+ max_value[cidx] = s->max_value[cidx][j];
+ }
+ mean[cidx] = mean[cidx] / s->thread_count;
+ stdev[cidx] = stdev[cidx] / s->thread_count;
+
+ set_meta_int(&in->metadata, "min", s->comps[p], min_value[cidx]);
+ set_meta_int(&in->metadata, "max", s->comps[p], max_value[cidx]);
+ set_meta_int(&in->metadata, "mean", s->comps[p], mean[cidx]);
+ set_meta_int(&in->metadata, "stdev", s->comps[p], stdev[cidx]);
+
+ set_meta_float(&in->metadata, "pmin", s->comps[p], min_value[cidx] / s->max);
+ set_meta_float(&in->metadata, "pmax", s->comps[p], max_value[cidx] / s->max);
+ set_meta_float(&in->metadata, "pmean", s->comps[p], mean[cidx] / s->max);
+ set_meta_float(&in->metadata, "pstdev", s->comps[p], stdev[cidx] / s->max);
+ }
+}
+
+static int activate(AVFilterContext *ctx)
+{
+ int ret;
+ AVFilterLink *inlink = ctx->inputs[0];
+ AVFilterLink *outlink = ctx->outputs[0];
+ ColorStatsContext *s = ctx->priv;
+ AVFrame *in;
+ ThreadData td;
+
+ FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink);
+
+ ret = ff_inlink_consume_frame(inlink, &in);
+ if (ret < 0)
+ return ret;
+
+ if (in) {
+ td.in = in;
+ ctx->internal->execute(ctx, s->stats_slice, &td, NULL, s->thread_count);
+
+ report_detect_result(ctx, in);
+ return ff_filter_frame(outlink, in);
+ }
+
+ FF_FILTER_FORWARD_STATUS(inlink, outlink);
+ FF_FILTER_FORWARD_WANTED(outlink, inlink);
+
+ return FFERROR_NOT_READY;
+}
+
+static const AVFilterPad inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_input,
+ },
+ { NULL }
+};
+
+static const AVFilterPad outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+#define DEFINE_COLOR_FILTER(name_, description_) \
+ AVFilter ff_vf_##name_ = { \
+ .name = #name_, \
+ .description = NULL_IF_CONFIG_SMALL(description_), \
+ .priv_size = sizeof(ColorStatsContext), \
+ .priv_class = &name_ ## _class, \
+ .init = name_##_init, \
+ .uninit = uninit, \
+ .query_formats = query_formats, \
+ .inputs = inputs, \
+ .outputs = outputs, \
+ .activate = activate, \
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | \
+ AVFILTER_FLAG_SLICE_THREADS, \
+ }
+
+#if CONFIG_COLORSTATS_FILTER
+
+#define colorstats_options options
+AVFILTER_DEFINE_CLASS(colorstats);
+
+static int colorstats_init(AVFilterContext *ctx)
+{
+ return 0;
+}
+
+DEFINE_COLOR_FILTER(colorstats, "Video color stats.");
+#endif
+
+#if CONFIG_COLORRGBSTATS_FILTER
+
+#define colorrgbstats_options options
+AVFILTER_DEFINE_CLASS(colorrgbstats);
+
+static int colorrgbstats_init(AVFilterContext *ctx)
+{
+ ColorStatsContext *s = ctx->priv;
+
+ s->force_fmt = 1;
+ return 0;
+}
+
+DEFINE_COLOR_FILTER(colorrgbstats, "Video RGB color stats.");
+#endif
+
+#if CONFIG_COLORYUVSTATS_FILTER
+
+#define coloryuvstats_options options
+AVFILTER_DEFINE_CLASS(coloryuvstats);
+
+static int coloryuvstats_init(AVFilterContext *ctx)
+{
+ ColorStatsContext *s = ctx->priv;
+
+ s->force_fmt = 2;
+ return 0;
+}
+
+DEFINE_COLOR_FILTER(coloryuvstats, "Video YUV color stats.");
+#endif
--
2.21.0
More information about the ffmpeg-devel
mailing list