diff --git a/libswscale/tests/swscale.c b/libswscale/tests/swscale.c
index af8069f728..c11a46024e 100644
--- a/libswscale/tests/swscale.c
+++ b/libswscale/tests/swscale.c
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2024      Nikles Haas
  * Copyright (C) 2003-2011 Michael Niedermayer <michaelni@gmx.at>
  *
  * This file is part of FFmpeg.
@@ -26,424 +27,307 @@
 
 #undef HAVE_AV_CONFIG_H
 #include "libavutil/cpu.h"
-#include "libavutil/imgutils.h"
-#include "libavutil/mem.h"
-#include "libavutil/avutil.h"
-#include "libavutil/crc.h"
-#include "libavutil/opt.h"
 #include "libavutil/pixdesc.h"
 #include "libavutil/lfg.h"
 #include "libavutil/sfc64.h"
+#include "libavutil/frame.h"
+#include "libavutil/pixfmt.h"
+#include "libavutil/avassert.h"
+#include "libavutil/macros.h"
 
 #include "libswscale/swscale.h"
 
-/* HACK Duplicated from swscale_internal.h.
- * Should be removed when a cleaner pixel format system exists. */
-#define isGray(x)                      \
-    ((x) == AV_PIX_FMT_GRAY8       ||     \
-     (x) == AV_PIX_FMT_YA8         ||     \
-     (x) == AV_PIX_FMT_GRAY16BE    ||     \
-     (x) == AV_PIX_FMT_GRAY16LE    ||     \
-     (x) == AV_PIX_FMT_YA16BE      ||     \
-     (x) == AV_PIX_FMT_YA16LE)
-#define hasChroma(x)                   \
-    (!(isGray(x)                ||     \
-       (x) == AV_PIX_FMT_MONOBLACK ||     \
-       (x) == AV_PIX_FMT_MONOWHITE))
-
-static av_always_inline int isALPHA(enum AVPixelFormat pix_fmt)
-{
-    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
-    return desc->flags & AV_PIX_FMT_FLAG_ALPHA;
-}
+enum {
+    WIDTH  = 96,
+    HEIGHT = 96,
+};
 
-static double prob = 1;
-FFSFC64 prng_state;
+struct options {
+    enum AVPixelFormat src_fmt;
+    enum AVPixelFormat dst_fmt;
+    double prob;
+};
 
-static uint64_t getSSD(const uint8_t *src1, const uint8_t *src2,
-                       int stride1, int stride2, int w, int h)
-{
-    int x, y;
-    uint64_t ssd = 0;
+struct mode {
+    SwsFlags flags;
+    SwsDither dither;
+};
 
-    for (y = 0; y < h; y++) {
-        for (x = 0; x < w; x++) {
-            int d = src1[x + y * stride1] - src2[x + y * stride2];
-            ssd += d * d;
-        }
-    }
-    return ssd;
-}
+const int dst_w[] = { WIDTH,  WIDTH  - WIDTH  / 3, WIDTH  + WIDTH  / 3 };
+const int dst_h[] = { HEIGHT, HEIGHT - HEIGHT / 3, HEIGHT + HEIGHT / 3 };
+
+const struct mode modes[] = {
+    { SWS_FAST_BILINEAR },
+    { SWS_BILINEAR },
+    { SWS_BICUBIC },
+    { SWS_X | SWS_BITEXACT },
+    { SWS_POINT },
+    { SWS_AREA | SWS_ACCURATE_RND },
+    { SWS_BICUBIC | SWS_FULL_CHR_H_INT | SWS_FULL_CHR_H_INP },
+    {0}, // test defaults
+};
 
