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/avstring.h"
32 #include "libavutil/parseutils.h"
33 #include "libavutil/pixdesc.h"
34 #include "libavutil/lfg.h"
35 #include "libavutil/sfc64.h"
36 #include "libavutil/frame.h"
37 #include "libavutil/opt.h"
38 #include "libavutil/time.h"
39 #include "libavutil/pixfmt.h"
40 #include "libavutil/avassert.h"
41 #include "libavutil/macros.h"
42 #include "libavutil/hwcontext.h"
43 
44 #include "libswscale/swscale.h"
45 #include "libswscale/format.h"
46 
47 #define IMPL_NEW 0
48 #define IMPL_LEGACY 1
49 
50 struct options {
53  double prob;
54  int w, h;
55  int dst_w;
56  int dst_h;
57  int threads;
58  int iters;
59  int bench;
60  int flags;
61  int dither;
62  int scaler;
64  int align_src;
65  int align_dst;
66  int api;
67  int pretty;
68  int backends;
69 };
70 
71 struct mode {
76 };
77 
78 struct test_results {
79  float ssim[4];
80  float loss;
82  int iters;
83 };
84 
85 const SwsFlags flags[] = {
86  0, // test defaults
91  SWS_POINT,
94 };
95 
97 
98 /* reused between tests for efficiency */
102 
105 
106 static double speedup_logavg;
107 static double speedup_min = 1e10;
108 static double speedup_max = 0;
109 static int speedup_count;
110 
111 static const char *speedup_color(double ratio)
112 {
113  return ratio > 10.00 ? "\033[1;94m" : /* bold blue */
114  ratio > 2.00 ? "\033[1;32m" : /* bold green */
115  ratio > 1.02 ? "\033[32m" : /* green */
116  ratio > 0.98 ? "" : /* default */
117  ratio > 0.90 ? "\033[33m" : /* yellow */
118  ratio > 0.75 ? "\033[31m" : /* red */
119  "\033[1;31m"; /* bold red */
120 }
121 
122 static void exit_handler(int sig)
123 {
124  if (speedup_count) {
125  double ratio = exp(speedup_logavg / speedup_count);
126  fprintf(stderr, "Overall speedup=%.3fx %s%s\033[0m, min=%.3fx max=%.3fx\n", ratio,
127  speedup_color(ratio), ratio >= 1.0 ? "faster" : "slower",
129  }
130 
131  exit(sig);
132 }
133 
134 /* Estimate luma variance assuming uniform dither noise distribution */
136 {
138  float variance = 1.0 / 12;
139  if (desc->comp[0].depth < 8) {
140  /* Extra headroom for very low bit depth output */
141  variance *= (8 - desc->comp[0].depth);
142  }
143 
144  if (desc->flags & AV_PIX_FMT_FLAG_FLOAT) {
145  return 0.0;
146  } else if (desc->flags & AV_PIX_FMT_FLAG_RGB) {
147  const float r = 0.299 / (1 << desc->comp[0].depth);
148  const float g = 0.587 / (1 << desc->comp[1].depth);
149  const float b = 0.114 / (1 << desc->comp[2].depth);
150  return (r * r + g * g + b * b) * variance;
151  } else {
152  const float y = 1.0 / (1 << desc->comp[0].depth);
153  return y * y * variance;
154  }
155 }
156 
157 static int fmt_comps(enum AVPixelFormat fmt)
158 {
160  int comps = desc->nb_components >= 3 ? 0x7 : 0x1;
161  if (desc->flags & AV_PIX_FMT_FLAG_ALPHA)
162  comps |= 0x8;
163  return comps;
164 }
165 
166 static void get_ssim(float ssim[4], const AVFrame *out, const AVFrame *ref, int comps)
167 {
168  av_assert1(out->format == AV_PIX_FMT_YUVA444P);
169  av_assert1(ref->format == out->format);
170  av_assert1(ref->width == out->width && ref->height == out->height);
171 
172  for (int p = 0; p < 4; p++) {
173  const int stride_a = out->linesize[p];
174  const int stride_b = ref->linesize[p];
175  const int w = out->width;
176  const int h = out->height;
177 
178  const int is_chroma = p == 1 || p == 2;
179  const uint8_t def = is_chroma ? 128 : 0xFF;
180  const int has_ref = comps & (1 << p);
181  double sum = 0;
182  int count = 0;
183 
184  /* 4x4 SSIM */
185  for (int y = 0; y < (h & ~3); y += 4) {
186  for (int x = 0; x < (w & ~3); x += 4) {
187  const float c1 = .01 * .01 * 255 * 255 * 64;
188  const float c2 = .03 * .03 * 255 * 255 * 64 * 63;
189  int s1 = 0, s2 = 0, ss = 0, s12 = 0, var, covar;
190 
191  for (int yy = 0; yy < 4; yy++) {
192  for (int xx = 0; xx < 4; xx++) {
193  int a = out->data[p][(y + yy) * stride_a + x + xx];
194  int b = has_ref ? ref->data[p][(y + yy) * stride_b + x + xx] : def;
195  s1 += a;
196  s2 += b;
197  ss += a * a + b * b;
198  s12 += a * b;
199  }
200  }
201 
202  var = ss * 64 - s1 * s1 - s2 * s2;
203  covar = s12 * 64 - s1 * s2;
204  sum += (2 * s1 * s2 + c1) * (2 * covar + c2) /
205  ((s1 * s1 + s2 * s2 + c1) * (var + c2));
206  count++;
207  }
208  }
209 
210  ssim[p] = count ? sum / count : 0.0;
211  }
212 }
213 
214 static float get_loss(const float ssim[4])
215 {
216  const float weights[3] = { 0.8, 0.1, 0.1 }; /* tuned for Y'CbCr */
217 
218  float sum = 0;
219  for (int i = 0; i < 3; i++)
220  sum += weights[i] * ssim[i];
221  sum *= ssim[3]; /* ensure alpha errors get caught */
222 
223  return 1.0 - sum;
224 }
225 
227 {
228  for (int i = 0; i < FF_ARRAY_ELEMS(frame->buf); i++) {
229  if (!frame->buf[i])
230  break;
231  av_buffer_unref(&frame->buf[i]);
232  }
233 
234  memset(frame->data, 0, sizeof(frame->data));
235  memset(frame->linesize, 0, sizeof(frame->linesize));
236 }
237 
239 {
240  int ret = sws_scale_frame(c, dst, src);
241  if (ret < 0) {
242  av_log(NULL, AV_LOG_ERROR, "Failed %s ---> %s\n",
243  av_get_pix_fmt_name(src->format), av_get_pix_fmt_name(dst->format));
244  }
245  return ret;
246 }
247 
248 static int scale_new(AVFrame *dst, const AVFrame *src,
249  const struct mode *mode, const struct options *opts,
250  int64_t *out_time)
251 {
256  sws_src_dst->threads = opts->threads;
257  sws_src_dst->backends = opts->backends;
258 
260  if (ret < 0) {
261  av_log(NULL, AV_LOG_ERROR, "Failed to setup %s ---> %s\n",
262  av_get_pix_fmt_name(src->format), av_get_pix_fmt_name(dst->format));
263  return ret;
264  }
265 
266  int64_t time = av_gettime_relative();
267  for (int i = 0; ret >= 0 && i < opts->iters; i++) {
269  if (opts->align_dst) {
270  ret = av_frame_get_buffer(dst, opts->align_dst);
271  if (ret < 0)
272  return ret;
273  }
274 
276  }
277  *out_time = av_gettime_relative() - time;
278 
279  return ret;
280 }
281 
282 static int scale_legacy(AVFrame *dst, const AVFrame *src,
283  const struct mode *mode, const struct options *opts,
284  int64_t *out_time)
285 {
286  SwsContext *sws_legacy;
287  int ret;
288 
289  sws_legacy = sws_alloc_context();
290  if (!sws_legacy)
291  return -1;
292 
293  sws_legacy->src_w = src->width;
294  sws_legacy->src_h = src->height;
295  sws_legacy->src_format = src->format;
296  sws_legacy->dst_w = dst->width;
297  sws_legacy->dst_h = dst->height;
298  sws_legacy->dst_format = dst->format;
299  sws_legacy->flags = mode->flags;
300  sws_legacy->dither = mode->dither;
301  sws_legacy->scaler = mode->scaler;
302  sws_legacy->scaler_sub = mode->scaler_sub;
303  sws_legacy->threads = opts->threads;
304 
306  dst->width = sws_legacy->dst_w;
307  dst->height = sws_legacy->dst_h;
308  dst->format = sws_legacy->dst_format;
309  ret = av_frame_get_buffer(dst, opts->align_dst);
310  if (ret < 0)
311  goto error;
312 
313  ret = sws_init_context(sws_legacy, NULL, NULL);
314  if (ret < 0)
315  goto error;
316 
317  int64_t time = av_gettime_relative();
318  for (int i = 0; ret >= 0 && i < opts->iters; i++)
319  ret = checked_sws_scale_frame(sws_legacy, dst, src);
320  *out_time = av_gettime_relative() - time;
321 
322 error:
323  sws_freeContext(sws_legacy);
324  return ret;
325 }
326 
327 static int scale_hw(AVFrame *dst, const AVFrame *src,
328  const struct mode *mode, const struct options *opts,
329  int64_t *out_time)
330 {
331  SwsContext *sws_hw = NULL;
332  AVBufferRef *in_ref = NULL;
333  AVBufferRef *out_ref = NULL;
334  AVHWFramesContext *in_ctx = NULL;
335  AVHWFramesContext *out_ctx = NULL;
336  AVFrame *in_f = NULL;
337  AVFrame *out_f = NULL;
338  int ret;
339 
340  if (src->format == dst->format)
341  return AVERROR(ENOTSUP);
342 
343  sws_hw = sws_alloc_context();
344  if (!sws_hw) {
345  ret = AVERROR(ENOMEM);
346  goto error;
347  }
348 
349  sws_hw->flags = mode->flags;
350  sws_hw->dither = mode->dither;
351 
353  if (!in_ref) {
354  ret = AVERROR(ENOMEM);
355  goto error;
356  }
357 
358  in_ctx = (AVHWFramesContext *)in_ref->data;
359  in_ctx->format = AV_PIX_FMT_VULKAN;
360  in_ctx->sw_format = src->format;
361  in_ctx->width = src->width;
362  in_ctx->height = src->height;
363  ret = av_hwframe_ctx_init(in_ref);
364  if (ret < 0) {
365  if (ret != AVERROR(ENOTSUP))
366  av_log(NULL, AV_LOG_ERROR, "Failed to create input HW context: %s\n",
367  av_err2str(ret));
368  goto error;
369  }
370 
372  if (!out_ref) {
373  ret = AVERROR(ENOMEM);
374  goto error;
375  }
376 
377  out_ctx = (AVHWFramesContext *) out_ref->data;
378  out_ctx->format = AV_PIX_FMT_VULKAN;
379  out_ctx->sw_format = dst->format;
380  out_ctx->width = dst->width;
381  out_ctx->height = dst->height;
382  ret = av_hwframe_ctx_init(out_ref);
383  if (ret < 0) {
384  if (ret != AVERROR(ENOTSUP))
385  av_log(NULL, AV_LOG_ERROR, "Failed to create output HW context: %s\n",
386  av_err2str(ret));
387  goto error;
388  }
389 
390  in_f = av_frame_alloc();
391  if (!in_f) {
392  ret = AVERROR(ENOMEM);
393  goto error;
394  }
395  in_f->width = src->width;
396  in_f->height = src->height;
397  in_f->format = AV_PIX_FMT_VULKAN;
398  ret = av_hwframe_get_buffer(in_ref, in_f, 0);
399  if (ret < 0) {
400  av_log(NULL, AV_LOG_ERROR, "Failed to allocate input HW frame\n");
401  goto error;
402  }
403 
404  ret = av_hwframe_transfer_data(in_f, src, 0);
405  if (ret < 0) {
406  av_log(NULL, AV_LOG_ERROR, "Failed to upload HW frame\n");
407  goto error;
408  }
409 
410  out_f = av_frame_alloc();
411  if (!out_f) {
412  ret = AVERROR(ENOMEM);
413  goto error;
414  }
415  out_f->width = dst->width;
416  out_f->height = dst->height;
417  out_f->format = AV_PIX_FMT_VULKAN;
418  ret = av_hwframe_get_buffer(out_ref, out_f, 0);
419  if (ret < 0) {
420  av_log(NULL, AV_LOG_ERROR, "Failed to allocate output HW frame\n");
421  goto error;
422  }
423 
424  int64_t time = av_gettime_relative();
425  for (int i = 0; ret >= 0 && i < opts->iters; i++) {
426  ret = checked_sws_scale_frame(sws_hw, out_f, in_f);
427  if (ret < 0)
428  goto error;
429  }
430  *out_time = av_gettime_relative() - time;
431 
433  if (ret < 0)
434  goto error;
435 
436  ret = av_hwframe_transfer_data(dst, out_f, 0);
437  if (ret < 0) {
438  av_log(NULL, AV_LOG_ERROR, "Failed to download HW frame\n");
439  goto error;
440  }
441 
442  ret = 0;
443 
444 error:
445  av_frame_free(&in_f);
446  av_frame_free(&out_f);
447  av_buffer_unref(&in_ref);
448  av_buffer_unref(&out_ref);
449  sws_free_context(&sws_hw);
450  return ret;
451 }
452 
453 static void print_test_params(char *buf, size_t buf_size,
454  const AVFrame *src, const AVFrame *dst,
455  const struct mode *mode, const struct options *opts)
456 {
457  snprintf(buf, buf_size,
458  "%-*s %*dx%*d -> %-*s %*dx%*d, flags=0x%0*x dither=%u scaler=%d/%d",
459  opts->pretty ? 14 : 0, av_get_pix_fmt_name(src->format),
460  opts->pretty ? 4 : 0, src->width,
461  opts->pretty ? 4 : 0, src->height,
462  opts->pretty ? 14 : 0, av_get_pix_fmt_name(dst->format),
463  opts->pretty ? 4 : 0, dst->width,
464  opts->pretty ? 4 : 0, dst->height,
465  opts->pretty ? 8 : 0, mode->flags,
466  mode->dither,
467  mode->scaler,
468  mode->scaler_sub);
469 }
470 
471 static void print_results(const AVFrame *ref, const AVFrame *src, const AVFrame *dst,
472  int dst_w, int dst_h,
473  const struct mode *mode, const struct options *opts,
474  const struct test_results *r,
475  const struct test_results *ref_r,
476  float expected_loss)
477 {
478  char buf[128];
479 
480  if (av_log_get_level() >= AV_LOG_INFO) {
481  print_test_params(buf, sizeof(buf), src, dst, mode, opts);
482  printf("%s", buf);
483 
484  if (!opts->bench || !ref_r) {
485  printf(", SSIM={Y=%f U=%f V=%f A=%f} loss=%e",
486  r->ssim[0], r->ssim[1], r->ssim[2], r->ssim[3],
487  r->loss);
488  if (ref_r)
489  printf(" (ref=%e)", ref_r->loss);
490  }
491 
492  if (opts->bench) {
493  printf(", time=%*"PRId64"/%u us",
494  opts->pretty ? 7 : 0, r->time, opts->iters);
495  if (ref_r) {
496  double ratio = ((double) ref_r->time / ref_r->iters)
497  / ((double) r->time / opts->iters);
498  if (FFMIN(r->time, ref_r->time) > 100 /* don't pollute stats with low precision */) {
499  speedup_min = FFMIN(speedup_min, ratio);
500  speedup_max = FFMAX(speedup_max, ratio);
501  speedup_logavg += log(ratio);
502  speedup_count++;
503  }
504 
505  printf(" (ref=%*"PRId64"/%u us), speedup=%*.3fx %s%s\033[0m",
506  opts->pretty ? 7 : 0, ref_r->time, ref_r->iters,
507  opts->pretty ? 6 : 0, ratio,
508  speedup_color(ratio), ratio >= 1.0 ? "faster" : "slower");
509  }
510  }
511  printf("\n");
512 
513  fflush(stdout);
514  }
515 
516  if (r->loss - expected_loss > 1e-4 && dst_w >= ref->width && dst_h >= ref->height) {
517  const int bad = r->loss - expected_loss > 1e-2;
518  const int level = bad ? AV_LOG_ERROR : AV_LOG_WARNING;
519  const char *worse_str = bad ? "WORSE" : "worse";
520  if (bad) {
521  print_test_params(buf, sizeof(buf), src, dst, mode, opts);
522  av_log(NULL, level, "%s\n", buf);
523  }
524  av_log(NULL, level,
525  " loss %e is %s by %e, expected loss %e\n",
526  r->loss, worse_str, r->loss - expected_loss, expected_loss);
527  }
528 
529  if (ref_r && r->loss - ref_r->loss > 1e-4) {
530  /**
531  * The new scaling code does not (yet) perform error diffusion for
532  * low bit depth output, which impacts the SSIM score slightly for
533  * very low bit-depth formats (e.g. monow, monob). Since this is an
534  * expected result, drop the badness from an error to a warning for
535  * such cases. This can be removed again once error diffusion is
536  * implemented in the new ops code.
537  */
538  const int dst_bits = av_pix_fmt_desc_get(dst->format)->comp[0].depth;
539  const int bad = r->loss - ref_r->loss > 1e-2 && dst_bits > 1;
540  const int level = bad ? AV_LOG_ERROR : AV_LOG_WARNING;
541  const char *worse_str = bad ? "WORSE" : "worse";
542  if (bad) {
543  print_test_params(buf, sizeof(buf), src, dst, mode, opts);
544  av_log(NULL, level, "%s\n", buf);
545  }
546  av_log(NULL, level,
547  " loss %e is %s by %e, ref loss %e SSIM={Y=%f U=%f V=%f A=%f}\n",
548  r->loss, worse_str, r->loss - ref_r->loss, ref_r->loss,
549  ref_r->ssim[0], ref_r->ssim[1], ref_r->ssim[2], ref_r->ssim[3]);
550  }
551 }
552 
553 static int init_frame(AVFrame **pframe, const AVFrame *ref,
554  int width, int height, enum AVPixelFormat format)
555 {
557  if (!frame)
558  return AVERROR(ENOMEM);
560  frame->width = width;
561  frame->height = height;
562  frame->format = format;
563  *pframe = frame;
564  return 0;
565 }
566 
567 /* Runs a series of ref -> src -> dst -> out, and compares out vs ref */
568 static int run_test(enum AVPixelFormat src_fmt, enum AVPixelFormat dst_fmt,
569  int dst_w, int dst_h,
570  const struct mode *mode, const struct options *opts,
571  const AVFrame *ref, AVFrame **psrc,
572  const struct test_results *ref_r)
573 {
574  AVFrame *src = *psrc;
575  AVFrame *dst = NULL, *out = NULL;
576  const int comps = fmt_comps(src_fmt) & fmt_comps(dst_fmt);
577  int ret;
578 
579  /* Estimate the expected amount of loss from bit depth reduction */
580  const float c1 = 0.01 * 0.01; /* stabilization constant */
581  const float ref_var = 1.0 / 12.0; /* uniformly distributed signal */
582  const float src_var = estimate_quantization_noise(src_fmt);
583  const float dst_var = estimate_quantization_noise(dst_fmt);
584  const float out_var = estimate_quantization_noise(ref->format);
585  const float total_var = src_var + dst_var + out_var;
586  const float ssim_luma = (2 * ref_var + c1) / (2 * ref_var + total_var + c1);
587  const float ssim_expected[4] = { ssim_luma, 1, 1, 1 }; /* for simplicity */
588  const float expected_loss = get_loss(ssim_expected);
589 
590  struct test_results r = { 0 };
591 
592  if (!src || src->format != src_fmt) {
593  av_frame_free(psrc);
594  ret = init_frame(&src, ref, ref->width, ref->height, src_fmt);
595  if (ret < 0)
596  goto error;
597  if (opts->align_src) {
598  ret = av_frame_get_buffer(src, opts->align_src);
599  if (ret < 0)
600  goto error;
601  }
602 
604  if (ret < 0)
605  goto error;
606  *psrc = src;
607  }
608 
609  ret = init_frame(&dst, ref, dst_w, dst_h, dst_fmt);
610  if (ret < 0)
611  goto error;
612 
613  ret = (opts->api == IMPL_LEGACY) ? scale_legacy(dst, src, mode, opts, &r.time)
614  : hw_device_ctx ? scale_hw(dst, src, mode, opts, &r.time)
615  : scale_new(dst, src, mode, opts, &r.time);
616  if (ret < 0) {
617  if (ret == AVERROR(ENOTSUP))
618  ret = 0;
619  goto error;
620  }
621 
622  ret = init_frame(&out, ref, ref->width, ref->height, ref->format);
623  if (ret < 0)
624  goto error;
625 
627  if (ret < 0)
628  goto error;
629 
630  get_ssim(r.ssim, out, ref, comps);
631 
632  if (opts->api == IMPL_LEGACY) {
633  /* Legacy swscale does not perform bit accurate upconversions of low
634  * bit depth RGB. This artificially improves the SSIM score because the
635  * resulting error deletes some of the input dither noise. This gives
636  * it an unfair advantage when compared against a bit exact reference.
637  * Work around this by ensuring that the resulting SSIM score is not
638  * higher than it theoretically "should" be. */
639  if (src_var > dst_var) {
640  const float src_loss = (2 * ref_var + c1) / (2 * ref_var + src_var + c1);
641  r.ssim[0] = FFMIN(r.ssim[0], src_loss);
642  }
643  }
644 
645  r.loss = get_loss(r.ssim);
646  if ((opts->api != IMPL_LEGACY) && r.loss - expected_loss > 1e-2 && dst_w >= ref->width && dst_h >= ref->height) {
647  ret = -1;
648  goto bad_loss;
649  }
650 
651  if (ref_r && r.loss - ref_r->loss > 1e-2) {
652  ret = -1;
653  goto bad_loss;
654  }
655 
656  ret = 0; /* fall through */
657 
658 bad_loss:
660  dst_w, dst_h,
661  mode, opts,
662  &r, ref_r,
663  expected_loss);
664 
665  error:
666  av_frame_free(&dst);
667  av_frame_free(&out);
668  return ret;
669 }
670 
671 static inline int fmt_is_subsampled(enum AVPixelFormat fmt)
672 {
673  return av_pix_fmt_desc_get(fmt)->log2_chroma_w != 0 ||
675 }
676 
677 static inline int fmt_is_supported_by_hw(enum AVPixelFormat fmt)
678 {
679  /* Semi-planar formats are only supported by the legacy path, which
680  * does not support hardware frames. */
681  if (fmt == AV_PIX_FMT_NV24 || fmt == AV_PIX_FMT_P410 ||
682  fmt == AV_PIX_FMT_P412 || fmt == AV_PIX_FMT_P416)
683  return 0;
684  for (int i = 0;
686  if (hw_device_constr->valid_sw_formats[i] == fmt)
687  return 1;
688  }
689  return 0;
690 }
691 
692 static inline int fmt_disabled(const struct options *opts, enum AVPixelFormat fmt)
693 {
694  return (hw_device_constr && !fmt_is_supported_by_hw(fmt)) ||
695  (opts->scaler < 0 && fmt_is_subsampled(fmt));
696 }
697 
698 static inline int test_formats(const struct options *opts,
699  enum AVPixelFormat src, enum AVPixelFormat dst)
700 {
701  /* Test auxiliary conversions */
704  return 0;
705 
706  /* Test main conversion */
707  enum SwsBackend backend = opts->backends ? opts->backends : SWS_BACKEND_STABLE;
708  if (opts->api == IMPL_LEGACY)
709  backend = SWS_BACKEND_LEGACY; /* Legacy API forces legacy backend */
710  return ff_sws_test_pixfmt_backend(backend, src, 0) &&
711  ff_sws_test_pixfmt_backend(backend, dst, 1);
712 }
713 
714 static int run_self_tests(const AVFrame *ref, const struct options *opts)
715 {
716  const int dst_w_values[] = { opts->w, opts->w - opts->w / 3, opts->w + opts->w / 3 };
717  const int dst_h_values[] = { opts->h, opts->h - opts->h / 3, opts->h + opts->h / 3 };
718 
719  enum AVPixelFormat src_fmt, dst_fmt,
720  src_fmt_min = 0,
721  dst_fmt_min = 0,
722  src_fmt_max = AV_PIX_FMT_NB - 1,
723  dst_fmt_max = AV_PIX_FMT_NB - 1;
724 
725  AVFrame *src = NULL;
726 
727  int ret = 0;
728 
729  if (opts->src_fmt != AV_PIX_FMT_NONE)
730  src_fmt_min = src_fmt_max = opts->src_fmt;
731  if (opts->dst_fmt != AV_PIX_FMT_NONE)
732  dst_fmt_min = dst_fmt_max = opts->dst_fmt;
733 
734  for (src_fmt = src_fmt_min; src_fmt <= src_fmt_max; src_fmt++) {
735  if (fmt_disabled(opts, src_fmt))
736  continue;
737  for (dst_fmt = dst_fmt_min; dst_fmt <= dst_fmt_max; dst_fmt++) {
738  if (fmt_disabled(opts, dst_fmt))
739  continue;
740  if (!test_formats(opts, src_fmt, dst_fmt))
741  continue;
742  for (int h = 0; h < FF_ARRAY_ELEMS(dst_h_values); h++) {
743  for (int w = 0; w < FF_ARRAY_ELEMS(dst_w_values); w++) {
744  for (int f = 0; f < FF_ARRAY_ELEMS(flags); f++) {
745  struct mode mode = {
746  .flags = opts->flags >= 0 ? opts->flags : flags[f],
747  .dither = opts->dither >= 0 ? opts->dither : SWS_DITHER_AUTO,
748  .scaler = opts->scaler >= 0 ? opts->scaler : SWS_SCALE_AUTO,
749  .scaler_sub = opts->scaler_sub >= 0 ? opts->scaler_sub : SWS_SCALE_AUTO,
750  };
751  int dst_w = (opts->dst_w >= 0) ? opts->dst_w : dst_w_values[w];
752  int dst_h = (opts->dst_h >= 0) ? opts->dst_h : dst_h_values[h];
753 
754  if (opts->scaler >= 0 && opts->w == dst_w && opts->h == dst_h)
755  continue;
756 
757  if (ff_sfc64_get(&prng_state) <= UINT64_MAX * opts->prob) {
758  ret = run_test(src_fmt, dst_fmt, dst_w, dst_h,
759  &mode, opts, ref, &src, NULL);
760  if (ret < 0)
761  goto error;
762  }
763 
764  if (opts->flags >= 0 || opts->scaler != SWS_SCALE_AUTO)
765  break;
766  }
767  if (opts->dst_w >= 0 || opts->dst_h >= 0)
768  break;
769  if (opts->scaler < 0)
770  break;
771  }
772  if (opts->dst_w >= 0 || opts->dst_h >= 0)
773  break;
774  if (opts->scaler < 0)
775  break;
776  }
777  }
778  }
779 
780  ret = 0;
781 
782 error:
783  av_frame_free(&src);
784  return ret;
785 }
786 
787 static int run_file_tests(const AVFrame *ref, FILE *fp, const struct options *opts)
788 {
789  char buf[256];
790  int ret = 0;
791 
792  AVFrame *src = NULL;
793 
794  for (int line = 1; fgets(buf, sizeof(buf), fp); line++) {
795  char src_fmt_str[21], dst_fmt_str[21];
796  enum AVPixelFormat src_fmt;
797  enum AVPixelFormat dst_fmt;
798  int sw, sh, dw, dh;
799  struct test_results r = { 0 };
800  struct mode mode;
801  int n = 0;
802 
803  ret = sscanf(buf,
804  "%20s %dx%d -> %20s %dx%d, flags=0x%x dither=%u scaler=%u/%u, "
805  "SSIM={Y=%f U=%f V=%f A=%f} loss=%e%n",
806  src_fmt_str, &sw, &sh, dst_fmt_str, &dw, &dh,
807  &mode.flags, &mode.dither,
809  &r.ssim[0], &r.ssim[1], &r.ssim[2], &r.ssim[3],
810  &r.loss, &n);
811  if (ret != 15) {
813  "Malformed reference file in line %d\n", line);
814  goto error;
815  }
816  if (opts->bench) {
817  ret = sscanf(buf + n,
818  ", time=%"PRId64"/%u us",
819  &r.time, &r.iters);
820  if (ret != 2) {
822  "Missing benchmarks from reference file in line %d\n",
823  line);
824  goto error;
825  }
826  }
827 
828  src_fmt = av_get_pix_fmt(src_fmt_str);
829  dst_fmt = av_get_pix_fmt(dst_fmt_str);
830  if (src_fmt == AV_PIX_FMT_NONE || dst_fmt == AV_PIX_FMT_NONE) {
832  "Unknown pixel formats (%s and/or %s) in line %d\n",
833  src_fmt_str, dst_fmt_str, line);
834  goto error;
835  }
836 
837  if (sw != ref->width || sh != ref->height) {
839  "Mismatching dimensions %dx%d (ref is %dx%d) in line %d\n",
840  sw, sh, ref->width, ref->height, line);
841  goto error;
842  }
843 
844  if (opts->src_fmt != AV_PIX_FMT_NONE && src_fmt != opts->src_fmt ||
845  opts->dst_fmt != AV_PIX_FMT_NONE && dst_fmt != opts->dst_fmt)
846  continue;
847 
848  ret = run_test(src_fmt, dst_fmt, dw, dh, &mode, opts, ref, &src, &r);
849  if (ret < 0)
850  goto error;
851  }
852 
853  ret = 0;
854 
855 error:
856  av_frame_free(&src);
857  return ret;
858 }
859 
860 static int init_ref(AVFrame *ref, const struct options *opts)
861 {
864  AVLFG rand;
865  int ret = -1;
866 
867  if (!ctx || !rgb)
868  goto error;
869 
870  rgb->width = opts->w > 32 ? opts->w / 12 : opts->w;
871  rgb->height = opts->h > 32 ? opts->h / 12 : opts->h;
872  rgb->format = AV_PIX_FMT_RGBA;
873  ret = av_frame_get_buffer(rgb, 32);
874  if (ret < 0)
875  goto error;
876 
877  av_lfg_init(&rand, 1);
878  for (int y = 0; y < rgb->height; y++) {
879  for (int x = 0; x < rgb->width; x++) {
880  for (int c = 0; c < 4; c++)
881  rgb->data[0][y * rgb->linesize[0] + x * 4 + c] = av_lfg_get(&rand);
882  }
883  }
884 
887 
888 error:
890  av_frame_free(&rgb);
891  return ret;
892 }
893 
894 static int parse_size(struct options *opts, const char *str, char **pbuf)
895 {
896  int ret = av_parse_video_size(&opts->w, &opts->h, str);
897  if (ret < 0 && strchr(str, ':')) {
898  av_freep(pbuf);
899  char *buf = av_strdup(str);
900  if (!buf)
901  return AVERROR(ENOMEM);
902  *pbuf = buf;
903  char *saveptr = NULL;
904  char *s = av_strtok(buf, ":", &saveptr);
905  if (s) {
906  ret = av_parse_video_size(&opts->w, &opts->h, s);
907  if (ret >= 0) {
908  s = av_strtok(NULL, ":", &saveptr);
909  if (s) {
910  ret = av_parse_video_size(&opts->dst_w, &opts->dst_h, s);
911  }
912  }
913  }
914  }
915  return ret;
916 }
917 
918 static int parse_implementation(const char *str)
919 {
920  if (!strcmp(str, "legacy"))
921  return IMPL_LEGACY;
922  if (!strcmp(str, "new"))
923  return IMPL_NEW;
924  return -1;
925 }
926 
927 static int parse_options(int argc, char **argv, struct options *opts, FILE **fp)
928 {
930  char *buf = NULL;
931  int ret;
932 
933  for (int i = 1; i < argc; i += 2) {
934  if (!strcmp(argv[i], "-help") || !strcmp(argv[i], "--help")) {
935  fprintf(stderr,
936  "swscale [options...]\n"
937  " -help\n"
938  " This text\n"
939  " -ref <file>\n"
940  " Uses file as reference to compare tests against. Tests that have become worse will contain the string worse or WORSE\n"
941  " -p <number between 0.0 and 1.0>\n"
942  " The proportion of tests or comparisons to perform.\n"
943  " It is often convenient to perform a random subset\n"
944  " -dst <pixfmt>\n"
945  " Only test the specified destination pixel format\n"
946  " -src <pixfmt>\n"
947  " Only test the specified source pixel format\n"
948  " -s <size>[:<size>]\n"
949  " Set frame size (WxH or abbreviation)\n"
950  " Optionally set destination frame size (after a ':' separator character).\n"
951  " -bench <iters>\n"
952  " Run benchmarks with the specified number of iterations. This mode also sets the frame size to 1920x1080 (unless -s is specified)\n"
953  " -flags <flags>\n"
954  " Test with a specific combination of flags\n"
955  " -dither <mode>\n"
956  " Test with a specific dither mode\n"
957  " -backends <backends>\n"
958  " Restrict to the given set of allowed swscale backends\n"
959  " -scaler <algorithm>\n"
960  " Test with a specified scaler algorithm\n"
961  " If 'none', test only conversions that do not involve scaling\n"
962  " -scaler_sub <algorithm>\n"
963  " Test with a specified scaler algorithm for chroma planes\n"
964  " -align_src <alignment>\n"
965  " If nonzero, allocate source buffers with a custom stride alignment\n"
966  " -align_dst <alignment>\n"
967  " If nonzero, allocate destination buffers with a custom stride alignment\n"
968  " -api <new or legacy>\n"
969  " Use selected swscale API for the main conversion (default: new)\n"
970  " -hw <device>\n"
971  " Use Vulkan hardware acceleration on the specified device for the main conversion\n"
972  " -threads <threads>\n"
973  " Use the specified number of threads\n"
974  " -cpuflags <cpuflags>\n"
975  " Uses the specified cpuflags in the tests\n"
976  " -pretty <1 or 0>\n"
977  " Align fields while printing results\n"
978  " -v <level>\n"
979  " Enable log verbosity at given level\n"
980  );
981  exit(0);
982  }
983  if (argv[i][0] != '-' || i + 1 == argc)
984  goto bad_option;
985  if (!strcmp(argv[i], "-ref")) {
986  *fp = fopen(argv[i + 1], "r");
987  if (!*fp) {
988  fprintf(stderr, "could not open '%s'\n", argv[i + 1]);
989  ret = AVERROR(errno);
990  goto end;
991  }
992  } else if (!strcmp(argv[i], "-cpuflags")) {
993  unsigned flags = av_get_cpu_flags();
994  ret = av_parse_cpu_caps(&flags, argv[i + 1]);
995  if (ret < 0) {
996  fprintf(stderr, "invalid cpu flags %s\n", argv[i + 1]);
997  goto end;
998  }
1000  } else if (!strcmp(argv[i], "-src")) {
1001  opts->src_fmt = av_get_pix_fmt(argv[i + 1]);
1002  if (opts->src_fmt == AV_PIX_FMT_NONE) {
1003  fprintf(stderr, "invalid pixel format %s\n", argv[i + 1]);
1004  ret = AVERROR(EINVAL);
1005  goto end;
1006  }
1007  } else if (!strcmp(argv[i], "-dst")) {
1008  opts->dst_fmt = av_get_pix_fmt(argv[i + 1]);
1009  if (opts->dst_fmt == AV_PIX_FMT_NONE) {
1010  fprintf(stderr, "invalid pixel format %s\n", argv[i + 1]);
1011  ret = AVERROR(EINVAL);
1012  goto end;
1013  }
1014  } else if (!strcmp(argv[i], "-s")) {
1015  ret = parse_size(opts, argv[i + 1], &buf);
1016  if (ret < 0) {
1017  fprintf(stderr, "invalid frame size %s\n", argv[i + 1]);
1018  goto end;
1019  }
1020  } else if (!strcmp(argv[i], "-bench")) {
1021  int iters = atoi(argv[i + 1]);
1022  if (iters <= 0) {
1023  opts->bench = 0;
1024  opts->iters = 1;
1025  } else {
1026  opts->bench = 1;
1027  opts->iters = iters;
1028  }
1029  } else if (!strcmp(argv[i], "-flags")) {
1030  const AVOption *flags_opt = av_opt_find(dummy, "sws_flags", NULL, 0, 0);
1031  ret = av_opt_eval_flags(dummy, flags_opt, argv[i + 1], &opts->flags);
1032  if (ret < 0) {
1033  fprintf(stderr, "invalid flags %s\n", argv[i + 1]);
1034  goto end;
1035  }
1036  } else if (!strcmp(argv[i], "-backends")) {
1037  const AVOption *backends_opt = av_opt_find(dummy, "sws_backends", NULL, 0, 0);
1038  ret = av_opt_eval_flags(dummy, backends_opt, argv[i + 1], &opts->backends);
1039  if (ret < 0) {
1040  fprintf(stderr, "invalid backends %s\n", argv[i + 1]);
1041  goto end;
1042  }
1043  } else if (!strcmp(argv[i], "-dither")) {
1044  opts->dither = atoi(argv[i + 1]);
1045  } else if (!strcmp(argv[i], "-scaler") || !strcmp(argv[i], "-scaler_sub")) {
1046  int opt_is_scaler = !strcmp(argv[i], "-scaler");
1047  if (opt_is_scaler && !strcmp(argv[i + 1], "none")) {
1048  opts->scaler = -1;
1049  continue;
1050  }
1051  const AVOption *scaler_opt = av_opt_find(dummy, "scaler", NULL, 0, 0);
1052  ret = av_opt_eval_int(dummy, scaler_opt, argv[i + 1], opt_is_scaler ? &opts->scaler : &opts->scaler_sub);
1053  if (ret < 0) {
1054  fprintf(stderr, "invalid scaler algorithm %s\n", argv[i + 1]);
1055  goto end;
1056  }
1057  } else if (!strcmp(argv[i], "-align_src")) {
1058  opts->align_src = atoi(argv[i + 1]);
1059  if (opts->align_src < 0 || (opts->align_src & (opts->align_src - 1))) {
1060  fprintf(stderr, "invalid alignment %s\n", argv[i + 1]);
1061  return -1;
1062  }
1063  } else if (!strcmp(argv[i], "-align_dst")) {
1064  opts->align_dst = atoi(argv[i + 1]);
1065  if (opts->align_dst < 0 || (opts->align_dst & (opts->align_dst - 1))) {
1066  fprintf(stderr, "invalid alignment %s\n", argv[i + 1]);
1067  return -1;
1068  }
1069  } else if (!strcmp(argv[i], "-api")) {
1070  ret = parse_implementation(argv[i + 1]);
1071  if (ret < 0) {
1072  fprintf(stderr, "invalid api %s\n", argv[i + 1]);
1073  goto end;
1074  }
1075  opts->api = ret;
1076  } else if (!strcmp(argv[i], "-hw")) {
1079  argv[i + 1], NULL, 0);
1080  if (ret < 0) {
1081  fprintf(stderr, "Failed to create Vulkan device '%s'\n",
1082  argv[i + 1]);
1083  goto end;
1084  }
1086  NULL);
1087  if (!hw_device_constr) {
1088  fprintf(stderr, "Failed to retrieve Vulkan device constraints '%s'\n",
1089  argv[i + 1]);
1090  ret = AVERROR(ENOMEM);
1091  goto end;
1092  }
1093  } else if (!strcmp(argv[i], "-threads")) {
1094  opts->threads = atoi(argv[i + 1]);
1095  } else if (!strcmp(argv[i], "-p")) {
1096  opts->prob = atof(argv[i + 1]);
1097  } else if (!strcmp(argv[i], "-pretty")) {
1098  opts->pretty = atoi(argv[i + 1]);
1099  } else if (!strcmp(argv[i], "-v")) {
1100  av_log_set_level(atoi(argv[i + 1]));
1101  } else {
1102 bad_option:
1103  fprintf(stderr, "bad option or argument missing (%s) see -help\n", argv[i]);
1104  ret = AVERROR(EINVAL);
1105  goto end;
1106  }
1107  }
1108 
1109  if (opts->w < 0 || opts->h < 0) {
1110  opts->w = opts->bench ? 1920 : 96;
1111  opts->h = opts->bench ? 1080 : 96;
1112  }
1113 
1114  ret = 0;
1115 
1116 end:
1118  av_freep(&buf);
1119  return ret;
1120 }
1121 
1122 int main(int argc, char **argv)
1123 {
1124  struct options opts = {
1125  .src_fmt = AV_PIX_FMT_NONE,
1126  .dst_fmt = AV_PIX_FMT_NONE,
1127  .w = -1,
1128  .h = -1,
1129  .dst_w = -1,
1130  .dst_h = -1,
1131  .threads = 1,
1132  .iters = 1,
1133  .prob = 1.0,
1134  .flags = -1,
1135  .dither = -1,
1136  .scaler = SWS_SCALE_AUTO,
1137  .scaler_sub = SWS_SCALE_AUTO,
1138  };
1139 
1140  AVFrame *ref = NULL;
1141  FILE *fp = NULL;
1142  int ret = -1;
1143 
1144  if (parse_options(argc, argv, &opts, &fp) < 0)
1145  goto error;
1146 
1147  ff_sfc64_init(&prng_state, 0, 0, 0, 12);
1148  signal(SIGINT, exit_handler);
1149 
1153  if (!sws_ref_src || !sws_src_dst || !sws_dst_out)
1154  goto error;
1159 
1160  ref = av_frame_alloc();
1161  if (!ref)
1162  goto error;
1163  ref->width = opts.w;
1164  ref->height = opts.h;
1165  ref->format = AV_PIX_FMT_YUVA444P;
1166 
1167  ret = init_ref(ref, &opts);
1168  if (ret < 0)
1169  goto error;
1170 
1171  ret = fp ? run_file_tests(ref, fp, &opts)
1172  : run_self_tests(ref, &opts);
1173 
1174  /* fall through */
1175 error:
1181  av_frame_free(&ref);
1182  if (fp)
1183  fclose(fp);
1184  exit_handler(ret);
1185 }
error
static void error(const char *err)
Definition: target_bsf_fuzzer.c:32
flags
const SwsFlags flags[]
Definition: swscale.c:85
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
IMPL_LEGACY
#define IMPL_LEGACY
Definition: swscale.c:48
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
SWS_SCALE_AUTO
@ SWS_SCALE_AUTO
Definition: swscale.h:97
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:238
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:671
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:276
AVBufferRef::data
uint8_t * data
The data buffer.
Definition: buffer.h:90
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:471
AVHWFramesContext::format
enum AVPixelFormat format
The pixel format identifying the underlying HW surface type.
Definition: hwcontext.h:200
estimate_quantization_noise
static float estimate_quantization_noise(enum AVPixelFormat fmt)
Definition: swscale.c:135
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:2297
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
av_hwframe_ctx_init
int av_hwframe_ctx_init(AVBufferRef *ref)
Finalize the context before use.
Definition: hwcontext.c:337
mode
Definition: swscale.c:71
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:459
pixdesc.h
AVFrame::width
int width
Definition: frame.h:531
speedup_color
static const char * speedup_color(double ratio)
Definition: swscale.c:111
av_hwframe_ctx_alloc
AVBufferRef * av_hwframe_ctx_alloc(AVBufferRef *device_ref_in)
Allocate an AVHWFramesContext tied to a given device context.
Definition: hwcontext.c:263
AVComponentDescriptor::depth
int depth
Number of bits in the component.
Definition: pixdesc.h:57
SWS_BILINEAR
@ SWS_BILINEAR
bilinear filtering
Definition: swscale.h:200
SWS_BITEXACT
@ SWS_BITEXACT
Definition: swscale.h:180
AVOption
AVOption.
Definition: opt.h:429
b
#define b
Definition: input.c:43
options::pretty
int pretty
Definition: swscale.c:67
options::dither
int dither
Definition: swscale.c:61
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:242
FFMAX
#define FFMAX(a, b)
Definition: macros.h:47
c1
static const uint64_t c1
Definition: murmur3.c:52
AVHWFramesContext::width
int width
The allocated dimensions of the frames in this pool.
Definition: hwcontext.h:220
mode::dither
SwsDither dither
Definition: swscale.c:73
av_hwdevice_get_hwframe_constraints
AVHWFramesConstraints * av_hwdevice_get_hwframe_constraints(AVBufferRef *ref, const void *hwconfig)
Get the constraints on HW frames given a device and the HW-specific configuration to be used with tha...
Definition: hwcontext.c:581
prng_state
static FFSFC64 prng_state
Definition: swscale.c:96
format.h
cpu.h
dummy
static int dummy
Definition: ffplay.c:3751
AV_PIX_FMT_VULKAN
@ AV_PIX_FMT_VULKAN
Vulkan hardware images.
Definition: pixfmt.h:379
AV_HWDEVICE_TYPE_VULKAN
@ AV_HWDEVICE_TYPE_VULKAN
Definition: hwcontext.h:39
speedup_max
static double speedup_max
Definition: swscale.c:108
run_self_tests
static int run_self_tests(const AVFrame *ref, const struct options *opts)
Definition: swscale.c:714
AVHWFramesConstraints
This struct describes the constraints on hardware frames attached to a given device with a hardware-s...
Definition: hwcontext.h:444
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:787
SWS_FAST_BILINEAR
@ SWS_FAST_BILINEAR
Scaler selection options.
Definition: swscale.h:199
rgb
Definition: rpzaenc.c:60
options::api
int api
Definition: swscale.c:66
SWS_FULL_CHR_H_INP
@ SWS_FULL_CHR_H_INP
Perform full chroma interpolation when downscaling RGB sources.
Definition: swscale.h:169
scale_hw
static int scale_hw(AVFrame *dst, const AVFrame *src, const struct mode *mode, const struct options *opts, int64_t *out_time)
Definition: swscale.c:327
macros.h
FFSFC64
Definition: sfc64.h:37
SwsDither
SwsDither
Definition: swscale.h:77
options::iters
int iters
Definition: swscale.c:58
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:1931
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:1450
ss
#define ss(width, name, subs,...)
Definition: cbs_vp9.c:202
mode::scaler
SwsScaler scaler
Definition: swscale.c:74
SWS_BACKEND_LEGACY
@ SWS_BACKEND_LEGACY
Legacy bespoke format-specific code.
Definition: swscale.h:112
options::scaler_sub
int scaler_sub
Definition: swscale.c:63
test_results::ssim
float ssim[4]
Definition: swscale.c:79
print_test_params
static void print_test_params(char *buf, size_t buf_size, const AVFrame *src, const AVFrame *dst, const struct mode *mode, const struct options *opts)
Definition: swscale.c:453
av_frame_alloc
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition: frame.c:52
sig
static volatile sig_atomic_t sig
Definition: signal.c:48
SwsBackend
SwsBackend
Definition: swscale.h:110
avassert.h
options::dst_fmt
enum AVPixelFormat dst_fmt
Definition: swscale.c:52
options::w
int w
Definition: swscale.c:54
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:204
FF_ARRAY_ELEMS
#define FF_ARRAY_ELEMS(a)
Definition: sinewin_tablegen.c:29
speedup_min
static double speedup_min
Definition: swscale.c:107
AVHWFramesContext::height
int height
Definition: hwcontext.h:220
AVHWFramesConstraints::valid_sw_formats
enum AVPixelFormat * valid_sw_formats
A list of possible values for sw_format in the hw_frames_ctx, terminated by AV_PIX_FMT_NONE.
Definition: hwcontext.h:456
SwsContext::dither
SwsDither dither
Dither mode.
Definition: swscale.h:258
av_hwframe_constraints_free
void av_hwframe_constraints_free(AVHWFramesConstraints **constraints)
Free an AVHWFrameConstraints structure.
Definition: hwcontext.c:606
options::h
int h
Definition: swscale.c:54
SwsFlags
SwsFlags
Definition: swscale.h:133
s
#define s(width, name)
Definition: cbs_vp9.c:198
SwsContext::threads
int threads
How many threads to use for processing, or 0 for automatic selection.
Definition: swscale.h:253
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:1465
g
const char * g
Definition: vf_curves.c:128
lfg.h
av_strtok
char * av_strtok(char *s, const char *delim, char **saveptr)
Split the string into several tokens which can be accessed by successive calls to av_strtok().
Definition: avstring.c:179
av_get_cpu_flags
int av_get_cpu_flags(void)
Return the flags which specify extensions supported by the CPU.
Definition: cpu.c:109
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
SWS_BACKEND_ALL
@ SWS_BACKEND_ALL
Definition: swscale.h:129
hw_device_ctx
static AVBufferRef * hw_device_ctx
Definition: swscale.c:103
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
parse_size
static int parse_size(struct options *opts, const char *str, char **pbuf)
Definition: swscale.c:894
AV_PIX_FMT_RGBA
@ AV_PIX_FMT_RGBA
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
Definition: pixfmt.h:100
fmt_is_supported_by_hw
static int fmt_is_supported_by_hw(enum AVPixelFormat fmt)
Definition: swscale.c:677
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
AVHWFramesContext::sw_format
enum AVPixelFormat sw_format
The pixel format identifying the actual data layout of the hardware frames.
Definition: hwcontext.h:213
SWS_BACKEND_STABLE
@ SWS_BACKEND_STABLE
Definition: swscale.h:113
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:201
options::dst_w
int dst_w
Definition: swscale.c:55
options::threads
int threads
Definition: swscale.c:57
AV_PIX_FMT_P410
#define AV_PIX_FMT_P410
Definition: pixfmt.h:617
parseutils.h
IMPL_NEW
#define IMPL_NEW
Definition: swscale.c:47
options
Definition: swscale.c:50
double
double
Definition: af_crystalizer.c:132
SwsScaler
SwsScaler
Definition: swscale.h:96
time.h
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:51
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:1043
sws_ref_src
static SwsContext * sws_ref_src
Definition: swscale.c:99
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
i
#define i(width, name, range_min, range_max)
Definition: cbs_h264.c:63
av_err2str
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition: error.h:122
mode::flags
SwsFlags flags
Definition: swscale.c:72
hw_device_constr
static AVHWFramesConstraints * hw_device_constr
Definition: swscale.c:104
SWS_POINT
@ SWS_POINT
nearest neighbor
Definition: swscale.h:203
SwsContext::src_h
int src_h
Width and height of the source frame.
Definition: swscale.h:276
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_src_dst
static SwsContext * sws_src_dst
Definition: swscale.c:100
exit_handler
static void exit_handler(int sig)
Definition: swscale.c:122
AVFrame::format
int format
format of the frame, -1 if unknown or unset Values correspond to enum AVPixelFormat for video frames,...
Definition: frame.h:546
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:282
frame.h
options::prob
double prob
Definition: swscale.c:53
options::align_src
int align_src
Definition: swscale.c:64
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:214
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
ff_sws_test_pixfmt_backend
int ff_sws_test_pixfmt_backend(const SwsBackend backends, enum AVPixelFormat format, int output)
Definition: format.c:564
line
Definition: graph2dot.c:48
SwsContext::backends
SwsBackend backends
Bitmask of SWS_BACKEND_*.
Definition: swscale.h:316
unref_buffers
static void unref_buffers(AVFrame *frame)
Definition: swscale.c:226
SwsContext::dst_format
int dst_format
Destination pixel format.
Definition: swscale.h:279
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::align_dst
int align_dst
Definition: swscale.c:65
options::flags
int flags
Definition: swscale.c:60
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:80
SWS_X
@ SWS_X
experimental
Definition: swscale.h:202
options::backends
int backends
Definition: swscale.c:68
weights
static const int weights[]
Definition: hevc_pel.c:32
AV_PIX_FMT_NV24
@ AV_PIX_FMT_NV24
planar YUV 4:4:4, 24bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (firs...
Definition: pixfmt.h:371
av_assert1
#define av_assert1(cond)
assert() equivalent, that does not lie in speed critical code.
Definition: avassert.h:58
av_force_cpu_flags
void av_force_cpu_flags(int arg)
Disables cpu detection and forces the specified flags.
Definition: cpu.c:81
SwsContext::scaler
SwsScaler scaler
Scaling filter.
Definition: swscale.h:298
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
test_results
Definition: swscale.c:78
options::dst_h
int dst_h
Definition: swscale.c:56
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::scaler_sub
SwsScaler scaler_sub
Scaler used specifically for up/downsampling subsampled (chroma) planes.
Definition: swscale.h:306
SwsContext::dst_h
int dst_h
Width and height of the destination frame.
Definition: swscale.h:277
test_formats
static int test_formats(const struct options *opts, enum AVPixelFormat src, enum AVPixelFormat dst)
Definition: swscale.c:698
ff_sfc64_get
static uint64_t ff_sfc64_get(FFSFC64 *s)
Definition: sfc64.h:41
AVHWFramesContext
This struct describes a set or pool of "hardware" frames (i.e.
Definition: hwcontext.h:118
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
av_opt_eval_int
int av_opt_eval_int(void *obj, const AVOption *o, const char *val, int *int_out)
av_hwdevice_ctx_create
int av_hwdevice_ctx_create(AVBufferRef **pdevice_ref, enum AVHWDeviceType type, const char *device, AVDictionary *opts, int flags)
Open a device of the specified type and create an AVHWDeviceContext for it.
Definition: hwcontext.c:615
test_results::time
int64_t time
Definition: swscale.c:81
SWS_FULL_CHR_H_INT
@ SWS_FULL_CHR_H_INT
Perform full chroma upsampling when upscaling to RGB.
Definition: swscale.h:156
get_ssim
static void get_ssim(float ssim[4], const AVFrame *out, const AVFrame *ref, int comps)
Definition: swscale.c:166
av_hwframe_transfer_data
int av_hwframe_transfer_data(AVFrame *dst, const AVFrame *src, int flags)
Copy data to or from a hw surface.
Definition: hwcontext.c:448
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:109
AVFrame::height
int height
Definition: frame.h:531
c2
static const uint64_t c2
Definition: murmur3.c:53
main
int main(int argc, char **argv)
Definition: swscale.c:1122
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:860
ref
static int ref[MAX_W *MAX_W]
Definition: jpeg2000dwt.c:117
parse_implementation
static int parse_implementation(const char *str)
Definition: swscale.c:918
AVPixFmtDescriptor::comp
AVComponentDescriptor comp[4]
Parameters that describe how pixels are packed.
Definition: pixdesc.h:105
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:83
sws_dst_out
static SwsContext * sws_dst_out
Definition: swscale.c:101
AVBufferRef
A reference to a data buffer.
Definition: buffer.h:82
av_strdup
#define av_strdup(s)
Definition: ops_asmgen.c:47
SwsContext::dst_w
int dst_w
Definition: swscale.h:277
SwsContext::src_format
int src_format
Source pixel format.
Definition: swscale.h:278
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::scaler
int scaler
Definition: swscale.c:62
mode::scaler_sub
SwsScaler scaler_sub
Definition: swscale.c:75
AV_PIX_FMT_P416
#define AV_PIX_FMT_P416
Definition: pixfmt.h:621
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
options::bench
int bench
Definition: swscale.c:59
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:2381
fmt_disabled
static int fmt_disabled(const struct options *opts, enum AVPixelFormat fmt)
Definition: swscale.c:692
hwcontext.h
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
AV_PIX_FMT_P412
#define AV_PIX_FMT_P412
Definition: pixfmt.h:619
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:1370
SWS_ACCURATE_RND
@ SWS_ACCURATE_RND
Force bit-exact output.
Definition: swscale.h:179
h
h
Definition: vp9dsp_template.c:2070
avstring.h
width
#define width
Definition: dsp.h:89
SwsContext
Main external API structure.
Definition: swscale.h:229
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 **psrc, const struct test_results *ref_r)
Definition: swscale.c:568
av_hwframe_get_buffer
int av_hwframe_get_buffer(AVBufferRef *hwframe_ref, AVFrame *frame, int flags)
Allocate a new frame attached to the given AVHWFramesContext.
Definition: hwcontext.c:506
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:248
fmt_comps
static int fmt_comps(enum AVPixelFormat fmt)
Definition: swscale.c:157
snprintf
#define snprintf
Definition: snprintf.h:34
test_results::iters
int iters
Definition: swscale.c:82
parse_options
static int parse_options(int argc, char **argv, struct options *opts, FILE **fp)
Definition: swscale.c:927
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:553
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:106