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/opt.h"
40 #include "libavutil/pixdesc.h"
41 #include "avfilter.h"
42 #include "drawutils.h"
43 #include "framesync.h"
44 #include "internal.h"
45 #include "ssim.h"
46 
47 typedef struct SSIMContext {
48  const AVClass *class;
50  FILE *stats_file;
54  int max;
55  uint64_t nb_frames;
56  double ssim[4], ssim_total;
57  char comps[4];
58  double coefs[4];
59  uint8_t rgba_map[4];
60  int planewidth[4];
61  int planeheight[4];
62  int **temp;
63  int is_rgb;
64  double **score;
66  int jobnr, int nb_jobs);
68 } SSIMContext;
69 
70 #define OFFSET(x) offsetof(SSIMContext, x)
71 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
72 
73 static const AVOption ssim_options[] = {
74  {"stats_file", "Set file where to store per-frame difference information", OFFSET(stats_file_str), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS },
75  {"f", "Set file where to store per-frame difference information", OFFSET(stats_file_str), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS },
76  { NULL }
77 };
78 
80 
81 static void set_meta(AVDictionary **metadata, const char *key, char comp, float d)
82 {
83  char value[128];
84  snprintf(value, sizeof(value), "%f", d);
85  if (comp) {
86  char key2[128];
87  snprintf(key2, sizeof(key2), "%s%c", key, comp);
88  av_dict_set(metadata, key2, value, 0);
89  } else {
90  av_dict_set(metadata, key, value, 0);
91  }
92 }
93 
94 static void ssim_4x4xn_16bit(const uint8_t *main8, ptrdiff_t main_stride,
95  const uint8_t *ref8, ptrdiff_t ref_stride,
96  int64_t (*sums)[4], int width)
97 {
98  const uint16_t *main16 = (const uint16_t *)main8;
99  const uint16_t *ref16 = (const uint16_t *)ref8;
100  int x, y, z;
101 
102  main_stride >>= 1;
103  ref_stride >>= 1;
104 
105  for (z = 0; z < width; z++) {
106  uint64_t s1 = 0, s2 = 0, ss = 0, s12 = 0;
107 
108  for (y = 0; y < 4; y++) {
109  for (x = 0; x < 4; x++) {
110  unsigned a = main16[x + y * main_stride];
111  unsigned b = ref16[x + y * ref_stride];
112 
113  s1 += a;
114  s2 += b;
115  ss += a*a;
116  ss += b*b;
117  s12 += a*b;
118  }
119  }
120 
121  sums[z][0] = s1;
122  sums[z][1] = s2;
123  sums[z][2] = ss;
124  sums[z][3] = s12;
125  main16 += 4;
126  ref16 += 4;
127  }
128 }
129 
130 static void ssim_4x4xn_8bit(const uint8_t *main, ptrdiff_t main_stride,
131  const uint8_t *ref, ptrdiff_t ref_stride,
132  int (*sums)[4], int width)
133 {
134  int x, y, z;
135 
136  for (z = 0; z < width; z++) {
137  uint32_t s1 = 0, s2 = 0, ss = 0, s12 = 0;
138 
139  for (y = 0; y < 4; y++) {
140  for (x = 0; x < 4; x++) {
141  int a = main[x + y * main_stride];
142  int b = ref[x + y * ref_stride];
143 
144  s1 += a;
145  s2 += b;
146  ss += a*a;
147  ss += b*b;
148  s12 += a*b;
149  }
150  }
151 
152  sums[z][0] = s1;
153  sums[z][1] = s2;
154  sums[z][2] = ss;
155  sums[z][3] = s12;
156  main += 4;
157  ref += 4;
158  }
159 }
160 
161 static float ssim_end1x(int64_t s1, int64_t s2, int64_t ss, int64_t s12, int max)
162 {
163  int64_t ssim_c1 = (int64_t)(.01*.01*max*max*64 + .5);
164  int64_t ssim_c2 = (int64_t)(.03*.03*max*max*64*63 + .5);
165 
166  int64_t fs1 = s1;
167  int64_t fs2 = s2;
168  int64_t fss = ss;
169  int64_t fs12 = s12;
170  int64_t vars = fss * 64 - fs1 * fs1 - fs2 * fs2;
171  int64_t covar = fs12 * 64 - fs1 * fs2;
172 
173  return (float)(2 * fs1 * fs2 + ssim_c1) * (float)(2 * covar + ssim_c2)
174  / ((float)(fs1 * fs1 + fs2 * fs2 + ssim_c1) * (float)(vars + ssim_c2));
175 }
176 
177 static float ssim_end1(int s1, int s2, int ss, int s12)
178 {
179  static const int ssim_c1 = (int)(.01*.01*255*255*64 + .5);
180  static const int ssim_c2 = (int)(.03*.03*255*255*64*63 + .5);
181 
182  int fs1 = s1;
183  int fs2 = s2;
184  int fss = ss;
185  int fs12 = s12;
186  int vars = fss * 64 - fs1 * fs1 - fs2 * fs2;
187  int covar = fs12 * 64 - fs1 * fs2;
188 
189  return (float)(2 * fs1 * fs2 + ssim_c1) * (float)(2 * covar + ssim_c2)
190  / ((float)(fs1 * fs1 + fs2 * fs2 + ssim_c1) * (float)(vars + ssim_c2));
191 }
192 
193 static float ssim_endn_16bit(const int64_t (*sum0)[4], const int64_t (*sum1)[4], int width, int max)
194 {
195  float ssim = 0.0;
196  int i;
197 
198  for (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  int i;
211 
212  for (i = 0; i < width; i++)
213  ssim += ssim_end1(sum0[i][0] + sum0[i + 1][0] + sum1[i][0] + sum1[i + 1][0],
214  sum0[i][1] + sum0[i + 1][1] + sum1[i][1] + sum1[i + 1][1],
215  sum0[i][2] + sum0[i + 1][2] + sum1[i][2] + sum1[i + 1][2],
216  sum0[i][3] + sum0[i + 1][3] + sum1[i][3] + sum1[i + 1][3]);
217  return ssim;
218 }
219 
220 #define SUM_LEN(w) (((w) >> 2) + 3)
221 
222 typedef struct ThreadData {
223  const uint8_t *main_data[4];
224  const uint8_t *ref_data[4];
225  int main_linesize[4];
226  int ref_linesize[4];
227  int planewidth[4];
228  int planeheight[4];
229  double **score;
230  int **temp;
231  int nb_components;
232  int max;
234 } ThreadData;
235 
237  int jobnr, int nb_jobs)
238 {
239  ThreadData *td = arg;
240  double *score = td->score[jobnr];
241  void *temp = td->temp[jobnr];
242  const int max = td->max;
243 
244  for (int c = 0; c < td->nb_components; c++) {
245  const uint8_t *main_data = td->main_data[c];
246  const uint8_t *ref_data = td->ref_data[c];
247  const int main_stride = td->main_linesize[c];
248  const int ref_stride = td->ref_linesize[c];
249  int width = td->planewidth[c];
250  int height = td->planeheight[c];
251  const int slice_start = ((height >> 2) * jobnr) / nb_jobs;
252  const int slice_end = ((height >> 2) * (jobnr+1)) / nb_jobs;
253  const int ystart = FFMAX(1, slice_start);
254  int z = ystart - 1;
255  double ssim = 0.0;
256  int64_t (*sum0)[4] = temp;
257  int64_t (*sum1)[4] = sum0 + SUM_LEN(width);
258 
259  width >>= 2;
260  height >>= 2;
261 
262  for (int y = ystart; y < slice_end; y++) {
263  for (; z <= y; z++) {
264  FFSWAP(void*, sum0, sum1);
265  ssim_4x4xn_16bit(&main_data[4 * z * main_stride], main_stride,
266  &ref_data[4 * z * ref_stride], ref_stride,
267  sum0, width);
268  }
269 
270  ssim += ssim_endn_16bit((const int64_t (*)[4])sum0, (const int64_t (*)[4])sum1, width - 1, max);
271  }
272 
273  score[c] = ssim;
274  }
275 
276  return 0;
277 }
278 
279 static int ssim_plane(AVFilterContext *ctx, void *arg,
280  int jobnr, int nb_jobs)
281 {
282  ThreadData *td = arg;
283  double *score = td->score[jobnr];
284  void *temp = td->temp[jobnr];
285  SSIMDSPContext *dsp = td->dsp;
286 
287  for (int c = 0; c < td->nb_components; c++) {
288  const uint8_t *main_data = td->main_data[c];
289  const uint8_t *ref_data = td->ref_data[c];
290  const int main_stride = td->main_linesize[c];
291  const int ref_stride = td->ref_linesize[c];
292  int width = td->planewidth[c];
293  int height = td->planeheight[c];
294  const int slice_start = ((height >> 2) * jobnr) / nb_jobs;
295  const int slice_end = ((height >> 2) * (jobnr+1)) / nb_jobs;
296  const int ystart = FFMAX(1, slice_start);
297  int z = ystart - 1;
298  double ssim = 0.0;
299  int (*sum0)[4] = temp;
300  int (*sum1)[4] = sum0 + SUM_LEN(width);
301 
302  width >>= 2;
303  height >>= 2;
304 
305  for (int y = ystart; y < slice_end; y++) {
306  for (; z <= y; z++) {
307  FFSWAP(void*, sum0, sum1);
308  dsp->ssim_4x4_line(&main_data[4 * z * main_stride], main_stride,
309  &ref_data[4 * z * ref_stride], ref_stride,
310  sum0, width);
311  }
312 
313  ssim += dsp->ssim_end_line((const int (*)[4])sum0, (const int (*)[4])sum1, width - 1);
314  }
315 
316  score[c] = ssim;
317  }
318 
319  return 0;
320 }
321 
322 static double ssim_db(double ssim, double weight)
323 {
324  return (fabs(weight - ssim) > 1e-9) ? 10.0 * log10(weight / (weight - ssim)) : INFINITY;
325 }
326 
327 static int do_ssim(FFFrameSync *fs)
328 {
329  AVFilterContext *ctx = fs->parent;
330  SSIMContext *s = ctx->priv;
331  AVFrame *master, *ref;
332  AVDictionary **metadata;
333  double c[4] = {0}, ssimv = 0.0;
334  ThreadData td;
335  int ret, i;
336 
338  if (ret < 0)
339  return ret;
340  if (ctx->is_disabled || !ref)
341  return ff_filter_frame(ctx->outputs[0], master);
342  metadata = &master->metadata;
343 
344  s->nb_frames++;
345 
346  td.nb_components = s->nb_components;
347  td.dsp = &s->dsp;
348  td.score = s->score;
349  td.temp = s->temp;
350  td.max = s->max;
351 
352  for (int n = 0; n < s->nb_components; n++) {
353  td.main_data[n] = master->data[n];
354  td.ref_data[n] = ref->data[n];
355  td.main_linesize[n] = master->linesize[n];
356  td.ref_linesize[n] = ref->linesize[n];
357  td.planewidth[n] = s->planewidth[n];
358  td.planeheight[n] = s->planeheight[n];
359  }
360 
361  ff_filter_execute(ctx, s->ssim_plane, &td, NULL,
362  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 = avpriv_fopen_utf8(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 
422 static const enum AVPixelFormat pix_fmts[] = {
430 #define PF(suf) AV_PIX_FMT_YUV420##suf, AV_PIX_FMT_YUV422##suf, AV_PIX_FMT_YUV444##suf, AV_PIX_FMT_GBR##suf
431  PF(P9), PF(P10), PF(P12), PF(P14), PF(P16),
433 };
434 
436 {
438  AVFilterContext *ctx = inlink->dst;
439  SSIMContext *s = ctx->priv;
440  int sum = 0, i;
441 
442  s->nb_threads = ff_filter_get_nb_threads(ctx);
443  s->nb_components = desc->nb_components;
444 
445  if (ctx->inputs[0]->w != ctx->inputs[1]->w ||
446  ctx->inputs[0]->h != ctx->inputs[1]->h) {
447  av_log(ctx, AV_LOG_ERROR, "Width and height of input videos must be same.\n");
448  return AVERROR(EINVAL);
449  }
450 
451  s->is_rgb = ff_fill_rgba_map(s->rgba_map, inlink->format) >= 0;
452  s->comps[0] = s->is_rgb ? 'R' : 'Y';
453  s->comps[1] = s->is_rgb ? 'G' : 'U';
454  s->comps[2] = s->is_rgb ? 'B' : 'V';
455  s->comps[3] = 'A';
456 
457  s->planeheight[1] = s->planeheight[2] = AV_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
458  s->planeheight[0] = s->planeheight[3] = inlink->h;
459  s->planewidth[1] = s->planewidth[2] = AV_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w);
460  s->planewidth[0] = s->planewidth[3] = inlink->w;
461  for (i = 0; i < s->nb_components; i++)
462  sum += s->planeheight[i] * s->planewidth[i];
463  for (i = 0; i < s->nb_components; i++)
464  s->coefs[i] = (double) s->planeheight[i] * s->planewidth[i] / sum;
465 
466  s->temp = av_calloc(s->nb_threads, sizeof(*s->temp));
467  if (!s->temp)
468  return AVERROR(ENOMEM);
469 
470  for (int t = 0; t < s->nb_threads; t++) {
471  s->temp[t] = av_calloc(2 * SUM_LEN(inlink->w), (desc->comp[0].depth > 8) ? sizeof(int64_t[4]) : sizeof(int[4]));
472  if (!s->temp[t])
473  return AVERROR(ENOMEM);
474  }
475  s->max = (1 << desc->comp[0].depth) - 1;
476 
477  s->ssim_plane = desc->comp[0].depth > 8 ? ssim_plane_16bit : ssim_plane;
478  s->dsp.ssim_4x4_line = ssim_4x4xn_8bit;
479  s->dsp.ssim_end_line = ssim_endn_8bit;
480 #if ARCH_X86
481  ff_ssim_init_x86(&s->dsp);
482 #endif
483 
484  s->score = av_calloc(s->nb_threads, sizeof(*s->score));
485  if (!s->score)
486  return AVERROR(ENOMEM);
487 
488  for (int t = 0; t < s->nb_threads; t++) {
489  s->score[t] = av_calloc(s->nb_components, sizeof(*s->score[0]));
490  if (!s->score[t])
491  return AVERROR(ENOMEM);
492  }
493 
494  return 0;
495 }
496 
497 static int config_output(AVFilterLink *outlink)
498 {
499  AVFilterContext *ctx = outlink->src;
500  SSIMContext *s = ctx->priv;
501  AVFilterLink *mainlink = ctx->inputs[0];
502  int ret;
503 
505  if (ret < 0)
506  return ret;
507  outlink->w = mainlink->w;
508  outlink->h = mainlink->h;
509  outlink->time_base = mainlink->time_base;
510  outlink->sample_aspect_ratio = mainlink->sample_aspect_ratio;
511  outlink->frame_rate = mainlink->frame_rate;
512 
513  if ((ret = ff_framesync_configure(&s->fs)) < 0)
514  return ret;
515 
516  outlink->time_base = s->fs.time_base;
517 
518  if (av_cmp_q(mainlink->time_base, outlink->time_base) ||
519  av_cmp_q(ctx->inputs[1]->time_base, outlink->time_base))
520  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",
521  mainlink->time_base.num, mainlink->time_base.den,
522  ctx->inputs[1]->time_base.num, ctx->inputs[1]->time_base.den);
523 
524  return 0;
525 }
526 
528 {
529  SSIMContext *s = ctx->priv;
530  return ff_framesync_activate(&s->fs);
531 }
532 
534 {
535  SSIMContext *s = ctx->priv;
536 
537  if (s->nb_frames > 0) {
538  char buf[256];
539  int i;
540  buf[0] = 0;
541  for (i = 0; i < s->nb_components; i++) {
542  int c = s->is_rgb ? s->rgba_map[i] : i;
543  av_strlcatf(buf, sizeof(buf), " %c:%f (%f)", s->comps[i], s->ssim[c] / s->nb_frames,
544  ssim_db(s->ssim[c], s->nb_frames));
545  }
546  av_log(ctx, AV_LOG_INFO, "SSIM%s All:%f (%f)\n", buf,
547  s->ssim_total / s->nb_frames, ssim_db(s->ssim_total, s->nb_frames));
548  }
549 
550  ff_framesync_uninit(&s->fs);
551 
552  if (s->stats_file && s->stats_file != stdout)
553  fclose(s->stats_file);
554 
555  for (int t = 0; t < s->nb_threads && s->score; t++)
556  av_freep(&s->score[t]);
557  av_freep(&s->score);
558 
559  for (int t = 0; t < s->nb_threads && s->temp; t++)
560  av_freep(&s->temp[t]);
561  av_freep(&s->temp);
562 }
563 
564 static const AVFilterPad ssim_inputs[] = {
565  {
566  .name = "main",
567  .type = AVMEDIA_TYPE_VIDEO,
568  },{
569  .name = "reference",
570  .type = AVMEDIA_TYPE_VIDEO,
571  .config_props = config_input_ref,
572  },
573 };
574 
575 static const AVFilterPad ssim_outputs[] = {
576  {
577  .name = "default",
578  .type = AVMEDIA_TYPE_VIDEO,
579  .config_props = config_output,
580  },
581 };
582 
584  .name = "ssim",
585  .description = NULL_IF_CONFIG_SMALL("Calculate the SSIM between two video streams."),
586  .preinit = ssim_framesync_preinit,
587  .init = init,
588  .uninit = uninit,
589  .activate = activate,
590  .priv_size = sizeof(SSIMContext),
591  .priv_class = &ssim_class,
598 };
SSIMContext::comps
char comps[4]
Definition: vf_ssim.c:57
ThreadData::temp
int ** temp
Definition: vf_ssim.c:230
ff_framesync_configure
int ff_framesync_configure(FFFrameSync *fs)
Configure a frame sync structure.
Definition: framesync.c:134
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:186
ff_ssim_init_x86
void ff_ssim_init_x86(SSIMDSPContext *dsp)
Definition: vf_ssim_init.c:33
td
#define td
Definition: regdef.h:70
AVPixelFormat
AVPixelFormat
Pixel format.
Definition: pixfmt.h:64
INFINITY
#define INFINITY
Definition: mathematics.h:67
SSIMContext::rgba_map
uint8_t rgba_map[4]
Definition: vf_ssim.c:59
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
ff_framesync_uninit
void ff_framesync_uninit(FFFrameSync *fs)
Free all memory currently allocated.
Definition: framesync.c:304
comp
static void comp(unsigned char *dst, ptrdiff_t dst_stride, unsigned char *src, ptrdiff_t src_stride, int add)
Definition: eamad.c:80
ff_filter_frame
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:969
av_pix_fmt_desc_get
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2888
ssim_end1x
static float ssim_end1x(int64_t s1, int64_t s2, int64_t ss, int64_t s12, int max)
Definition: vf_ssim.c:161
ThreadData::max
int max
Definition: vf_ssim.c:232
FILTER_PIXFMTS_ARRAY
#define FILTER_PIXFMTS_ARRAY(array)
Definition: internal.h:174
activate
static int activate(AVFilterContext *ctx)
Definition: vf_ssim.c:527
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:435
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:330
pixdesc.h
ThreadData::ref_linesize
int ref_linesize
Definition: vf_bm3d.c:58
AVOption
AVOption.
Definition: opt.h:251
b
#define b
Definition: input.c:41
SSIMContext::coefs
double coefs[4]
Definition: vf_ssim.c:58
AV_PIX_FMT_YUV440P
@ AV_PIX_FMT_YUV440P
planar YUV 4:4:0 (1 Cr & Cb sample per 1x2 Y samples)
Definition: pixfmt.h:99
max
#define max(a, b)
Definition: cuda_runtime.h:33
FLAGS
#define FLAGS
Definition: vf_ssim.c:71
AVDictionary
Definition: dict.c:32
FFMAX
#define FFMAX(a, b)
Definition: macros.h:47
AVFilter::name
const char * name
Filter name.
Definition: avfilter.h:165
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:104
AV_PIX_FMT_GRAY9
#define AV_PIX_FMT_GRAY9
Definition: pixfmt.h:439
SSIMContext::fs
FFFrameSync fs
Definition: vf_ssim.c:49
ssim.h
ssim_options
static const AVOption ssim_options[]
Definition: vf_ssim.c:73
PF
#define PF(suf)
av_strerror
int av_strerror(int errnum, char *errbuf, size_t errbuf_size)
Put a description of the AVERROR code errnum in errbuf.
Definition: error.c:108
SSIMContext::ssim
double ssim[4]
Definition: vf_ssim.c:56
AV_PIX_FMT_GRAY16
#define AV_PIX_FMT_GRAY16
Definition: pixfmt.h:443
ss
#define ss(width, name, subs,...)
Definition: cbs_vp9.c:260
AVRational::num
int num
Numerator.
Definition: rational.h:59
AVFilterPad
A filter pad used for either input or output.
Definition: internal.h:49
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:276
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
av_cold
#define av_cold
Definition: attributes.h:90
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:79
width
#define width
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:193
s
#define s(width, name)
Definition: cbs_vp9.c:256
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:50
ssim_inputs
static const AVFilterPad ssim_inputs[]
Definition: vf_ssim.c:564
s1
#define s1
Definition: regdef.h:38
slice_end
static int slice_end(AVCodecContext *avctx, AVFrame *pict)
Handle slice ends.
Definition: mpeg12dec.c:2006
SSIMContext::planeheight
int planeheight[4]
Definition: vf_ssim.c:61
ctx
AVFormatContext * ctx
Definition: movenc.c:48
AV_PIX_FMT_GRAY14
#define AV_PIX_FMT_GRAY14
Definition: pixfmt.h:442
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:66
key
const char * key
Definition: hwcontext_opencl.c:174
FILTER_INPUTS
#define FILTER_INPUTS(array)
Definition: internal.h:194
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:80
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:130
AV_PIX_FMT_GRAY10
#define AV_PIX_FMT_GRAY10
Definition: pixfmt.h:440
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:66
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:258
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:279
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:78
FRAMESYNC_DEFINE_CLASS
FRAMESYNC_DEFINE_CLASS(ssim, SSIMContext, fs)
ThreadData::planewidth
int planewidth[4]
Definition: vf_identity.c:90
SUM_LEN
#define SUM_LEN(w)
Definition: vf_ssim.c:220
AV_PIX_FMT_GRAY8
@ AV_PIX_FMT_GRAY8
Y , 8bpp.
Definition: pixfmt.h:74
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
weight
static int weight(int i, int blen, int offset)
Definition: diracdec.c:1562
main
int main(int argc, char **argv)
Definition: avio_http_serve_files.c:99
s2
#define s2
Definition: regdef.h:39
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:115
ff_framesync_init_dualinput
int ff_framesync_init_dualinput(FFFrameSync *fs, AVFilterContext *parent)
Initialize a frame sync structure for dualinput.
Definition: framesync.c:372
master
const char * master
Definition: vf_curves.c:129
ssim_db
static double ssim_db(double ssim, double weight)
Definition: vf_ssim.c:322
for
for(k=2;k<=8;++k)
Definition: h264pred_template.c:425
ff_vf_ssim
const AVFilter ff_vf_ssim
Definition: vf_ssim.c:583
ThreadData::dsp
SSIMDSPContext * dsp
Definition: vf_ssim.c:233
init
static av_cold int init(AVFilterContext *ctx)
Definition: vf_ssim.c:398
SSIMContext::planewidth
int planewidth[4]
Definition: vf_ssim.c:60
height
#define height
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:229
SSIMContext::nb_components
int nb_components
Definition: vf_ssim.c:52
AV_LOG_INFO
#define AV_LOG_INFO
Standard information.
Definition: log.h:191
uninit
static av_cold void uninit(AVFilterContext *ctx)
Definition: vf_ssim.c:533
internal.h
ssim_outputs
static const AVFilterPad ssim_outputs[]
Definition: vf_ssim.c:575
do_ssim
static int do_ssim(FFFrameSync *fs)
Definition: vf_ssim.c:327
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:94
SSIMContext::ssim_total
double ssim_total
Definition: vf_ssim.c:56
ssim_end1
static float ssim_end1(int s1, int s2, int ss, int s12)
Definition: vf_ssim.c:177
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:269
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:777
OFFSET
#define OFFSET(x)
Definition: vf_ssim.c:70
ThreadData
Used for passing data between threads.
Definition: dsddec.c:69
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:100
SSIMContext::nb_frames
uint64_t nb_frames
Definition: vf_ssim.c:55
AVFilterPad::name
const char * name
Pad name.
Definition: internal.h:55
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:159
av_calloc
void * av_calloc(size_t nmemb, size_t size)
Definition: mem.c:262
SSIMContext::score
double ** score
Definition: vf_ssim.c:64
SSIMContext::stats_file_str
char * stats_file_str
Definition: vf_ssim.c:51
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:161
ret
ret
Definition: filter_design.txt:187
SSIMContext::nb_threads
int nb_threads
Definition: vf_ssim.c:53
config_output
static int config_output(AVFilterLink *outlink)
Definition: vf_ssim.c:497
FFSWAP
#define FFSWAP(type, a, b)
Definition: macros.h:52
SSIMContext::is_rgb
int is_rgb
Definition: vf_ssim.c:63
SSIMContext::ssim_plane
int(* ssim_plane)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_ssim.c:65
pix_fmts
static enum AVPixelFormat pix_fmts[]
Definition: vf_ssim.c:422
SSIMContext::dsp
SSIMDSPContext dsp
Definition: vf_ssim.c:67
framesync.h
AVRational::den
int den
Denominator.
Definition: rational.h:60
AV_PIX_FMT_NONE
@ AV_PIX_FMT_NONE
Definition: pixfmt.h:65
SSIMContext::temp
int ** temp
Definition: vf_ssim.c:62
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:133
ref
static int ref[MAX_W *MAX_W]
Definition: jpeg2000dwt.c:112
temp
else temp
Definition: vf_mcdeint.c:248
ThreadData::main_linesize
int main_linesize[4]
Definition: vf_identity.c:88
SSIMDSPContext
Definition: ssim.h:27
set_meta
static void set_meta(AVDictionary **metadata, const char *key, char comp, float d)
Definition: vf_ssim.c:81
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:71
AVFilterContext
An instance of a filter.
Definition: avfilter.h:392
AV_PIX_FMT_GBRP
@ AV_PIX_FMT_GBRP
planar GBR 4:4:4 24bpp
Definition: pixfmt.h:158
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:117
desc
const char * desc
Definition: libsvtav1.c:83
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:70
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:93
FILTER_OUTPUTS
#define FILTER_OUTPUTS(array)
Definition: internal.h:195
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:86
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:73
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:91
SSIMContext
Definition: vf_ssim.c:47
d
d
Definition: ffmpeg_filter.c:156
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:150
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:72
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
SSIMContext::max
int max
Definition: vf_ssim.c:54
SSIMContext::stats_file
FILE * stats_file
Definition: vf_ssim.c:50
ssim_plane_16bit
static int ssim_plane_16bit(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_ssim.c:236
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:355
avstring.h
ff_framesync_dualinput_get
int ff_framesync_dualinput_get(FFFrameSync *fs, AVFrame **f0, AVFrame **f1)
Definition: framesync.c:390
AV_OPT_TYPE_STRING
@ AV_OPT_TYPE_STRING
Definition: opt.h:229
AV_PIX_FMT_GRAY12
#define AV_PIX_FMT_GRAY12
Definition: pixfmt.h:441
drawutils.h
ff_filter_execute
static av_always_inline int ff_filter_execute(AVFilterContext *ctx, avfilter_action_func *func, void *arg, int *ret, int nb_jobs)
Definition: internal.h:146
ThreadData::ref_data
const uint8_t * ref_data[4]
Definition: vf_identity.c:87
int
int
Definition: ffmpeg_filter.c:156
snprintf
#define snprintf
Definition: snprintf.h:34
ThreadData::main_data
const uint8_t * main_data[4]
Definition: vf_identity.c:86