-static uint64_t getSSD0(int ref, const uint8_t *src1, int stride1,
-                        int w, int h)
-{
-    int x, y;
-    uint64_t ssd = 0;
+static FFSFC64 prng_state;
+static SwsContext *sws[3]; /* reused between tests for efficiency */
 
-    for (y = 0; y < h; y++) {
-        for (x = 0; x < w; x++) {
-            int d = src1[x + y * stride1] - ref;
-            ssd += d * d;
-        }
-    }
-    return ssd;
+static int fmt_comps(enum AVPixelFormat fmt)
+{
+    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
+    int comps = desc->nb_components >= 3 ? 0b111 : 0b1;
+    if (desc->flags & AV_PIX_FMT_FLAG_ALPHA)
+        comps |= 0b1000;
+    return comps;
 }
 
-struct Results {
-    uint64_t ssdY;
-    uint64_t ssdU;
-    uint64_t ssdV;
-    uint64_t ssdA;
-    uint32_t crc;
-};
-
-// test by ref -> src -> dst -> out & compare out against ref
-// ref & out are YV12
-static int doTest(const uint8_t * const ref[4], int refStride[4], int w, int h,
-                  enum AVPixelFormat srcFormat, enum AVPixelFormat dstFormat,
-                  int srcW, int srcH, int dstW, int dstH, int flags,
-                  struct Results *r)
+static void get_mse(int mse[4], const AVFrame *a, const AVFrame *b, int comps)
 {
-    const AVPixFmtDescriptor *desc_yuva420p = av_pix_fmt_desc_get(AV_PIX_FMT_YUVA420P);
-    const AVPixFmtDescriptor *desc_src      = av_pix_fmt_desc_get(srcFormat);
-    const AVPixFmtDescriptor *desc_dst      = av_pix_fmt_desc_get(dstFormat);
-    static enum AVPixelFormat cur_srcFormat;
-    static int cur_srcW, cur_srcH;
-    static const uint8_t *src[4];
-    static int srcStride[4];
-    uint8_t *dst[4] = { 0 };
-    uint8_t *out[4] = { 0 };
-    int dstStride[4] = {0};
-    int i;
-    uint64_t ssdY, ssdU = 0, ssdV = 0, ssdA = 0;
-    SwsContext *dstContext = NULL, *outContext = NULL;
-    uint32_t crc = 0;
-    int res      = 0;
-
-    if (ff_sfc64_get(&prng_state) > UINT64_MAX * prob)
-        return 0;
-
-    if (cur_srcFormat != srcFormat || cur_srcW != srcW || cur_srcH != srcH) {
-        SwsContext *srcContext = NULL;
-        int p;
-
-        for (p = 0; p < 4; p++)
-            av_freep(&src[p]);
-
-        res = av_image_fill_linesizes(srcStride, srcFormat, srcW);
-        if (res < 0) {
-            fprintf(stderr, "av_image_fill_linesizes failed\n");
-            goto end;
-        }
-        for (p = 0; p < 4; p++) {
-            srcStride[p] = FFALIGN(srcStride[p], 16);
-            if (srcStride[p])
-                src[p] = av_mallocz(srcStride[p] * srcH + 16);
-            if (srcStride[p] && !src[p]) {
-                perror("Malloc");
-                res = -1;
-                goto end;
+    av_assert1(a->format == AV_PIX_FMT_YUVA420P);
+    av_assert1(b->format == a->format);
+    av_assert1(b->width == a->width && b->height == a->height);
+
+    for (int p = 0; p < 4; p++) {
+        const int is_chroma = p == 1 || p == 2;
+        const int stride_a = a->linesize[p];
+        const int stride_b = b->linesize[p];
+        const int w = (a->width + is_chroma) >> is_chroma;
+        const int h = (a->height + is_chroma) >> is_chroma;
+        uint64_t sum = 0;
+
+        if (comps & (1 << p)) {
+            for (int y = 0; y < h; y++) {
+                for (int x = 0; x < w; x++) {
+                    int d = a->data[p][y * stride_a + x] - b->data[p][y * stride_b + x];
+                    sum += d * d;
+                }
+            }
+        } else {
+            const int ref = is_chroma ? 128 : 0xFF;
+            for (int y = 0; y < h; y++) {
+                for (int x = 0; x < w; x++) {
+                    int d = a->data[p][y * stride_a + x] - ref;
+                    sum += d * d;
+                }
             }
         }
-        srcContext = sws_getContext(w, h, AV_PIX_FMT_YUVA420P, srcW, srcH,
-                                    srcFormat, SWS_BILINEAR, NULL, NULL, NULL);
-        if (!srcContext) {
-            fprintf(stderr, "Failed to get %s ---> %s\n",
-                    desc_yuva420p->name,
-                    desc_src->name);
-            res = -1;
-            goto end;
-        }
-        sws_scale(srcContext, ref, refStride, 0, h,
-                  (uint8_t * const *) src, srcStride);
-        sws_freeContext(srcContext);
 
-        cur_srcFormat = srcFormat;
-        cur_srcW      = srcW;
-        cur_srcH      = srcH;
+        mse[p] = sum / (w * h);
     }
+}
 
-    res = av_image_fill_linesizes(dstStride, dstFormat, dstW);
-    if (res < 0) {
-        fprintf(stderr, "av_image_fill_linesizes failed\n");
-        goto end;
-    }
+static int scale_legacy(AVFrame *dst, const AVFrame *src, struct mode mode)
+{
+    SwsContext *sws_legacy;
+    int ret;
 
-    for (i = 0; i < 4; i++) {
-        /* Image buffers passed into libswscale can be allocated any way you
-         * prefer, as long as they're aligned enough for the architecture, and
-         * they're freed appropriately (such as using av_free for buffers
-         * allocated with av_malloc). */
-        /* An extra 16 bytes is being allocated because some scalers may write
-         * out of bounds. */
-        dstStride[i] = FFALIGN(dstStride[i], 16);
-        if (dstStride[i])
-            dst[i] = av_mallocz(dstStride[i] * dstH + 16);
-        if (dstStride[i] && !dst[i]) {
-            perror("Malloc");
-            res = -1;
-
-            goto end;
-        }
-    }
+    sws_legacy = sws_alloc_context();
+    if (!sws_legacy)
+        return -1;
+
+    sws_legacy->src_w      = src->width;
+    sws_legacy->src_h      = src->height;
+    sws_legacy->src_format = src->format;
+    sws_legacy->dst_w      = dst->width;
+    sws_legacy->dst_h      = dst->height;
+    sws_legacy->dst_format = dst->format;
+    sws_legacy->flags      = mode.flags;
+    sws_legacy->dither     = mode.dither;
+
+    ret = sws_init_context(sws_legacy, NULL, NULL);
+    if (!ret)
+        ret = sws_scale_frame(sws_legacy, dst, src);
+
+    sws_freeContext(sws_legacy);
+    return ret;
+}
+
+/* Runs a series of ref -> src -> dst -> out, and compares out vs ref */
+static int run_test(enum AVPixelFormat src_fmt, enum AVPixelFormat dst_fmt,
+                    int dst_w, int dst_h, struct mode mode, const AVFrame *ref,
+                    const int mse_ref[4])
+{
+    AVFrame *src = NULL, *dst = NULL, *out = NULL;
+    int mse[4], mse_sws[4], ret = -1;
+    const int comps = fmt_comps(src_fmt) & fmt_comps(dst_fmt);
+
+    src = av_frame_alloc();
+    dst = av_frame_alloc();
+    out = av_frame_alloc();
+    if (!src || !dst || !out)
+        goto error;
 
-    dstContext = sws_alloc_context();
-    if (!dstContext) {
-        fprintf(stderr, "Failed to alloc %s ---> %s\n",
-                desc_src->name, desc_dst->name);
-        res = -1;
-        goto end;
+    av_frame_copy_props(src, ref);
+    av_frame_copy_props(dst, ref);
+    av_frame_copy_props(out, ref);
+    src->width  = out->width  = ref->width;
+    src->height = out->height = ref->height;
+    out->format = ref->format;
+    src->format = src_fmt;
+    dst->format = dst_fmt;
+    dst->width  = dst_w;
+    dst->height = dst_h;
+
+    if (sws_scale_frame(sws[0], src, ref) < 0) {
+        fprintf(stderr, "Failed %s ---> %s\n", av_get_pix_fmt_name(ref->format),
+                av_get_pix_fmt_name(src->format));
+        goto error;
     }
 
-    av_opt_set_int(dstContext, "sws_flags",  flags, 0);
-    av_opt_set_int(dstContext, "srcw",       srcW, 0);
-    av_opt_set_int(dstContext, "srch",       srcH, 0);
-    av_opt_set_int(dstContext, "dstw",       dstW, 0);
-    av_opt_set_int(dstContext, "dsth",       dstH, 0);
-    av_opt_set_int(dstContext, "src_format", srcFormat, 0);
-    av_opt_set_int(dstContext, "dst_format", dstFormat, 0);
-    av_opt_set(dstContext, "alphablend", "none", 0);
-
-    if (sws_init_context(dstContext, NULL, NULL) < 0) {
-        sws_freeContext(dstContext);
-        fprintf(stderr, "Failed to init %s ---> %s\n",
-                desc_src->name, desc_dst->name);
-        res = -1;
-        goto end;
+    sws[1]->flags  = mode.flags;
+    sws[1]->dither = mode.dither;
+    if (sws_scale_frame(sws[1], dst, src) < 0) {
+        fprintf(stderr, "Failed %s ---> %s\n", av_get_pix_fmt_name(src->format),
+                av_get_pix_fmt_name(dst->format));
+        goto error;
     }
 
-    printf(" %s %dx%d -> %s %3dx%3d flags=%2d",
-           desc_src->name, srcW, srcH,
-           desc_dst->name, dstW, dstH,
-           flags);
-    fflush(stdout);
+    if (sws_scale_frame(sws[2], out, dst) < 0) {
+        fprintf(stderr, "Failed %s ---> %s\n", av_get_pix_fmt_name(dst->format),
+                av_get_pix_fmt_name(out->format));
+        goto error;
+    }
 
-    sws_scale(dstContext, (const uint8_t * const*)src, srcStride, 0, srcH, dst, dstStride);
-
-    for (i = 0; i < 4 && dstStride[i]; i++)
-        crc = av_crc(av_crc_get_table(AV_CRC_32_IEEE), crc, dst[i],
-                     dstStride[i] * dstH);
-
-    if (r && crc == r->crc) {
-        ssdY = r->ssdY;
-        ssdU = r->ssdU;
-        ssdV = r->ssdV;
-        ssdA = r->ssdA;
-    } else {
-        for (i = 0; i < 4; i++) {
-            refStride[i] = FFALIGN(refStride[i], 16);
-            if (refStride[i])
-                out[i] = av_mallocz(refStride[i] * h);
-            if (refStride[i] && !out[i]) {
-                perror("Malloc");
-                res = -1;
-                goto end;
-            }
-        }
-        outContext = sws_getContext(dstW, dstH, dstFormat, w, h,
-                                    AV_PIX_FMT_YUVA420P, SWS_BILINEAR,
-                                    NULL, NULL, NULL);
-        if (!outContext) {
-            fprintf(stderr, "Failed to get %s ---> %s\n",
-                    desc_dst->name,
-                    desc_yuva420p->name);
-            res = -1;
-            goto end;
-        }
-        sws_scale(outContext, (const uint8_t * const *) dst, dstStride, 0, dstH,
-                  out, refStride);
-
-        ssdY = getSSD(ref[0], out[0], refStride[0], refStride[0], w, h);
-        if (hasChroma(srcFormat) && hasChroma(dstFormat)) {
-            //FIXME check that output is really gray
-            ssdU = getSSD(ref[1], out[1], refStride[1], refStride[1],
-                          (w + 1) >> 1, (h + 1) >> 1);
-            ssdV = getSSD(ref[2], out[2], refStride[2], refStride[2],
-                          (w + 1) >> 1, (h + 1) >> 1);
-        } else {
-            ssdU = getSSD0(128, out[1], refStride[1],
-                          (w + 1) >> 1, (h + 1) >> 1);
-            ssdV = getSSD0(128, out[2], refStride[2],
-                          (w + 1) >> 1, (h + 1) >> 1);
-        }
-        if (isALPHA(srcFormat) && isALPHA(dstFormat)) {
-            ssdA = getSSD(ref[3], out[3], refStride[3], refStride[3], w, h);
-        } else {
-            ssdA = getSSD0(0xFF, out[3], refStride[3], w, h);
+    get_mse(mse, out, ref, comps);
+    printf("%s %dx%d -> %s %3dx%3d, flags=%u dither=%u, "
+           "MSE={%5d %5d %5d %5d}\n",
+           av_get_pix_fmt_name(src->format), src->width, src->height,
+           av_get_pix_fmt_name(dst->format), dst->width, dst->height,
+           mode.flags, mode.dither,
+           mse[0], mse[1], mse[2], mse[3]);
+
+    if (!mse_ref) {
+        /* Compare against the legacy swscale API as a reference */
+        if (scale_legacy(dst, src, mode) < 0) {
+            fprintf(stderr, "Failed ref %s ---> %s\n", av_get_pix_fmt_name(src->format),
+                    av_get_pix_fmt_name(dst->format));
+            goto error;
         }
 
-        ssdY /= w * h;
-        ssdU /= w * h / 4;
-        ssdV /= w * h / 4;
-        ssdA /= w * h;
-
-        sws_freeContext(outContext);
+        if (sws_scale_frame(sws[2], out, dst) < 0)
+            goto error;
 
-        for (i = 0; i < 4; i++)
-            if (refStride[i])
-                av_free(out[i]);
+        get_mse(mse_sws, out, ref, comps);
+        mse_ref = mse_sws;
     }
 
-    if(r){
-        if(ssdY>r->ssdY*1.02+1 || ssdU>r->ssdU*1.02+1 || ssdV>r->ssdV*1.02+1|| ssdA>r->ssdA*1.02+1)
-            printf("WORSE SSD=%5"PRId64",%5"PRId64",%5"PRId64",%5"PRId64"",
-            r->ssdY, r->ssdU, r->ssdV, r->ssdA);
-        else if(ssdY>r->ssdY || ssdU>r->ssdU || ssdV>r->ssdV|| ssdA>r->ssdA)
-            printf("worse SSD=%5"PRId64",%5"PRId64",%5"PRId64",%5"PRId64"",
-            r->ssdY, r->ssdU, r->ssdV, r->ssdA);
+    for (int i = 0; i < 4; i++) {
+        if (mse[i] > mse_ref[i]) {
+            int bad = mse[i] > mse_ref[i] * 1.02 + 1;
+            printf("\033[1;31m  %s, ref MSE={%5d %5d %5d %5d}\033[0m\n",
+                   bad ? "WORSE" : "worse",
+                   mse_ref[0], mse_ref[1], mse_ref[2], mse_ref[3]);
+            if (bad)
+                goto error;
+            break;
+        }
     }
 
-    printf(" CRC=%08x SSD=%5"PRId64 ",%5"PRId64 ",%5"PRId64 ",%5"PRId64 "\n",
-           crc, ssdY, ssdU, ssdV, ssdA);
-
-end:
-    sws_freeContext(dstContext);
-
-    for (i = 0; i < 4; i++)
-        if (dstStride[i])
-            av_free(dst[i]);
-
-    return !!res;
+    fflush(stdout);
+    ret = 0; /* fall through */
+ error:
+    av_frame_free(&src);
+    av_frame_free(&dst);
+    av_frame_free(&out);
+    return ret;
 }
 
-static void selfTest(const uint8_t * const ref[4], int refStride[4],
-                     int w, int h,
-                     enum AVPixelFormat srcFormat_in,
-                     enum AVPixelFormat dstFormat_in)
+static int run_self_tests(const AVFrame *ref, struct options opts)
 {
-    const int flags[] = { SWS_FAST_BILINEAR,
-                          SWS_BILINEAR, SWS_BICUBIC,
-                          SWS_X|SWS_BITEXACT       , SWS_POINT  , SWS_AREA|SWS_ACCURATE_RND,
-                          SWS_BICUBIC|SWS_FULL_CHR_H_INT|SWS_FULL_CHR_H_INP, 0};
-    const int srcW   = w;
-    const int srcH   = h;
-    const int dstW[] = { srcW - srcW / 3, srcW, srcW + srcW / 3, 0 };
-    const int dstH[] = { srcH - srcH / 3, srcH, srcH + srcH / 3, 0 };
-    enum AVPixelFormat srcFormat, dstFormat;
-    const AVPixFmtDescriptor *desc_src, *desc_dst;
-
-    for (srcFormat = srcFormat_in != AV_PIX_FMT_NONE ? srcFormat_in : 0;
-         srcFormat < AV_PIX_FMT_NB; srcFormat++) {
-        if (!sws_isSupportedInput(srcFormat) ||
-            !sws_isSupportedOutput(srcFormat))
+    enum AVPixelFormat src_fmt, dst_fmt,
+                       src_fmt_min = 0,
+                       dst_fmt_min = 0,
+                       src_fmt_max = AV_PIX_FMT_NB - 1,
+                       dst_fmt_max = AV_PIX_FMT_NB - 1;
+
+    if (opts.src_fmt != AV_PIX_FMT_NONE)
+        src_fmt_min = src_fmt_max = opts.src_fmt;
+    if (opts.dst_fmt != AV_PIX_FMT_NONE)
+        dst_fmt_min = dst_fmt_max = opts.dst_fmt;
+
+    for (src_fmt = src_fmt_min; src_fmt <= src_fmt_max; src_fmt++) {
+        if (!sws_test_format(src_fmt, 0) || !sws_test_format(src_fmt, 1))
             continue;
-
-        desc_src = av_pix_fmt_desc_get(srcFormat);
-
-        for (dstFormat = dstFormat_in != AV_PIX_FMT_NONE ? dstFormat_in : 0;
-             dstFormat < AV_PIX_FMT_NB; dstFormat++) {
-            int i, j, k;
-            int res = 0;
-
-            if (!sws_isSupportedInput(dstFormat) ||
-                !sws_isSupportedOutput(dstFormat))
+        for (dst_fmt = dst_fmt_min; dst_fmt <= dst_fmt_max; dst_fmt++) {
+            if (!sws_test_format(dst_fmt, 0) || !sws_test_format(dst_fmt, 1))
                 continue;
-
-            desc_dst = av_pix_fmt_desc_get(dstFormat);
-
-            printf("%s -> %s\n", desc_src->name, desc_dst->name);
-            fflush(stdout);
-
-            for (k = 0; flags[k] && !res; k++)
-                for (i = 0; dstW[i] && !res; i++)
-                    for (j = 0; dstH[j] && !res; j++)
-                        res = doTest(ref, refStride, w, h,
-                                     srcFormat, dstFormat,
-                                     srcW, srcH, dstW[i], dstH[j], flags[k],
-                                     NULL);
-            if (dstFormat_in != AV_PIX_FMT_NONE)
-                break;
+            for (int h = 0; h < FF_ARRAY_ELEMS(dst_h); h++)
+                for (int w = 0; w < FF_ARRAY_ELEMS(dst_w); w++)
+                    for (int m = 0; m < FF_ARRAY_ELEMS(modes); m++) {
+                        if (ff_sfc64_get(&prng_state) > UINT64_MAX * opts.prob)
+                            continue;
+                        if (run_test(src_fmt, dst_fmt, dst_w[w], dst_h[h],
+                                     modes[m], ref, NULL) < 0)
+                            return -1;
+                    }
         }
-        if (srcFormat_in != AV_PIX_FMT_NONE)
-            break;
     }
+
+    return 0;
 }
 
-static int fileTest(const uint8_t * const ref[4], int refStride[4],
-                    int w, int h, FILE *fp,
-                    enum AVPixelFormat srcFormat_in,
-                    enum AVPixelFormat dstFormat_in)
+static int run_file_tests(const AVFrame *ref, FILE *fp, struct options opts)
 {
     char buf[256];
+    int ret;
 
     while (fgets(buf, sizeof(buf), fp)) {
-        struct Results r;
-        enum AVPixelFormat srcFormat;
-        char srcStr[21];
-        int srcW = 0, srcH = 0;
-        enum AVPixelFormat dstFormat;
-        char dstStr[21];
-        int dstW = 0, dstH = 0;
-        int flags;
-        int ret;
+        char src_fmt_str[20], dst_fmt_str[20];
+        enum AVPixelFormat src_fmt;
+        enum AVPixelFormat dst_fmt;
+        int sw, sh, dw, dh, mse[4];
+        struct mode mode;
 
         ret = sscanf(buf,
-                     " %20s %dx%d -> %20s %dx%d flags=%d CRC=%x"
-                     " SSD=%"SCNu64 ", %"SCNu64 ", %"SCNu64 ", %"SCNu64 "\n",
-                     srcStr, &srcW, &srcH, dstStr, &dstW, &dstH,
-                     &flags, &r.crc, &r.ssdY, &r.ssdU, &r.ssdV, &r.ssdA);
-        if (ret != 12) {
-            srcStr[0] = dstStr[0] = 0;
-            ret       = sscanf(buf, "%20s -> %20s\n", srcStr, dstStr);
+                     " %20s %dx%d -> %20s %dx%d, flags=%u dither=%u, "
+                     "MSE={%d %d %d %d}\n",
+                     src_fmt_str, &sw, &sh, dst_fmt_str, &dw, &dh,
+                     &mode.flags, &mode.dither,
+                     &mse[0], &mse[1], &mse[2], &mse[3]);
+        if (ret != 13) {
+            printf("%s", buf);
+            continue;
         }
 
-        srcFormat = av_get_pix_fmt(srcStr);
-        dstFormat = av_get_pix_fmt(dstStr);
-
-        if (srcFormat == AV_PIX_FMT_NONE || dstFormat == AV_PIX_FMT_NONE ||
-            srcW > 8192U || srcH > 8192U || dstW > 8192U || dstH > 8192U) {
+        src_fmt = av_get_pix_fmt(src_fmt_str);
+        dst_fmt = av_get_pix_fmt(dst_fmt_str);
+        if (src_fmt == AV_PIX_FMT_NONE || dst_fmt == AV_PIX_FMT_NONE ||
+            sw != ref->width || sh != ref->height || dw > 8192 || dh > 8192 ||
+            mode.dither >= SWS_DITHER_NB) {
             fprintf(stderr, "malformed input file\n");
             return -1;
         }
-        if ((srcFormat_in != AV_PIX_FMT_NONE && srcFormat_in != srcFormat) ||
-            (dstFormat_in != AV_PIX_FMT_NONE && dstFormat_in != dstFormat))
-            continue;
-        if (ret != 12) {
-            printf("%s", buf);
+
+        if (opts.src_fmt != AV_PIX_FMT_NONE && src_fmt != opts.src_fmt ||
+            opts.dst_fmt != AV_PIX_FMT_NONE && dst_fmt != opts.dst_fmt)
             continue;
-        }
 
-        doTest(ref, refStride, w, h,
-               srcFormat, dstFormat,
-               srcW, srcH, dstW, dstH, flags,
-               &r);
+        if (run_test(src_fmt, dst_fmt, dw, dh, mode, ref, mse) < 0)
+            return -1;
     }
 
     return 0;
 }
 
-#define W 96
-#define H 96
-
 int main(int argc, char **argv)
 {
-    enum AVPixelFormat srcFormat = AV_PIX_FMT_NONE;
-    enum AVPixelFormat dstFormat = AV_PIX_FMT_NONE;
-    uint8_t *rgb_data   = av_malloc(W * H * 4);
-    const uint8_t * const rgb_src[4] = { rgb_data, NULL, NULL, NULL };
-    int rgb_stride[4]   = { 4 * W, 0, 0, 0 };
-    uint8_t *data       = av_malloc(4 * W * H);
-    const uint8_t * const src[4] = { data, data + W * H, data + W * H * 2, data + W * H * 3 };
-    int stride[4]       = { W, W, W, W };
-    int x, y;
-    SwsContext *sws;
-    AVLFG rand;
-    int res = -1;
-    int i;
-    FILE *fp = NULL;
+    struct options opts = {
+        .src_fmt = AV_PIX_FMT_NONE,
+        .dst_fmt = AV_PIX_FMT_NONE,
+        .prob = 1.0,
+    };
 
-    if (!rgb_data || !data)
-        return -1;
+    AVFrame *rgb = NULL, *ref = NULL;
+    FILE *fp = NULL;
+    AVLFG rand;
+    int ret = -1;
 
-    for (i = 1; i < argc; i += 2) {
+    for (int i = 1; i < argc; i += 2) {
         if (!strcmp(argv[i], "-help") || !strcmp(argv[i], "--help")) {
             fprintf(stderr,
                     "swscale [options...]\n"
                     "   -help\n"
                     "       This text\n"
                     "   -ref <file>\n"
-                    "       Uses file as reference to compae tests againsts. Tests that have become worse will contain the string worse or WORSE\n"
+                    "       Uses file as reference to compare tests againsts. Tests that have become worse will contain the string worse or WORSE\n"
                     "   -p <number between 0.0 and 1.0>\n"
                     "       The percentage of tests or comparisons to perform. Doing all tests will take long and generate over a hundred MB text output\n"
                     "       It is often convenient to perform a random subset\n"
@@ -454,7 +338,7 @@ int main(int argc, char **argv)
                     "   -cpuflags <cpuflags>\n"
                     "       Uses the specified cpuflags in the tests\n"
             );
-            goto error;
+            return 0;
         }
         if (argv[i][0] != '-' || i + 1 == argc)
             goto bad_option;
@@ -466,26 +350,26 @@ int main(int argc, char **argv)
             }
         } else if (!strcmp(argv[i], "-cpuflags")) {
             unsigned flags = av_get_cpu_flags();
-            int ret = av_parse_cpu_caps(&flags, argv[i + 1]);
-            if (ret < 0) {
+            int res = av_parse_cpu_caps(&flags, argv[i + 1]);
+            if (res < 0) {
                 fprintf(stderr, "invalid cpu flags %s\n", argv[i + 1]);
-                return ret;
+                goto error;
             }
             av_force_cpu_flags(flags);
         } else if (!strcmp(argv[i], "-src")) {
-            srcFormat = av_get_pix_fmt(argv[i + 1]);
-            if (srcFormat == AV_PIX_FMT_NONE) {
+            opts.src_fmt = av_get_pix_fmt(argv[i + 1]);
+            if (opts.src_fmt == AV_PIX_FMT_NONE) {
                 fprintf(stderr, "invalid pixel format %s\n", argv[i + 1]);
-                return -1;
+                goto error;
             }
         } else if (!strcmp(argv[i], "-dst")) {
-            dstFormat = av_get_pix_fmt(argv[i + 1]);
-            if (dstFormat == AV_PIX_FMT_NONE) {
+            opts.dst_fmt = av_get_pix_fmt(argv[i + 1]);
+            if (opts.dst_fmt == AV_PIX_FMT_NONE) {
                 fprintf(stderr, "invalid pixel format %s\n", argv[i + 1]);
-                return -1;
+                goto error;
             }
         } else if (!strcmp(argv[i], "-p")) {
-            prob = atof(argv[i + 1]);
+            opts.prob = atof(argv[i + 1]);
         } else {
 bad_option:
             fprintf(stderr, "bad option or argument missing (%s) see -help\n", argv[i]);
@@ -494,32 +378,51 @@ bad_option:
     }
 
     ff_sfc64_init(&prng_state, 0, 0, 0, 12);
-
-    sws = sws_getContext(W / 12, H / 12, AV_PIX_FMT_RGB32, W, H,
-                         AV_PIX_FMT_YUVA420P, SWS_BILINEAR, NULL, NULL, NULL);
-
     av_lfg_init(&rand, 1);
 
-    for (y = 0; y < H; y++)
-        for (x = 0; x < W * 4; x++)
-            rgb_data[ x + y * 4 * W] = av_lfg_get(&rand);
-    res = sws_scale(sws, rgb_src, rgb_stride, 0, H / 12, (uint8_t * const *) src, stride);
-    if (res < 0 || res != H) {
-        res = -1;
-        goto error;
+    for (int i = 0; i < 3; i++) {
+        sws[i] = sws_alloc_context();
+        if (!sws[i])
+            goto error;
+        sws[i]->flags = SWS_BILINEAR;
     }
-    sws_freeContext(sws);
-    av_free(rgb_data);
 
-    if(fp) {
-        res = fileTest(src, stride, W, H, fp, srcFormat, dstFormat);
-        fclose(fp);
-    } else {
-        selfTest(src, stride, W, H, srcFormat, dstFormat);
-        res = 0;
+    rgb = av_frame_alloc();
+    if (!rgb)
+        goto error;
+    rgb->width  = WIDTH  / 12;
+    rgb->height = HEIGHT / 12;
+    rgb->format = AV_PIX_FMT_RGBA;
+    if (av_frame_get_buffer(rgb, 32) < 0)
+        goto error;
+
+    for (int y = 0; y < rgb->height; y++) {
+        for (int x = 0; x < rgb->width; x++) {
+            for (int c = 0; c < 4; c++)
+                rgb->data[0][y * rgb->linesize[0] + x * 4 + c] = av_lfg_get(&rand);
+        }
     }
-error:
-    av_free(data);
 
-    return res;
+    ref = av_frame_alloc();
+    if (!ref)
+        goto error;
+    ref->width  = WIDTH;
+    ref->height = HEIGHT;
+    ref->format = AV_PIX_FMT_YUVA420P;
+
+    if (sws_scale_frame(sws[0], ref, rgb) < 0)
+        goto error;
+
+    ret = fp ? run_file_tests(ref, fp, opts)
+             : run_self_tests(ref, opts);
+
+    /* fall through */
+error:
+    for (int i = 0; i < 3; i++)
+        sws_free_context(&sws[i]);
+    av_frame_free(&rgb);
+    av_frame_free(&ref);
+    if (fp)
+        fclose(fp);
+    return ret;
 }
