On 12/27/19, Limin Wang <lance.lmw...@gmail.com> wrote: > On Fri, Dec 27, 2019 at 12:35:25PM +0100, Paul B Mahol wrote: >> You are duplicating some functionality of signalstats filter. >> > Yes, I have other function need to use the mean and stdev which is > support in showinfo filter(only 8bit and don't support packed format, > no multi-thread), and signalstats don't support rgb format and don't > have stdev, also it have too many other function and difficult to change > it, so I think it's more simple to create a new filter to do it. >
No, unacceptable. use signalstats filter. > >> On 12/27/19, lance.lmw...@gmail.com <lance.lmw...@gmail.com> wrote: >> > From: Limin Wang <lance.lmw...@gmail.com> >> > >> > Signed-off-by: Limin Wang <lance.lmw...@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 >> > >> > +@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. >> > + >> > +@var{colorrgbstats} report the color stats for RGB input video, >> > @var{coloryuvstats} >> > +to an YUV input video. >> > + >> > +These filters accept the following parameters: >> > +@table @option >> > +@item planes >> > +Set which planes to filter. Default is only the first plane. >> > +@end table >> > + >> > +By default the filter will report these metadata values if the planes >> > +are processed: >> > + >> > +@table @option >> > +@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] >> > + >> > +@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] >> > + >> > +@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] >> > + >> > +@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] >> > + >> > +@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] >> > + >> > +@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] >> > + >> > +@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] >> > + >> > +@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] >> > +@end table >> > + >> > +@subsection Examples >> > + >> > +@itemize >> > +@item >> > +Show all YUV color stats for each frame: >> > +@example >> > +ffprobe -f lavfi movie=example.mov,coloryuvstats=planes=0xf >> > -show_frames >> > +@end example >> > + >> > +@item >> > +Draw graph for the pmean and pstdev value of the Y plane per frame: >> > +@example >> > +ffplay -i example.mov -vf >> > coloryuvstats,drawgraph=m1=lavf.colorstats.pmean.y:m2=lavf.colorstats.pstdev.y:min=0:max=1 >> > +@end example >> > + >> > +@item >> > +Print all RGB color stats for each frame: >> > +@example >> > +ffplay -i example.mov -vf colorrgbstats=planes=0xf,metadata=mode=print >> > +@end example >> > + >> > +@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 >> > >> > _______________________________________________ >> > ffmpeg-devel mailing list >> > ffmpeg-devel@ffmpeg.org >> > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel >> > >> > To unsubscribe, visit link above, or email >> > ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe". > > -- > Thanks, > Limin Wang > _______________________________________________ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > To unsubscribe, visit link above, or email > ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe". _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".