| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* | ||
| 2 | * Copyright (c) 2021 Thilo Borgmann <thilo.borgmann _at_ mail.de> | ||
| 3 | * | ||
| 4 | * This file is part of FFmpeg. | ||
| 5 | * | ||
| 6 | * FFmpeg is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU Lesser General Public | ||
| 8 | * License as published by the Free Software Foundation; either | ||
| 9 | * version 2.1 of the License, or (at your option) any later version. | ||
| 10 | * | ||
| 11 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * Lesser General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Lesser General Public | ||
| 17 | * License along with FFmpeg; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | /** | ||
| 22 | * @file | ||
| 23 | * No-reference blurdetect filter | ||
| 24 | * | ||
| 25 | * Implementing: | ||
| 26 | * Marziliano, Pina, et al. "A no-reference perceptual blur metric." Proceedings. | ||
| 27 | * International conference on image processing. Vol. 3. IEEE, 2002. | ||
| 28 | * https://infoscience.epfl.ch/record/111802/files/14%20A%20no-reference%20perceptual%20blur%20metric.pdf | ||
| 29 | * | ||
| 30 | * @author Thilo Borgmann <thilo.borgmann _at_ mail.de> | ||
| 31 | */ | ||
| 32 | |||
| 33 | #include "libavutil/mem.h" | ||
| 34 | #include "libavutil/opt.h" | ||
| 35 | #include "libavutil/pixdesc.h" | ||
| 36 | #include "libavutil/qsort.h" | ||
| 37 | |||
| 38 | #include "filters.h" | ||
| 39 | #include "edge_common.h" | ||
| 40 | #include "video.h" | ||
| 41 | |||
| 42 | ✗ | static int comp(const float *a,const float *b) | |
| 43 | { | ||
| 44 | ✗ | return FFDIFFSIGN(*a, *b); | |
| 45 | } | ||
| 46 | |||
| 47 | typedef struct BLRContext { | ||
| 48 | const AVClass *class; | ||
| 49 | |||
| 50 | int hsub, vsub; | ||
| 51 | int nb_planes; | ||
| 52 | |||
| 53 | float low, high; | ||
| 54 | uint8_t low_u8, high_u8; | ||
| 55 | int radius; // radius during local maxima detection | ||
| 56 | int block_pct; // percentage of "sharpest" blocks in the image to use for bluriness calculation | ||
| 57 | int block_width; // width for block abbreviation | ||
| 58 | int block_height; // height for block abbreviation | ||
| 59 | int planes; // number of planes to filter | ||
| 60 | |||
| 61 | double blur_total; | ||
| 62 | uint64_t nb_frames; | ||
| 63 | |||
| 64 | float *blks; | ||
| 65 | uint8_t *filterbuf; | ||
| 66 | uint8_t *tmpbuf; | ||
| 67 | uint16_t *gradients; | ||
| 68 | int8_t *directions; | ||
| 69 | } BLRContext; | ||
| 70 | |||
| 71 | #define OFFSET(x) offsetof(BLRContext, x) | ||
| 72 | #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM | ||
| 73 | static const AVOption blurdetect_options[] = { | ||
| 74 | { "high", "set high threshold", OFFSET(high), AV_OPT_TYPE_FLOAT, {.dbl=30/255.}, 0, 1, FLAGS }, | ||
| 75 | { "low", "set low threshold", OFFSET(low), AV_OPT_TYPE_FLOAT, {.dbl=15/255.}, 0, 1, FLAGS }, | ||
| 76 | { "radius", "search radius for maxima detection", OFFSET(radius), AV_OPT_TYPE_INT, {.i64=50}, 1, 100, FLAGS }, | ||
| 77 | { "block_pct", "block pooling threshold when calculating blurriness", OFFSET(block_pct), AV_OPT_TYPE_INT, {.i64=80}, 1, 100, FLAGS }, | ||
| 78 | { "block_width", "block size for block-based abbreviation of blurriness", OFFSET(block_width), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX, FLAGS }, | ||
| 79 | { "block_height", "block size for block-based abbreviation of blurriness", OFFSET(block_height), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX, FLAGS }, | ||
| 80 | { "planes", "set planes to filter", OFFSET(planes), AV_OPT_TYPE_INT, {.i64=1}, 0, 15, FLAGS }, | ||
| 81 | { NULL } | ||
| 82 | }; | ||
| 83 | |||
| 84 | AVFILTER_DEFINE_CLASS(blurdetect); | ||
| 85 | |||
| 86 | 2 | static av_cold int blurdetect_init(AVFilterContext *ctx) | |
| 87 | { | ||
| 88 | 2 | BLRContext *s = ctx->priv; | |
| 89 | |||
| 90 | 2 | s->low_u8 = s->low * 255. + .5; | |
| 91 | 2 | s->high_u8 = s->high * 255. + .5; | |
| 92 | |||
| 93 | 2 | return 0; | |
| 94 | } | ||
| 95 | |||
| 96 | 1 | static int blurdetect_config_input(AVFilterLink *inlink) | |
| 97 | { | ||
| 98 | 1 | AVFilterContext *ctx = inlink->dst; | |
| 99 | 1 | BLRContext *s = ctx->priv; | |
| 100 | 1 | const int bufsize = inlink->w * inlink->h; | |
| 101 | const AVPixFmtDescriptor *pix_desc; | ||
| 102 | |||
| 103 | 1 | pix_desc = av_pix_fmt_desc_get(inlink->format); | |
| 104 | 1 | s->hsub = pix_desc->log2_chroma_w; | |
| 105 | 1 | s->vsub = pix_desc->log2_chroma_h; | |
| 106 | 1 | s->nb_planes = av_pix_fmt_count_planes(inlink->format); | |
| 107 | |||
| 108 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
1 | if (s->block_width < 1 || s->block_height < 1) { |
| 109 | 1 | s->block_width = inlink->w; | |
| 110 | 1 | s->block_height = inlink->h; | |
| 111 | } | ||
| 112 | |||
| 113 | 1 | s->tmpbuf = av_malloc(bufsize); | |
| 114 | 1 | s->filterbuf = av_malloc(bufsize); | |
| 115 | 1 | s->gradients = av_calloc(bufsize, sizeof(*s->gradients)); | |
| 116 | 1 | s->directions = av_malloc(bufsize); | |
| 117 | 1 | s->blks = av_calloc((inlink->w / s->block_width) * (inlink->h / s->block_height), | |
| 118 | sizeof(*s->blks)); | ||
| 119 | |||
| 120 |
5/10✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 times.
|
1 | if (!s->tmpbuf || !s->filterbuf || !s->gradients || !s->directions || !s->blks) |
| 121 | ✗ | return AVERROR(ENOMEM); | |
| 122 | |||
| 123 | 1 | return 0; | |
| 124 | } | ||
| 125 | |||
| 126 | // edge width is defined as the distance between surrounding maxima of the edge pixel | ||
| 127 | 9475 | static float edge_width(BLRContext *blr, int i, int j, int8_t dir, int w, int h, | |
| 128 | int edge, const uint8_t *src, int src_linesize) | ||
| 129 | { | ||
| 130 | 9475 | float width = 0; | |
| 131 | int dX, dY; | ||
| 132 | int sign; | ||
| 133 | int tmp; | ||
| 134 | int p1; | ||
| 135 | int p2; | ||
| 136 | int k, x, y; | ||
| 137 | 9475 | int radius = blr->radius; | |
| 138 | |||
| 139 |
4/5✓ Branch 0 taken 2344 times.
✓ Branch 1 taken 3412 times.
✓ Branch 2 taken 1970 times.
✓ Branch 3 taken 1749 times.
✗ Branch 4 not taken.
|
9475 | switch(dir) { |
| 140 | 2344 | case DIRECTION_HORIZONTAL: dX = 1; dY = 0; break; | |
| 141 | 3412 | case DIRECTION_VERTICAL: dX = 0; dY = 1; break; | |
| 142 | 1970 | case DIRECTION_45UP: dX = 1; dY = -1; break; | |
| 143 | 1749 | case DIRECTION_45DOWN: dX = 1; dY = 1; break; | |
| 144 | ✗ | default: dX = 1; dY = 1; break; | |
| 145 | } | ||
| 146 | |||
| 147 | // determines if search in direction dX/dY is looking for a maximum or minimum | ||
| 148 |
2/2✓ Branch 0 taken 4985 times.
✓ Branch 1 taken 4490 times.
|
9475 | sign = src[j * src_linesize + i] > src[(j - dY) * src_linesize + i - dX] ? 1 : -1; |
| 149 | |||
| 150 | // search in -(dX/dY) direction | ||
| 151 |
1/2✓ Branch 0 taken 34427 times.
✗ Branch 1 not taken.
|
34427 | for (k = 0; k < radius; k++) { |
| 152 | 34427 | x = i - k*dX; | |
| 153 | 34427 | y = j - k*dY; | |
| 154 | 34427 | p1 = y * src_linesize + x; | |
| 155 | 34427 | x -= dX; | |
| 156 | 34427 | y -= dY; | |
| 157 | 34427 | p2 = y * src_linesize + x; | |
| 158 |
5/8✓ Branch 0 taken 34426 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 34426 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 34426 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 34426 times.
|
34427 | if (x < 0 || x >= w || y < 0 || y >= h) |
| 159 | 1 | return 0; | |
| 160 | |||
| 161 | 34426 | tmp = (src[p1] - src[p2]) * sign; | |
| 162 | |||
| 163 |
2/2✓ Branch 0 taken 9474 times.
✓ Branch 1 taken 24952 times.
|
34426 | if (tmp <= 0) // local maximum found |
| 164 | 9474 | break; | |
| 165 | } | ||
| 166 | 9474 | width += k; | |
| 167 | |||
| 168 | // search in +(dX/dY) direction | ||
| 169 |
1/2✓ Branch 0 taken 34177 times.
✗ Branch 1 not taken.
|
34177 | for (k = 0; k < radius; k++) { |
| 170 | 34177 | x = i + k * dX; | |
| 171 | 34177 | y = j + k * dY; | |
| 172 | 34177 | p1 = y * src_linesize + x; | |
| 173 | 34177 | x += dX; | |
| 174 | 34177 | y += dY; | |
| 175 | 34177 | p2 = y * src_linesize + x; | |
| 176 |
5/8✓ Branch 0 taken 34177 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 34177 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 34167 times.
✓ Branch 5 taken 10 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 34167 times.
|
34177 | if (x < 0 || x >= w || y < 0 || y >= h) |
| 177 | 10 | return 0; | |
| 178 | |||
| 179 | 34167 | tmp = (src[p1] - src[p2]) * sign; | |
| 180 | |||
| 181 |
2/2✓ Branch 0 taken 9464 times.
✓ Branch 1 taken 24703 times.
|
34167 | if (tmp >= 0) // local maximum found |
| 182 | 9464 | break; | |
| 183 | } | ||
| 184 | 9464 | width += k; | |
| 185 | |||
| 186 | // for 45 degree directions approximate edge width in pixel units: 0.7 ~= sqrt(2)/2 | ||
| 187 |
4/4✓ Branch 0 taken 7504 times.
✓ Branch 1 taken 1960 times.
✓ Branch 2 taken 1748 times.
✓ Branch 3 taken 5756 times.
|
9464 | if (dir == DIRECTION_45UP || dir == DIRECTION_45DOWN) |
| 188 | 3708 | width *= 0.7; | |
| 189 | |||
| 190 | 9464 | return width; | |
| 191 | } | ||
| 192 | |||
| 193 | 5 | static float calculate_blur(BLRContext *s, int w, int h, int hsub, int vsub, | |
| 194 | int8_t* dir, int dir_linesize, | ||
| 195 | uint8_t* dst, int dst_linesize, | ||
| 196 | uint8_t* src, int src_linesize) | ||
| 197 | { | ||
| 198 | 5 | float total_width = 0.0; | |
| 199 | |||
| 200 | 5 | int blkcnt = 0; | |
| 201 | |||
| 202 | 5 | float *blks = s->blks; | |
| 203 | 5 | float block_pool_threshold = s->block_pct / 100.0; | |
| 204 | |||
| 205 | 5 | int block_width = AV_CEIL_RSHIFT(s->block_width, hsub); | |
| 206 | 5 | int block_height = AV_CEIL_RSHIFT(s->block_height, vsub); | |
| 207 | 5 | int brows = h / block_height; | |
| 208 | 5 | int bcols = w / block_width; | |
| 209 | |||
| 210 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
|
10 | for (int blkj = 0; blkj < brows; blkj++) { |
| 211 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
|
10 | for (int blki = 0; blki < bcols; blki++) { |
| 212 | 5 | double block_total_width = 0.0; | |
| 213 | 5 | int block_count = 0; | |
| 214 |
2/2✓ Branch 0 taken 1000 times.
✓ Branch 1 taken 5 times.
|
1005 | for (int inj = 0; inj < block_height; inj++) { |
| 215 |
2/2✓ Branch 0 taken 300000 times.
✓ Branch 1 taken 1000 times.
|
301000 | for (int ini = 0; ini < block_width; ini++) { |
| 216 | 300000 | int i = blki * block_width + ini; | |
| 217 | 300000 | int j = blkj * block_height + inj; | |
| 218 | |||
| 219 |
2/2✓ Branch 0 taken 9475 times.
✓ Branch 1 taken 290525 times.
|
300000 | if (dst[j * dst_linesize + i] > 0) { |
| 220 | 9475 | float width = edge_width(s, i, j, dir[j*dir_linesize+i], | |
| 221 | 9475 | w, h, dst[j*dst_linesize+i], | |
| 222 | src, src_linesize); | ||
| 223 |
2/2✓ Branch 0 taken 9455 times.
✓ Branch 1 taken 20 times.
|
9475 | if (width > 0.001) { // throw away zeros |
| 224 | 9455 | block_count++; | |
| 225 | 9455 | block_total_width += width; | |
| 226 | } | ||
| 227 | } | ||
| 228 | } | ||
| 229 | } | ||
| 230 | // if not enough edge pixels in a block, consider it smooth | ||
| 231 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | if (block_total_width >= 2 && block_count) { |
| 232 | 5 | blks[blkcnt] = block_total_width / block_count; | |
| 233 | 5 | blkcnt++; | |
| 234 | } | ||
| 235 | } | ||
| 236 | } | ||
| 237 | |||
| 238 | // simple block pooling by sorting and keeping the sharper blocks | ||
| 239 |
3/44✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 39 not taken.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✗ Branch 42 not taken.
✗ Branch 43 not taken.
✗ Branch 44 not taken.
✗ Branch 46 not taken.
✗ Branch 47 not taken.
✗ Branch 48 not taken.
✓ Branch 49 taken 5 times.
✓ Branch 50 taken 5 times.
✓ Branch 51 taken 5 times.
|
10 | AV_QSORT(blks, blkcnt, float, comp); |
| 240 | 5 | blkcnt = ceil(blkcnt * block_pool_threshold); | |
| 241 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
|
10 | for (int i = 0; i < blkcnt; i++) { |
| 242 | 5 | total_width += blks[i]; | |
| 243 | } | ||
| 244 | |||
| 245 | 5 | return total_width / blkcnt; | |
| 246 | } | ||
| 247 | |||
| 248 | 5 | static void set_meta(AVDictionary **metadata, const char *key, float d) | |
| 249 | { | ||
| 250 | char value[128]; | ||
| 251 | 5 | snprintf(value, sizeof(value), "%f", d); | |
| 252 | 5 | av_dict_set(metadata, key, value, 0); | |
| 253 | 5 | } | |
| 254 | |||
| 255 | 5 | static int blurdetect_filter_frame(AVFilterLink *inlink, AVFrame *in) | |
| 256 | { | ||
| 257 | 5 | FilterLink *inl = ff_filter_link(inlink); | |
| 258 | 5 | AVFilterContext *ctx = inlink->dst; | |
| 259 | 5 | BLRContext *s = ctx->priv; | |
| 260 | 5 | AVFilterLink *outlink = ctx->outputs[0]; | |
| 261 | |||
| 262 | 5 | const int inw = inlink->w; | |
| 263 | 5 | const int inh = inlink->h; | |
| 264 | |||
| 265 | 5 | uint8_t *tmpbuf = s->tmpbuf; | |
| 266 | 5 | uint8_t *filterbuf = s->filterbuf; | |
| 267 | 5 | uint16_t *gradients = s->gradients; | |
| 268 | 5 | int8_t *directions = s->directions; | |
| 269 | |||
| 270 | 5 | float blur = 0.0f; | |
| 271 | 5 | int nplanes = 0; | |
| 272 | AVDictionary **metadata; | ||
| 273 | 5 | metadata = &in->metadata; | |
| 274 | |||
| 275 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 5 times.
|
20 | for (int plane = 0; plane < s->nb_planes; plane++) { |
| 276 |
4/4✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 5 times.
|
15 | int hsub = plane == 1 || plane == 2 ? s->hsub : 0; |
| 277 |
4/4✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 5 times.
|
15 | int vsub = plane == 1 || plane == 2 ? s->vsub : 0; |
| 278 | 15 | int w = AV_CEIL_RSHIFT(inw, hsub); | |
| 279 | 15 | int h = AV_CEIL_RSHIFT(inh, vsub); | |
| 280 | |||
| 281 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
|
15 | if (!((1 << plane) & s->planes)) |
| 282 | 10 | continue; | |
| 283 | |||
| 284 | 5 | nplanes++; | |
| 285 | |||
| 286 | // gaussian filter to reduce noise | ||
| 287 | 5 | ff_gaussian_blur_8(w, h, | |
| 288 | filterbuf, w, | ||
| 289 | 5 | in->data[plane], in->linesize[plane], 1); | |
| 290 | |||
| 291 | // compute the 16-bits gradients and directions for the next step | ||
| 292 | 5 | ff_sobel_8(w, h, gradients, w, directions, w, filterbuf, w, 1); | |
| 293 | |||
| 294 | // non_maximum_suppression() will actually keep & clip what's necessary and | ||
| 295 | // ignore the rest, so we need a clean output buffer | ||
| 296 | 5 | memset(tmpbuf, 0, inw * inh); | |
| 297 | 5 | ff_non_maximum_suppression(w, h, tmpbuf, w, directions, w, gradients, w); | |
| 298 | |||
| 299 | |||
| 300 | // keep high values, or low values surrounded by high values | ||
| 301 | 5 | ff_double_threshold(s->low_u8, s->high_u8, w, h, | |
| 302 | tmpbuf, w, tmpbuf, w); | ||
| 303 | |||
| 304 | 5 | blur += calculate_blur(s, w, h, hsub, vsub, directions, w, | |
| 305 | tmpbuf, w, filterbuf, w); | ||
| 306 | } | ||
| 307 | |||
| 308 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | if (nplanes) |
| 309 | 5 | blur /= nplanes; | |
| 310 | |||
| 311 | 5 | s->blur_total += blur; | |
| 312 | |||
| 313 | // write stats | ||
| 314 | 5 | av_log(ctx, AV_LOG_VERBOSE, "blur: %.7f\n", blur); | |
| 315 | |||
| 316 | 5 | set_meta(metadata, "lavfi.blur", blur); | |
| 317 | |||
| 318 | 5 | s->nb_frames = inl->frame_count_in; | |
| 319 | |||
| 320 | 5 | return ff_filter_frame(outlink, in); | |
| 321 | } | ||
| 322 | |||
| 323 | 2 | static av_cold void blurdetect_uninit(AVFilterContext *ctx) | |
| 324 | { | ||
| 325 | 2 | BLRContext *s = ctx->priv; | |
| 326 | |||
| 327 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (s->nb_frames > 0) { |
| 328 | 1 | av_log(ctx, AV_LOG_INFO, "blur mean: %.7f\n", | |
| 329 | 1 | s->blur_total / s->nb_frames); | |
| 330 | } | ||
| 331 | |||
| 332 | 2 | av_freep(&s->tmpbuf); | |
| 333 | 2 | av_freep(&s->filterbuf); | |
| 334 | 2 | av_freep(&s->gradients); | |
| 335 | 2 | av_freep(&s->directions); | |
| 336 | 2 | av_freep(&s->blks); | |
| 337 | 2 | } | |
| 338 | |||
| 339 | static const enum AVPixelFormat pix_fmts[] = { | ||
| 340 | AV_PIX_FMT_GRAY8, | ||
| 341 | AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, | ||
| 342 | AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P, | ||
| 343 | AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV440P, | ||
| 344 | AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P, | ||
| 345 | AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUVJ420P, | ||
| 346 | AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P, | ||
| 347 | AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA420P, | ||
| 348 | AV_PIX_FMT_NONE | ||
| 349 | }; | ||
| 350 | |||
| 351 | static const AVFilterPad blurdetect_inputs[] = { | ||
| 352 | { | ||
| 353 | .name = "default", | ||
| 354 | .type = AVMEDIA_TYPE_VIDEO, | ||
| 355 | .config_props = blurdetect_config_input, | ||
| 356 | .filter_frame = blurdetect_filter_frame, | ||
| 357 | }, | ||
| 358 | }; | ||
| 359 | |||
| 360 | const FFFilter ff_vf_blurdetect = { | ||
| 361 | .p.name = "blurdetect", | ||
| 362 | .p.description = NULL_IF_CONFIG_SMALL("Blurdetect filter."), | ||
| 363 | .p.priv_class = &blurdetect_class, | ||
| 364 | .p.flags = AVFILTER_FLAG_METADATA_ONLY, | ||
| 365 | .priv_size = sizeof(BLRContext), | ||
| 366 | .init = blurdetect_init, | ||
| 367 | .uninit = blurdetect_uninit, | ||
| 368 | FILTER_PIXFMTS_ARRAY(pix_fmts), | ||
| 369 | FILTER_INPUTS(blurdetect_inputs), | ||
| 370 | FILTER_OUTPUTS(ff_video_default_filterpad), | ||
| 371 | }; | ||
| 372 |