{
  "schemaVersion": 1,
  "contentVersion": "ca42e61ede0a24f789d7287a0001244ad22f4abf",
  "id": "docs/reference/metrics/xpsnr",
  "collection": "docs",
  "title": "XPSNR",
  "description": "XPSNR is a fast, perceptually weighted PSNR for video, built into FFmpeg since 7.1; this page covers running it (reference first) and reading its per-plane scores.",
  "canonicalUrl": "https://encode.wiki/reference/metrics/xpsnr/",
  "apiUrl": "https://encode.wiki/api/v1/documents/docs/reference/metrics/xpsnr.json",
  "markdownUrl": "https://encode.wiki/api/v1/markdown/docs/reference/metrics/xpsnr.md",
  "status": "current",
  "tags": [
    "migrated"
  ],
  "license": "CC BY-SA 4.0",
  "dates": {
    "lastVerified": "2026-10-08T00:00:00.000Z"
  },
  "authors": [],
  "sources": [
    {
      "title": "FFmpeg xpsnr filter documentation",
      "url": "https://ffmpeg.org/ffmpeg-filters.html#xpsnr",
      "accessedAt": "2026-10-08T00:00:00.000Z"
    },
    {
      "title": "FFmpeg 9.0.2 xpsnr filter source",
      "url": "https://github.com/FFmpeg/FFmpeg/blob/n9.0.2/libavfilter/vf_xpsnr.c",
      "accessedAt": "2026-10-08T00:00:00.000Z"
    },
    {
      "title": "FFmpeg 7.1 filter list (first release with xpsnr)",
      "url": "https://github.com/FFmpeg/FFmpeg/blob/n7.1/libavfilter/allfilters.c",
      "accessedAt": "2026-10-08T00:00:00.000Z"
    },
    {
      "title": "Fraunhofer HHI XPSNR plug-in (unmaintained, now in FFmpeg)",
      "url": "https://github.com/fraunhoferhhi/xpsnr",
      "accessedAt": "2026-10-08T00:00:00.000Z"
    },
    {
      "title": "Helmrich et al., A Study of the Extended Perceptually Weighted PSNR (XPSNR), ITU Journal ICT Discoveries 2020",
      "url": "https://www.itu.int/pub/S-JOURNAL-ICTS.V3I1-2020-8",
      "accessedAt": "2026-10-08T00:00:00.000Z"
    },
    {
      "title": "vszip XPSNR filter",
      "url": "https://github.com/dnjulek/vapoursynth-zip/wiki/XPSNR",
      "accessedAt": "2026-10-08T00:00:00.000Z"
    },
    {
      "title": "FFMetrics 1.8.0 beta 1 release notes (XPSNR input order fix)",
      "url": "https://github.com/fifonik/FFMetrics/releases/tag/v1.8.0-beta.1",
      "accessedAt": "2026-10-08T00:00:00.000Z"
    },
    {
      "title": "Av1an XPSNR target metrics (xpsnr-minimum, xpsnr-weighted)",
      "url": "https://github.com/rust-av/Av1an/blob/master/av1an-core/src/metrics/xpsnr.rs",
      "accessedAt": "2026-10-08T00:00:00.000Z"
    }
  ],
  "provenance": {
    "originUrl": "https://github.com/av1-community-contributors/codec-wiki/blob/37c3317fd058b23c71a87679bed5619a98f77752/docs/metrics/XPSNR.mdx",
    "originCommit": "37c3317fd058b23c71a87679bed5619a98f77752",
    "migratedAt": "2026-08-21T00:00:00.000Z",
    "modified": true,
    "originPath": "docs/metrics/XPSNR.mdx"
  },
  "headings": [
    {
      "depth": 2,
      "text": "Why use it",
      "anchor": "why-use-it"
    },
    {
      "depth": 2,
      "text": "Measure XPSNR with FFmpeg",
      "anchor": "measure-xpsnr-with-ffmpeg"
    },
    {
      "depth": 2,
      "text": "Read the results",
      "anchor": "read-the-results"
    },
    {
      "depth": 2,
      "text": "In VapourSynth",
      "anchor": "in-vapoursynth"
    }
  ],
  "sections": [
    {
      "id": "_preamble",
      "title": "Page introduction",
      "depth": 0,
      "canonicalUrl": "https://encode.wiki/reference/metrics/xpsnr/",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/reference/metrics/xpsnr/_preamble.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/reference/metrics/xpsnr/_preamble.md",
      "checksum": "47416d84750fe8d8511232731737cd86cbe33eb5e905770c3cabc67a445f9559",
      "bytes": 422
    },
    {
      "id": "why-use-it",
      "title": "Why use it",
      "depth": 2,
      "anchor": "why-use-it",
      "canonicalUrl": "https://encode.wiki/reference/metrics/xpsnr/#why-use-it",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/reference/metrics/xpsnr/why-use-it.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/reference/metrics/xpsnr/why-use-it.md",
      "checksum": "c6d0d0978b3b1bfc2bacda8ce0c1d0d579c636d835390359dccc65d5c4d791b8",
      "bytes": 594
    },
    {
      "id": "measure-xpsnr-with-ffmpeg",
      "title": "Measure XPSNR with FFmpeg",
      "depth": 2,
      "anchor": "measure-xpsnr-with-ffmpeg",
      "canonicalUrl": "https://encode.wiki/reference/metrics/xpsnr/#measure-xpsnr-with-ffmpeg",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/reference/metrics/xpsnr/measure-xpsnr-with-ffmpeg.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/reference/metrics/xpsnr/measure-xpsnr-with-ffmpeg.md",
      "checksum": "be743c41134f70d99b4b8e66970213eda66587fef62d87003678ff863e00342f",
      "bytes": 1222
    },
    {
      "id": "read-the-results",
      "title": "Read the results",
      "depth": 2,
      "anchor": "read-the-results",
      "canonicalUrl": "https://encode.wiki/reference/metrics/xpsnr/#read-the-results",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/reference/metrics/xpsnr/read-the-results.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/reference/metrics/xpsnr/read-the-results.md",
      "checksum": "3fd4fc3aa188ae5b92fe096522d27f51ea9729d0826b964b309ae100daf52be5",
      "bytes": 549
    },
    {
      "id": "in-vapoursynth",
      "title": "In VapourSynth",
      "depth": 2,
      "anchor": "in-vapoursynth",
      "canonicalUrl": "https://encode.wiki/reference/metrics/xpsnr/#in-vapoursynth",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/reference/metrics/xpsnr/in-vapoursynth.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/reference/metrics/xpsnr/in-vapoursynth.md",
      "checksum": "5123fb3ecb4404f052af044c16f4bbe15bc43d5e311f81af6cbc865fd355069c",
      "bytes": 339
    }
  ],
  "outboundReferences": [
    "/guides/compare-encoding-quality/",
    "/reference/metrics/butteraugli/",
    "/reference/metrics/ssimulacra2/",
    "https://github.com/dnjulek/vapoursynth-zip"
  ],
  "checksum": "3fae47156e4973730cdbd551e339709b53951f16e84994b1819ddb3a8e21e015",
  "contentFormat": "markdown",
  "markdown": "XPSNR (extended perceptually weighted peak signal-to-noise ratio) is a full-reference video metric from Fraunhofer HHI. It computes PSNR block by block and weights each block by the reference's local spatial activity and, for video, its temporal activity. Errors in busy or fast-moving areas, where they are hard to see, count for less; errors in flat, static areas count for more. Scores are in dB, per plane, like PSNR.\n\n## Why use it\n\nXPSNR keeps PSNR's low cost but correlates better with how video looks, and unlike image metrics such as [SSIMULACRA2](/reference/metrics/ssimulacra2/) it takes motion into account. That makes it a good first pass over many test encodes and a useful companion to SSIMULACRA2 and [Butteraugli](/reference/metrics/butteraugli/): the metrics have different blind spots, so agreement between them means more than any one score.\n\nIt is still a PSNR derivative. Scores depend heavily on the content, so there is no fixed \"good\" value; compare encodes of the same clip with each other.\n\n## Measure XPSNR with FFmpeg\n\nThe `xpsnr` filter has been built into FFmpeg since 7.1; the Fraunhofer patch for FFmpeg 7.0 is no longer needed or maintained.\n\n```sh\nffmpeg -i reference.mkv -i distorted.mkv -lavfi xpsnr=stats_file=xpsnr.log -f null -\n```\n\n> **Caution — Reference first.**\n>\n> Unlike `psnr`, `ssim` and `libvmaf`, the `xpsnr` filter expects the **reference first** and the distorted video second. The perceptual weights come from the first input, so swapping the files gives different, wrong scores. FFMetrics 1.7.0 had them swapped; 1.8.0 beta 1 fixed it.\nThe summary looks like `XPSNR  y: 29.5228  u: 30.0330  v: 29.9182  (minimum: 29.5228)`, and `xpsnr.log` holds the per-frame values for each plane.\n\n- Both inputs need the same dimensions. Scale the encode to the reference size if needed: `-lavfi \"[1:v]scale=1920:1080:flags=bicubic[d];[0:v][d]xpsnr\"`.\n- The bit depths may differ. Other pixel-format differences are converted automatically; the filter is designed for YCbCr input.\n- As with the other FFmpeg metric filters, check that frame counts match, because FFmpeg repeats the last frame of a shorter input. Add `setpts=PTS-STARTPTS` to both inputs only if one starts at a non-zero timestamp.\n\n## Read the results\n\nThe XPSNR authors recommend reporting the **minimum** of the per-plane averages, which FFmpeg prints as `minimum`. Some community tools, such as Av1an's `xpsnr-weighted` target, instead combine the planes with luma weighted 4:1:1 against the two chroma planes. That gives a different number, so say which one you report and don't mix them.\n\nThe printed averages hide short bad sections. Use the per-frame log to find the lowest-scoring frames and look at them; see [Compare encoding quality](/guides/compare-encoding-quality/).\n\n## In VapourSynth\n\n[vszip](https://github.com/dnjulek/vapoursynth-zip) (`pip install vapoursynth-vszip`) has an XPSNR filter that matches FFmpeg's numbers. It also takes the reference first and stores per-frame scores in the `XPSNR_Y`, `XPSNR_U` and `XPSNR_V` frame properties:\n\n```python\nclip = core.vszip.XPSNR(reference, distorted)\n```\n"
}
