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;
55  int max;
56  uint64_t nb_frames;
57  double ssim[4], ssim_total;
58  char comps[4];
59  double coefs[4];
61  int planewidth[4];
62  int planeheight[4];
63  int **temp;
64  int is_rgb;
65  double **score;
67  int jobnr, int nb_jobs);
69 } SSIMContext;
70 
71 #define OFFSET(x) offsetof(SSIMContext, x)
72 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
73 
74 static const AVOption ssim_options[] = {
75  {"stats_file", "Set file where to store per-frame difference information", OFFSET(stats_file_str), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS },
76  {"f", "Set file where to store per-frame difference information", OFFSET(stats_file_str), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS },
77  { NULL }
78 };
79 
81 
82 static void set_meta(AVDictionary **metadata, const char *key, char comp, float d)
83 {
84  char value[128];
85  snprintf(value, sizeof(value), "%f", d);
86  if (comp) {
87  char key2[128];
88  snprintf(key2, sizeof(key2), "%s%c", key, comp);
89  av_dict_set(metadata, key2, value, 0);
90  } else {
91  av_dict_set(metadata, key, value, 0);
92  }
93 }
94 
95 static void ssim_4x4xn_16bit(const uint8_t *main8, ptrdiff_t main_stride,
96  const uint8_t *ref8, ptrdiff_t ref_stride,
97  int64_t (*sums)[4], int width)
98 {
99  const uint16_t *main16 = (const uint16_t *)main8;
100  const uint16_t *ref16 = (const uint16_t *)ref8;
101  int x, y, z;
102 
103  main_stride >>= 1;
104  ref_stride >>= 1;
105 
106  for (z = 0; z < width; z++) {
107  uint64_t s1 = 0, s2 = 0, ss = 0, s12 = 0;
108 
109  for (y = 0; y < 4; y++) {
110  for (x = 0; x < 4; x++) {
111  unsigned a = main16[x + y * main_stride];
112  unsigned b = ref16[x + y * ref_stride];
113 
114  s1 += a;
115  s2 += b;
116  ss += a*a;
117  ss += b*b;
118  s12 += a*b;
119  }
120  }
121 
122  sums[z][0] = s1;
123  sums[z][1] = s2;
124  sums[z][2] = ss;
125  sums[z][3] = s12;
126  main16 += 4;
127  ref16 += 4;
128  }
129 }
130 
131 static void ssim_4x4xn_8bit(const uint8_t *main, ptrdiff_t main_stride,
132  const uint8_t *ref, ptrdiff_t ref_stride,
133  int (*sums)[4], int width)
134 {
135  int x, y, z;
136 
137  for (z = 0; z < width; z++) {
138  uint32_t s1 = 0, s2 = 0, ss = 0, s12 = 0;
139 
140  for (y = 0; y < 4; y++) {
141  for (x = 0; x < 4; x++) {
142  int a = main[x + y * main_stride];
143  int b = ref[x + y * ref_stride];
144 
145  s1 += a;
146  s2 += b;
147  ss += a*a;
148  ss += b*b;
149  s12 += a*b;
150  }
151  }
152 
153  sums[z][0] = s1;
154  sums[z][1] = s2;
155  sums[z][2] = ss;
156  sums[z][3] = s12;
157  main += 4;
158  ref += 4;
159  }
160 }
161 
162 static float ssim_end1x(int64_t s1, int64_t s2, int64_t ss, int64_t s12, int max)
163 {
164  int64_t ssim_c1 = (int64_t)(.01*.01*max*max*64 + .5);
165  int64_t ssim_c2 = (int64_t)(.03*.03*max*max*64*63 + .5);
166 
167  int64_t fs1 = s1;
168  int64_t fs2 = s2;
169  int64_t fss = ss;
170  int64_t fs12 = s12;
171  int64_t vars = fss * 64 - fs1 * fs1 - fs2 * fs2;
172  int64_t covar = fs12 * 64 - fs1 * fs2;
173 
174  return (float)(2 * fs1 * fs2 + ssim_c1) * (float)(2 * covar + ssim_c2)
175  / ((float)(fs1 * fs1 + fs2 * fs2 + ssim_c1) * (float)(vars + ssim_c2));
176 }
177 
178 static float ssim_end1(int s1, int s2, int ss, int s12)
179 {
180  static const int ssim_c1 = (int)(.01*.01*255*255*64 + .5);
181  static const int ssim_c2 = (int)(.03*.03*255*255*64*63 + .5);
182 
183  int fs1 = s1;
184  int fs2 = s2;
185  int fss = ss;
186  int fs12 = s12;
187  int vars = fss * 64 - fs1 * fs1 - fs2 * fs2;
188  int covar = fs12 * 64 - fs1 * fs2;
189 
190  return (float)(2 * fs1 * fs2 + ssim_c1) * (float)(2 * covar + ssim_c2)
191  / ((float)(fs1 * fs1 + fs2 * fs2 + ssim_c1) * (float)(vars + ssim_c2));
192 }
193 
194 static float ssim_endn_16bit(const int64_t (*sum0)[4], const int64_t (*sum1)[4], int width, int max)
195 {
196  float ssim = 0.0;
197  int i;
198 
199  for (i = 0; i < width; i++)
200  ssim += ssim_end1x(sum0[i][0] + sum0[i + 1][0] + sum1[i][0] + sum1[i + 1][0],
201  sum0[i][1] + sum0[i + 1][1] + sum1[i][1] + sum1[i + 1][1],
202  sum0[i][2] + sum0[i + 1][2] + sum1[i][2] + sum1[i + 1][2],
203  sum0[i][3] + sum0[i + 1][3] + sum1[i][3] + sum1[i + 1][3],
204  max);
205  return ssim;
206 }
207 
208 static double ssim_endn_8bit(const int (*sum0)[4], const int (*sum1)[4], int width)
209 {
210  double ssim = 0.0;
211  int i;
212 
213  for (i = 0; i < width; i++)
214  ssim += ssim_end1(sum0[i][0] + sum0[i + 1][0] + sum1[i][0] + sum1[i + 1][0],
215  sum0[i][1] + sum0[i + 1][1] + sum1[i][1] + sum1[i + 1][1],
216  sum0[i][2] + sum0[i + 1][2] + sum1[i][2] + sum1[i + 1][2],
217  sum0[i][3] + sum0[i + 1][3] + sum1[i][3] + sum1[i + 1][3]);
218  return ssim;
219 }
220 
221 #define SUM_LEN(w) (((w) >> 2) + 3)
222 
223 typedef struct ThreadData {
224  const uint8_t *main_data[4];
225  const uint8_t *ref_data[4];
226  int main_linesize[4];
227  int ref_linesize[4];
228  int planewidth[4];
229  int planeheight[4];
230  double **score;
231  int **temp;
232  int nb_components;
233  int max;
235 } ThreadData;
236 
238  int jobnr, int nb_jobs)
239 {
240  ThreadData *td = arg;
241  double *score = td->score[jobnr];
242  void *temp = td->temp[jobnr];
243  const int max = td->max;
244 
245  for (int c = 0; c < td->nb_components; c++) {
246  const uint8_t *main = td->main_data[c];
247  const uint8_t *ref = td->ref_data[c];
248  const int main_stride = td->main_linesize[c];
249  const int ref_stride = td->ref_linesize[c];
250  int width = td->planewidth[c];
251  int height = td->planeheight[c];
252  const int slice_start = ((height >> 2) * jobnr) / nb_jobs;
253  const int slice_end = ((height >> 2) * (jobnr+1)) / nb_jobs;
254  const int ystart = FFMAX(1, slice_start);
255  int z = ystart - 1;
256  double ssim = 0.0;
257  int64_t (*sum0)[4] = temp;
258  int64_t (*sum1)[4] = sum0 + SUM_LEN(width);
259 
260  width >>= 2;
261  height >>= 2;
262 
263  for (int y = ystart; y < slice_end; y++) {
264  for (; z <= y; z++) {
265  FFSWAP(void*, sum0, sum1);
266  ssim_4x4xn_16bit(&main[4 * z * main_stride], main_stride,
267  &ref[4 * z * ref_stride], ref_stride,
268  sum0, width);
269  }
270 
271  ssim += ssim_endn_16bit((const int64_t (*)[4])sum0, (const int64_t (*)[4])sum1, width - 1, max);
272  }
273 
274  score[c] = ssim;
275  }
276 
277  return 0;
278 }
279 
280 static int ssim_plane(AVFilterContext *ctx, void *arg,
281  int jobnr, int nb_jobs)
282 {
283  ThreadData *td = arg;
284  double *score = td->score[jobnr];
285  void *temp = td->temp[jobnr];
286  SSIMDSPContext *dsp = td->dsp;
287 
288  for (int c = 0; c < td->nb_components; c++) {
289  const uint8_t *main = td->main_data[c];
290  const uint8_t *ref = td->ref_data[c];
291  const int main_stride = td->main_linesize[c];
292  const int ref_stride = td->ref_linesize[c];
293  int width = td->planewidth[c];
294  int height = td->planeheight[c];
295  const int slice_start = ((height >> 2) * jobnr) / nb_jobs;
296  const int slice_end = ((height >> 2) * (jobnr+1)) / nb_jobs;
297  const int ystart = FFMAX(1, slice_start);
298  int z = ystart - 1;
299  double ssim = 0.0;
300  int (*sum0)[4] = temp;
301  int (*sum1)[4] = sum0 + SUM_LEN(width);
302 
303  width >>= 2;
304  height >>= 2;
305 
306  for (int y = ystart; y < slice_end; y++) {
307  for (; z <= y; z++) {
308  FFSWAP(void*, sum0, sum1);
309  dsp->ssim_4x4_line(&main[4 * z * main_stride], main_stride,
310  &ref[4 * z * ref_stride], ref_stride,
311  sum0, width);
312  }
313 
314  ssim += dsp->ssim_end_line((const int (*)[4])sum0, (const int (*)[4])sum1, width - 1);
315  }
316 
317  score[c] = ssim;
318  }
319 
320  return 0;
321 }
322 
323 static double ssim_db(double ssim, double weight)
324 {
325  return (fabs(weight - ssim) > 1e-9) ? 10.0 * log10(weight / (weight - ssim)) : INFINITY;
326 }
327 
328 static int do_ssim(FFFrameSync *fs)
329 {
330  AVFilterContext *ctx = fs->parent;
331  SSIMContext *s = ctx->priv;
332  AVFrame *master, *ref;
333  AVDictionary **metadata;
334  double c[4] = {0}, ssimv = 0.0;
335  ThreadData td;
336  int ret, i;
337 
338  ret = ff_framesync_dualinput_get(fs, &master, &ref);
339  if (ret < 0)
340  return ret;
341  if (ctx->is_disabled || !ref)
342  return ff_filter_frame(ctx->outputs[0], master);
343  metadata = &master->metadata;
344 
345  s->nb_frames++;
346 
348  td.dsp = &s->dsp;
349  td.score = s->score;
350  td.temp = s->temp;
351  td.max = s->max;
352 
353  for (int n = 0; n < s->nb_components; n++) {
354  td.main_data[n] = master->data[n];
355  td.ref_data[n] = ref->data[n];
356  td.main_linesize[n] = master->linesize[n];
357  td.ref_linesize[n] = ref->linesize[n];
358  td.planewidth[n] = s->planewidth[n];
359  td.planeheight[n] = s->planeheight[n];
360  }
361 
362  ctx->internal->execute(ctx, s->ssim_plane, &td, NULL, FFMIN((s->planeheight[1] + 3) >> 2, s->nb_threads));
363 
364  for (i = 0; i < s->nb_components; i++) {
365  for (int j = 0; j < s->nb_threads; j++)
366  c[i] += s->score[j][i];
367  c[i] = c[i] / (((s->planewidth[i] >> 2) - 1) * ((s->planeheight[i] >> 2) - 1));
368  }
369 
370  for (i = 0; i < s->nb_components; i++) {
371  ssimv += s->coefs[i] * c[i];
372  s->ssim[i] += c[i];
373  }
374 
375  for (i = 0; i < s->nb_components; i++) {
376  int cidx = s->is_rgb ? s->rgba_map[i] : i;
377  set_meta(metadata, "lavfi.ssim.", s->comps[i], c[cidx]);
378  }
379  s->ssim_total += ssimv;
380 
381  set_meta(metadata, "lavfi.ssim.All", 0, ssimv);
382  set_meta(metadata, "lavfi.ssim.dB", 0, ssim_db(ssimv, 1.0));
383 
384  if (s->stats_file) {
385  fprintf(s->stats_file, "n:%"PRId64" ", s->nb_frames);
386 
387  for (i = 0; i < s->nb_components; i++) {
388  int cidx = s->is_rgb ? s->rgba_map[i] : i;
389  fprintf(s->stats_file, "%c:%f ", s->comps[i], c[cidx]);
390  }
391 
392  fprintf(s->stats_file, "All:%f (%f)\n", ssimv, ssim_db(ssimv, 1.0));
393  }
394 
395  return ff_filter_frame(ctx->outputs[0], master);
396 }
397 
399 {
400  SSIMContext *s = ctx->priv;
401 
402  if (s->stats_file_str) {
403  if (!strcmp(s->stats_file_str, "-")) {
404  s->stats_file = stdout;
405  } else {
406  s->stats_file = fopen(s->stats_file_str, "w");
407  if (!s->stats_file) {
408  int err = AVERROR(errno);
409  char buf[128];
410  av_strerror(err, buf, sizeof(buf));
411  av_log(ctx, AV_LOG_ERROR, "Could not open stats file %s: %s\n",
412  s->stats_file_str, buf);
413  return err;
414  }
415  }
416  }
417 
418  s->fs.on_event = do_ssim;
419  return 0;
420 }
421 
423 {
424  static const enum AVPixelFormat pix_fmts[] = {
432 #define PF(suf) AV_PIX_FMT_YUV420##suf, AV_PIX_FMT_YUV422##suf, AV_PIX_FMT_YUV444##suf, AV_PIX_FMT_GBR##suf
433  PF(P9), PF(P10), PF(P12), PF(P14), PF(P16),
435  };
436 
437  AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
438  if (!fmts_list)
439  return AVERROR(ENOMEM);
440  return ff_set_common_formats(ctx, fmts_list);
441 }
442 
444 {
446  AVFilterContext *ctx = inlink->dst;
447  SSIMContext *s = ctx->priv;
448  int sum = 0, i;
449 
451  s->nb_components = desc->nb_components;
452 
453  if (ctx->inputs[0]->w != ctx->inputs[1]->w ||
454  ctx->inputs[0]->h != ctx->inputs[1]->h) {
455  av_log(ctx, AV_LOG_ERROR, "Width and height of input videos must be same.\n");
456  return AVERROR(EINVAL);
457  }
458  if (ctx->inputs[0]->format != ctx->inputs[1]->format) {
459  av_log(ctx, AV_LOG_ERROR, "Inputs must be of same pixel format.\n");
460  return AVERROR(EINVAL);
461  }
462 
463  s->is_rgb = ff_fill_rgba_map(s->rgba_map, inlink->format) >= 0;
464  s->comps[0] = s->is_rgb ? 'R' : 'Y';
465  s->comps[1] = s->is_rgb ? 'G' : 'U';
466  s->comps[2] = s->is_rgb ? 'B' : 'V';
467  s->comps[3] = 'A';
468 
469  s->planeheight[1] = s->planeheight[2] = AV_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
470  s->planeheight[0] = s->planeheight[3] = inlink->h;
471  s->planewidth[1] = s->planewidth[2] = AV_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w);
472  s->planewidth[0] = s->planewidth[3] = inlink->w;
473  for (i = 0; i < s->nb_components; i++)
474  sum += s->planeheight[i] * s->planewidth[i];
475  for (i = 0; i < s->nb_components; i++)
476  s->coefs[i] = (double) s->planeheight[i] * s->planewidth[i] / sum;
477 
478  s->temp = av_calloc(s->nb_threads, sizeof(*s->temp));
479  if (!s->temp)
480  return AVERROR(ENOMEM);
481 
482  for (int t = 0; t < s->nb_threads; t++) {
483  s->temp[t] = av_mallocz_array(2 * SUM_LEN(inlink->w), (desc->comp[0].depth > 8) ? sizeof(int64_t[4]) : sizeof(int[4]));
484  if (!s->temp[t])
485  return AVERROR(ENOMEM);
486  }
487  s->max = (1 << desc->comp[0].depth) - 1;
488 
489  s->ssim_plane = desc->comp[0].depth > 8 ? ssim_plane_16bit : ssim_plane;
492  if (ARCH_X86)
493  ff_ssim_init_x86(&s->dsp);
494 
495  s->score = av_calloc(s->nb_threads, sizeof(*s->score));
496  if (!s->score)
497  return AVERROR(ENOMEM);
498 
499  for (int t = 0; t < s->nb_threads && s->score; t++) {
500  s->score[t] = av_calloc(s->nb_components, sizeof(*s->score[0]));
501  if (!s->score[t])
502  return AVERROR(ENOMEM);
503  }
504 
505  return 0;
506 }
507 
508 static int config_output(AVFilterLink *outlink)
509 {
510  AVFilterContext *ctx = outlink->src;
511  SSIMContext *s = ctx->priv;
512  AVFilterLink *mainlink = ctx->inputs[0];
513  int ret;
514 
515  ret = ff_framesync_init_dualinput(&s->fs, ctx);
516  if (ret < 0)
517  return ret;
518  outlink->w = mainlink->w;
519  outlink->h = mainlink->h;
520  outlink->time_base = mainlink->time_base;
521  outlink->sample_aspect_ratio = mainlink->sample_aspect_ratio;
522  outlink->frame_rate = mainlink->frame_rate;
523 
524  if ((ret = ff_framesync_configure(&s->fs)) < 0)
525  return ret;
526 
527  outlink->time_base = s->fs.time_base;
528 
529  if (av_cmp_q(mainlink->time_base, outlink->time_base) ||
530  av_cmp_q(ctx->inputs[1]->time_base, outlink->time_base))
531  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",
532  mainlink->time_base.num, mainlink->time_base.den,
533  ctx->inputs[1]->time_base.num, ctx->inputs[1]->time_base.den);
534 
535  return 0;
536 }
537 
539 {
540  SSIMContext *s = ctx->priv;
541  return ff_framesync_activate(&s->fs);
542 }
543 
545 {
546  SSIMContext *s = ctx->priv;
547 
548  if (s->nb_frames > 0) {
549  char buf[256];
550  int i;
551  buf[0] = 0;
552  for (i = 0; i < s->nb_components; i++) {
553  int c = s->is_rgb ? s->rgba_map[i] : i;
554  av_strlcatf(buf, sizeof(buf), " %c:%f (%f)", s->comps[i], s->ssim[c] / s->nb_frames,
555  ssim_db(s->ssim[c], s->nb_frames));
556  }
557  av_log(ctx, AV_LOG_INFO, "SSIM%s All:%f (%f)\n", buf,
558  s->ssim_total / s->nb_frames, ssim_db(s->ssim_total, s->nb_frames));
559  }
560 
561  ff_framesync_uninit(&s->fs);
562 
563  if (s->stats_file && s->stats_file != stdout)
564  fclose(s->stats_file);
565 
566  for (int t = 0; t < s->nb_threads && s->score; t++)
567  av_freep(&s->score[t]);
568  av_freep(&s->score);
569 
570  for (int t = 0; t < s->nb_threads && s->temp; t++)
571  av_freep(&s->temp[t]);
572  av_freep(&s->temp);
573 }
574 
575 static const AVFilterPad ssim_inputs[] = {
576  {
577  .name = "main",
578  .type = AVMEDIA_TYPE_VIDEO,
579  },{
580  .name = "reference",
581  .type = AVMEDIA_TYPE_VIDEO,
582  .config_props = config_input_ref,
583  },
584  { NULL }
585 };
586 
587 static const AVFilterPad ssim_outputs[] = {
588  {
589  .name = "default",
590  .type = AVMEDIA_TYPE_VIDEO,
591  .config_props = config_output,
592  },
593  { NULL }
594 };
595 
597  .name = "ssim",
598  .description = NULL_IF_CONFIG_SMALL("Calculate the SSIM between two video streams."),
599  .preinit = ssim_framesync_preinit,
600  .init = init,
601  .uninit = uninit,
602  .query_formats = query_formats,
603  .activate = activate,
604  .priv_size = sizeof(SSIMContext),
605  .priv_class = &ssim_class,
606  .inputs = ssim_inputs,
607  .outputs = ssim_outputs,
609 };
const uint8_t * ref_data[4]
Definition: vf_psnr.c:111
#define NULL
Definition: coverity.c:32
int nb_threads
Definition: vf_ssim.c:54
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2573
This structure describes decoded (raw) audio or video data.
Definition: frame.h:314
int max
Definition: vf_ssim.c:233
AVOption.
Definition: opt.h:248
static av_cold void uninit(AVFilterContext *ctx)
Definition: vf_ssim.c:544
const char * desc
Definition: libsvtav1.c:79
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:200
int planeheight[4]
Definition: vf_psnr.c:115
Main libavfilter public API header.
static int ssim_plane_16bit(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_ssim.c:237
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
static double ssim_endn_8bit(const int(*sum0)[4], const int(*sum1)[4], int width)
Definition: vf_ssim.c:208
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:379
int ff_framesync_configure(FFFrameSync *fs)
Configure a frame sync structure.
Definition: framesync.c:124
const char * key
const char * master
Definition: vf_curves.c:119
int max
Definition: vf_ssim.c:55
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:131
int is_disabled
the enabled state from the last expression evaluation
Definition: avfilter.h:388
uint8_t log2_chroma_w
Amount to shift the luma width right to find the chroma width.
Definition: pixdesc.h:92
int ref_linesize
Definition: vf_bm3d.c:59
void * av_calloc(size_t nmemb, size_t size)
Non-inlined equivalent of av_mallocz_array().
Definition: mem.c:245
AVFilterFormats * ff_make_format_list(const int *fmts)
Create a list of supported formats.
Definition: formats.c:287
#define AV_PIX_FMT_GRAY10
Definition: pixfmt.h:380
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:381
FRAMESYNC_DEFINE_CLASS(ssim, SSIMContext, fs)
AVFilterLink ** inputs
array of pointers to input links
Definition: avfilter.h:349
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1093
int(* ssim_plane)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_ssim.c:66
static av_cold int init(AVFilterContext *ctx)
Definition: vf_ssim.c:398
double(* ssim_end_line)(const int(*sum0)[4], const int(*sum1)[4], int w)
Definition: ssim.h:31
AVComponentDescriptor comp[4]
Parameters that describe how pixels are packed.
Definition: pixdesc.h:117
uint8_t
#define av_cold
Definition: attributes.h:88
AVOptions.
int ff_framesync_init_dualinput(FFFrameSync *fs, AVFilterContext *parent)
Initialize a frame sync structure for dualinput.
Definition: framesync.c:358
static const AVFilterPad ssim_inputs[]
Definition: vf_ssim.c:575
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:376
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:95
#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:600
static float ssim_end1(int s1, int s2, int ss, int s12)
Definition: vf_ssim.c:178
double coefs[4]
Definition: vf_ssim.c:59
int planewidth[4]
Definition: vf_psnr.c:114
#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:72
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:194
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:588
#define td
Definition: regdef.h:70
uint8_t log2_chroma_h
Amount to shift the luma height right to find the chroma height.
Definition: pixdesc.h:101
#define s2
Definition: regdef.h:39
void ff_framesync_uninit(FFFrameSync *fs)
Free all memory currently allocated.
Definition: framesync.c:290
Frame sync structure.
Definition: framesync.h:146
static __device__ float fabs(float a)
Definition: cuda_runtime.h:182
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:115
uint8_t rgba_map[4]
Definition: vf_ssim.c:60
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:356
#define AVFILTER_FLAG_SLICE_THREADS
The filter supports multithreading by splitting frames into multiple parts and processing them concur...
Definition: avfilter.h:117
const char * arg
Definition: jacosubdec.c:66
int ff_framesync_activate(FFFrameSync *fs)
Examine the frames in the filter&#39;s input and try to produce output.
Definition: framesync.c:341
int(* on_event)(struct FFFrameSync *fs)
Callback called when a frame event is ready.
Definition: framesync.h:172
#define FFMAX(a, b)
Definition: common.h:103
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:61
#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:71
int ff_filter_get_nb_threads(AVFilterContext *ctx)
Get number of threads for current filter instance.
Definition: avfilter.c:801
#define AV_PIX_FMT_GRAY16
Definition: pixfmt.h:383
#define FFMIN(a, b)
Definition: common.h:105
#define PF(suf)
#define SUM_LEN(w)
Definition: vf_ssim.c:221
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
double ** score
Definition: vf_ssim.c:65
int main(int argc, char *argv[])
double ** score
Definition: vf_ssim.c:230
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
PSNRDSPContext * dsp
Definition: vf_psnr.c:118
static void comp(unsigned char *dst, ptrdiff_t dst_stride, unsigned char *src, ptrdiff_t src_stride, int add)
Definition: eamad.c:85
static const AVOption ssim_options[]
Definition: vf_ssim.c:74
static const uint8_t vars[2][12]
Definition: camellia.c:179
#define AV_LOG_INFO
Standard information.
Definition: log.h:205
misc drawing utilities
Used for passing data between threads.
Definition: dsddec.c:67
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:345
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:382
FILE * stats_file
Definition: vf_ssim.c:51
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:443
Describe the class of an AVClass context structure.
Definition: log.h:67
Filter definition.
Definition: avfilter.h:145
int planeheight[4]
Definition: vf_ssim.c:62
size_t av_strlcatf(char *dst, size_t size, const char *fmt,...)
Definition: avstring.c:101
uint64_t nb_frames
Definition: vf_ssim.c:56
const char * name
Filter name.
Definition: avfilter.h:149
#define s1
Definition: regdef.h:38
SSIMDSPContext * dsp
Definition: vf_ssim.c:234
#define snprintf
Definition: snprintf.h:34
#define AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL
Same as AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, except that the filter will have its filter_frame() c...
Definition: avfilter.h:134
int ** temp
Definition: vf_ssim.c:63
AVFilterLink ** outputs
array of pointers to output links
Definition: avfilter.h:353
static int weight(int i, int blen, int offset)
Definition: diracdec.c:1561
static enum AVPixelFormat pix_fmts[]
Definition: libkvazaar.c:303
SSIMDSPContext dsp
Definition: vf_ssim.c:68
#define flags(name, subs,...)
Definition: cbs_av1.c:561
AVFilterInternal * internal
An opaque struct for libavfilter internal use.
Definition: avfilter.h:381
uint64_t ** score
Definition: vf_psnr.c:116
char comps[4]
Definition: vf_ssim.c:58
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:328
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:323
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 main_linesize[4]
Definition: vf_psnr.c:112
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:538
static int ref[MAX_W *MAX_W]
Definition: jpeg2000dwt.c:107
double ssim_total
Definition: vf_ssim.c:57
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:508
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_execute_func * execute
Definition: internal.h:136
int nb_components
Definition: vf_psnr.c:117
AVFilter ff_vf_ssim
Definition: vf_ssim.c:596
double ssim[4]
Definition: vf_ssim.c:57
static int slice_end(AVCodecContext *avctx, AVFrame *pict)
Handle slice ends.
Definition: mpeg12dec.c:2033
static float ssim_endn_16bit(const int64_t(*sum0)[4], const int64_t(*sum1)[4], int width, int max)
Definition: vf_ssim.c:194
static float ssim_end1x(int64_t s1, int64_t s2, int64_t ss, int64_t s12, int max)
Definition: vf_ssim.c:162
static const AVFilterPad ssim_outputs[]
Definition: vf_ssim.c:587
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:65
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:422
An instance of a filter.
Definition: avfilter.h:341
const uint8_t * main_data[4]
Definition: vf_psnr.c:110
#define av_freep(p)
planar YUV 4:4:0 (1 Cr & Cb sample per 1x2 Y samples)
Definition: pixfmt.h:99
#define FFSWAP(type, a, b)
Definition: common.h:108
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
int ** temp
Definition: vf_ssim.c:231
#define INFINITY
Definition: mathematics.h:67
static int do_ssim(FFFrameSync *fs)
Definition: vf_ssim.c:328
static void set_meta(AVDictionary **metadata, const char *key, char comp, float d)
Definition: vf_ssim.c:82
AVPixelFormat
Pixel format.
Definition: pixfmt.h:64
int is_rgb
Definition: vf_ssim.c:64
char * stats_file_str
Definition: vf_ssim.c:52
for(j=16;j >0;--j)
int i
Definition: input.c:407
void * av_mallocz_array(size_t nmemb, size_t size)
Definition: mem.c:190
#define AV_CEIL_RSHIFT(a, b)
Definition: common.h:58