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  * Calculate the SSIM between two input videos.
35  */
36 
37 #include "libavutil/avstring.h"
38 #include "libavutil/file_open.h"
39 #include "libavutil/mem.h"
40 #include "libavutil/opt.h"
41 #include "libavutil/pixdesc.h"
42 #include "avfilter.h"
43 #include "drawutils.h"
44 #include "filters.h"
45 #include "framesync.h"
46 #include "ssim.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];
60  uint8_t rgba_map[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 
198  for (int i = 0; i < width; i++)
199  ssim += ssim_end1x(sum0[i][0] + sum0[i + 1][0] + sum1[i][0] + sum1[i + 1][0],
200  sum0[i][1] + sum0[i + 1][1] + sum1[i][1] + sum1[i + 1][1],
201  sum0[i][2] + sum0[i + 1][2] + sum1[i][2] + sum1[i + 1][2],
202  sum0[i][3] + sum0[i + 1][3] + sum1[i][3] + sum1[i + 1][3],
203  max);
204  return ssim;
205 }
206 
207 static double ssim_endn_8bit(const int (*sum0)[4], const int (*sum1)[4], int width)
208 {
209  double ssim = 0.0;
210 
211  for (int i = 0; i < width; i++)
212  ssim += ssim_end1(sum0[i][0] + sum0[i + 1][0] + sum1[i][0] + sum1[i + 1][0],
213  sum0[i][1] + sum0[i + 1][1] + sum1[i][1] + sum1[i + 1][1],
214  sum0[i][2] + sum0[i + 1][2] + sum1[i][2] + sum1[i + 1][2],
215  sum0[i][3] + sum0[i + 1][3] + sum1[i][3] + sum1[i + 1][3]);
216  return ssim;
217 }
218 
219 #define SUM_LEN(w) (((w) >> 2) + 3)
220 
221 typedef struct ThreadData {
222  const uint8_t *main_data[4];
223  const uint8_t *ref_data[4];
224  int main_linesize[4];
225  int ref_linesize[4];
226  int planewidth[4];
227  int planeheight[4];
228  double **score;
229  int **temp;
230  int nb_components;
231  int max;
233 } ThreadData;
234 
236  int jobnr, int nb_jobs)
237 {
238  ThreadData *td = arg;
239  double *score = td->score[jobnr];
240  void *temp = td->temp[jobnr];
241  const int max = td->max;
242 
243  for (int c = 0; c < td->nb_components; c++) {
244  const uint8_t *main_data = td->main_data[c];
245  const uint8_t *ref_data = td->ref_data[c];
246  const int main_stride = td->main_linesize[c];
247  const int ref_stride = td->ref_linesize[c];
248  int width = td->planewidth[c];
249  int height = td->planeheight[c];
250  const int slice_start = ((height >> 2) * jobnr) / nb_jobs;
251  const int slice_end = ((height >> 2) * (jobnr+1)) / nb_jobs;
252  const int ystart = FFMAX(1, slice_start);
253  int z = ystart - 1;
254  double ssim = 0.0;
255  int64_t (*sum0)[4] = temp;
256  int64_t (*sum1)[4] = sum0 + SUM_LEN(width);
257 
258  width >>= 2;
259  height >>= 2;
260 
261  for (int y = ystart; y < slice_end; y++) {
262  for (; z <= y; z++) {
263  FFSWAP(void*, sum0, sum1);
264  ssim_4x4xn_16bit(&main_data[4 * z * main_stride], main_stride,
265  &ref_data[4 * z * ref_stride], ref_stride,
266  sum0, width);
267  }
268 
269  ssim += ssim_endn_16bit((const int64_t (*)[4])sum0, (const int64_t (*)[4])sum1, width - 1, max);
270  }
271 
272  score[c] = ssim;
273  }
274 
275  return 0;
276 }
277 
278 static int ssim_plane(AVFilterContext *ctx, void *arg,
279  int jobnr, int nb_jobs)
280 {
281  ThreadData *td = arg;
282  double *score = td->score[jobnr];
283  void *temp = td->temp[jobnr];
284  SSIMDSPContext *dsp = td->dsp;
285 
286  for (int c = 0; c < td->nb_components; c++) {
287  const uint8_t *main_data = td->main_data[c];
288  const uint8_t *ref_data = td->ref_data[c];
289  const int main_stride = td->main_linesize[c];
290  const int ref_stride = td->ref_linesize[c];
291  int width = td->planewidth[c];
292  int height = td->planeheight[c];
293  const int slice_start = ((height >> 2) * jobnr) / nb_jobs;
294  const int slice_end = ((height >> 2) * (jobnr+1)) / nb_jobs;
295  const int ystart = FFMAX(1, slice_start);
296  int z = ystart - 1;
297  double ssim = 0.0;
298  int (*sum0)[4] = temp;
299  int (*sum1)[4] = sum0 + SUM_LEN(width);
300 
301  width >>= 2;
302  height >>= 2;
303 
304  for (int y = ystart; y < slice_end; y++) {
305  for (; z <= y; z++) {
306  FFSWAP(void*, sum0, sum1);
307  dsp->ssim_4x4_line(&main_data[4 * z * main_stride], main_stride,
308  &ref_data[4 * z * ref_stride], ref_stride,
309  sum0, width);
310  }
311 
312  ssim += dsp->ssim_end_line((const int (*)[4])sum0, (const int (*)[4])sum1, width - 1);
313  }
314 
315  score[c] = ssim;
316  }
317 
318  return 0;
319 }
320 
321 static double ssim_db(double ssim, double weight)
322 {
323  return (fabs(weight - ssim) > 1e-9) ? 10.0 * log10(weight / (weight - ssim)) : INFINITY;
324 }
325 
326 static int do_ssim(FFFrameSync *fs)
327 {
328  AVFilterContext *ctx = fs->parent;
329  SSIMContext *s = ctx->priv;
330  AVFrame *master, *ref;
331  AVDictionary **metadata;
332  double c[4] = {0}, ssimv = 0.0;
333  ThreadData td;
334  int ret, i;
335 
337  if (ret < 0)
338  return ret;
339  if (ctx->is_disabled || !ref)
340  return ff_filter_frame(ctx->outputs[0], master);
341  metadata = &master->metadata;
342 
343  s->nb_frames++;
344 
345  td.nb_components = s->nb_components;
346  td.dsp = &s->dsp;
347  td.score = s->score;
348  td.temp = s->temp;
349  td.max = s->max;
350 
351  for (int n = 0; n < s->nb_components; n++) {
352  td.main_data[n] = master->data[n];
353  td.ref_data[n] = ref->data[n];
354  td.main_linesize[n] = master->linesize[n];
355  td.ref_linesize[n] = ref->linesize[n];
356  td.planewidth[n] = s->planewidth[n];
357  td.planeheight[n] = s->planeheight[n];
358  }
359 
360  if (master->color_range != ref->color_range) {
361  av_log(ctx, AV_LOG_WARNING, "master and reference "
362  "frames use different color ranges (%s != %s)\n",
363  av_color_range_name(master->color_range),
364  av_color_range_name(ref->color_range));
365  }
366 
367  ff_filter_execute(ctx, s->ssim_plane, &td, NULL,
368  FFMIN((s->planeheight[1] + 3) >> 2, s->nb_threads));
369 
370  for (i = 0; i < s->nb_components; i++) {
371  for (int j = 0; j < s->nb_threads; j++)
372  c[i] += s->score[j][i];
373  c[i] = c[i] / (((s->planewidth[i] >> 2) - 1) * ((s->planeheight[i] >> 2) - 1));
374  }
375 
376  for (i = 0; i < s->nb_components; i++) {
377  ssimv += s->coefs[i] * c[i];
378  s->ssim[i] += c[i];
379  }
380 
381  for (i = 0; i < s->nb_components; i++) {
382  int cidx = s->is_rgb ? s->rgba_map[i] : i;
383  set_meta(metadata, "lavfi.ssim.", s->comps[i], c[cidx]);
384  }
385  s->ssim_total += ssimv;
386 
387  set_meta(metadata, "lavfi.ssim.All", 0, ssimv);
388  set_meta(metadata, "lavfi.ssim.dB", 0, ssim_db(ssimv, 1.0));
389 
390  if (s->stats_file) {
391  fprintf(s->stats_file, "n:%"PRId64" ", s->nb_frames);
392 
393  for (i = 0; i < s->nb_components; i++) {
394  int cidx = s->is_rgb ? s->rgba_map[i] : i;
395  fprintf(s->stats_file, "%c:%f ", s->comps[i], c[cidx]);
396  }
397 
398  fprintf(s->stats_file, "All:%f (%f)\n", ssimv, ssim_db(ssimv, 1.0));
399  }
400 
401  return ff_filter_frame(ctx->outputs[0], master);
402 }
403 
405 {
406  SSIMContext *s = ctx->priv;
407 
408  if (s->stats_file_str) {
409  if (!strcmp(s->stats_file_str, "-")) {
410  s->stats_file = stdout;
411  } else {
412  s->stats_file = avpriv_fopen_utf8(s->stats_file_str, "w");
413  if (!s->stats_file) {
414  int err = AVERROR(errno);
415  av_log(ctx, AV_LOG_ERROR, "Could not open stats file %s: %s\n",
416  s->stats_file_str, av_err2str(err));
417  return err;
418  }
419  }
420  }
421 
422  s->fs.on_event = do_ssim;
423  return 0;
424 }
425 
426 static const enum AVPixelFormat pix_fmts[] = {
434 #define PF(suf) AV_PIX_FMT_YUV420##suf, AV_PIX_FMT_YUV422##suf, AV_PIX_FMT_YUV444##suf, AV_PIX_FMT_GBR##suf
435  PF(P9), PF(P10), PF(P12), PF(P14), PF(P16),
437 };
438 
440 {
442  AVFilterContext *ctx = inlink->dst;
443  SSIMContext *s = ctx->priv;
444  int sum = 0;
445 
446  s->nb_threads = ff_filter_get_nb_threads(ctx);
447  s->nb_components = desc->nb_components;
448 
449  if (ctx->inputs[0]->w != ctx->inputs[1]->w ||
450  ctx->inputs[0]->h != ctx->inputs[1]->h) {
451  av_log(ctx, AV_LOG_ERROR, "Width and height of input videos must be same.\n");
452  return AVERROR(EINVAL);
453  }
454 
455  s->is_rgb = ff_fill_rgba_map(s->rgba_map, inlink->format) >= 0;
456  s->comps[0] = s->is_rgb ? 'R' : 'Y';
457  s->comps[1] = s->is_rgb ? 'G' : 'U';
458  s->comps[2] = s->is_rgb ? 'B' : 'V';
459  s->comps[3] = 'A';
460 
461  s->planeheight[1] = s->planeheight[2] = AV_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
462  s->planeheight[0] = s->planeheight[3] = inlink->h;
463  s->planewidth[1] = s->planewidth[2] = AV_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w);
464  s->planewidth[0] = s->planewidth[3] = inlink->w;
465  for (int i = 0; i < s->nb_components; i++)
466  sum += s->planeheight[i] * s->planewidth[i];
467  for (int i = 0; i < s->nb_components; i++)
468  s->coefs[i] = (double) s->planeheight[i] * s->planewidth[i] / sum;
469 
470  s->temp = av_calloc(s->nb_threads, sizeof(*s->temp));
471  if (!s->temp)
472  return AVERROR(ENOMEM);
473 
474  for (int t = 0; t < s->nb_threads; t++) {
475  s->temp[t] = av_calloc(2 * SUM_LEN(inlink->w), (desc->comp[0].depth > 8) ? sizeof(int64_t[4]) : sizeof(int[4]));
476  if (!s->temp[t])
477  return AVERROR(ENOMEM);
478  }
479  s->max = (1 << desc->comp[0].depth) - 1;
480 
481  s->ssim_plane = desc->comp[0].depth > 8 ? ssim_plane_16bit : ssim_plane;
482  s->dsp.ssim_4x4_line = ssim_4x4xn_8bit;
483  s->dsp.ssim_end_line = ssim_endn_8bit;
484 #if ARCH_X86
485  ff_ssim_init_x86(&s->dsp);
486 #endif
487 
488  s->score = av_calloc(s->nb_threads, sizeof(*s->score));
489  if (!s->score)
490  return AVERROR(ENOMEM);
491 
492  for (int t = 0; t < s->nb_threads; t++) {
493  s->score[t] = av_calloc(s->nb_components, sizeof(*s->score[0]));
494  if (!s->score[t])
495  return AVERROR(ENOMEM);
496  }
497 
498  return 0;
499 }
500 
501 static int config_output(AVFilterLink *outlink)
502 {
503  AVFilterContext *ctx = outlink->src;
504  SSIMContext *s = ctx->priv;
505  AVFilterLink *mainlink = ctx->inputs[0];
506  FilterLink *il = ff_filter_link(mainlink);
507  FilterLink *ol = ff_filter_link(outlink);
508  int ret;
509 
511  if (ret < 0)
512  return ret;
513  outlink->w = mainlink->w;
514  outlink->h = mainlink->h;
515  outlink->time_base = mainlink->time_base;
516  outlink->sample_aspect_ratio = mainlink->sample_aspect_ratio;
517  ol->frame_rate = il->frame_rate;
518 
519  if ((ret = ff_framesync_configure(&s->fs)) < 0)
520  return ret;
521 
522  outlink->time_base = s->fs.time_base;
523 
524  if (av_cmp_q(mainlink->time_base, outlink->time_base) ||
525  av_cmp_q(ctx->inputs[1]->time_base, outlink->time_base))
526  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",
527  mainlink->time_base.num, mainlink->time_base.den,
528  ctx->inputs[1]->time_base.num, ctx->inputs[1]->time_base.den);
529 
530  return 0;
531 }
532 
534 {
535  SSIMContext *s = ctx->priv;
536  return ff_framesync_activate(&s->fs);
537 }
538 
540 {
541  SSIMContext *s = ctx->priv;
542 
543  if (s->nb_frames > 0) {
544  char buf[256];
545  buf[0] = 0;
546  for (int i = 0; i < s->nb_components; i++) {
547  int c = s->is_rgb ? s->rgba_map[i] : i;
548  av_strlcatf(buf, sizeof(buf), " %c:%f (%f)", s->comps[i], s->ssim[c] / s->nb_frames,
549  ssim_db(s->ssim[c], s->nb_frames));
550  }
551  av_log(ctx, AV_LOG_INFO, "SSIM%s All:%f (%f)\n", buf,
552  s->ssim_total / s->nb_frames, ssim_db(s->ssim_total, s->nb_frames));
553  }
554 
555  ff_framesync_uninit(&s->fs);
556 
557  if (s->stats_file && s->stats_file != stdout)
558  fclose(s->stats_file);
559 
560  for (int t = 0; t < s->nb_threads && s->score; t++)
561  av_freep(&s->score[t]);
562  av_freep(&s->score);
563 
564  for (int t = 0; t < s->nb_threads && s->temp; t++)
565  av_freep(&s->temp[t]);
566  av_freep(&s->temp);
567 }
568 
569 static const AVFilterPad ssim_inputs[] = {
570  {
571  .name = "main",
572  .type = AVMEDIA_TYPE_VIDEO,
573  },{
574  .name = "reference",
575  .type = AVMEDIA_TYPE_VIDEO,
576  .config_props = config_input_ref,
577  },
578 };
579 
580 static const AVFilterPad ssim_outputs[] = {
581  {
582  .name = "default",
583  .type = AVMEDIA_TYPE_VIDEO,
584  .config_props = config_output,
585  },
586 };
587 
589  .name = "ssim",
590  .description = NULL_IF_CONFIG_SMALL("Calculate the SSIM between two video streams."),
591  .preinit = ssim_framesync_preinit,
592  .init = init,
593  .uninit = uninit,
594  .activate = activate,
595  .priv_size = sizeof(SSIMContext),
596  .priv_class = &ssim_class,
603 };
SSIMContext::comps
char comps[4]
Definition: vf_ssim.c:58
ThreadData::temp
int ** temp
Definition: vf_ssim.c:229
ff_framesync_configure
int ff_framesync_configure(FFFrameSync *fs)
Configure a frame sync structure.
Definition: framesync.c:137
ff_ssim_init_x86
void ff_ssim_init_x86(SSIMDSPContext *dsp)
Definition: vf_ssim_init.c:33
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:215
AVPixelFormat
AVPixelFormat
Pixel format.
Definition: pixfmt.h:71
INFINITY
#define INFINITY
Definition: mathematics.h:118
SSIMContext::rgba_map
uint8_t rgba_map[4]
Definition: vf_ssim.c:60
AVERROR
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
opt.h
FILTER_PIXFMTS_ARRAY
#define FILTER_PIXFMTS_ARRAY(array)
Definition: filters.h:242
ff_framesync_uninit
void ff_framesync_uninit(FFFrameSync *fs)
Free all memory currently allocated.
Definition: framesync.c:302
comp
static void comp(unsigned char *dst, ptrdiff_t dst_stride, unsigned char *src, ptrdiff_t src_stride, int add)
Definition: eamad.c:81
ff_filter_frame
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1062
av_pix_fmt_desc_get
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:3025
ssim_end1x
static float ssim_end1x(int64_t s1, int64_t s2, int64_t ss, int64_t s12, int max)
Definition: vf_ssim.c:162
ThreadData::max
int max
Definition: vf_ssim.c:231
activate
static int activate(AVFilterContext *ctx)
Definition: vf_ssim.c:533
int64_t
long long int64_t
Definition: coverity.c:34
inlink
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
Definition: filter_design.txt:212
config_input_ref
static int config_input_ref(AVFilterLink *inlink)
Definition: vf_ssim.c:439
FILTER_INPUTS
#define FILTER_INPUTS(array)
Definition: filters.h:262
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:389
pixdesc.h
ThreadData::ref_linesize
int ref_linesize
Definition: vf_bm3d.c:57
AVOption
AVOption.
Definition: opt.h:429
b
#define b
Definition: input.c:41
SSIMContext::coefs
double coefs[4]
Definition: vf_ssim.c:59
AV_PIX_FMT_YUV440P
@ AV_PIX_FMT_YUV440P
planar YUV 4:4:0 (1 Cr & Cb sample per 1x2 Y samples)
Definition: pixfmt.h:106
max
#define max(a, b)
Definition: cuda_runtime.h:33
FLAGS
#define FLAGS
Definition: vf_ssim.c:72
AVDictionary
Definition: dict.c:34
FFMAX
#define FFMAX(a, b)
Definition: macros.h:47
AVFilter::name
const char * name
Filter name.
Definition: avfilter.h:205
FFFrameSync
Frame sync structure.
Definition: framesync.h:168
av_strlcatf
size_t av_strlcatf(char *dst, size_t size, const char *fmt,...)
Definition: avstring.c:103
AV_PIX_FMT_GRAY9
#define AV_PIX_FMT_GRAY9
Definition: pixfmt.h:467
SSIMContext::fs
FFFrameSync fs
Definition: vf_ssim.c:50
ssim.h
slice_end
static int slice_end(AVCodecContext *avctx, AVFrame *pict, int *got_output)
Handle slice ends.
Definition: mpeg12dec.c:1719
ssim_options
static const AVOption ssim_options[]
Definition: vf_ssim.c:74
PF
#define PF(suf)
SSIMContext::ssim
double ssim[4]
Definition: vf_ssim.c:57
weight
const h264_weight_func weight
Definition: h264dsp_init.c:33
AV_PIX_FMT_GRAY16
#define AV_PIX_FMT_GRAY16
Definition: pixfmt.h:471
ss
#define ss(width, name, subs,...)
Definition: cbs_vp9.c:202
AVRational::num
int num
Numerator.
Definition: rational.h:59
AVFilterPad
A filter pad used for either input or output.
Definition: filters.h:38
AV_PIX_FMT_YUVJ411P
@ 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_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:209
av_cold
#define av_cold
Definition: attributes.h:90
main
int main
Definition: dovi_rpuenc.c:37
AV_PIX_FMT_YUVJ422P
@ 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
ssim_endn_16bit
static float ssim_endn_16bit(const int64_t(*sum0)[4], const int64_t(*sum1)[4], int width, int max)
Definition: vf_ssim.c:194
s
#define s(width, name)
Definition: cbs_vp9.c:198
SSIMDSPContext::ssim_4x4_line
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
ssim_endn_8bit
static double ssim_endn_8bit(const int(*sum0)[4], const int(*sum1)[4], int width)
Definition: vf_ssim.c:207
AV_CEIL_RSHIFT
#define AV_CEIL_RSHIFT(a, b)
Definition: common.h:60
ssim_inputs
static const AVFilterPad ssim_inputs[]
Definition: vf_ssim.c:569
filters.h
SSIMContext::planeheight
int planeheight[4]
Definition: vf_ssim.c:62
ctx
AVFormatContext * ctx
Definition: movenc.c:49
AV_PIX_FMT_GRAY14
#define AV_PIX_FMT_GRAY14
Definition: pixfmt.h:470
AV_PIX_FMT_YUV420P
@ AV_PIX_FMT_YUV420P
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition: pixfmt.h:73
key
const char * key
Definition: hwcontext_opencl.c:189
FILTER_OUTPUTS
#define FILTER_OUTPUTS(array)
Definition: filters.h:263
file_open.h
AV_PIX_FMT_YUVJ444P
@ 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
arg
const char * arg
Definition: jacosubdec.c:67
ssim_4x4xn_8bit
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
AV_PIX_FMT_GRAY10
#define AV_PIX_FMT_GRAY10
Definition: pixfmt.h:468
av_color_range_name
const char * av_color_range_name(enum AVColorRange range)
Definition: pixdesc.c:3341
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:75
fabs
static __device__ float fabs(float a)
Definition: cuda_runtime.h:182
NULL
#define NULL
Definition: coverity.c:32
fs
#define fs(width, name, subs,...)
Definition: cbs_vp9.c:200
vars
static const uint8_t vars[2][12]
Definition: camellia.c:183
ssim_plane
static int ssim_plane(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_ssim.c:278
AV_PIX_FMT_YUVJ420P
@ 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
FRAMESYNC_DEFINE_CLASS
FRAMESYNC_DEFINE_CLASS(ssim, SSIMContext, fs)
ThreadData::planewidth
int planewidth[4]
Definition: vf_identity.c:89
SUM_LEN
#define SUM_LEN(w)
Definition: vf_ssim.c:219
AV_PIX_FMT_GRAY8
@ AV_PIX_FMT_GRAY8
Y , 8bpp.
Definition: pixfmt.h:81
c
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
ff_filter_link
static FilterLink * ff_filter_link(AVFilterLink *link)
Definition: filters.h:197
ThreadData::dsp
PSNRDSPContext * dsp
Definition: vf_psnr.c:94
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:94
ff_framesync_init_dualinput
int ff_framesync_init_dualinput(FFFrameSync *fs, AVFilterContext *parent)
Initialize a frame sync structure for dualinput.
Definition: framesync.c:373
master
const char * master
Definition: vf_curves.c:130
height
#define height
Definition: dsp.h:85
ssim_db
static double ssim_db(double ssim, double weight)
Definition: vf_ssim.c:321
av_err2str
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition: error.h:122
for
for(k=2;k<=8;++k)
Definition: h264pred_template.c:425
ff_vf_ssim
const AVFilter ff_vf_ssim
Definition: vf_ssim.c:588
ThreadData::dsp
SSIMDSPContext * dsp
Definition: vf_ssim.c:232
init
static av_cold int init(AVFilterContext *ctx)
Definition: vf_ssim.c:404
SSIMContext::planewidth
int planewidth[4]
Definition: vf_ssim.c:61
a
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:41
ThreadData::score
double ** score
Definition: vf_ssim.c:228
SSIMContext::nb_components
int nb_components
Definition: vf_ssim.c:53
AV_LOG_INFO
#define AV_LOG_INFO
Standard information.
Definition: log.h:220
uninit
static av_cold void uninit(AVFilterContext *ctx)
Definition: vf_ssim.c:539
ThreadData::score
uint64_t ** score
Definition: vf_identity.c:91
ssim_outputs
static const AVFilterPad ssim_outputs[]
Definition: vf_ssim.c:580
do_ssim
static int do_ssim(FFFrameSync *fs)
Definition: vf_ssim.c:326
ssim_4x4xn_16bit
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
SSIMContext::ssim_total
double ssim_total
Definition: vf_ssim.c:57
ssim_end1
static float ssim_end1(int s1, int s2, int ss, int s12)
Definition: vf_ssim.c:178
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
SSIMDSPContext::ssim_end_line
double(* ssim_end_line)(const int(*sum0)[4], const int(*sum1)[4], int w)
Definition: ssim.h:31
ff_filter_get_nb_threads
int ff_filter_get_nb_threads(AVFilterContext *ctx)
Get number of threads for current filter instance.
Definition: avfilter.c:841
OFFSET
#define OFFSET(x)
Definition: vf_ssim.c:71
ThreadData
Used for passing data between threads.
Definition: dsddec.c:71
value
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default value
Definition: writing_filters.txt:86
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
AV_PIX_FMT_YUVJ440P
@ 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
SSIMContext::nb_frames
uint64_t nb_frames
Definition: vf_ssim.c:56
AVFilterPad::name
const char * name
Pad name.
Definition: filters.h:44
avpriv_fopen_utf8
FILE * avpriv_fopen_utf8(const char *path, const char *mode)
Open a file using a UTF-8 filename.
Definition: file_open.c:161
av_calloc
void * av_calloc(size_t nmemb, size_t size)
Definition: mem.c:264
SSIMContext::score
double ** score
Definition: vf_ssim.c:65
slice_start
static int slice_start(SliceContext *sc, VVCContext *s, VVCFrameContext *fc, const CodedBitstreamUnit *unit, const int is_first_slice)
Definition: dec.c:737
SSIMContext::stats_file_str
char * stats_file_str
Definition: vf_ssim.c:52
av_cmp_q
static int av_cmp_q(AVRational a, AVRational b)
Compare two rationals.
Definition: rational.h:89
AVFilter
Filter definition.
Definition: avfilter.h:201
ret
ret
Definition: filter_design.txt:187
SSIMContext::nb_threads
int nb_threads
Definition: vf_ssim.c:54
config_output
static int config_output(AVFilterLink *outlink)
Definition: vf_ssim.c:501
FFSWAP
#define FFSWAP(type, a, b)
Definition: macros.h:52
SSIMContext::is_rgb
int is_rgb
Definition: vf_ssim.c:64
SSIMContext::ssim_plane
int(* ssim_plane)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_ssim.c:66
pix_fmts
static enum AVPixelFormat pix_fmts[]
Definition: vf_ssim.c:426
SSIMContext::dsp
SSIMDSPContext dsp
Definition: vf_ssim.c:68
framesync.h
ff_filter_execute
int ff_filter_execute(AVFilterContext *ctx, avfilter_action_func *func, void *arg, int *ret, int nb_jobs)
Definition: avfilter.c:1667
AVRational::den
int den
Denominator.
Definition: rational.h:60
AV_PIX_FMT_NONE
@ AV_PIX_FMT_NONE
Definition: pixfmt.h:72
SSIMContext::temp
int ** temp
Definition: vf_ssim.c:63
avfilter.h
AVFILTER_FLAG_METADATA_ONLY
#define AVFILTER_FLAG_METADATA_ONLY
The filter is a "metadata" filter - it does not modify the frame data in any way.
Definition: avfilter.h:168
ref
static int ref[MAX_W *MAX_W]
Definition: jpeg2000dwt.c:112
temp
else temp
Definition: vf_mcdeint.c:263
ThreadData::main_linesize
int main_linesize[4]
Definition: vf_identity.c:87
SSIMDSPContext
Definition: ssim.h:27
set_meta
static void set_meta(AVDictionary **metadata, const char *key, char comp, float d)
Definition: vf_ssim.c:82
AV_PIX_FMT_YUV444P
@ AV_PIX_FMT_YUV444P
planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
Definition: pixfmt.h:78
AVFilterContext
An instance of a filter.
Definition: avfilter.h:457
AV_PIX_FMT_GBRP
@ AV_PIX_FMT_GBRP
planar GBR 4:4:4 24bpp
Definition: pixfmt.h:165
AVFILTER_FLAG_SLICE_THREADS
#define AVFILTER_FLAG_SLICE_THREADS
The filter supports multithreading by splitting frames into multiple parts and processing them concur...
Definition: avfilter.h:152
desc
const char * desc
Definition: libsvtav1.c:79
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
AV_PIX_FMT_YUV422P
@ AV_PIX_FMT_YUV422P
planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
Definition: pixfmt.h:77
mem.h
AVPixFmtDescriptor
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:69
ThreadData::nb_components
int nb_components
Definition: vf_identity.c:92
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:34
av_dict_set
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:88
AV_PIX_FMT_YUV411P
@ AV_PIX_FMT_YUV411P
planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples)
Definition: pixfmt.h:80
ff_fill_rgba_map
int ff_fill_rgba_map(uint8_t *rgba_map, enum AVPixelFormat pix_fmt)
Definition: drawutils.c:35
ThreadData::planeheight
int planeheight[4]
Definition: vf_identity.c:90
SSIMContext
Definition: vf_ssim.c:48
AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL
#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:190
AV_PIX_FMT_YUV410P
@ AV_PIX_FMT_YUV410P
planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples)
Definition: pixfmt.h:79
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
SSIMContext::max
int max
Definition: vf_ssim.c:55
SSIMContext::stats_file
FILE * stats_file
Definition: vf_ssim.c:51
ssim_plane_16bit
static int ssim_plane_16bit(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_ssim.c:235
ff_framesync_activate
int ff_framesync_activate(FFFrameSync *fs)
Examine the frames in the filter's input and try to produce output.
Definition: framesync.c:353
avstring.h
ff_framesync_dualinput_get
int ff_framesync_dualinput_get(FFFrameSync *fs, AVFrame **f0, AVFrame **f1)
Definition: framesync.c:391
AV_OPT_TYPE_STRING
@ AV_OPT_TYPE_STRING
Underlying C type is a uint8_t* that is either NULL or points to a C string allocated with the av_mal...
Definition: opt.h:276
width
#define width
Definition: dsp.h:85
AV_PIX_FMT_GRAY12
#define AV_PIX_FMT_GRAY12
Definition: pixfmt.h:469
drawutils.h
ThreadData::ref_data
const uint8_t * ref_data[4]
Definition: vf_identity.c:86
snprintf
#define snprintf
Definition: snprintf.h:34
ThreadData::main_data
const uint8_t * main_data[4]
Definition: vf_identity.c:85