FFmpeg
Loading...
Searching...
No Matches
vf_blockdetect.c
Go to the documentation of this file.
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 blockdetect filter
24 *
25 * Implementing:
26 * Remco Muijs and Ihor Kirenko: "A no-reference blocking artifact measure for adaptive video processing." 2005 13th European signal processing conference. IEEE, 2005.
27 * http://www.eurasip.org/Proceedings/Eusipco/Eusipco2005/defevent/papers/cr1042.pdf
28 *
29 * @author Thilo Borgmann <thilo.borgmann _at_ mail.de>
30 */
31
32#include "libavutil/mem.h"
33#include "libavutil/opt.h"
34#include "libavutil/pixdesc.h"
35
36#include "filters.h"
37#include "video.h"
38
39typedef struct BLKContext {
40 const AVClass *class;
41
42 int hsub, vsub;
44
45 int period_min; // minimum period to search for
46 int period_max; // maximum period to search for
47 int planes; // number of planes to filter
48
50 uint64_t nb_frames;
51
52 float *gradients;
54
55#define OFFSET(x) offsetof(BLKContext, x)
56#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
57static const AVOption blockdetect_options[] = {
58 { "period_min", "Minimum period to search for", OFFSET(period_min), AV_OPT_TYPE_INT, {.i64=3}, 2, 32, FLAGS},
59 { "period_max", "Maximum period to search for", OFFSET(period_max), AV_OPT_TYPE_INT, {.i64=24}, 2, 64, FLAGS},
60 { "planes", "set planes to filter", OFFSET(planes), AV_OPT_TYPE_INT, {.i64=1}, 0, 15, FLAGS },
61 { NULL }
62};
63
65
67{
68 AVFilterContext *ctx = inlink->dst;
69 BLKContext *s = ctx->priv;
70 const int bufsize = inlink->w * inlink->h;
71 const AVPixFmtDescriptor *pix_desc;
72
73 pix_desc = av_pix_fmt_desc_get(inlink->format);
74 s->hsub = pix_desc->log2_chroma_w;
75 s->vsub = pix_desc->log2_chroma_h;
76 s->nb_planes = av_pix_fmt_count_planes(inlink->format);
77
78 s->gradients = av_calloc(bufsize, sizeof(*s->gradients));
79
80 if (!s->gradients)
81 return AVERROR(ENOMEM);
82
83 return 0;
84}
85
86static float calculate_blockiness(BLKContext *s, int w, int h,
87 float *grad, int grad_linesize,
88 uint8_t* src, int src_linesize)
89{
90 float block = 0.0f;
91 float nonblock = 0.0f;
92 int block_count = 0;
93 int nonblock_count = 0;
94 float ret = 0;
95
96 // Calculate BS in horizontal and vertical directions according to (1)(2)(3).
97 // Also try to find integer pixel periods (grids) even for scaled images.
98 // In case of fractional periods, FFMAX of current and neighbor pixels
99 // can help improve the correlation with MQS.
100 // Skip linear correction term (4)(5), as it appears only valid for their own test samples.
101
102 // horizontal blockiness (fixed width)
103 for (int j = 1; j < h; j++) {
104 for (int i = 3; i < w - 4; i++) {
105 float temp = 0.0f;
106 grad[j * grad_linesize + i] =
107 abs(src[j * src_linesize + i + 0] - src[j * src_linesize + i + 1]);
108 temp += abs(src[j * src_linesize + i + 1] - src[j * src_linesize + i + 2]);
109 temp += abs(src[j * src_linesize + i + 2] - src[j * src_linesize + i + 3]);
110 temp += abs(src[j * src_linesize + i + 3] - src[j * src_linesize + i + 4]);
111 temp += abs(src[j * src_linesize + i - 0] - src[j * src_linesize + i - 1]);
112 temp += abs(src[j * src_linesize + i - 1] - src[j * src_linesize + i - 2]);
113 temp += abs(src[j * src_linesize + i - 2] - src[j * src_linesize + i - 3]);
114 temp = FFMAX(1, temp);
115 grad[j * grad_linesize + i] /= temp;
116
117 // use first row to store acculated results
118 grad[i] += grad[j * grad_linesize + i];
119 }
120 }
121
122 // find horizontal period
123 for (int period = s->period_min; period < s->period_max + 1; period++) {
124 float temp;
125 block = 0;
126 nonblock = 0;
127 block_count = 0;
128 nonblock_count = 0;
129 for (int i = 3; i < w - 4; i++) {
130 if ((i % period) == (period - 1)) {
131 block += FFMAX(FFMAX(grad[i + 0], grad[i + 1]), grad[i - 1]);
132 block_count++;
133 } else {
134 nonblock += grad[i];
135 nonblock_count++;
136 }
137 }
138 if (block_count && nonblock_count) {
139 temp = (block / block_count) / (nonblock / nonblock_count);
140 ret = FFMAX(ret, temp);
141 }
142 }
143
144 // vertical blockiness (fixed height)
145 block_count = 0;
146 for (int j = 3; j < h - 4; j++) {
147 for (int i = 1; i < w; i++) {
148 float temp = 0.0f;
149 grad[j * grad_linesize + i] =
150 abs(src[(j + 0) * src_linesize + i] - src[(j + 1) * src_linesize + i]);
151 temp += abs(src[(j + 1) * src_linesize + i] - src[(j + 2) * src_linesize + i]);
152 temp += abs(src[(j + 2) * src_linesize + i] - src[(j + 3) * src_linesize + i]);
153 temp += abs(src[(j + 3) * src_linesize + i] - src[(j + 4) * src_linesize + i]);
154 temp += abs(src[(j - 0) * src_linesize + i] - src[(j - 1) * src_linesize + i]);
155 temp += abs(src[(j - 1) * src_linesize + i] - src[(j - 2) * src_linesize + i]);
156 temp += abs(src[(j - 2) * src_linesize + i] - src[(j - 3) * src_linesize + i]);
157 temp = FFMAX(1, temp);
158 grad[j * grad_linesize + i] /= temp;
159
160 // use first column to store accumulated results
161 grad[j * grad_linesize] += grad[j * grad_linesize + i];
162 }
163 }
164
165 // find vertical period
166 for (int period = s->period_min; period < s->period_max + 1; period++) {
167 float temp;
168 block = 0;
169 nonblock = 0;
170 block_count = 0;
171 nonblock_count = 0;
172 for (int j = 3; j < h - 4; j++) {
173 if ((j % period) == (period - 1)) {
174 block += FFMAX(FFMAX(grad[(j + 0) * grad_linesize],
175 grad[(j + 1) * grad_linesize]),
176 grad[(j - 1) * grad_linesize]);
177 block_count++;
178 } else {
179 nonblock += grad[j * grad_linesize];
180 nonblock_count++;
181 }
182 }
183 if (block_count && nonblock_count) {
184 temp = (block / block_count) / (nonblock / nonblock_count);
185 ret = FFMAX(ret, temp);
186 }
187 }
188
189 // return highest value of horz||vert
190 return ret;
191}
192
193static void set_meta(AVDictionary **metadata, const char *key, float d)
194{
195 char value[128];
196 snprintf(value, sizeof(value), "%f", d);
198}
199
201{
202 FilterLink *inl = ff_filter_link(inlink);
203 AVFilterContext *ctx = inlink->dst;
204 BLKContext *s = ctx->priv;
205 AVFilterLink *outlink = ctx->outputs[0];
206
207 const int inw = inlink->w;
208 const int inh = inlink->h;
209
210 float *gradients = s->gradients;
211
212 float block = 0.0f;
213 int nplanes = 0;
215 metadata = &in->metadata;
216
217 for (int plane = 0; plane < s->nb_planes; plane++) {
218 int hsub = plane == 1 || plane == 2 ? s->hsub : 0;
219 int vsub = plane == 1 || plane == 2 ? s->vsub : 0;
220 int w = AV_CEIL_RSHIFT(inw, hsub);
221 int h = AV_CEIL_RSHIFT(inh, vsub);
222
223 if (!((1 << plane) & s->planes))
224 continue;
225
226 nplanes++;
227
228 block += calculate_blockiness(s, w, h, gradients, w, in->data[plane], in->linesize[plane]);
229 }
230
231 if (nplanes)
232 block /= nplanes;
233
234 s->block_total += block;
235
236 // write stats
237 av_log(ctx, AV_LOG_VERBOSE, "block: %.7f\n", block);
238
239 set_meta(metadata, "lavfi.block", block);
240
241 s->nb_frames = inl->frame_count_in;
242
243 return ff_filter_frame(outlink, in);
244}
245
247{
248 BLKContext *s = ctx->priv;
249
250 if (s->nb_frames > 0) {
251 av_log(ctx, AV_LOG_INFO, "block mean: %.7f\n",
252 s->block_total / s->nb_frames);
253 }
254
255 av_freep(&s->gradients);
256}
257
269
271 {
272 .name = "default",
273 .type = AVMEDIA_TYPE_VIDEO,
274 .config_props = blockdetect_config_input,
275 .filter_frame = blockdetect_filter_frame,
276 },
277};
278
280 .p.name = "blockdetect",
281 .p.description = NULL_IF_CONFIG_SMALL("Blockdetect filter."),
282 .p.priv_class = &blockdetect_class,
284 .priv_size = sizeof(BLKContext),
289};
const FFFilter ff_vf_blockdetect
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition avfilter.c:1068
static int FUNC metadata(CodedBitstreamContext *ctx, RWContext *rw, APVRawMetadata *current)
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define s(width, name)
Definition cbs_vp9.c:198
#define FLAGS
Definition cmdutils.c:598
#define AV_CEIL_RSHIFT(a, b)
Definition common.h:60
#define NULL
Definition coverity.c:32
#define abs(x)
static int16_t block[64]
Definition dct.c:125
double value
Definition eval.c:102
const char * key
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition opt.h:258
#define AVFILTER_FLAG_METADATA_ONLY
The filter is a "metadata" filter - it does not modify the frame data in any way.
Definition avfilter.h:182
int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags)
Set the given entry in *pm, overwriting an existing entry.
Definition dict.c:86
#define AVERROR(e)
Definition error.h:45
#define AV_LOG_VERBOSE
Detailed information.
Definition log.h:226
#define AV_LOG_INFO
Standard information.
Definition log.h:221
@ AVMEDIA_TYPE_VIDEO
Definition avutil.h:200
static av_cold void uninit(AVBitStreamFilterContext *ctx)
#define FILTER_INPUTS(array)
Definition filters.h:264
#define FILTER_OUTPUTS(array)
Definition filters.h:265
#define FILTER_PIXFMTS_ARRAY(array)
Definition filters.h:244
static FilterLink * ff_filter_link(AVFilterLink *link)
Definition filters.h:199
#define AVFILTER_DEFINE_CLASS(fname)
Definition filters.h:478
#define av_cold
Definition attributes.h:117
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition internal.h:88
static enum AVPixelFormat pix_fmts[]
Definition libkvazaar.c:296
static const struct @257111027162314367033347246032313251342043035002 planes[]
uint8_t w
Definition llvidencdsp.c:39
#define FFMAX(a, b)
Definition macros.h:47
void * av_calloc(size_t nmemb, size_t size)
Definition mem.c:264
Memory handling functions.
AVOptions.
static double grad(int hash, double x, double y, double z)
Definition perlin.c:42
int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt)
Definition pixdesc.c:3500
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition pixdesc.c:3460
AVPixelFormat
Pixel format.
Definition pixfmt.h:71
@ AV_PIX_FMT_NONE
Definition pixfmt.h:72
@ AV_PIX_FMT_YUV420P
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition pixfmt.h:73
@ AV_PIX_FMT_YUV440P
planar YUV 4:4:0 (1 Cr & Cb sample per 1x2 Y samples)
Definition pixfmt.h:106
@ AV_PIX_FMT_YUV422P
planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
Definition pixfmt.h:77
@ AV_PIX_FMT_GRAY8
Y , 8bpp.
Definition pixfmt.h:81
@ AV_PIX_FMT_YUVA420P
planar YUV 4:2:0, 20bpp, (1 Cr & Cb sample per 2x2 Y & A samples)
Definition pixfmt.h:108
@ AV_PIX_FMT_YUVJ440P
planar YUV 4:4:0 full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV440P and setting color_range
Definition pixfmt.h:107
@ AV_PIX_FMT_YUV410P
planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples)
Definition pixfmt.h:79
@ AV_PIX_FMT_YUV411P
planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples)
Definition pixfmt.h:80
@ AV_PIX_FMT_YUV444P
planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
Definition pixfmt.h:78
@ AV_PIX_FMT_YUVA444P
planar YUV 4:4:4 32bpp, (1 Cr & Cb sample per 1x1 Y & A samples)
Definition pixfmt.h:174
@ AV_PIX_FMT_YUVJ411P
planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples) full scale (JPEG), deprecated in favor ...
Definition pixfmt.h:283
@ AV_PIX_FMT_GBRAP
planar GBRA 4:4:4:4 32bpp
Definition pixfmt.h:212
@ AV_PIX_FMT_YUVJ422P
planar YUV 4:2:2, 16bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV422P and setting col...
Definition pixfmt.h:86
@ AV_PIX_FMT_YUVA422P
planar YUV 4:2:2 24bpp, (1 Cr & Cb sample per 2x1 Y & A samples)
Definition pixfmt.h:173
@ AV_PIX_FMT_GBRP
planar GBR 4:4:4 24bpp
Definition pixfmt.h:165
@ AV_PIX_FMT_YUVJ444P
planar YUV 4:4:4, 24bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV444P and setting col...
Definition pixfmt.h:87
@ AV_PIX_FMT_YUVJ420P
planar YUV 4:2:0, 12bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV420P and setting col...
Definition pixfmt.h:85
#define snprintf
Definition snprintf.h:34
Describe the class of an AVClass context structure.
Definition log.h:76
An instance of a filter.
Definition avfilter.h:273
A filter pad used for either input or output.
Definition filters.h:40
This structure describes decoded (raw) audio or video data.
Definition frame.h:472
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition frame.h:493
AVDictionary * metadata
metadata.
Definition frame.h:750
int linesize[AV_NUM_DATA_POINTERS]
For video, a positive or negative value, which is typically indicating the size in bytes of each pict...
Definition frame.h:517
AVOption.
Definition opt.h:428
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition pixdesc.h:69
uint8_t log2_chroma_w
Amount to shift the luma width right to find the chroma width.
Definition pixdesc.h:80
uint8_t log2_chroma_h
Amount to shift the luma height right to find the chroma height.
Definition pixdesc.h:89
double block_total
uint64_t nb_frames
float * gradients
#define av_freep(p)
#define av_log(a,...)
#define src
Definition vp8dsp.c:248
static AVFormatContext * ctx
Definition movenc.c:49
static float calculate_blockiness(BLKContext *s, int w, int h, float *grad, int grad_linesize, uint8_t *src, int src_linesize)
static av_cold void blockdetect_uninit(AVFilterContext *ctx)
static int blockdetect_config_input(AVFilterLink *inlink)
static void set_meta(AVDictionary **metadata, const char *key, float d)
static const AVFilterPad blockdetect_inputs[]
static int blockdetect_filter_frame(AVFilterLink *inlink, AVFrame *in)
static const AVOption blockdetect_options[]
#define OFFSET(x)
else temp
Definition vf_mcdeint.c:275
static void hsub(htype *dst, const htype *src, int bins)
Definition vf_median.c:74
const AVFilterPad ff_video_default_filterpad[1]
An AVFilterPad array whose only entry has name "default" and is of type AVMEDIA_TYPE_VIDEO.
Definition video.c:37