FFmpeg
vf_ssim.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2003-2013 Loren Merritt
3  * Copyright (c) 2015 Paul B Mahol
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 /* Computes the Structural Similarity Metric between two video streams.
23  * original algorithm:
24  * Z. Wang, A. C. Bovik, H. R. Sheikh and E. P. Simoncelli,
25  * "Image quality assessment: From error visibility to structural similarity,"
26  * IEEE Transactions on Image Processing, vol. 13, no. 4, pp. 600-612, Apr. 2004.
27  *
28  * To improve speed, this implementation uses the standard approximation of
29  * overlapped 8x8 block sums, rather than the original gaussian weights.
30  */
31 
32 /*
33  * @file
34  * Caculate the SSIM between two input videos.
35  */
36 
37 #include "libavutil/avstring.h"
38 #include "libavutil/opt.h"
39 #include "libavutil/pixdesc.h"
40 #include "avfilter.h"
41 #include "drawutils.h"
42 #include "formats.h"
43 #include "framesync.h"
44 #include "internal.h"
45 #include "ssim.h"
46 #include "video.h"
47 
48 typedef struct SSIMContext {
49  const AVClass *class;
51  FILE *stats_file;
54  int max;
55  uint64_t nb_frames;
56  double ssim[4], ssim_total;
57  char comps[4];
58  float coefs[4];
60  int planewidth[4];
61  int planeheight[4];
62  int *temp;
63  int is_rgb;
65  uint8_t *main, int main_stride,
66  uint8_t *ref, int ref_stride,
67  int width, int height, void *temp,
68  int max);
70 } SSIMContext;
71 
72 #define OFFSET(x) offsetof(SSIMContext, x)
73 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
74 
75 static const AVOption ssim_options[] = {
76  {"stats_file", "Set file where to store per-frame difference information", OFFSET(stats_file_str), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS },
77  {"f", "Set file where to store per-frame difference information", OFFSET(stats_file_str), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS },
78  { NULL }
79 };
80 
82 
83 static void set_meta(AVDictionary **metadata, const char *key, char comp, float d)
84 {
85  char value[128];
86  snprintf(value, sizeof(value), "%0.2f", d);
87  if (comp) {
88  char key2[128];
89  snprintf(key2, sizeof(key2), "%s%c", key, comp);
90  av_dict_set(metadata, key2, value, 0);
91  } else {
92  av_dict_set(metadata, key, value, 0);
93  }
94 }
95 
96 static void ssim_4x4xn_16bit(const uint8_t *main8, ptrdiff_t main_stride,
97  const uint8_t *ref8, ptrdiff_t ref_stride,
98  int64_t (*sums)[4], int width)
99 {
100  const uint16_t *main16 = (const uint16_t *)main8;
101  const uint16_t *ref16 = (const uint16_t *)ref8;
102  int x, y, z;
103 
104  main_stride >>= 1;
105  ref_stride >>= 1;
106 
107  for (z = 0; z < width; z++) {
108  uint64_t s1 = 0, s2 = 0, ss = 0, s12 = 0;
109 
110  for (y = 0; y < 4; y++) {
111  for (x = 0; x < 4; x++) {
112  unsigned a = main16[x + y * main_stride];
113  unsigned b = ref16[x + y * ref_stride];
114 
115  s1 += a;
116  s2 += b;
117  ss += a*a;
118  ss += b*b;
119  s12 += a*b;
120  }
121  }
122 
123  sums[z][0] = s1;
124  sums[z][1] = s2;
125  sums[z][2] = ss;
126  sums[z][3] = s12;
127  main16 += 4;
128  ref16 += 4;
129  }
130 }
131 
132 static void ssim_4x4xn_8bit(const uint8_t *main, ptrdiff_t main_stride,
133  const uint8_t *ref, ptrdiff_t ref_stride,
134  int (*sums)[4], int width)
135 {
136  int x, y, z;
137 
138  for (z = 0; z < width; z++) {
139  uint32_t s1 = 0, s2 = 0, ss = 0, s12 = 0;
140 
141  for (y = 0; y < 4; y++) {
142  for (x = 0; x < 4; x++) {
143  int a = main[x + y * main_stride];
144  int b = ref[x + y * ref_stride];
145 
146  s1 += a;
147  s2 += b;
148  ss += a*a;
149  ss += b*b;
150  s12 += a*b;
151  }
152  }
153 
154  sums[z][0] = s1;
155  sums[z][1] = s2;
156  sums[z][2] = ss;
157  sums[z][3] = s12;
158  main += 4;
159  ref += 4;
160  }
161 }
162 
163 static float ssim_end1x(int64_t s1, int64_t s2, int64_t ss, int64_t s12, int max)
164 {
165  int64_t ssim_c1 = (int64_t)(.01*.01*max*max*64 + .5);
166  int64_t ssim_c2 = (int64_t)(.03*.03*max*max*64*63 + .5);
167 
168  int64_t fs1 = s1;
169  int64_t fs2 = s2;
170  int64_t fss = ss;
171  int64_t fs12 = s12;
172  int64_t vars = fss * 64 - fs1 * fs1 - fs2 * fs2;
173  int64_t covar = fs12 * 64 - fs1 * fs2;
174 
175  return (float)(2 * fs1 * fs2 + ssim_c1) * (float)(2 * covar + ssim_c2)
176  / ((float)(fs1 * fs1 + fs2 * fs2 + ssim_c1) * (float)(vars + ssim_c2));
177 }
178 
179 static float ssim_end1(int s1, int s2, int ss, int s12)
180 {
181  static const int ssim_c1 = (int)(.01*.01*255*255*64 + .5);
182  static const int ssim_c2 = (int)(.03*.03*255*255*64*63 + .5);
183 
184  int fs1 = s1;
185  int fs2 = s2;
186  int fss = ss;
187  int fs12 = s12;
188  int vars = fss * 64 - fs1 * fs1 - fs2 * fs2;
189  int covar = fs12 * 64 - fs1 * fs2;
190 
191  return (float)(2 * fs1 * fs2 + ssim_c1) * (float)(2 * covar + ssim_c2)
192  / ((float)(fs1 * fs1 + fs2 * fs2 + ssim_c1) * (float)(vars + ssim_c2));
193 }
194 
195 static float ssim_endn_16bit(const int64_t (*sum0)[4], const int64_t (*sum1)[4], int width, int max)
196 {
197  float ssim = 0.0;
198  int i;
199 
200  for (i = 0; i < width; i++)
201  ssim += ssim_end1x(sum0[i][0] + sum0[i + 1][0] + sum1[i][0] + sum1[i + 1][0],
202  sum0[i][1] + sum0[i + 1][1] + sum1[i][1] + sum1[i + 1][1],
203  sum0[i][2] + sum0[i + 1][2] + sum1[i][2] + sum1[i + 1][2],
204  sum0[i][3] + sum0[i + 1][3] + sum1[i][3] + sum1[i + 1][3],
205  max);
206  return ssim;
207 }
208 
209 static float ssim_endn_8bit(const int (*sum0)[4], const int (*sum1)[4], int width)
210 {
211  float ssim = 0.0;
212  int i;
213 
214  for (i = 0; i < width; i++)
215  ssim += ssim_end1(sum0[i][0] + sum0[i + 1][0] + sum1[i][0] + sum1[i + 1][0],
216  sum0[i][1] + sum0[i + 1][1] + sum1[i][1] + sum1[i + 1][1],
217  sum0[i][2] + sum0[i + 1][2] + sum1[i][2] + sum1[i + 1][2],
218  sum0[i][3] + sum0[i + 1][3] + sum1[i][3] + sum1[i + 1][3]);
219  return ssim;
220 }
221 
222 #define SUM_LEN(w) (((w) >> 2) + 3)
223 
225  uint8_t *main, int main_stride,
226  uint8_t *ref, int ref_stride,
227  int width, int height, void *temp,
228  int max)
229 {
230  int z = 0, y;
231  float ssim = 0.0;
232  int64_t (*sum0)[4] = temp;
233  int64_t (*sum1)[4] = sum0 + SUM_LEN(width);
234 
235  width >>= 2;
236  height >>= 2;
237 
238  for (y = 1; y < height; y++) {
239  for (; z <= y; z++) {
240  FFSWAP(void*, sum0, sum1);
241  ssim_4x4xn_16bit(&main[4 * z * main_stride], main_stride,
242  &ref[4 * z * ref_stride], ref_stride,
243  sum0, width);
244  }
245 
246  ssim += ssim_endn_16bit((const int64_t (*)[4])sum0, (const int64_t (*)[4])sum1, width - 1, max);
247  }
248 
249  return ssim / ((height - 1) * (width - 1));
250 }
251 
253  uint8_t *main, int main_stride,
254  uint8_t *ref, int ref_stride,
255  int width, int height, void *temp,
256  int max)
257 {
258  int z = 0, y;
259  float ssim = 0.0;
260  int (*sum0)[4] = temp;
261  int (*sum1)[4] = sum0 + SUM_LEN(width);
262 
263  width >>= 2;
264  height >>= 2;
265 
266  for (y = 1; y < height; y++) {
267  for (; z <= y; z++) {
268  FFSWAP(void*, sum0, sum1);
269  dsp->ssim_4x4_line(&main[4 * z * main_stride], main_stride,
270  &ref[4 * z * ref_stride], ref_stride,
271  sum0, width);
272  }
273 
274  ssim += dsp->ssim_end_line((const int (*)[4])sum0, (const int (*)[4])sum1, width - 1);
275  }
276 
277  return ssim / ((height - 1) * (width - 1));
278 }
279 
280 static double ssim_db(double ssim, double weight)
281 {
282  return 10 * log10(weight / (weight - ssim));
283 }
284 
285 static int do_ssim(FFFrameSync *fs)
286 {
287  AVFilterContext *ctx = fs->parent;
288  SSIMContext *s = ctx->priv;
289  AVFrame *master, *ref;
290  AVDictionary **metadata;
291  float c[4], ssimv = 0.0;
292  int ret, i;
293 
294  ret = ff_framesync_dualinput_get(fs, &master, &ref);
295  if (ret < 0)
296  return ret;
297  if (!ref)
298  return ff_filter_frame(ctx->outputs[0], master);
299  metadata = &master->metadata;
300 
301  s->nb_frames++;
302 
303  for (i = 0; i < s->nb_components; i++) {
304  c[i] = s->ssim_plane(&s->dsp, master->data[i], master->linesize[i],
305  ref->data[i], ref->linesize[i],
306  s->planewidth[i], s->planeheight[i], s->temp,
307  s->max);
308  ssimv += s->coefs[i] * c[i];
309  s->ssim[i] += c[i];
310  }
311  for (i = 0; i < s->nb_components; i++) {
312  int cidx = s->is_rgb ? s->rgba_map[i] : i;
313  set_meta(metadata, "lavfi.ssim.", s->comps[i], c[cidx]);
314  }
315  s->ssim_total += ssimv;
316 
317  set_meta(metadata, "lavfi.ssim.All", 0, ssimv);
318  set_meta(metadata, "lavfi.ssim.dB", 0, ssim_db(ssimv, 1.0));
319 
320  if (s->stats_file) {
321  fprintf(s->stats_file, "n:%"PRId64" ", s->nb_frames);
322 
323  for (i = 0; i < s->nb_components; i++) {
324  int cidx = s->is_rgb ? s->rgba_map[i] : i;
325  fprintf(s->stats_file, "%c:%f ", s->comps[i], c[cidx]);
326  }
327 
328  fprintf(s->stats_file, "All:%f (%f)\n", ssimv, ssim_db(ssimv, 1.0));
329  }
330 
331  return ff_filter_frame(ctx->outputs[0], master);
332 }
333 
335 {
336  SSIMContext *s = ctx->priv;
337 
338  if (s->stats_file_str) {
339  if (!strcmp(s->stats_file_str, "-")) {
340  s->stats_file = stdout;
341  } else {
342  s->stats_file = fopen(s->stats_file_str, "w");
343  if (!s->stats_file) {
344  int err = AVERROR(errno);
345  char buf[128];
346  av_strerror(err, buf, sizeof(buf));
347  av_log(ctx, AV_LOG_ERROR, "Could not open stats file %s: %s\n",
348  s->stats_file_str, buf);
349  return err;
350  }
351  }
352  }
353 
354  s->fs.on_event = do_ssim;
355  return 0;
356 }
357 
359 {
360  static const enum AVPixelFormat pix_fmts[] = {
368 #define PF(suf) AV_PIX_FMT_YUV420##suf, AV_PIX_FMT_YUV422##suf, AV_PIX_FMT_YUV444##suf, AV_PIX_FMT_GBR##suf
369  PF(P9), PF(P10), PF(P12), PF(P14), PF(P16),
371  };
372 
373  AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
374  if (!fmts_list)
375  return AVERROR(ENOMEM);
376  return ff_set_common_formats(ctx, fmts_list);
377 }
378 
380 {
382  AVFilterContext *ctx = inlink->dst;
383  SSIMContext *s = ctx->priv;
384  int sum = 0, i;
385 
386  s->nb_components = desc->nb_components;
387 
388  if (ctx->inputs[0]->w != ctx->inputs[1]->w ||
389  ctx->inputs[0]->h != ctx->inputs[1]->h) {
390  av_log(ctx, AV_LOG_ERROR, "Width and height of input videos must be same.\n");
391  return AVERROR(EINVAL);
392  }
393  if (ctx->inputs[0]->format != ctx->inputs[1]->format) {
394  av_log(ctx, AV_LOG_ERROR, "Inputs must be of same pixel format.\n");
395  return AVERROR(EINVAL);
396  }
397 
398  s->is_rgb = ff_fill_rgba_map(s->rgba_map, inlink->format) >= 0;
399  s->comps[0] = s->is_rgb ? 'R' : 'Y';
400  s->comps[1] = s->is_rgb ? 'G' : 'U';
401  s->comps[2] = s->is_rgb ? 'B' : 'V';
402  s->comps[3] = 'A';
403 
404  s->planeheight[1] = s->planeheight[2] = AV_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
405  s->planeheight[0] = s->planeheight[3] = inlink->h;
406  s->planewidth[1] = s->planewidth[2] = AV_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w);
407  s->planewidth[0] = s->planewidth[3] = inlink->w;
408  for (i = 0; i < s->nb_components; i++)
409  sum += s->planeheight[i] * s->planewidth[i];
410  for (i = 0; i < s->nb_components; i++)
411  s->coefs[i] = (double) s->planeheight[i] * s->planewidth[i] / sum;
412 
413  s->temp = av_mallocz_array(2 * SUM_LEN(inlink->w), (desc->comp[0].depth > 8) ? sizeof(int64_t[4]) : sizeof(int[4]));
414  if (!s->temp)
415  return AVERROR(ENOMEM);
416  s->max = (1 << desc->comp[0].depth) - 1;
417 
418  s->ssim_plane = desc->comp[0].depth > 8 ? ssim_plane_16bit : ssim_plane;
421  if (ARCH_X86)
422  ff_ssim_init_x86(&s->dsp);
423 
424  return 0;
425 }
426 
427 static int config_output(AVFilterLink *outlink)
428 {
429  AVFilterContext *ctx = outlink->src;
430  SSIMContext *s = ctx->priv;
431  AVFilterLink *mainlink = ctx->inputs[0];
432  int ret;
433 
434  ret = ff_framesync_init_dualinput(&s->fs, ctx);
435  if (ret < 0)
436  return ret;
437  outlink->w = mainlink->w;
438  outlink->h = mainlink->h;
439  outlink->time_base = mainlink->time_base;
440  outlink->sample_aspect_ratio = mainlink->sample_aspect_ratio;
441  outlink->frame_rate = mainlink->frame_rate;
442 
443  if ((ret = ff_framesync_configure(&s->fs)) < 0)
444  return ret;
445 
446  outlink->time_base = s->fs.time_base;
447 
448  if (av_cmp_q(mainlink->time_base, outlink->time_base) &&
449  av_cmp_q(ctx->inputs[1]->time_base, outlink->time_base))
450  av_log(ctx, AV_LOG_WARNING, "not matching timebases found between first input: %d/%d and second input %d/%d, results may be incorrect!\n",
451  mainlink->time_base.num, mainlink->time_base.den,
452  ctx->inputs[1]->time_base.num, ctx->inputs[1]->time_base.den);
453 
454  return 0;
455 }
456 
458 {
459  SSIMContext *s = ctx->priv;
460  return ff_framesync_activate(&s->fs);
461 }
462 
464 {
465  SSIMContext *s = ctx->priv;
466 
467  if (s->nb_frames > 0) {
468  char buf[256];
469  int i;
470  buf[0] = 0;
471  for (i = 0; i < s->nb_components; i++) {
472  int c = s->is_rgb ? s->rgba_map[i] : i;
473  av_strlcatf(buf, sizeof(buf), " %c:%f (%f)", s->comps[i], s->ssim[c] / s->nb_frames,
474  ssim_db(s->ssim[c], s->nb_frames));
475  }
476  av_log(ctx, AV_LOG_INFO, "SSIM%s All:%f (%f)\n", buf,
477  s->ssim_total / s->nb_frames, ssim_db(s->ssim_total, s->nb_frames));
478  }
479 
480  ff_framesync_uninit(&s->fs);
481 
482  if (s->stats_file && s->stats_file != stdout)
483  fclose(s->stats_file);
484 
485  av_freep(&s->temp);
486 }
487 
488 static const AVFilterPad ssim_inputs[] = {
489  {
490  .name = "main",
491  .type = AVMEDIA_TYPE_VIDEO,
492  },{
493  .name = "reference",
494  .type = AVMEDIA_TYPE_VIDEO,
495  .config_props = config_input_ref,
496  },
497  { NULL }
498 };
499 
500 static const AVFilterPad ssim_outputs[] = {
501  {
502  .name = "default",
503  .type = AVMEDIA_TYPE_VIDEO,
504  .config_props = config_output,
505  },
506  { NULL }
507 };
508 
510  .name = "ssim",
511  .description = NULL_IF_CONFIG_SMALL("Calculate the SSIM between two video streams."),
512  .preinit = ssim_framesync_preinit,
513  .init = init,
514  .uninit = uninit,
515  .query_formats = query_formats,
516  .activate = activate,
517  .priv_size = sizeof(SSIMContext),
518  .priv_class = &ssim_class,
519  .inputs = ssim_inputs,
520  .outputs = ssim_outputs,
521 };
#define NULL
Definition: coverity.c:32
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2522
This structure describes decoded (raw) audio or video data.
Definition: frame.h:295
AVOption.
Definition: opt.h:246
static av_cold void uninit(AVFilterContext *ctx)
Definition: vf_ssim.c:463
planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
Definition: pixfmt.h:71
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:182
Main libavfilter public API header.
float(* ssim_end_line)(const int(*sum0)[4], const int(*sum1)[4], int w)
Definition: ssim.h:31
const char * desc
Definition: nvenc.c:68
int nb_components
Definition: vf_ssim.c:53
planar GBR 4:4:4 24bpp
Definition: pixfmt.h:168
int num
Numerator.
Definition: rational.h:59
The reader does not expect b to be semantically here and if the code is changed by maybe adding a a division or other the signedness will almost certainly be mistaken To avoid this confusion a new type was SUINT is the C unsigned type but it holds a signed int to use the same example SUINT a
Definition: undefined.txt:36
#define AV_PIX_FMT_GRAY9
Definition: pixfmt.h:367
int ff_framesync_configure(FFFrameSync *fs)
Configure a frame sync structure.
Definition: framesync.c:117
const char * key
const char * master
Definition: vf_curves.c:117
int max
Definition: vf_ssim.c:54
static void ssim_4x4xn_8bit(const uint8_t *main, ptrdiff_t main_stride, const uint8_t *ref, ptrdiff_t ref_stride, int(*sums)[4], int width)
Definition: vf_ssim.c:132
uint8_t log2_chroma_w
Amount to shift the luma width right to find the chroma width.
Definition: pixdesc.h:92
AVFilterFormats * ff_make_format_list(const int *fmts)
Create a list of supported formats.
Definition: formats.c:283
#define AV_PIX_FMT_GRAY10
Definition: pixfmt.h:368
const char * name
Pad name.
Definition: internal.h:60
AVFilterContext * parent
Parent filter context.
Definition: framesync.h:152
#define AV_PIX_FMT_GRAY12
Definition: pixfmt.h:369
FRAMESYNC_DEFINE_CLASS(ssim, SSIMContext, fs)
AVFilterLink ** inputs
array of pointers to input links
Definition: avfilter.h:346
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1093
static av_cold int init(AVFilterContext *ctx)
Definition: vf_ssim.c:334
AVComponentDescriptor comp[4]
Parameters that describe how pixels are packed.
Definition: pixdesc.h:117
uint8_t
#define av_cold
Definition: attributes.h:82
AVOptions.
int ff_framesync_init_dualinput(FFFrameSync *fs, AVFilterContext *parent)
Initialize a frame sync structure for dualinput.
Definition: framesync.c:361
static const AVFilterPad ssim_inputs[]
Definition: vf_ssim.c:488
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
int ff_framesync_dualinput_get(FFFrameSync *fs, AVFrame **f0, AVFrame **f1)
Definition: framesync.c:379
GLsizei GLboolean const GLfloat * value
Definition: opengl_enc.c:108
static void ssim_4x4xn_16bit(const uint8_t *main8, ptrdiff_t main_stride, const uint8_t *ref8, ptrdiff_t ref_stride, int64_t(*sums)[4], int width)
Definition: vf_ssim.c:96
#define height
planar YUV 4:4:0 full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV440P and setting color_range...
Definition: pixfmt.h:100
planar YUV 4:2:2, 16bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV422P and setting col...
Definition: pixfmt.h:79
AVDictionary * metadata
metadata.
Definition: frame.h:581
static float ssim_end1(int s1, int s2, int ss, int s12)
Definition: vf_ssim.c:179
int main(int argc, char *argv[])
Definition: avio_dir_cmd.c:134
#define av_log(a,...)
FFFrameSync fs
Definition: vf_ssim.c:50
A filter pad used for either input or output.
Definition: internal.h:54
#define FLAGS
Definition: vf_ssim.c:73
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:259
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
int ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats)
A helper for query_formats() which sets all links to the same list of formats.
Definition: formats.c:569
uint8_t log2_chroma_h
Amount to shift the luma height right to find the chroma height.
Definition: pixdesc.h:101
float(* ssim_plane)(SSIMDSPContext *dsp, uint8_t *main, int main_stride, uint8_t *ref, int ref_stride, int width, int height, void *temp, int max)
Definition: vf_ssim.c:64
#define s2
Definition: regdef.h:39
void ff_framesync_uninit(FFFrameSync *fs)
Free all memory currently allocated.
Definition: framesync.c:293
Frame sync structure.
Definition: framesync.h:146
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:186
uint8_t rgba_map[4]
Definition: vf_ssim.c:59
void ff_ssim_init_x86(SSIMDSPContext *dsp)
Definition: vf_ssim_init.c:33
void * priv
private data for use by the filter
Definition: avfilter.h:353
int ff_framesync_activate(FFFrameSync *fs)
Examine the frames in the filter&#39;s input and try to produce output.
Definition: framesync.c:344
int(* on_event)(struct FFFrameSync *fs)
Callback called when a frame event is ready.
Definition: framesync.h:172
planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
Definition: pixfmt.h:70
int planewidth[4]
Definition: vf_ssim.c:60
#define ss(width, name, subs,...)
Definition: cbs_vp9.c:261
uint8_t nb_components
The number of components each pixel has, (1-4)
Definition: pixdesc.h:83
#define b
Definition: input.c:41
#define OFFSET(x)
Definition: vf_ssim.c:72
#define AV_PIX_FMT_GRAY16
Definition: pixfmt.h:371
#define PF(suf)
#define SUM_LEN(w)
Definition: vf_ssim.c:222
planar YUV 4:2:0, 12bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV420P and setting col...
Definition: pixfmt.h:78
#define width
AVFormatContext * ctx
Definition: movenc.c:48
AVRational time_base
Time base for the output events.
Definition: framesync.h:162
#define s(width, name)
Definition: cbs_vp9.c:257
static const AVFilterPad outputs[]
Definition: af_acontrast.c:203
int ff_fill_rgba_map(uint8_t *rgba_map, enum AVPixelFormat pix_fmt)
Definition: drawutils.c:35
static void comp(unsigned char *dst, ptrdiff_t dst_stride, unsigned char *src, ptrdiff_t src_stride, int add)
Definition: eamad.c:83
static const AVOption ssim_options[]
Definition: vf_ssim.c:75
static const uint8_t vars[2][12]
Definition: camellia.c:179
#define AV_LOG_INFO
Standard information.
Definition: log.h:187
misc drawing utilities
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:326
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:81
#define AV_PIX_FMT_GRAY14
Definition: pixfmt.h:370
FILE * stats_file
Definition: vf_ssim.c:51
void * buf
Definition: avisynth_c.h:766
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several inputs
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:70
planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples)
Definition: pixfmt.h:72
static int config_input_ref(AVFilterLink *inlink)
Definition: vf_ssim.c:379
Describe the class of an AVClass context structure.
Definition: log.h:67
Filter definition.
Definition: avfilter.h:144
int planeheight[4]
Definition: vf_ssim.c:61
float coefs[4]
Definition: vf_ssim.c:58
size_t av_strlcatf(char *dst, size_t size, const char *fmt,...)
Definition: avstring.c:101
uint64_t nb_frames
Definition: vf_ssim.c:55
const char * name
Filter name.
Definition: avfilter.h:148
#define s1
Definition: regdef.h:38
#define snprintf
Definition: snprintf.h:34
AVFilterLink ** outputs
array of pointers to output links
Definition: avfilter.h:350
static int weight(int i, int blen, int offset)
Definition: diracdec.c:1564
static enum AVPixelFormat pix_fmts[]
Definition: libkvazaar.c:275
SSIMDSPContext dsp
Definition: vf_ssim.c:69
char comps[4]
Definition: vf_ssim.c:57
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:309
int av_strerror(int errnum, char *errbuf, size_t errbuf_size)
Put a description of the AVERROR code errnum in errbuf.
Definition: error.c:105
static double ssim_db(double ssim, double weight)
Definition: vf_ssim.c:280
The exact code depends on how similar the blocks are and how related they are to the and needs to apply these operations to the correct inlink or outlink if there are several Macros are available to factor that when no extra processing is inlink
static int av_cmp_q(AVRational a, AVRational b)
Compare two rationals.
Definition: rational.h:89
int
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition: pixfmt.h:66
Y , 8bpp.
Definition: pixfmt.h:74
static int activate(AVFilterContext *ctx)
Definition: vf_ssim.c:457
static int ref[MAX_W *MAX_W]
Definition: jpeg2000dwt.c:107
double ssim_total
Definition: vf_ssim.c:56
planar YUV 4:4:4, 24bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV444P and setting col...
Definition: pixfmt.h:80
static int config_output(AVFilterLink *outlink)
Definition: vf_ssim.c:427
planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples)
Definition: pixfmt.h:73
int den
Denominator.
Definition: rational.h:60
AVFilter ff_vf_ssim
Definition: vf_ssim.c:509
double ssim[4]
Definition: vf_ssim.c:56
static float ssim_endn_16bit(const int64_t(*sum0)[4], const int64_t(*sum1)[4], int width, int max)
Definition: vf_ssim.c:195
static float ssim_end1x(int64_t s1, int64_t s2, int64_t ss, int64_t s12, int max)
Definition: vf_ssim.c:163
static const AVFilterPad ssim_outputs[]
Definition: vf_ssim.c:500
void(* ssim_4x4_line)(const uint8_t *buf, ptrdiff_t buf_stride, const uint8_t *ref, ptrdiff_t ref_stride, int(*sums)[4], int w)
Definition: ssim.h:28
A list of supported formats for one end of a filter link.
Definition: formats.h:64
planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples) full scale (JPEG), deprecated in favor ...
Definition: pixfmt.h:258
static int query_formats(AVFilterContext *ctx)
Definition: vf_ssim.c:358
An instance of a filter.
Definition: avfilter.h:338
#define av_freep(p)
int * temp
Definition: vf_ssim.c:62
planar YUV 4:4:0 (1 Cr & Cb sample per 1x2 Y samples)
Definition: pixfmt.h:99
static float ssim_endn_8bit(const int(*sum0)[4], const int(*sum1)[4], int width)
Definition: vf_ssim.c:209
#define FFSWAP(type, a, b)
Definition: common.h:99
static float ssim_plane_16bit(SSIMDSPContext *dsp, uint8_t *main, int main_stride, uint8_t *ref, int ref_stride, int width, int height, void *temp, int max)
Definition: vf_ssim.c:224
internal API functions
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Frame references ownership and permissions
int depth
Number of bits in the component.
Definition: pixdesc.h:58
static int do_ssim(FFFrameSync *fs)
Definition: vf_ssim.c:285
static void set_meta(AVDictionary **metadata, const char *key, char comp, float d)
Definition: vf_ssim.c:83
AVPixelFormat
Pixel format.
Definition: pixfmt.h:64
int is_rgb
Definition: vf_ssim.c:63
char * stats_file_str
Definition: vf_ssim.c:52
for(j=16;j >0;--j)
void * av_mallocz_array(size_t nmemb, size_t size)
Definition: mem.c:191
#define AV_CEIL_RSHIFT(a, b)
Definition: common.h:58