FFmpeg
swscale.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2024 Niklas Haas
3  * Copyright (C) 2003-2011 Michael Niedermayer <michaelni@gmx.at>
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 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <inttypes.h>
26 #include <stdarg.h>
27 #include <signal.h>
28 
29 #undef HAVE_AV_CONFIG_H
30 #include "libavutil/cpu.h"
31 #include "libavutil/parseutils.h"
32 #include "libavutil/pixdesc.h"
33 #include "libavutil/lfg.h"
34 #include "libavutil/sfc64.h"
35 #include "libavutil/frame.h"
36 #include "libavutil/opt.h"
37 #include "libavutil/time.h"
38 #include "libavutil/pixfmt.h"
39 #include "libavutil/avassert.h"
40 #include "libavutil/macros.h"
41 
42 #include "libswscale/swscale.h"
43 
44 struct options {
47  double prob;
48  int w, h;
49  int threads;
50  int iters;
51  int bench;
52  int flags;
53  int dither;
54  int unscaled;
55  int legacy;
56  int pretty;
57 };
58 
59 struct mode {
62 };
63 
64 struct test_results {
65  float ssim[4];
66  float loss;
68  int iters;
69 };
70 
71 const SwsFlags flags[] = {
72  0, // test defaults
77  SWS_POINT,
80 };
81 
83 
84 /* reused between tests for efficiency */
88 
89 static double speedup_logavg;
90 static double speedup_min = 1e10;
91 static double speedup_max = 0;
92 static int speedup_count;
93 
94 static const char *speedup_color(double ratio)
95 {
96  return ratio > 10.00 ? "\033[1;94m" : /* bold blue */
97  ratio > 2.00 ? "\033[1;32m" : /* bold green */
98  ratio > 1.02 ? "\033[32m" : /* green */
99  ratio > 0.98 ? "" : /* default */
100  ratio > 0.90 ? "\033[33m" : /* yellow */
101  ratio > 0.75 ? "\033[31m" : /* red */
102  "\033[1;31m"; /* bold red */
103 }
104 
105 static void exit_handler(int sig)
106 {
107  if (speedup_count) {
108  double ratio = exp(speedup_logavg / speedup_count);
109  fprintf(stderr, "Overall speedup=%.3fx %s%s\033[0m, min=%.3fx max=%.3fx\n", ratio,
110  speedup_color(ratio), ratio >= 1.0 ? "faster" : "slower",
112  }
113 
114  exit(sig);
115 }
116 
117 /* Estimate luma variance assuming uniform dither noise distribution */
119 {
121  float variance = 1.0 / 12;
122  if (desc->comp[0].depth < 8) {
123  /* Extra headroom for very low bit depth output */
124  variance *= (8 - desc->comp[0].depth);
125  }
126 
127  if (desc->flags & AV_PIX_FMT_FLAG_FLOAT) {
128  return 0.0;
129  } else if (desc->flags & AV_PIX_FMT_FLAG_RGB) {
130  const float r = 0.299 / (1 << desc->comp[0].depth);
131  const float g = 0.587 / (1 << desc->comp[1].depth);
132  const float b = 0.114 / (1 << desc->comp[2].depth);
133  return (r * r + g * g + b * b) * variance;
134  } else {
135  const float y = 1.0 / (1 << desc->comp[0].depth);
136  return y * y * variance;
137  }
138 }
139 
140 static int fmt_comps(enum AVPixelFormat fmt)
141 {
143  int comps = desc->nb_components >= 3 ? 0x7 : 0x1;
144  if (desc->flags & AV_PIX_FMT_FLAG_ALPHA)
145  comps |= 0x8;
146  return comps;
147 }
148 
149 static void get_ssim(float ssim[4], const AVFrame *out, const AVFrame *ref, int comps)
150 {
151  av_assert1(out->format == AV_PIX_FMT_YUVA444P);
152  av_assert1(ref->format == out->format);
153  av_assert1(ref->width == out->width && ref->height == out->height);
154 
155  for (int p = 0; p < 4; p++) {
156  const int stride_a = out->linesize[p];
157  const int stride_b = ref->linesize[p];
158  const int w = out->width;
159  const int h = out->height;
160 
161  const int is_chroma = p == 1 || p == 2;
162  const uint8_t def = is_chroma ? 128 : 0xFF;
163  const int has_ref = comps & (1 << p);
164  double sum = 0;
165  int count = 0;
166 
167  /* 4x4 SSIM */
168  for (int y = 0; y < (h & ~3); y += 4) {
169  for (int x = 0; x < (w & ~3); x += 4) {
170  const float c1 = .01 * .01 * 255 * 255 * 64;
171  const float c2 = .03 * .03 * 255 * 255 * 64 * 63;
172  int s1 = 0, s2 = 0, ss = 0, s12 = 0, var, covar;
173 
174  for (int yy = 0; yy < 4; yy++) {
175  for (int xx = 0; xx < 4; xx++) {
176  int a = out->data[p][(y + yy) * stride_a + x + xx];
177  int b = has_ref ? ref->data[p][(y + yy) * stride_b + x + xx] : def;
178  s1 += a;
179  s2 += b;
180  ss += a * a + b * b;
181  s12 += a * b;
182  }
183  }
184 
185  var = ss * 64 - s1 * s1 - s2 * s2;
186  covar = s12 * 64 - s1 * s2;
187  sum += (2 * s1 * s2 + c1) * (2 * covar + c2) /
188  ((s1 * s1 + s2 * s2 + c1) * (var + c2));
189  count++;
190  }
191  }
192 
193  ssim[p] = count ? sum / count : 0.0;
194  }
195 }
196 
197 static float get_loss(const float ssim[4])
198 {
199  const float weights[3] = { 0.8, 0.1, 0.1 }; /* tuned for Y'CbCr */
200 
201  float sum = 0;
202  for (int i = 0; i < 3; i++)
203  sum += weights[i] * ssim[i];
204  sum *= ssim[3]; /* ensure alpha errors get caught */
205 
206  return 1.0 - sum;
207 }
208 
210 {
211  for (int i = 0; i < FF_ARRAY_ELEMS(frame->buf); i++) {
212  if (!frame->buf[i])
213  break;
214  av_buffer_unref(&frame->buf[i]);
215  }
216 
217  memset(frame->data, 0, sizeof(frame->data));
218  memset(frame->linesize, 0, sizeof(frame->linesize));
219 }
220 
222 {
223  int ret = sws_scale_frame(c, dst, src);
224  if (ret < 0) {
225  av_log(NULL, AV_LOG_ERROR, "Failed %s ---> %s\n",
226  av_get_pix_fmt_name(src->format), av_get_pix_fmt_name(dst->format));
227  }
228  return ret;
229 }
230 
231 static int scale_new(AVFrame *dst, const AVFrame *src,
232  const struct mode *mode, const struct options *opts,
233  int64_t *out_time)
234 {
237  sws_src_dst->threads = opts->threads;
238 
240  if (ret < 0) {
241  av_log(NULL, AV_LOG_ERROR, "Failed to setup %s ---> %s\n",
242  av_get_pix_fmt_name(src->format), av_get_pix_fmt_name(dst->format));
243  return ret;
244  }
245 
246  int64_t time = av_gettime_relative();
247  for (int i = 0; ret >= 0 && i < opts->iters; i++) {
250  }
251  *out_time = av_gettime_relative() - time;
252 
253  return ret;
254 }
255 
256 static int scale_legacy(AVFrame *dst, const AVFrame *src,
257  const struct mode *mode, const struct options *opts,
258  int64_t *out_time)
259 {
260  SwsContext *sws_legacy;
261  int ret;
262 
263  sws_legacy = sws_alloc_context();
264  if (!sws_legacy)
265  return -1;
266 
267  sws_legacy->src_w = src->width;
268  sws_legacy->src_h = src->height;
269  sws_legacy->src_format = src->format;
270  sws_legacy->dst_w = dst->width;
271  sws_legacy->dst_h = dst->height;
272  sws_legacy->dst_format = dst->format;
273  sws_legacy->flags = mode->flags;
274  sws_legacy->dither = mode->dither;
275  sws_legacy->threads = opts->threads;
276 
278  dst->width = sws_legacy->dst_w;
279  dst->height = sws_legacy->dst_h;
280  dst->format = sws_legacy->dst_format;
282  if (ret < 0)
283  goto error;
284 
285  ret = sws_init_context(sws_legacy, NULL, NULL);
286  if (ret < 0)
287  goto error;
288 
289  int64_t time = av_gettime_relative();
290  for (int i = 0; ret >= 0 && i < opts->iters; i++)
291  ret = checked_sws_scale_frame(sws_legacy, dst, src);
292  *out_time = av_gettime_relative() - time;
293 
294 error:
295  sws_freeContext(sws_legacy);
296  return ret;
297 }
298 
299 static void print_results(const AVFrame *ref, const AVFrame *src, const AVFrame *dst,
300  int dst_w, int dst_h,
301  const struct mode *mode, const struct options *opts,
302  const struct test_results *r,
303  const struct test_results *ref_r,
304  float expected_loss)
305 {
306  if (av_log_get_level() >= AV_LOG_INFO) {
307  printf("%-*s %*dx%*d -> %-*s %*dx%*d, flags=0x%0*x dither=%u",
308  opts->pretty ? 14 : 0, av_get_pix_fmt_name(src->format),
309  opts->pretty ? 4 : 0, src->width,
310  opts->pretty ? 4 : 0, src->height,
311  opts->pretty ? 14 : 0, av_get_pix_fmt_name(dst->format),
312  opts->pretty ? 4 : 0, dst->width,
313  opts->pretty ? 4 : 0, dst->height,
314  opts->pretty ? 8 : 0, mode->flags,
315  mode->dither);
316 
317  if (!opts->bench || !ref_r) {
318  printf(", SSIM={Y=%f U=%f V=%f A=%f} loss=%e",
319  r->ssim[0], r->ssim[1], r->ssim[2], r->ssim[3],
320  r->loss);
321  if (ref_r)
322  printf(" (ref=%e)", ref_r->loss);
323  }
324 
325  if (opts->bench) {
326  printf(", time=%*"PRId64"/%u us",
327  opts->pretty ? 7 : 0, r->time, opts->iters);
328  if (ref_r) {
329  double ratio = ((double) ref_r->time / ref_r->iters)
330  / ((double) r->time / opts->iters);
331  if (FFMIN(r->time, ref_r->time) > 100 /* don't pollute stats with low precision */) {
332  speedup_min = FFMIN(speedup_min, ratio);
333  speedup_max = FFMAX(speedup_max, ratio);
334  speedup_logavg += log(ratio);
335  speedup_count++;
336  }
337 
338  printf(" (ref=%*"PRId64"/%u us), speedup=%*.3fx %s%s\033[0m",
339  opts->pretty ? 7 : 0, ref_r->time, ref_r->iters,
340  opts->pretty ? 6 : 0, ratio,
341  speedup_color(ratio), ratio >= 1.0 ? "faster" : "slower");
342  }
343  }
344  printf("\n");
345 
346  fflush(stdout);
347  }
348 
349  if (r->loss - expected_loss > 1e-4 && dst_w >= ref->width && dst_h >= ref->height) {
350  const int bad = r->loss - expected_loss > 1e-2;
351  const int level = bad ? AV_LOG_ERROR : AV_LOG_WARNING;
352  const char *worse_str = bad ? "WORSE" : "worse";
353  av_log(NULL, level,
354  " loss %e is %s by %e, expected loss %e\n",
355  r->loss, worse_str, r->loss - expected_loss, expected_loss);
356  }
357 
358  if (ref_r && r->loss - ref_r->loss > 1e-4) {
359  const int bad = r->loss - ref_r->loss > 1e-2;
360  const int level = bad ? AV_LOG_ERROR : AV_LOG_WARNING;
361  const char *worse_str = bad ? "WORSE" : "worse";
362  av_log(NULL, level,
363  " loss %e is %s by %e, ref loss %e SSIM={Y=%f U=%f V=%f A=%f}\n",
364  r->loss, worse_str, r->loss - ref_r->loss, ref_r->loss,
365  ref_r->ssim[0], ref_r->ssim[1], ref_r->ssim[2], ref_r->ssim[3]);
366  }
367 }
368 
369 static int init_frame(AVFrame **pframe, const AVFrame *ref,
370  int width, int height, enum AVPixelFormat format)
371 {
373  if (!frame)
374  return AVERROR(ENOMEM);
376  frame->width = width;
377  frame->height = height;
378  frame->format = format;
379  *pframe = frame;
380  return 0;
381 }
382 
383 /* Runs a series of ref -> src -> dst -> out, and compares out vs ref */
384 static int run_test(enum AVPixelFormat src_fmt, enum AVPixelFormat dst_fmt,
385  int dst_w, int dst_h,
386  const struct mode *mode, const struct options *opts,
387  const AVFrame *ref, AVFrame *src,
388  const struct test_results *ref_r)
389 {
390  AVFrame *dst = NULL, *out = NULL;
391  const int comps = fmt_comps(src_fmt) & fmt_comps(dst_fmt);
392  int ret;
393 
394  /* Estimate the expected amount of loss from bit depth reduction */
395  const float c1 = 0.01 * 0.01; /* stabilization constant */
396  const float ref_var = 1.0 / 12.0; /* uniformly distributed signal */
397  const float src_var = estimate_quantization_noise(src_fmt);
398  const float dst_var = estimate_quantization_noise(dst_fmt);
399  const float out_var = estimate_quantization_noise(ref->format);
400  const float total_var = src_var + dst_var + out_var;
401  const float ssim_luma = (2 * ref_var + c1) / (2 * ref_var + total_var + c1);
402  const float ssim_expected[4] = { ssim_luma, 1, 1, 1 }; /* for simplicity */
403  const float expected_loss = get_loss(ssim_expected);
404 
405  struct test_results r = { 0 };
406 
407  if (src->format != src_fmt) {
410  src->width = ref->width;
411  src->height = ref->height;
412  src->format = src_fmt;
414  if (ret < 0)
415  goto error;
416  }
417 
418  ret = init_frame(&dst, ref, dst_w, dst_h, dst_fmt);
419  if (ret < 0)
420  goto error;
421 
422  ret = opts->legacy ? scale_legacy(dst, src, mode, opts, &r.time)
423  : scale_new(dst, src, mode, opts, &r.time);
424  if (ret < 0)
425  goto error;
426 
427  ret = init_frame(&out, ref, ref->width, ref->height, ref->format);
428  if (ret < 0)
429  goto error;
430 
432  if (ret < 0)
433  goto error;
434 
435  get_ssim(r.ssim, out, ref, comps);
436 
437  if (opts->legacy) {
438  /* Legacy swscale does not perform bit accurate upconversions of low
439  * bit depth RGB. This artificially improves the SSIM score because the
440  * resulting error deletes some of the input dither noise. This gives
441  * it an unfair advantage when compared against a bit exact reference.
442  * Work around this by ensuring that the resulting SSIM score is not
443  * higher than it theoretically "should" be. */
444  if (src_var > dst_var) {
445  const float src_loss = (2 * ref_var + c1) / (2 * ref_var + src_var + c1);
446  r.ssim[0] = FFMIN(r.ssim[0], src_loss);
447  }
448  }
449 
450  r.loss = get_loss(r.ssim);
451  if (!opts->legacy && r.loss - expected_loss > 1e-2 && dst_w >= ref->width && dst_h >= ref->height) {
452  ret = -1;
453  goto bad_loss;
454  }
455 
456  if (ref_r && r.loss - ref_r->loss > 1e-2) {
457  ret = -1;
458  goto bad_loss;
459  }
460 
461  ret = 0; /* fall through */
462 
463 bad_loss:
465  dst_w, dst_h,
466  mode, opts,
467  &r, ref_r,
468  expected_loss);
469 
470  error:
471  av_frame_free(&dst);
472  av_frame_free(&out);
473  return ret;
474 }
475 
476 static inline int fmt_is_subsampled(enum AVPixelFormat fmt)
477 {
478  return av_pix_fmt_desc_get(fmt)->log2_chroma_w != 0 ||
480 }
481 
482 static int run_self_tests(const AVFrame *ref, const struct options *opts)
483 {
484  const int dst_w[] = { opts->w, opts->w - opts->w / 3, opts->w + opts->w / 3 };
485  const int dst_h[] = { opts->h, opts->h - opts->h / 3, opts->h + opts->h / 3 };
486 
487  enum AVPixelFormat src_fmt, dst_fmt,
488  src_fmt_min = 0,
489  dst_fmt_min = 0,
490  src_fmt_max = AV_PIX_FMT_NB - 1,
491  dst_fmt_max = AV_PIX_FMT_NB - 1;
492 
494  if (!src)
495  return AVERROR(ENOMEM);
496 
497  int ret = 0;
498 
499  if (opts->src_fmt != AV_PIX_FMT_NONE)
500  src_fmt_min = src_fmt_max = opts->src_fmt;
501  if (opts->dst_fmt != AV_PIX_FMT_NONE)
502  dst_fmt_min = dst_fmt_max = opts->dst_fmt;
503 
504  for (src_fmt = src_fmt_min; src_fmt <= src_fmt_max; src_fmt++) {
505  if (opts->unscaled && fmt_is_subsampled(src_fmt))
506  continue;
507  if (!sws_test_format(src_fmt, 0) || !sws_test_format(src_fmt, 1))
508  continue;
509  for (dst_fmt = dst_fmt_min; dst_fmt <= dst_fmt_max; dst_fmt++) {
510  if (opts->unscaled && fmt_is_subsampled(dst_fmt))
511  continue;
512  if (!sws_test_format(dst_fmt, 0) || !sws_test_format(dst_fmt, 1))
513  continue;
514  for (int h = 0; h < FF_ARRAY_ELEMS(dst_h); h++) {
515  for (int w = 0; w < FF_ARRAY_ELEMS(dst_w); w++) {
516  for (int f = 0; f < FF_ARRAY_ELEMS(flags); f++) {
517  struct mode mode = {
518  .flags = opts->flags >= 0 ? opts->flags : flags[f],
519  .dither = opts->dither >= 0 ? opts->dither : SWS_DITHER_AUTO,
520  };
521 
522  if (ff_sfc64_get(&prng_state) > UINT64_MAX * opts->prob)
523  continue;
524 
525  ret = run_test(src_fmt, dst_fmt, dst_w[w], dst_h[h],
526  &mode, opts, ref, src, NULL);
527  if (ret < 0)
528  goto error;
529 
530  if (opts->flags >= 0 || opts->unscaled)
531  break;
532  }
533  if (opts->unscaled)
534  break;
535  }
536  if (opts->unscaled)
537  break;
538  }
539  }
540  }
541 
542  ret = 0;
543 
544 error:
545  av_frame_free(&src);
546  return ret;
547 }
548 
549 static int run_file_tests(const AVFrame *ref, FILE *fp, const struct options *opts)
550 {
551  char buf[256];
552  int ret = 0;
553 
555  if (!src)
556  return AVERROR(ENOMEM);
557 
558  for (int line = 1; fgets(buf, sizeof(buf), fp); line++) {
559  char src_fmt_str[21], dst_fmt_str[21];
560  enum AVPixelFormat src_fmt;
561  enum AVPixelFormat dst_fmt;
562  int sw, sh, dw, dh;
563  struct test_results r = { 0 };
564  struct mode mode;
565  int n = 0;
566 
567  ret = sscanf(buf,
568  "%20s %dx%d -> %20s %dx%d, flags=0x%x dither=%u, "
569  "SSIM={Y=%f U=%f V=%f A=%f} loss=%e%n",
570  src_fmt_str, &sw, &sh, dst_fmt_str, &dw, &dh,
571  &mode.flags, &mode.dither,
572  &r.ssim[0], &r.ssim[1], &r.ssim[2], &r.ssim[3],
573  &r.loss, &n);
574  if (ret != 13) {
576  "Malformed reference file in line %d\n", line);
577  goto error;
578  }
579  if (opts->bench) {
580  ret = sscanf(buf + n,
581  ", time=%"PRId64"/%u us",
582  &r.time, &r.iters);
583  if (ret != 2) {
585  "Missing benchmarks from reference file in line %d\n",
586  line);
587  goto error;
588  }
589  }
590 
591  src_fmt = av_get_pix_fmt(src_fmt_str);
592  dst_fmt = av_get_pix_fmt(dst_fmt_str);
593  if (src_fmt == AV_PIX_FMT_NONE || dst_fmt == AV_PIX_FMT_NONE) {
595  "Unknown pixel formats (%s and/or %s) in line %d\n",
596  src_fmt_str, dst_fmt_str, line);
597  goto error;
598  }
599 
600  if (sw != ref->width || sh != ref->height) {
602  "Mismatching dimensions %dx%d (ref is %dx%d) in line %d\n",
603  sw, sh, ref->width, ref->height, line);
604  goto error;
605  }
606 
607  if (opts->src_fmt != AV_PIX_FMT_NONE && src_fmt != opts->src_fmt ||
608  opts->dst_fmt != AV_PIX_FMT_NONE && dst_fmt != opts->dst_fmt)
609  continue;
610 
611  ret = run_test(src_fmt, dst_fmt, dw, dh, &mode, opts, ref, src, &r);
612  if (ret < 0)
613  goto error;
614  }
615 
616  ret = 0;
617 
618 error:
619  av_frame_free(&src);
620  return ret;
621 }
622 
623 static int init_ref(AVFrame *ref, const struct options *opts)
624 {
627  AVLFG rand;
628  int ret = -1;
629 
630  if (!ctx || !rgb)
631  goto error;
632 
633  rgb->width = opts->w / 12;
634  rgb->height = opts->h / 12;
635  rgb->format = AV_PIX_FMT_RGBA;
636  ret = av_frame_get_buffer(rgb, 32);
637  if (ret < 0)
638  goto error;
639 
640  av_lfg_init(&rand, 1);
641  for (int y = 0; y < rgb->height; y++) {
642  for (int x = 0; x < rgb->width; x++) {
643  for (int c = 0; c < 4; c++)
644  rgb->data[0][y * rgb->linesize[0] + x * 4 + c] = av_lfg_get(&rand);
645  }
646  }
647 
650 
651 error:
653  av_frame_free(&rgb);
654  return ret;
655 }
656 
657 static int parse_options(int argc, char **argv, struct options *opts, FILE **fp)
658 {
659  for (int i = 1; i < argc; i += 2) {
660  if (!strcmp(argv[i], "-help") || !strcmp(argv[i], "--help")) {
661  fprintf(stderr,
662  "swscale [options...]\n"
663  " -help\n"
664  " This text\n"
665  " -ref <file>\n"
666  " Uses file as reference to compare tests against. Tests that have become worse will contain the string worse or WORSE\n"
667  " -p <number between 0.0 and 1.0>\n"
668  " The percentage of tests or comparisons to perform. Doing all tests will take long and generate over a hundred MB text output\n"
669  " It is often convenient to perform a random subset\n"
670  " -dst <pixfmt>\n"
671  " Only test the specified destination pixel format\n"
672  " -src <pixfmt>\n"
673  " Only test the specified source pixel format\n"
674  " -s <size>\n"
675  " Set frame size (WxH or abbreviation)\n"
676  " -bench <iters>\n"
677  " Run benchmarks with the specified number of iterations. This mode also sets the frame size to 1920x1080 (unless -s is specified)\n"
678  " -flags <flags>\n"
679  " Test with a specific combination of flags\n"
680  " -dither <mode>\n"
681  " Test with a specific dither mode\n"
682  " -unscaled <1 or 0>\n"
683  " If 1, test only conversions that do not involve scaling\n"
684  " -legacy <1 or 0>\n"
685  " If 1, force using legacy swscale for the main conversion\n"
686  " -threads <threads>\n"
687  " Use the specified number of threads\n"
688  " -cpuflags <cpuflags>\n"
689  " Uses the specified cpuflags in the tests\n"
690  " -pretty <1 or 0>\n"
691  " Align fields while printing results\n"
692  " -v <level>\n"
693  " Enable log verbosity at given level\n"
694  );
695  exit(0);
696  }
697  if (argv[i][0] != '-' || i + 1 == argc)
698  goto bad_option;
699  if (!strcmp(argv[i], "-ref")) {
700  *fp = fopen(argv[i + 1], "r");
701  if (!*fp) {
702  fprintf(stderr, "could not open '%s'\n", argv[i + 1]);
703  return -1;
704  }
705  } else if (!strcmp(argv[i], "-cpuflags")) {
706  unsigned flags = av_get_cpu_flags();
707  int res = av_parse_cpu_caps(&flags, argv[i + 1]);
708  if (res < 0) {
709  fprintf(stderr, "invalid cpu flags %s\n", argv[i + 1]);
710  return -1;
711  }
713  } else if (!strcmp(argv[i], "-src")) {
714  opts->src_fmt = av_get_pix_fmt(argv[i + 1]);
715  if (opts->src_fmt == AV_PIX_FMT_NONE) {
716  fprintf(stderr, "invalid pixel format %s\n", argv[i + 1]);
717  return -1;
718  }
719  } else if (!strcmp(argv[i], "-dst")) {
720  opts->dst_fmt = av_get_pix_fmt(argv[i + 1]);
721  if (opts->dst_fmt == AV_PIX_FMT_NONE) {
722  fprintf(stderr, "invalid pixel format %s\n", argv[i + 1]);
723  return -1;
724  }
725  } else if (!strcmp(argv[i], "-s")) {
726  if (av_parse_video_size(&opts->w, &opts->h, argv[i + 1]) < 0) {
727  fprintf(stderr, "invalid frame size %s\n", argv[i + 1]);
728  return -1;
729  }
730  } else if (!strcmp(argv[i], "-bench")) {
731  int iters = atoi(argv[i + 1]);
732  if (iters <= 0) {
733  opts->bench = 0;
734  opts->iters = 1;
735  } else {
736  opts->bench = 1;
737  opts->iters = iters;
738  }
739  } else if (!strcmp(argv[i], "-flags")) {
741  const AVOption *flags_opt = av_opt_find(dummy, "sws_flags", NULL, 0, 0);
742  int ret = av_opt_eval_flags(dummy, flags_opt, argv[i + 1], &opts->flags);
744  if (ret < 0) {
745  fprintf(stderr, "invalid flags %s\n", argv[i + 1]);
746  return -1;
747  }
748  } else if (!strcmp(argv[i], "-dither")) {
749  opts->dither = atoi(argv[i + 1]);
750  } else if (!strcmp(argv[i], "-unscaled")) {
751  opts->unscaled = atoi(argv[i + 1]);
752  } else if (!strcmp(argv[i], "-legacy")) {
753  opts->legacy = atoi(argv[i + 1]);
754  } else if (!strcmp(argv[i], "-threads")) {
755  opts->threads = atoi(argv[i + 1]);
756  } else if (!strcmp(argv[i], "-p")) {
757  opts->prob = atof(argv[i + 1]);
758  } else if (!strcmp(argv[i], "-pretty")) {
759  opts->pretty = atoi(argv[i + 1]);
760  } else if (!strcmp(argv[i], "-v")) {
761  av_log_set_level(atoi(argv[i + 1]));
762  } else {
763 bad_option:
764  fprintf(stderr, "bad option or argument missing (%s) see -help\n", argv[i]);
765  return -1;
766  }
767  }
768 
769  if (opts->w < 0 || opts->h < 0) {
770  opts->w = opts->bench ? 1920 : 96;
771  opts->h = opts->bench ? 1080 : 96;
772  }
773 
774  return 0;
775 }
776 
777 int main(int argc, char **argv)
778 {
779  struct options opts = {
780  .src_fmt = AV_PIX_FMT_NONE,
781  .dst_fmt = AV_PIX_FMT_NONE,
782  .w = -1,
783  .h = -1,
784  .threads = 1,
785  .iters = 1,
786  .prob = 1.0,
787  .flags = -1,
788  .dither = -1,
789  };
790 
791  AVFrame *ref = NULL;
792  FILE *fp = NULL;
793  int ret = -1;
794 
795  if (parse_options(argc, argv, &opts, &fp) < 0)
796  goto error;
797 
798  ff_sfc64_init(&prng_state, 0, 0, 0, 12);
799  signal(SIGINT, exit_handler);
800 
804  if (!sws_ref_src || !sws_src_dst || !sws_dst_out)
805  goto error;
808 
809  ref = av_frame_alloc();
810  if (!ref)
811  goto error;
812  ref->width = opts.w;
813  ref->height = opts.h;
814  ref->format = AV_PIX_FMT_YUVA444P;
815 
816  ret = init_ref(ref, &opts);
817  if (ret < 0)
818  goto error;
819 
820  ret = fp ? run_file_tests(ref, fp, &opts)
821  : run_self_tests(ref, &opts);
822 
823  /* fall through */
824 error:
828  av_frame_free(&ref);
829  if (fp)
830  fclose(fp);
831  exit_handler(ret);
832 }
error
static void error(const char *err)
Definition: target_bsf_fuzzer.c:32
flags
const SwsFlags flags[]
Definition: swscale.c:71
av_force_cpu_flags
void av_force_cpu_flags(int arg)
Disables cpu detection and forces the specified flags.
Definition: cpu.c:81
av_gettime_relative
int64_t av_gettime_relative(void)
Get the current time in microseconds since some unspecified starting point.
Definition: time.c:56
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:216
AVPixelFormat
AVPixelFormat
Pixel format.
Definition: pixfmt.h:71
level
uint8_t level
Definition: svq3.c:208
SWS_DITHER_AUTO
@ SWS_DITHER_AUTO
Definition: swscale.h:81
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
printf
__device__ int printf(const char *,...)
opt.h
checked_sws_scale_frame
static int checked_sws_scale_frame(SwsContext *c, AVFrame *dst, const AVFrame *src)
Definition: swscale.c:221
out
static FILE * out
Definition: movenc.c:55
av_frame_get_buffer
int av_frame_get_buffer(AVFrame *frame, int align)
Allocate new buffer(s) for audio or video data.
Definition: frame.c:206
av_lfg_init
av_cold void av_lfg_init(AVLFG *c, unsigned int seed)
Definition: lfg.c:32
fmt_is_subsampled
static int fmt_is_subsampled(enum AVPixelFormat fmt)
Definition: swscale.c:476
av_pix_fmt_desc_get
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:3456
SwsContext::src_w
int src_w
Deprecated frame property overrides, for the legacy API only.
Definition: swscale.h:253
print_results
static void print_results(const AVFrame *ref, const AVFrame *src, const AVFrame *dst, int dst_w, int dst_h, const struct mode *mode, const struct options *opts, const struct test_results *r, const struct test_results *ref_r, float expected_loss)
Definition: swscale.c:299
estimate_quantization_noise
static float estimate_quantization_noise(enum AVPixelFormat fmt)
Definition: swscale.c:118
int64_t
long long int64_t
Definition: coverity.c:34
AV_PIX_FMT_FLAG_FLOAT
#define AV_PIX_FMT_FLAG_FLOAT
The pixel format contains IEEE-754 floating point values.
Definition: pixdesc.h:158
sws_freeContext
void sws_freeContext(SwsContext *swsContext)
Free the swscaler context swsContext.
Definition: utils.c:2285
normalize.log
log
Definition: normalize.py:21
av_frame_free
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:64
options::unscaled
int unscaled
Definition: swscale.c:54
mode
Definition: swscale.c:59
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:427
pixdesc.h
speedup_color
static const char * speedup_color(double ratio)
Definition: swscale.c:94
SWS_BILINEAR
@ SWS_BILINEAR
bilinear filtering
Definition: swscale.h:177
SWS_BITEXACT
@ SWS_BITEXACT
Definition: swscale.h:157
AVOption
AVOption.
Definition: opt.h:429
b
#define b
Definition: input.c:42
options::pretty
int pretty
Definition: swscale.c:56
options::dither
int dither
Definition: swscale.c:53
ff_sfc64_init
static void ff_sfc64_init(FFSFC64 *s, uint64_t seeda, uint64_t seedb, uint64_t seedc, int rounds)
Initialize sfc64 with up to 3 seeds.
Definition: sfc64.h:75
SwsContext::flags
unsigned flags
Bitmask of SWS_*.
Definition: swscale.h:219
FFMAX
#define FFMAX(a, b)
Definition: macros.h:47
av_get_cpu_flags
int av_get_cpu_flags(void)
Return the flags which specify extensions supported by the CPU.
Definition: cpu.c:109
c1
static const uint64_t c1
Definition: murmur3.c:52
mode::dither
SwsDither dither
Definition: swscale.c:61
prng_state
static FFSFC64 prng_state
Definition: swscale.c:82
speedup_max
static double speedup_max
Definition: swscale.c:91
run_self_tests
static int run_self_tests(const AVFrame *ref, const struct options *opts)
Definition: swscale.c:482
AV_PIX_FMT_NB
@ AV_PIX_FMT_NB
hardware decoding through openharmony
Definition: pixfmt.h:502
run_file_tests
static int run_file_tests(const AVFrame *ref, FILE *fp, const struct options *opts)
Definition: swscale.c:549
SWS_FAST_BILINEAR
@ SWS_FAST_BILINEAR
Scaler selection options.
Definition: swscale.h:176
rgb
Definition: rpzaenc.c:60
SWS_FULL_CHR_H_INP
@ SWS_FULL_CHR_H_INP
Perform full chroma interpolation when downscaling RGB sources.
Definition: swscale.h:146
macros.h
FFSFC64
Definition: sfc64.h:37
SwsDither
SwsDither
Definition: swscale.h:77
dummy
int dummy
Definition: motion.c:64
options::iters
int iters
Definition: swscale.c:50
av_parse_cpu_caps
int av_parse_cpu_caps(unsigned *flags, const char *s)
Parse CPU caps from a string and update the given AV_CPU_* flags based on that.
Definition: cpu.c:119
sws_init_context
av_warn_unused_result int sws_init_context(SwsContext *sws_context, SwsFilter *srcFilter, SwsFilter *dstFilter)
Initialize the swscaler context sws_context.
Definition: utils.c:1919
sws_frame_setup
int sws_frame_setup(SwsContext *ctx, const AVFrame *dst, const AVFrame *src)
Like sws_scale_frame, but without actually scaling.
Definition: swscale.c:1422
ss
#define ss(width, name, subs,...)
Definition: cbs_vp9.c:202
test_results::ssim
float ssim[4]
Definition: swscale.c:65
av_frame_alloc
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition: frame.c:52
avassert.h
options::dst_fmt
enum AVPixelFormat dst_fmt
Definition: swscale.c:46
options::w
int w
Definition: swscale.c:48
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:210
SWS_AREA
@ SWS_AREA
area averaging
Definition: swscale.h:181
FF_ARRAY_ELEMS
#define FF_ARRAY_ELEMS(a)
Definition: sinewin_tablegen.c:29
speedup_min
static double speedup_min
Definition: swscale.c:90
SwsContext::dither
SwsDither dither
Dither mode.
Definition: swscale.h:235
options::h
int h
Definition: swscale.c:48
SwsFlags
SwsFlags
Definition: swscale.h:110
SwsContext::threads
int threads
How many threads to use for processing, or 0 for automatic selection.
Definition: swscale.h:230
av_lfg_get
static unsigned int av_lfg_get(AVLFG *c)
Get the next random unsigned 32-bit number using an ALFG.
Definition: lfg.h:53
AVFormatContext::flags
int flags
Flags modifying the (de)muxer behaviour.
Definition: avformat.h:1414
g
const char * g
Definition: vf_curves.c:128
lfg.h
AV_PIX_FMT_FLAG_ALPHA
#define AV_PIX_FMT_FLAG_ALPHA
The pixel format has an alpha channel.
Definition: pixdesc.h:147
ctx
static AVFormatContext * ctx
Definition: movenc.c:49
sfc64.h
AVPixFmtDescriptor::log2_chroma_w
uint8_t log2_chroma_w
Amount to shift the luma width right to find the chroma width.
Definition: pixdesc.h:80
options::legacy
int legacy
Definition: swscale.c:55
AV_PIX_FMT_RGBA
@ AV_PIX_FMT_RGBA
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
Definition: pixfmt.h:100
av_log_get_level
int av_log_get_level(void)
Get the current log level.
Definition: log.c:472
opts
static AVDictionary * opts
Definition: movenc.c:51
NULL
#define NULL
Definition: coverity.c:32
av_frame_copy_props
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition: frame.c:599
format
New swscale design to change SwsGraph is what coordinates multiple passes These can include cascaded scaling error diffusion and so on Or we could have separate passes for the vertical and horizontal scaling In between each SwsPass lies a fully allocated image buffer Graph passes may have different levels of e g we can have a single threaded error diffusion pass following a multi threaded scaling pass SwsGraph is internally recreated whenever the image format
Definition: swscale-v2.txt:14
av_buffer_unref
void av_buffer_unref(AVBufferRef **buf)
Free a given reference and automatically free the buffer if there are no more references to it.
Definition: buffer.c:139
SWS_BICUBIC
@ SWS_BICUBIC
2-tap cubic B-spline
Definition: swscale.h:178
options::threads
int threads
Definition: swscale.c:49
parseutils.h
options
Definition: swscale.c:44
sws_test_format
int sws_test_format(enum AVPixelFormat format, int output)
Test if a given (software) pixel format is supported.
Definition: format.c:543
double
double
Definition: af_crystalizer.c:132
time.h
run_test
static int run_test(enum AVPixelFormat src_fmt, enum AVPixelFormat dst_fmt, int dst_w, int dst_h, const struct mode *mode, const struct options *opts, const AVFrame *ref, AVFrame *src, const struct test_results *ref_r)
Definition: swscale.c:384
exp
int8_t exp
Definition: eval.c:76
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
options::src_fmt
enum AVPixelFormat src_fmt
Definition: swscale.c:45
av_opt_find
const AVOption * av_opt_find(void *obj, const char *name, const char *unit, int opt_flags, int search_flags)
Look for an option in an object.
Definition: opt.c:1985
AVLFG
Context structure for the Lagged Fibonacci PRNG.
Definition: lfg.h:33
f
f
Definition: af_crystalizer.c:122
height
#define height
Definition: dsp.h:89
sws_alloc_context
SwsContext * sws_alloc_context(void)
Allocate an empty SwsContext and set its fields to default values.
Definition: utils.c:1031
sws_ref_src
static SwsContext * sws_ref_src
Definition: swscale.c:85
AV_PIX_FMT_FLAG_RGB
#define AV_PIX_FMT_FLAG_RGB
The pixel format contains RGB-like data (as opposed to YUV/grayscale).
Definition: pixdesc.h:136
dst
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition: dsp.h:87
cpu.h
i
#define i(width, name, range_min, range_max)
Definition: cbs_h264.c:63
mode::flags
SwsFlags flags
Definition: swscale.c:60
SWS_POINT
@ SWS_POINT
nearest neighbor
Definition: swscale.h:180
SwsContext::src_h
int src_h
Width and height of the source frame.
Definition: swscale.h:253
sws_src_dst
static SwsContext * sws_src_dst
Definition: swscale.c:86
exit_handler
static void exit_handler(int sig)
Definition: swscale.c:105
scale_legacy
static int scale_legacy(AVFrame *dst, const AVFrame *src, const struct mode *mode, const struct options *opts, int64_t *out_time)
Definition: swscale.c:256
frame.h
options::prob
double prob
Definition: swscale.c:47
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
get_loss
static float get_loss(const float ssim[4])
Definition: swscale.c:197
AV_PIX_FMT_YUVA444P
@ AV_PIX_FMT_YUVA444P
planar YUV 4:4:4 32bpp, (1 Cr & Cb sample per 1x1 Y & A samples)
Definition: pixfmt.h:174
line
Definition: graph2dot.c:48
unref_buffers
static void unref_buffers(AVFrame *frame)
Definition: swscale.c:209
SwsContext::dst_format
int dst_format
Destination pixel format.
Definition: swscale.h:256
av_parse_video_size
int av_parse_video_size(int *width_ptr, int *height_ptr, const char *str)
Parse str and put in width_ptr and height_ptr the detected values.
Definition: parseutils.c:150
AV_LOG_INFO
#define AV_LOG_INFO
Standard information.
Definition: log.h:221
options::flags
int flags
Definition: swscale.c:52
av_log_set_level
void av_log_set_level(int level)
Set the log level.
Definition: log.c:477
test_results::loss
float loss
Definition: swscale.c:66
SWS_X
@ SWS_X
experimental
Definition: swscale.h:179
weights
static const int weights[]
Definition: hevc_pel.c:32
av_assert1
#define av_assert1(cond)
assert() equivalent, that does not lie in speed critical code.
Definition: avassert.h:58
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
test_results
Definition: swscale.c:64
av_frame_unref
void av_frame_unref(AVFrame *frame)
Unreference all the buffers referenced by frame and reset the frame fields.
Definition: frame.c:496
SwsContext::dst_h
int dst_h
Width and height of the destination frame.
Definition: swscale.h:254
ff_sfc64_get
static uint64_t ff_sfc64_get(FFSFC64 *s)
Definition: sfc64.h:41
av_opt_eval_flags
int av_opt_eval_flags(void *obj, const AVOption *o, const char *val, int *flags_out)
ret
ret
Definition: filter_design.txt:187
AV_LOG_FATAL
#define AV_LOG_FATAL
Something went wrong and recovery is not possible.
Definition: log.h:204
pixfmt.h
frame
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
Definition: filter_design.txt:265
test_results::time
int64_t time
Definition: swscale.c:67
SWS_FULL_CHR_H_INT
@ SWS_FULL_CHR_H_INT
Perform full chroma upsampling when upscaling to RGB.
Definition: swscale.h:133
get_ssim
static void get_ssim(float ssim[4], const AVFrame *out, const AVFrame *ref, int comps)
Definition: swscale.c:149
av_get_pix_fmt
enum AVPixelFormat av_get_pix_fmt(const char *name)
Return the pixel format corresponding to name.
Definition: pixdesc.c:3388
speedup_count
static int speedup_count
Definition: swscale.c:92
c2
static const uint64_t c2
Definition: murmur3.c:53
main
int main(int argc, char **argv)
Definition: swscale.c:777
AV_PIX_FMT_NONE
@ AV_PIX_FMT_NONE
Definition: pixfmt.h:72
init_ref
static int init_ref(AVFrame *ref, const struct options *opts)
Definition: swscale.c:623
ref
static int ref[MAX_W *MAX_W]
Definition: jpeg2000dwt.c:117
Windows::Graphics::DirectX::Direct3D11::p
IDirect3DDxgiInterfaceAccess _COM_Outptr_ void ** p
Definition: vsrc_gfxcapture_winrt.hpp:53
bad
static int bad(InterplayACMContext *s, unsigned ind, unsigned col)
Definition: interplayacm.c:130
desc
const char * desc
Definition: libsvtav1.c:82
sws_dst_out
static SwsContext * sws_dst_out
Definition: swscale.c:87
SwsContext::dst_w
int dst_w
Definition: swscale.h:254
SwsContext::src_format
int src_format
Source pixel format.
Definition: swscale.h:255
AVPixFmtDescriptor
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:69
w
uint8_t w
Definition: llvidencdsp.c:39
options::bench
int bench
Definition: swscale.c:51
sws_free_context
void sws_free_context(SwsContext **ctx)
Free the context and everything associated with it, and write NULL to the provided pointer.
Definition: utils.c:2368
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
sws_scale_frame
int sws_scale_frame(SwsContext *sws, AVFrame *dst, const AVFrame *src)
Scale source data from src and write the output to dst.
Definition: swscale.c:1349
SWS_ACCURATE_RND
@ SWS_ACCURATE_RND
Force bit-exact output.
Definition: swscale.h:156
h
h
Definition: vp9dsp_template.c:2070
width
#define width
Definition: dsp.h:89
SwsContext
Main external API structure.
Definition: swscale.h:206
scale_new
static int scale_new(AVFrame *dst, const AVFrame *src, const struct mode *mode, const struct options *opts, int64_t *out_time)
Definition: swscale.c:231
fmt_comps
static int fmt_comps(enum AVPixelFormat fmt)
Definition: swscale.c:140
test_results::iters
int iters
Definition: swscale.c:68
parse_options
static int parse_options(int argc, char **argv, struct options *opts, FILE **fp)
Definition: swscale.c:657
AVPixFmtDescriptor::log2_chroma_h
uint8_t log2_chroma_h
Amount to shift the luma height right to find the chroma height.
Definition: pixdesc.h:89
src
#define src
Definition: vp8dsp.c:248
swscale.h
init_frame
static int init_frame(AVFrame **pframe, const AVFrame *ref, int width, int height, enum AVPixelFormat format)
Definition: swscale.c:369
av_get_pix_fmt_name
const char * av_get_pix_fmt_name(enum AVPixelFormat pix_fmt)
Return the short name for a pixel format, NULL in case pix_fmt is unknown.
Definition: pixdesc.c:3376
speedup_logavg
static double speedup_logavg
Definition: swscale.c:89