FFmpeg
vf_xpsnr.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2024 Christian R. Helmrich
3  * Copyright (c) 2024 Christian Lehmann
4  * Copyright (c) 2024 Christian Stoffers
5  *
6  * This file is part of FFmpeg.
7  *
8  * FFmpeg is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * FFmpeg is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with FFmpeg; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 /**
24  * @file
25  * Calculate the extended perceptually weighted PSNR (XPSNR) between two input videos.
26  *
27  * Authors: Christian Helmrich, Lehmann, and Stoffers, Fraunhofer HHI, Berlin, Germany
28  */
29 
30 #include "libavutil/avstring.h"
31 #include "libavutil/file_open.h"
32 #include "libavutil/mem.h"
33 #include "libavutil/opt.h"
34 #include "libavutil/pixdesc.h"
35 #include "avfilter.h"
36 #include "drawutils.h"
37 #include "filters.h"
38 #include "framesync.h"
39 #include "psnr.h"
40 #include "xpsnr.h"
41 
42 /* XPSNR structure definition */
43 
44 typedef struct XPSNRContext {
45  /* required basic variables */
46  const AVClass *class;
47  int bpp; /* unpacked */
48  int depth; /* packed */
49  char comps[4];
50  int num_comps;
51  uint64_t num_frames_64;
52  unsigned frame_rate;
54  int line_sizes[4];
55  int plane_height[4];
56  int plane_width[4];
57  uint8_t rgba_map[4];
58  FILE *stats_file;
60  /* XPSNR specific variables */
61  double *sse_luma;
62  double *weights;
67  uint64_t max_error_64;
68  double sum_wdist [3];
69  double sum_xpsnr [3];
70  int and_is_inf[3];
71  int is_rgb;
74 } XPSNRContext;
75 
76 /* required macro definitions */
77 
78 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM
79 #define OFFSET(x) offsetof(XPSNRContext, x)
80 #define XPSNR_GAMMA 2
81 
82 static const AVOption xpsnr_options[] = {
83  {"stats_file", "Set file where to store per-frame XPSNR information", OFFSET(stats_file_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS},
84  {"f", "Set file where to store per-frame XPSNR information", OFFSET(stats_file_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS},
85  { NULL }
86 };
87 
89 
90 /* XPSNR function definitions */
91 
92 static uint64_t highds(const int x_act, const int y_act, const int w_act, const int h_act, const int16_t *o_m0, const int o)
93 {
94  uint64_t sa_act = 0;
95 
96  for (int y = y_act; y < h_act; y += 2) {
97  for (int x = x_act; x < w_act; x += 2) {
98  const int f = 12 * ((int)o_m0[ y *o + x ] + (int)o_m0[ y *o + x+1] + (int)o_m0[(y+1)*o + x ] + (int)o_m0[(y+1)*o + x+1])
99  - 3 * ((int)o_m0[(y-1)*o + x ] + (int)o_m0[(y-1)*o + x+1] + (int)o_m0[(y+2)*o + x ] + (int)o_m0[(y+2)*o + x+1])
100  - 3 * ((int)o_m0[ y *o + x-1] + (int)o_m0[ y *o + x+2] + (int)o_m0[(y+1)*o + x-1] + (int)o_m0[(y+1)*o + x+2])
101  - 2 * ((int)o_m0[(y-1)*o + x-1] + (int)o_m0[(y-1)*o + x+2] + (int)o_m0[(y+2)*o + x-1] + (int)o_m0[(y+2)*o + x+2])
102  - ((int)o_m0[(y-2)*o + x-1] + (int)o_m0[(y-2)*o + x ] + (int)o_m0[(y-2)*o + x+1] + (int)o_m0[(y-2)*o + x+2]
103  + (int)o_m0[(y+3)*o + x-1] + (int)o_m0[(y+3)*o + x ] + (int)o_m0[(y+3)*o + x+1] + (int)o_m0[(y+3)*o + x+2]
104  + (int)o_m0[(y-1)*o + x-2] + (int)o_m0[ y *o + x-2] + (int)o_m0[(y+1)*o + x-2] + (int)o_m0[(y+2)*o + x-2]
105  + (int)o_m0[(y-1)*o + x+3] + (int)o_m0[ y *o + x+3] + (int)o_m0[(y+1)*o + x+3] + (int)o_m0[(y+2)*o + x+3]);
106  sa_act += (uint64_t) abs(f);
107  }
108  }
109  return sa_act;
110 }
111 
112 static uint64_t diff1st(const uint32_t w_act, const uint32_t h_act, const int16_t *o_m0, int16_t *o_m1, const int o)
113 {
114  uint64_t ta_act = 0;
115 
116  for (uint32_t y = 0; y < h_act; y += 2) {
117  for (uint32_t x = 0; x < w_act; x += 2) {
118  const int t = (int)o_m0[y*o + x] + (int)o_m0[y*o + x+1] + (int)o_m0[(y+1)*o + x] + (int)o_m0[(y+1)*o + x+1]
119  - ((int)o_m1[y*o + x] + (int)o_m1[y*o + x+1] + (int)o_m1[(y+1)*o + x] + (int)o_m1[(y+1)*o + x+1]);
120  ta_act += (uint64_t) abs(t);
121  o_m1[y*o + x ] = o_m0[y*o + x ]; o_m1[(y+1)*o + x ] = o_m0[(y+1)*o + x ];
122  o_m1[y*o + x+1] = o_m0[y*o + x+1]; o_m1[(y+1)*o + x+1] = o_m0[(y+1)*o + x+1];
123  }
124  }
125  return (ta_act * XPSNR_GAMMA);
126 }
127 
128 static uint64_t diff2nd(const uint32_t w_act, const uint32_t h_act, const int16_t *o_m0, int16_t *o_m1, int16_t *o_m2, const int o)
129 {
130  uint64_t ta_act = 0;
131 
132  for (uint32_t y = 0; y < h_act; y += 2) {
133  for (uint32_t x = 0; x < w_act; x += 2) {
134  const int t = (int)o_m0[y*o + x] + (int)o_m0[y*o + x+1] + (int)o_m0[(y+1)*o + x] + (int)o_m0[(y+1)*o + x+1]
135  - 2 * ((int)o_m1[y*o + x] + (int)o_m1[y*o + x+1] + (int)o_m1[(y+1)*o + x] + (int)o_m1[(y+1)*o + x+1])
136  + (int)o_m2[y*o + x] + (int)o_m2[y*o + x+1] + (int)o_m2[(y+1)*o + x] + (int)o_m2[(y+1)*o + x+1];
137  ta_act += (uint64_t) abs(t);
138  o_m2[y*o + x ] = o_m1[y*o + x ]; o_m2[(y+1)*o + x ] = o_m1[(y+1)*o + x ];
139  o_m2[y*o + x+1] = o_m1[y*o + x+1]; o_m2[(y+1)*o + x+1] = o_m1[(y+1)*o + x+1];
140  o_m1[y*o + x ] = o_m0[y*o + x ]; o_m1[(y+1)*o + x ] = o_m0[(y+1)*o + x ];
141  o_m1[y*o + x+1] = o_m0[y*o + x+1]; o_m1[(y+1)*o + x+1] = o_m0[(y+1)*o + x+1];
142  }
143  }
144  return (ta_act * XPSNR_GAMMA);
145 }
146 
147 static inline uint64_t calc_squared_error(XPSNRContext const *s,
148  const int16_t *blk_org, const uint32_t stride_org,
149  const int16_t *blk_rec, const uint32_t stride_rec,
150  const uint32_t block_width, const uint32_t block_height)
151 {
152  uint64_t sse = 0; /* sum of squared errors */
153 
154  for (uint32_t y = 0; y < block_height; y++) {
155  sse += s->pdsp.sse_line((const uint8_t *) blk_org, (const uint8_t *) blk_rec, (int) block_width);
156  blk_org += stride_org;
157  blk_rec += stride_rec;
158  }
159 
160  /* return nonweighted sum of squared errors */
161  return sse;
162 }
163 
164 static inline double calc_squared_error_and_weight (XPSNRContext const *s,
165  const int16_t *pic_org, const uint32_t stride_org,
166  int16_t *pic_org_m1, int16_t *pic_org_m2,
167  const int16_t *pic_rec, const uint32_t stride_rec,
168  const uint32_t offset_x, const uint32_t offset_y,
169  const uint32_t block_width, const uint32_t block_height,
170  const uint32_t bit_depth, const uint32_t int_frame_rate, double *ms_act)
171 {
172  const int o = (int) stride_org;
173  const int r = (int) stride_rec;
174  const int16_t *o_m0 = pic_org + offset_y * o + offset_x;
175  int16_t *o_m1 = pic_org_m1 + offset_y * o + offset_x;
176  int16_t *o_m2 = pic_org_m2 + offset_y * o + offset_x;
177  const int16_t *r_m0 = pic_rec + offset_y * r + offset_x;
178  const int b_val = (s->plane_width[0] * s->plane_height[0] > 2048 * 1152 ? 2 : 1); /* threshold is a bit more than HD resolution */
179  const int x_act = (offset_x > 0 ? 0 : b_val);
180  const int y_act = (offset_y > 0 ? 0 : b_val);
181  const int w_act = (offset_x + block_width < (uint32_t) s->plane_width [0] ? (int) block_width : (int) block_width - b_val);
182  const int h_act = (offset_y + block_height < (uint32_t) s->plane_height[0] ? (int) block_height : (int) block_height - b_val);
183 
184  const double sse = (double) calc_squared_error (s, o_m0, stride_org,
185  r_m0, stride_rec,
186  block_width, block_height);
187  uint64_t sa_act = 0; /* spatial abs. activity */
188  uint64_t ta_act = 0; /* temporal abs. activity */
189 
190  if (w_act <= x_act || h_act <= y_act) /* small */
191  return sse;
192 
193  if (b_val > 1) { /* highpass with downsampling */
194  if (w_act > 12)
195  sa_act = s->dsp.highds_func(x_act, y_act, w_act, h_act, o_m0, o);
196  else
197  highds(x_act, y_act, w_act, h_act, o_m0, o);
198  } else { /* <=HD highpass without downsampling */
199  for (int y = y_act; y < h_act; y++) {
200  for (int x = x_act; x < w_act; x++) {
201  const int f = 12 * (int)o_m0[y*o + x] - 2 * ((int)o_m0[y*o + x-1] + (int)o_m0[y*o + x+1] + (int)o_m0[(y-1)*o + x] + (int)o_m0[(y+1)*o + x])
202  - ((int)o_m0[(y-1)*o + x-1] + (int)o_m0[(y-1)*o + x+1] + (int)o_m0[(y+1)*o + x-1] + (int)o_m0[(y+1)*o + x+1]);
203  sa_act += (uint64_t) abs(f);
204  }
205  }
206  }
207 
208  /* calculate weight (average squared activity) */
209  *ms_act = (double) sa_act / ((double) (w_act - x_act) * (double) (h_act - y_act));
210 
211  if (b_val > 1) { /* highpass with downsampling */
212  if (int_frame_rate < 32) /* 1st-order diff */
213  ta_act = s->dsp.diff1st_func(block_width, block_height, o_m0, o_m1, o);
214  else /* 2nd-order diff (diff of two diffs) */
215  ta_act = s->dsp.diff2nd_func(block_width, block_height, o_m0, o_m1, o_m2, o);
216  } else { /* <=HD highpass without downsampling */
217  if (int_frame_rate < 32) { /* 1st-order diff */
218  for (uint32_t y = 0; y < block_height; y++) {
219  for (uint32_t x = 0; x < block_width; x++) {
220  const int t = (int)o_m0[y * o + x] - (int)o_m1[y * o + x];
221 
222  ta_act += XPSNR_GAMMA * (uint64_t) abs(t);
223  o_m1[y * o + x] = o_m0[y * o + x];
224  }
225  }
226  } else { /* 2nd-order diff (diff of 2 diffs) */
227  for (uint32_t y = 0; y < block_height; y++) {
228  for (uint32_t x = 0; x < block_width; x++) {
229  const int t = (int)o_m0[y * o + x] - 2 * (int)o_m1[y * o + x] + (int)o_m2[y * o + x];
230 
231  ta_act += XPSNR_GAMMA * (uint64_t) abs(t);
232  o_m2[y * o + x] = o_m1[y * o + x];
233  o_m1[y * o + x] = o_m0[y * o + x];
234  }
235  }
236  }
237  }
238 
239  /* weight += mean squared temporal activity */
240  *ms_act += (double) ta_act / ((double) block_width * (double) block_height);
241 
242  /* lower limit, accounts for high-pass gain */
243  if (*ms_act < (double) (1 << (bit_depth - 6)))
244  *ms_act = (double) (1 << (bit_depth - 6));
245 
246  *ms_act *= *ms_act; /* since SSE is squared */
247 
248  /* return nonweighted sum of squared errors */
249  return sse;
250 }
251 
252 static inline double get_avg_xpsnr (const double sqrt_wsse_val, const double sum_xpsnr_val,
253  const uint32_t image_width, const uint32_t image_height,
254  const uint64_t max_error_64, const uint64_t num_frames_64)
255 {
256  if (num_frames_64 == 0)
257  return INFINITY;
258 
259  if (sqrt_wsse_val >= (double) num_frames_64) { /* square-mean-root average */
260  const double avg_dist = sqrt_wsse_val / (double) num_frames_64;
261  const uint64_t num64 = (uint64_t) image_width * (uint64_t) image_height * max_error_64;
262 
263  return 10.0 * log10((double) num64 / ((double) avg_dist * (double) avg_dist));
264  }
265 
266  return sum_xpsnr_val / (double) num_frames_64; /* older log-domain average */
267 }
268 
269 static int get_wsse(AVFilterContext *ctx, int16_t **org, int16_t **org_m1, int16_t **org_m2, int16_t **rec,
270  uint64_t *const wsse64)
271 {
272  XPSNRContext *const s = ctx->priv;
273  const uint32_t w = s->plane_width [0]; /* luma image width in pixels */
274  const uint32_t h = s->plane_height[0];/* luma image height in pixels */
275  const double r = (double)(w * h) / (3840.0 * 2160.0); /* UHD ratio */
276  const uint32_t b = FFMAX(0, 4 * (int32_t) (32.0 * sqrt(r) +
277  0.5)); /* block size, integer multiple of 4 for SIMD */
278  const uint32_t w_blk = (w + b - 1) / b; /* luma width in units of blocks */
279  const double avg_act = sqrt(16.0 * (double) (1 << (2 * s->depth - 9)) / sqrt(FFMAX(0.00001,
280  r))); /* the sqrt(a_pic) */
281  const int *stride_org = (s->bpp == 1 ? s->plane_width : s->line_sizes);
282  uint32_t x, y, idx_blk = 0; /* the "16.0" above is due to fixed-point code */
283  double *const sse_luma = s->sse_luma;
284  double *const weights = s->weights;
285  int c;
286 
287  if (!wsse64 || (s->depth < 6) || (s->depth > 16) || (s->num_comps <= 0) ||
288  (s->num_comps > 3) || (w == 0) || (h == 0)) {
289  av_log(ctx, AV_LOG_ERROR, "Error in XPSNR routine: invalid argument(s).\n");
290  return AVERROR(EINVAL);
291  }
292  if (!weights || (b >= 4 && !sse_luma)) {
293  av_log(ctx, AV_LOG_ERROR, "Failed to allocate temporary block memory.\n");
294  return AVERROR(ENOMEM);
295  }
296 
297  if (b >= 4) {
298  const int16_t *p_org = org[0];
299  const uint32_t s_org = stride_org[0] / s->bpp;
300  const int16_t *p_rec = rec[0];
301  const uint32_t s_rec = s->plane_width[0];
302  int16_t *p_org_m1 = org_m1[0]; /* pixel */
303  int16_t *p_org_m2 = org_m2[0]; /* memory */
304  double wsse_luma = 0.0;
305 
306  for (y = 0; y < h; y += b) { /* calculate block SSE and perceptual weights */
307  const uint32_t block_height = (y + b > h ? h - y : b);
308 
309  for (x = 0; x < w; x += b, idx_blk++) {
310  const uint32_t block_width = (x + b > w ? w - x : b);
311  double ms_act = 1.0, ms_act_prev = 0.0;
312 
313  sse_luma[idx_blk] = calc_squared_error_and_weight(s, p_org, s_org,
314  p_org_m1, p_org_m2,
315  p_rec, s_rec,
316  x, y,
317  block_width, block_height,
318  s->depth, s->frame_rate, &ms_act);
319  weights[idx_blk] = 1.0 / sqrt(ms_act);
320 
321  if (w * h <= 640 * 480) { /* in-line "min-smoothing" as in paper */
322  if (x == 0) /* first column */
323  ms_act_prev = (idx_blk > 1 ? weights[idx_blk - 2] : 0);
324  else /* after first column */
325  ms_act_prev = (x > b ? FFMAX(weights[idx_blk - 2], weights[idx_blk]) : weights[idx_blk]);
326 
327  if (idx_blk > w_blk) /* after the first row and first column */
328  ms_act_prev = FFMAX(ms_act_prev, weights[idx_blk - 1 - w_blk]); /* min (L, T) */
329  if ((idx_blk > 0) && (weights[idx_blk - 1] > ms_act_prev))
330  weights[idx_blk - 1] = ms_act_prev;
331 
332  if ((x + b >= w) && (y + b >= h) && (idx_blk > w_blk)) { /* last block in picture */
333  ms_act_prev = FFMAX(weights[idx_blk - 1], weights[idx_blk - w_blk]);
334  if (weights[idx_blk] > ms_act_prev)
335  weights[idx_blk] = ms_act_prev;
336  }
337  }
338  } /* for x */
339  } /* for y */
340 
341  for (y = idx_blk = 0; y < h; y += b) { /* calculate sum for luma (Y) XPSNR */
342  for (x = 0; x < w; x += b, idx_blk++) {
343  wsse_luma += sse_luma[idx_blk] * weights[idx_blk];
344  }
345  }
346  wsse64[0] = (wsse_luma <= 0.0 ? 0 : (uint64_t) (wsse_luma * avg_act + 0.5));
347  } /* b >= 4 */
348 
349  for (c = 0; c < s->num_comps; c++) { /* finalize WSSE value for each component */
350  const int16_t *p_org = org[c];
351  const uint32_t s_org = stride_org[c] / s->bpp;
352  const int16_t *p_rec = rec[c];
353  const uint32_t s_rec = s->plane_width[c];
354  const uint32_t w_pln = s->plane_width[c];
355  const uint32_t h_pln = s->plane_height[c];
356 
357  if (b < 4) /* picture is too small for XPSNR, calculate nonweighted PSNR */
358  wsse64[c] = calc_squared_error (s, p_org, s_org,
359  p_rec, s_rec,
360  w_pln, h_pln);
361  else if (c > 0) { /* b >= 4 so Y XPSNR has already been calculated above */
362  const uint32_t bx = (b * w_pln) / w;
363  const uint32_t by = (b * h_pln) / h; /* up to chroma downsampling by 4 */
364  double wsse_chroma = 0.0;
365 
366  for (y = idx_blk = 0; y < h_pln; y += by) { /* calc chroma (Cb/Cr) XPSNR */
367  const uint32_t block_height = (y + by > h_pln ? h_pln - y : by);
368 
369  for (x = 0; x < w_pln; x += bx, idx_blk++) {
370  const uint32_t block_width = (x + bx > w_pln ? w_pln - x : bx);
371 
372  wsse_chroma += (double) calc_squared_error (s, p_org + y * s_org + x, s_org,
373  p_rec + y * s_rec + x, s_rec,
374  block_width, block_height) * weights[idx_blk];
375  }
376  }
377  wsse64[c] = (wsse_chroma <= 0.0 ? 0 : (uint64_t) (wsse_chroma * avg_act + 0.5));
378  }
379  } /* for c */
380 
381  return 0;
382 }
383 
384 static void set_meta(AVDictionary **metadata, const char *key, char comp, float d)
385 {
386  char value[128];
387  snprintf(value, sizeof(value), "%f", d);
388  if (comp) {
389  char key2[128];
390  snprintf(key2, sizeof(key2), "%s%c", key, comp);
391  av_dict_set(metadata, key2, value, 0);
392  } else {
393  av_dict_set(metadata, key, value, 0);
394  }
395 }
396 
397 static int do_xpsnr(FFFrameSync *fs)
398 {
399  AVFilterContext *ctx = fs->parent;
400  XPSNRContext *const s = ctx->priv;
401  const uint32_t w = s->plane_width [0]; /* luma image width in pixels */
402  const uint32_t h = s->plane_height[0]; /* luma image height in pixels */
403  const uint32_t b = FFMAX(0, 4 * (int32_t) (32.0 * sqrt((double) (w * h) / (3840.0 * 2160.0)) + 0.5)); /* block size */
404  const uint32_t w_blk = (w + b - 1) / b; /* luma width in units of blocks */
405  const uint32_t h_blk = (h + b - 1) / b; /* luma height in units of blocks */
406  AVFrame *master, *ref = NULL;
407  int16_t *porg [3];
408  int16_t *porg_m1[3];
409  int16_t *porg_m2[3];
410  int16_t *prec [3];
411  uint64_t wsse64 [3] = {0, 0, 0};
412  double cur_xpsnr[3] = {INFINITY, INFINITY, INFINITY};
413  int c, ret_value;
414  AVDictionary **metadata;
415 
416  if ((ret_value = ff_framesync_dualinput_get(fs, &master, &ref)) < 0)
417  return ret_value;
418  if (ctx->is_disabled || !ref)
419  return ff_filter_frame(ctx->outputs[0], master);
420  metadata = &master->metadata;
421 
422  /* prepare XPSNR calculations: allocate temporary picture and block memory */
423  if (!s->sse_luma)
424  s->sse_luma = av_malloc_array(w_blk * h_blk, sizeof(double));
425  if (!s->weights)
426  s->weights = av_malloc_array(w_blk * h_blk, sizeof(double));
427 
428  for (c = 0; c < s->num_comps; c++) { /* create temporal org buffer memory */
429  s->line_sizes[c] = master->linesize[c];
430 
431  if (c == 0) { /* luma ch. */
432  const int stride_org_bpp = (s->bpp == 1 ? s->plane_width[c] : s->line_sizes[c] / s->bpp);
433 
434  if (!s->buf_org_m1[c])
435  s->buf_org_m1[c] = av_buffer_allocz(stride_org_bpp * s->plane_height[c] * sizeof(int16_t));
436  if (!s->buf_org_m2[c])
437  s->buf_org_m2[c] = av_buffer_allocz(stride_org_bpp * s->plane_height[c] * sizeof(int16_t));
438 
439  porg_m1[c] = (int16_t *) s->buf_org_m1[c]->data;
440  porg_m2[c] = (int16_t *) s->buf_org_m2[c]->data;
441  }
442  }
443 
444  if (s->bpp == 1) { /* 8 bit */
445  for (c = 0; c < s->num_comps; c++) { /* allocate org/rec buffer memory */
446  const int m = s->line_sizes[c]; /* master stride */
447  const int r = ref->linesize[c]; /* ref/c stride */
448  const int o = s->plane_width[c]; /* XPSNR stride */
449 
450  if (!s->buf_org[c])
451  s->buf_org[c] = av_buffer_allocz(s->plane_width[c] * s->plane_height[c] * sizeof(int16_t));
452  if (!s->buf_rec[c])
453  s->buf_rec[c] = av_buffer_allocz(s->plane_width[c] * s->plane_height[c] * sizeof(int16_t));
454 
455  porg[c] = (int16_t *) s->buf_org[c]->data;
456  prec[c] = (int16_t *) s->buf_rec[c]->data;
457 
458  for (int y = 0; y < s->plane_height[c]; y++) {
459  for (int x = 0; x < s->plane_width[c]; x++) {
460  porg[c][y * o + x] = (int16_t) master->data[c][y * m + x];
461  prec[c][y * o + x] = (int16_t) ref->data[c][y * r + x];
462  }
463  }
464  }
465  } else { /* 10, 12, 14 bit */
466  for (c = 0; c < s->num_comps; c++) {
467  porg[c] = (int16_t *) master->data[c];
468  prec[c] = (int16_t *) ref->data[c];
469  }
470  }
471 
472  /* extended perceptually weighted peak signal-to-noise ratio (XPSNR) value */
473  ret_value = get_wsse(ctx, (int16_t **) &porg, (int16_t **) &porg_m1, (int16_t **) &porg_m2,
474  (int16_t **) &prec, wsse64);
475  if ( ret_value < 0 )
476  return ret_value; /* an error here means something went wrong earlier! */
477 
478  for (c = 0; c < s->num_comps; c++) {
479  const double sqrt_wsse = sqrt((double) wsse64[c]);
480 
481  cur_xpsnr[c] = get_avg_xpsnr (sqrt_wsse, INFINITY,
482  s->plane_width[c], s->plane_height[c],
483  s->max_error_64, 1 /* single frame */);
484  s->sum_wdist[c] += sqrt_wsse;
485  s->sum_xpsnr[c] += cur_xpsnr[c];
486  s->and_is_inf[c] &= isinf(cur_xpsnr[c]);
487  }
488  s->num_frames_64++;
489 
490  for (int j = 0; j < s->num_comps; j++) {
491  int c = s->is_rgb ? s->rgba_map[j] : j;
492  set_meta(metadata, "lavfi.xpsnr.xpsnr.", s->comps[j], cur_xpsnr[c]);
493  }
494 
495  if (s->stats_file) { /* print out frame- and component-wise XPSNR averages */
496  fprintf(s->stats_file, "n: %4"PRId64"", s->num_frames_64);
497 
498  for (c = 0; c < s->num_comps; c++)
499  fprintf(s->stats_file, " XPSNR %c: %3.4f", s->comps[c], cur_xpsnr[c]);
500  fprintf(s->stats_file, "\n");
501  }
502 
503  return ff_filter_frame(ctx->outputs[0], master);
504 }
505 
507 {
508  XPSNRContext *const s = ctx->priv;
509  int c;
510 
511  if (s->stats_file_str) {
512  if (!strcmp(s->stats_file_str, "-")) /* no stats file, so use stdout */
513  s->stats_file = stdout;
514  else {
515  s->stats_file = avpriv_fopen_utf8(s->stats_file_str, "w");
516 
517  if (!s->stats_file) {
518  const int err = AVERROR(errno);
519  char buf[128];
520 
521  av_strerror(err, buf, sizeof(buf));
522  av_log(ctx, AV_LOG_ERROR, "Could not open statistics file %s: %s\n", s->stats_file_str, buf);
523  return err;
524  }
525  }
526  }
527 
528  s->sse_luma = NULL;
529  s->weights = NULL;
530 
531  for (c = 0; c < 3; c++) { /* initialize XPSNR data of each color component */
532  s->buf_org [c] = NULL;
533  s->buf_org_m1[c] = NULL;
534  s->buf_org_m2[c] = NULL;
535  s->buf_rec [c] = NULL;
536  s->sum_wdist [c] = 0.0;
537  s->sum_xpsnr [c] = 0.0;
538  s->and_is_inf[c] = 1;
539  }
540 
541  s->fs.on_event = do_xpsnr;
542 
543  return 0;
544 }
545 
546 static const enum AVPixelFormat xpsnr_formats[] = {
548 #define PF_NOALPHA(suf) AV_PIX_FMT_YUV420##suf, AV_PIX_FMT_YUV422##suf, AV_PIX_FMT_YUV444##suf
549 #define PF_ALPHA(suf) AV_PIX_FMT_YUVA420##suf, AV_PIX_FMT_YUVA422##suf, AV_PIX_FMT_YUVA444##suf
550 #define PF(suf) PF_NOALPHA(suf), PF_ALPHA(suf)
551  PF(P), PF(P9), PF(P10), PF_NOALPHA(P12), PF_NOALPHA(P14), PF(P16),
559 };
560 
562 {
564  AVFilterContext *ctx = inlink->dst;
565  XPSNRContext *const s = ctx->priv;
567 
568  if ((ctx->inputs[0]->w != ctx->inputs[1]->w) ||
569  (ctx->inputs[0]->h != ctx->inputs[1]->h)) {
570  av_log(ctx, AV_LOG_ERROR, "Width and height of the input videos must match.\n");
571  return AVERROR(EINVAL);
572  }
573  if (ctx->inputs[0]->format != ctx->inputs[1]->format) {
574  av_log(ctx, AV_LOG_ERROR, "The input videos must be of the same pixel format.\n");
575  return AVERROR(EINVAL);
576  }
577 
578  s->bpp = (desc->comp[0].depth <= 8 ? 1 : 2);
579  s->depth = desc->comp[0].depth;
580  s->max_error_64 = (1 << s->depth) - 1; /* conventional limit */
581  s->max_error_64 *= s->max_error_64;
582 
583  s->frame_rate = il->frame_rate.num / il->frame_rate.den;
584 
585  s->num_comps = (desc->nb_components > 3 ? 3 : desc->nb_components);
586 
587  s->is_rgb = (ff_fill_rgba_map(s->rgba_map, inlink->format) >= 0);
588  s->comps[0] = (s->is_rgb ? 'r' : 'y');
589  s->comps[1] = (s->is_rgb ? 'g' : 'u');
590  s->comps[2] = (s->is_rgb ? 'b' : 'v');
591  s->comps[3] = 'a';
592 
593  s->plane_width [1] = s->plane_width [2] = AV_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w);
594  s->plane_width [0] = s->plane_width [3] = inlink->w;
595  s->plane_height[1] = s->plane_height[2] = AV_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
596  s->plane_height[0] = s->plane_height[3] = inlink->h;
597 
598  /* XPSNR always operates with 16-bit internal precision */
599  ff_psnr_init(&s->pdsp, 15);
600  s->dsp.highds_func = highds; /* initialize filtering methods */
601  s->dsp.diff1st_func = diff1st;
602  s->dsp.diff2nd_func = diff2nd;
603 
604  return 0;
605 }
606 
607 static int config_output(AVFilterLink *outlink)
608 {
609  AVFilterContext *ctx = outlink->src;
610  XPSNRContext *s = ctx->priv;
611  AVFilterLink *mainlink = ctx->inputs[0];
612  FilterLink *il = ff_filter_link(mainlink);
613  FilterLink *ol = ff_filter_link(outlink);
614  int ret;
615 
616  if ((ret = ff_framesync_init_dualinput(&s->fs, ctx)) < 0)
617  return ret;
618 
619  outlink->w = mainlink->w;
620  outlink->h = mainlink->h;
621  outlink->time_base = mainlink->time_base;
622  outlink->sample_aspect_ratio = mainlink->sample_aspect_ratio;
623  ol->frame_rate = il->frame_rate;
624 
625  if ((ret = ff_framesync_configure(&s->fs)) < 0)
626  return ret;
627 
628  outlink->time_base = s->fs.time_base;
629 
630  if (av_cmp_q(mainlink->time_base, outlink->time_base) ||
631  av_cmp_q(ctx->inputs[1]->time_base, outlink->time_base))
632  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",
633  mainlink->time_base.num, mainlink->time_base.den,
634  ctx->inputs[1]->time_base.num, ctx->inputs[1]->time_base.den);
635 
636  return 0;
637 }
638 
640 {
641  XPSNRContext *s = ctx->priv;
642 
643  return ff_framesync_activate(&s->fs);
644 }
645 
647 {
648  XPSNRContext *const s = ctx->priv;
649  int c;
650 
651  if (s->num_frames_64 > 0) { /* print out overall component-wise mean XPSNR */
652  const double xpsnr_luma = get_avg_xpsnr(s->sum_wdist[0], s->sum_xpsnr[0],
653  s->plane_width[0], s->plane_height[0],
654  s->max_error_64, s->num_frames_64);
655  double xpsnr_min = xpsnr_luma;
656 
657  /* luma */
658  av_log(ctx, AV_LOG_INFO, "XPSNR %c: %3.4f", s->comps[0], xpsnr_luma);
659  if (s->stats_file) {
660  fprintf(s->stats_file, "\nXPSNR average, %"PRId64" frames", s->num_frames_64);
661  fprintf(s->stats_file, " %c: %3.4f", s->comps[0], xpsnr_luma);
662  }
663  /* chroma */
664  for (c = 1; c < s->num_comps; c++) {
665  const double xpsnr_chroma = get_avg_xpsnr(s->sum_wdist[c], s->sum_xpsnr[c],
666  s->plane_width[c], s->plane_height[c],
667  s->max_error_64, s->num_frames_64);
668  if (xpsnr_min > xpsnr_chroma)
669  xpsnr_min = xpsnr_chroma;
670 
671  av_log(ctx, AV_LOG_INFO, " %c: %3.4f", s->comps[c], xpsnr_chroma);
672  if (s->stats_file && s->stats_file != stdout)
673  fprintf(s->stats_file, " %c: %3.4f", s->comps[c], xpsnr_chroma);
674  }
675  /* print out line break, and minimum XPSNR across the color components */
676  if (s->num_comps > 1) {
677  av_log(ctx, AV_LOG_INFO, " (minimum: %3.4f)\n", xpsnr_min);
678  if (s->stats_file && s->stats_file != stdout)
679  fprintf(s->stats_file, " (minimum: %3.4f)\n", xpsnr_min);
680  } else {
681  av_log(ctx, AV_LOG_INFO, "\n");
682  if (s->stats_file && s->stats_file != stdout)
683  fprintf(s->stats_file, "\n");
684  }
685  }
686 
687  ff_framesync_uninit(&s->fs); /* free temporary picture or block buf memory */
688 
689  if (s->stats_file && s->stats_file != stdout)
690  fclose(s->stats_file);
691 
692  av_freep(&s->sse_luma);
693  av_freep(&s->weights );
694 
695  for (c = 0; c < s->num_comps; c++) { /* free extra temporal org buf memory */
696  if(s->buf_org_m1[c])
697  av_freep(s->buf_org_m1[c]);
698  if(s->buf_org_m2[c])
699  av_freep(s->buf_org_m2[c]);
700  }
701  if (s->bpp == 1) { /* 8 bit */
702  for (c = 0; c < s->num_comps; c++) { /* and org/rec picture buf memory */
703  if(s->buf_org_m2[c])
704  av_freep(s->buf_org[c]);
705  if(s->buf_rec[c])
706  av_freep(s->buf_rec[c]);
707  }
708  }
709 }
710 
711 static const AVFilterPad xpsnr_inputs[] = {
712  {
713  .name = "main",
714  .type = AVMEDIA_TYPE_VIDEO,
715  }, {
716  .name = "reference",
717  .type = AVMEDIA_TYPE_VIDEO,
718  .config_props = config_input_ref,
719  }
720 };
721 
722 static const AVFilterPad xpsnr_outputs[] = {
723  {
724  .name = "default",
725  .type = AVMEDIA_TYPE_VIDEO,
726  .config_props = config_output,
727  }
728 };
729 
731  .name = "xpsnr",
732  .description = NULL_IF_CONFIG_SMALL("Calculate the extended perceptually weighted peak signal-to-noise ratio (XPSNR) between two video streams."),
733  .preinit = xpsnr_framesync_preinit,
734  .init = init,
735  .uninit = uninit,
736  .activate = activate,
737  .priv_size = sizeof(XPSNRContext),
738  .priv_class = &xpsnr_class,
743 };
XPSNRContext::and_is_inf
int and_is_inf[3]
Definition: vf_xpsnr.c:70
AV_PIX_FMT_GBRAP16
#define AV_PIX_FMT_GBRAP16
Definition: pixfmt.h:525
ff_framesync_configure
int ff_framesync_configure(FFFrameSync *fs)
Configure a frame sync structure.
Definition: framesync.c:137
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
ff_psnr_init
void ff_psnr_init(PSNRDSPContext *dsp, int bpp)
Definition: psnr.c:58
XPSNRContext::pdsp
PSNRDSPContext pdsp
Definition: vf_xpsnr.c:73
INFINITY
#define INFINITY
Definition: mathematics.h:118
r
const char * r
Definition: vf_curves.c:127
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:301
FRAMESYNC_DEFINE_CLASS
FRAMESYNC_DEFINE_CLASS(xpsnr, XPSNRContext, fs)
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:1061
av_pix_fmt_desc_get
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:3170
init
static av_cold int init(AVFilterContext *ctx)
Definition: vf_xpsnr.c:506
XPSNRContext::buf_org_m2
AVBufferRef * buf_org_m2[3]
Definition: vf_xpsnr.c:65
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
XPSNRContext::comps
char comps[4]
Definition: vf_xpsnr.c:49
FLAGS
#define FLAGS
Definition: vf_xpsnr.c:78
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
w
uint8_t w
Definition: llviddspenc.c:38
AVOption
AVOption.
Definition: opt.h:429
b
#define b
Definition: input.c:41
XPSNRContext::frame_rate
unsigned frame_rate
Definition: vf_xpsnr.c:52
uninit
static av_cold void uninit(AVFilterContext *ctx)
Definition: vf_xpsnr.c:646
OFFSET
#define OFFSET(x)
Definition: vf_xpsnr.c:79
XPSNRContext::is_rgb
int is_rgb
Definition: vf_xpsnr.c:71
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
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
bit_depth
static void bit_depth(AudioStatsContext *s, const uint64_t *const mask, uint8_t *depth)
Definition: af_astats.c:246
AV_PIX_FMT_GRAY9
#define AV_PIX_FMT_GRAY9
Definition: pixfmt.h:482
XPSNRContext::buf_org_m1
AVBufferRef * buf_org_m1[3]
Definition: vf_xpsnr.c:64
ff_vf_xpsnr
const AVFilter ff_vf_xpsnr
Definition: vf_xpsnr.c:730
activate
static int activate(AVFilterContext *ctx)
Definition: vf_xpsnr.c:639
XPSNRContext::num_comps
int num_comps
Definition: vf_xpsnr.c:50
AV_PIX_FMT_GBRP14
#define AV_PIX_FMT_GBRP14
Definition: pixfmt.h:520
AV_PIX_FMT_GBRAP
@ AV_PIX_FMT_GBRAP
planar GBRA 4:4:4:4 32bpp
Definition: pixfmt.h:212
XPSNRContext::depth
int depth
Definition: vf_xpsnr.c:48
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:109
AV_PIX_FMT_GBRP10
#define AV_PIX_FMT_GBRP10
Definition: pixfmt.h:518
XPSNRContext::num_frames_64
uint64_t num_frames_64
Definition: vf_xpsnr.c:51
AV_PIX_FMT_GRAY16
#define AV_PIX_FMT_GRAY16
Definition: pixfmt.h:486
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
calc_squared_error_and_weight
static double calc_squared_error_and_weight(XPSNRContext const *s, const int16_t *pic_org, const uint32_t stride_org, int16_t *pic_org_m1, int16_t *pic_org_m2, const int16_t *pic_rec, const uint32_t stride_rec, const uint32_t offset_x, const uint32_t offset_y, const uint32_t block_width, const uint32_t block_height, const uint32_t bit_depth, const uint32_t int_frame_rate, double *ms_act)
Definition: vf_xpsnr.c:164
av_cold
#define av_cold
Definition: attributes.h:90
XPSNRContext::fs
FFFrameSync fs
Definition: vf_xpsnr.c:53
psnr.h
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
AV_PIX_FMT_GBRAP10
#define AV_PIX_FMT_GBRAP10
Definition: pixfmt.h:522
s
#define s(width, name)
Definition: cbs_vp9.c:198
AV_PIX_FMT_GBRAP12
#define AV_PIX_FMT_GBRAP12
Definition: pixfmt.h:523
AV_CEIL_RSHIFT
#define AV_CEIL_RSHIFT(a, b)
Definition: common.h:60
config_output
static int config_output(AVFilterLink *outlink)
Definition: vf_xpsnr.c:607
XPSNRContext::dsp
XPSNRDSPContext dsp
Definition: vf_xpsnr.c:72
filters.h
XPSNRContext::line_sizes
int line_sizes[4]
Definition: vf_xpsnr.c:54
ctx
AVFormatContext * ctx
Definition: movenc.c:49
XPSNRContext::stats_file_str
char * stats_file_str
Definition: vf_xpsnr.c:59
AV_PIX_FMT_GRAY14
#define AV_PIX_FMT_GRAY14
Definition: pixfmt.h:485
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
AV_PIX_FMT_GRAY10
#define AV_PIX_FMT_GRAY10
Definition: pixfmt.h:483
XPSNRContext::rgba_map
uint8_t rgba_map[4]
Definition: vf_xpsnr.c:57
AV_PIX_FMT_GBRP16
#define AV_PIX_FMT_GBRP16
Definition: pixfmt.h:521
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:75
NULL
#define NULL
Definition: coverity.c:32
fs
#define fs(width, name, subs,...)
Definition: cbs_vp9.c:200
XPSNRContext::sum_wdist
double sum_wdist[3]
Definition: vf_xpsnr.c:68
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
set_meta
static void set_meta(AVDictionary **metadata, const char *key, char comp, float d)
Definition: vf_xpsnr.c:384
isinf
#define isinf(x)
Definition: libm.h:317
double
double
Definition: af_crystalizer.c:132
abs
#define abs(x)
Definition: cuda_runtime.h:35
XPSNRContext::plane_width
int plane_width[4]
Definition: vf_xpsnr.c:56
diff1st
static uint64_t diff1st(const uint32_t w_act, const uint32_t h_act, const int16_t *o_m0, int16_t *o_m1, const int o)
Definition: vf_xpsnr.c:112
AV_PIX_FMT_GRAY8
@ AV_PIX_FMT_GRAY8
Y , 8bpp.
Definition: pixfmt.h:81
PF
#define PF(suf)
AV_PIX_FMT_GBRP9
#define AV_PIX_FMT_GBRP9
Definition: pixfmt.h:517
PSNRDSPContext
Definition: psnr.h:27
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
xpsnr_formats
static enum AVPixelFormat xpsnr_formats[]
Definition: vf_xpsnr.c:546
xpsnr_options
static const AVOption xpsnr_options[]
Definition: vf_xpsnr.c:82
f
f
Definition: af_crystalizer.c:122
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:372
master
const char * master
Definition: vf_curves.c:130
XPSNRContext::sse_luma
double * sse_luma
Definition: vf_xpsnr.c:61
P
#define P
calc_squared_error
static uint64_t calc_squared_error(XPSNRContext const *s, const int16_t *blk_org, const uint32_t stride_org, const int16_t *blk_rec, const uint32_t stride_rec, const uint32_t block_width, const uint32_t block_height)
Definition: vf_xpsnr.c:147
PF_NOALPHA
#define PF_NOALPHA(suf)
AV_LOG_INFO
#define AV_LOG_INFO
Standard information.
Definition: log.h:220
xpsnr_outputs
static const AVFilterPad xpsnr_outputs[]
Definition: vf_xpsnr.c:722
XPSNRContext::buf_org
AVBufferRef * buf_org[3]
Definition: vf_xpsnr.c:63
AV_PIX_FMT_GBRP12
#define AV_PIX_FMT_GBRP12
Definition: pixfmt.h:519
av_malloc_array
#define av_malloc_array(a, b)
Definition: tableprint_vlc.h:31
weights
static const int weights[]
Definition: hevc_pel.c:32
XPSNRContext::max_error_64
uint64_t max_error_64
Definition: vf_xpsnr.c:67
get_avg_xpsnr
static double get_avg_xpsnr(const double sqrt_wsse_val, const double sum_xpsnr_val, const uint32_t image_width, const uint32_t image_height, const uint64_t max_error_64, const uint64_t num_frames_64)
Definition: vf_xpsnr.c:252
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
highds
static uint64_t highds(const int x_act, const int y_act, const int w_act, const int h_act, const int16_t *o_m0, const int o)
Definition: vf_xpsnr.c:92
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
XPSNRContext::sum_xpsnr
double sum_xpsnr[3]
Definition: vf_xpsnr.c:69
XPSNRContext::bpp
int bpp
Definition: vf_xpsnr.c:47
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
xpsnr.h
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
av_buffer_allocz
AVBufferRef * av_buffer_allocz(size_t size)
Same as av_buffer_alloc(), except the returned buffer will be initialized to zero.
Definition: buffer.c:93
ret
ret
Definition: filter_design.txt:187
XPSNRDSPContext
Definition: xpsnr.h:39
xpsnr_inputs
static const AVFilterPad xpsnr_inputs[]
Definition: vf_xpsnr.c:711
framesync.h
AVRational::den
int den
Denominator.
Definition: rational.h:60
AV_PIX_FMT_NONE
@ AV_PIX_FMT_NONE
Definition: pixfmt.h:72
XPSNR_GAMMA
#define XPSNR_GAMMA
Definition: vf_xpsnr.c:80
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:117
get_wsse
static int get_wsse(AVFilterContext *ctx, int16_t **org, int16_t **org_m1, int16_t **org_m2, int16_t **rec, uint64_t *const wsse64)
Definition: vf_xpsnr.c:269
AVFilterContext
An instance of a filter.
Definition: avfilter.h:457
config_input_ref
static int config_input_ref(AVFilterLink *inlink)
Definition: vf_xpsnr.c:561
AV_PIX_FMT_GBRP
@ AV_PIX_FMT_GBRP
planar GBR 4:4:4 24bpp
Definition: pixfmt.h:165
desc
const char * desc
Definition: libsvtav1.c:79
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
mem.h
AVBufferRef
A reference to a data buffer.
Definition: buffer.h:82
XPSNRContext
Definition: vf_xpsnr.c:44
AVPixFmtDescriptor
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:69
XPSNRContext::plane_height
int plane_height[4]
Definition: vf_xpsnr.c:55
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
XPSNRContext::stats_file
FILE * stats_file
Definition: vf_xpsnr.c:58
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:79
int32_t
int32_t
Definition: audioconvert.c:56
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
sse
static int sse(MpegEncContext *s, const uint8_t *src1, const uint8_t *src2, int w, int h, int stride)
Definition: mpegvideo_enc.c:2653
h
h
Definition: vp9dsp_template.c:2070
XPSNRContext::buf_rec
AVBufferRef * buf_rec[3]
Definition: vf_xpsnr.c:66
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:352
avstring.h
do_xpsnr
static int do_xpsnr(FFFrameSync *fs)
Definition: vf_xpsnr.c:397
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
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
AV_PIX_FMT_GRAY12
#define AV_PIX_FMT_GRAY12
Definition: pixfmt.h:484
drawutils.h
XPSNRContext::weights
double * weights
Definition: vf_xpsnr.c:62
snprintf
#define snprintf
Definition: snprintf.h:34
diff2nd
static uint64_t diff2nd(const uint32_t w_act, const uint32_t h_act, const int16_t *o_m0, int16_t *o_m1, int16_t *o_m2, const int o)
Definition: vf_xpsnr.c:128