{
  "schemaVersion": 1,
  "contentVersion": "ca42e61ede0a24f789d7287a0001244ad22f4abf",
  "id": "docs/reference/metrics/psnr",
  "collection": "docs",
  "title": "PSNR",
  "description": "PSNR measures squared pixel error in decibels; it is useful for codec development and catching pipeline mistakes, but a poor guide to how an encode looks.",
  "canonicalUrl": "https://encode.wiki/reference/metrics/psnr/",
  "apiUrl": "https://encode.wiki/api/v1/documents/docs/reference/metrics/psnr.json",
  "markdownUrl": "https://encode.wiki/api/v1/markdown/docs/reference/metrics/psnr.md",
  "status": "current",
  "tags": [
    "migrated"
  ],
  "license": "CC BY-SA 4.0",
  "dates": {
    "lastVerified": "2026-10-08T00:00:00.000Z"
  },
  "authors": [],
  "sources": [
    {
      "title": "FFmpeg psnr filter documentation",
      "url": "https://ffmpeg.org/ffmpeg-filters.html#psnr",
      "accessedAt": "2026-10-08T00:00:00.000Z"
    },
    {
      "title": "FFmpeg 9.0.2 psnr filter source",
      "url": "https://github.com/FFmpeg/FFmpeg/blob/n9.0.2/libavfilter/vf_psnr.c",
      "accessedAt": "2026-10-08T00:00:00.000Z"
    },
    {
      "title": "x264 encoder warnings for PSNR/SSIM measurement with psy enabled",
      "url": "https://code.videolan.org/videolan/x264/-/blob/master/encoder/encoder.c",
      "accessedAt": "2026-10-08T00:00:00.000Z"
    },
    {
      "title": "SSIMULACRA 2 README, metric correlation tables",
      "url": "https://github.com/cloudinary/ssimulacra2/blob/main/README.md",
      "accessedAt": "2026-10-08T00:00:00.000Z"
    },
    {
      "title": "Netflix VMAF FAQ (PSNR caps in libvmaf)",
      "url": "https://github.com/Netflix/vmaf/blob/v3.2.1/resource/doc/faq.md",
      "accessedAt": "2026-10-08T00:00:00.000Z"
    },
    {
      "title": "x265 tuning options (psnr and ssim tunes disable psy optimisations)",
      "url": "https://x265.readthedocs.io/en/master/presets.html",
      "accessedAt": "2026-10-08T00:00:00.000Z"
    }
  ],
  "provenance": {
    "originUrl": "https://github.com/av1-community-contributors/codec-wiki/blob/37c3317fd058b23c71a87679bed5619a98f77752/docs/metrics/PSNR.mdx",
    "originCommit": "37c3317fd058b23c71a87679bed5619a98f77752",
    "migratedAt": "2026-08-21T00:00:00.000Z",
    "modified": true,
    "originPath": "docs/metrics/PSNR.mdx"
  },
  "headings": [
    {
      "depth": 2,
      "text": "What PSNR is good for, and what it isn't",
      "anchor": "what-psnr-is-good-for-and-what-it-isnt"
    },
    {
      "depth": 2,
      "text": "Measure PSNR with FFmpeg",
      "anchor": "measure-psnr-with-ffmpeg"
    },
    {
      "depth": 2,
      "text": "Read the numbers",
      "anchor": "read-the-numbers"
    }
  ],
  "sections": [
    {
      "id": "_preamble",
      "title": "Page introduction",
      "depth": 0,
      "canonicalUrl": "https://encode.wiki/reference/metrics/psnr/",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/reference/metrics/psnr/_preamble.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/reference/metrics/psnr/_preamble.md",
      "checksum": "bf68ac1350be85a54fe8d28b237949fb900d589608b87e7ae0798ff5aff69b42",
      "bytes": 452
    },
    {
      "id": "what-psnr-is-good-for-and-what-it-isnt",
      "title": "What PSNR is good for, and what it isn't",
      "depth": 2,
      "anchor": "what-psnr-is-good-for-and-what-it-isnt",
      "canonicalUrl": "https://encode.wiki/reference/metrics/psnr/#what-psnr-is-good-for-and-what-it-isnt",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/reference/metrics/psnr/what-psnr-is-good-for-and-what-it-isnt.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/reference/metrics/psnr/what-psnr-is-good-for-and-what-it-isnt.md",
      "checksum": "1ec278886e87b731e2abf9b9bdda09d3586efb53a952a88012833d4935a28a15",
      "bytes": 1636
    },
    {
      "id": "measure-psnr-with-ffmpeg",
      "title": "Measure PSNR with FFmpeg",
      "depth": 2,
      "anchor": "measure-psnr-with-ffmpeg",
      "canonicalUrl": "https://encode.wiki/reference/metrics/psnr/#measure-psnr-with-ffmpeg",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/reference/metrics/psnr/measure-psnr-with-ffmpeg.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/reference/metrics/psnr/measure-psnr-with-ffmpeg.md",
      "checksum": "d1c613cff5decbcc975db2961ce581c5a3065d14145f3a2661d3a69387bb40b4",
      "bytes": 1135
    },
    {
      "id": "read-the-numbers",
      "title": "Read the numbers",
      "depth": 2,
      "anchor": "read-the-numbers",
      "canonicalUrl": "https://encode.wiki/reference/metrics/psnr/#read-the-numbers",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/reference/metrics/psnr/read-the-numbers.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/reference/metrics/psnr/read-the-numbers.md",
      "checksum": "44e7ec925004e6e7657718754b8ea119a23e88f8e4174a8eedea4b135846c038",
      "bytes": 630
    }
  ],
  "outboundReferences": [
    "/guides/compare-encoding-quality/",
    "/reference/metrics/butteraugli/",
    "/reference/metrics/cvvdp/",
    "/reference/metrics/ssimulacra2/",
    "/reference/metrics/xpsnr/",
    "/start-here/psychovisual/"
  ],
  "checksum": "2c3328deb444d5c419f321a6bf961c74472d4ce892841d487106c262bb650443",
  "contentFormat": "markdown",
  "markdown": "PSNR (peak signal-to-noise ratio) is the mean squared error (MSE) between a reference and a distorted image, expressed in decibels relative to the largest possible sample value: `10 × log10(MAX² / MSE)`. Higher is better, and identical inputs score infinity. It is cheap and exact, which makes it the standard yardstick for codec development, but it rewards blur and ignores how the eye works, so it can't tell you which of two encodes looks better.\n\n## What PSNR is good for, and what it isn't\n\nPSNR is the classic metric for regression tests, conformance work and BD-rate figures in codec papers. It is also a good pipeline check: a PSNR far below what you expect usually means misaligned frames, an unintended scale, or a wrong colour range or matrix rather than a bad encode.\n\nIt is a poor judge of how an encode looks. Squared error treats every difference the same, whether it sits in flat sky or in busy foliage where nobody would notice it. A smooth approximation of grain or fine texture has lower squared error than a sharp reproduction that doesn't match the source pixel for pixel, so blur and denoising raise PSNR while the detail that psychovisual tuning keeps lowers it. On Cloudinary's CID22 image dataset, PSNR-Y's rank correlation with viewer scores is 0.62, against 0.88 for SSIMULACRA2.\n\nThis is why encodes tuned for PSNR (x264 and x265 `--tune psnr`, SVT-AV1 `--tune 1`, which is its default) look worse than psychovisually tuned encodes that score lower. x264 warns that `--psnr` results \"will be invalid\" when psy optimisations are on. Don't use PSNR to compare encoders or settings that use psychovisual tuning, or to decide whether an encode looks good enough.\n\nFor perceptual comparisons use [SSIMULACRA2](/reference/metrics/ssimulacra2/), [Butteraugli](/reference/metrics/butteraugli/), [XPSNR](/reference/metrics/xpsnr/) or [CVVDP](/reference/metrics/cvvdp/), and watch the video. See [Compare encoding quality](/guides/compare-encoding-quality/) for the full method. The reasoning behind psy tuning is on the [psychovisual](/start-here/psychovisual/) page.\n\n## Measure PSNR with FFmpeg\n\n```sh\nffmpeg -i distorted.mkv -i reference.mkv -lavfi psnr=stats_file=psnr.log -f null -\n```\n\nFFmpeg prints a summary at the end: PSNR per plane (`y`, `u`, `v`), an `average` over all planes, and the `min` and `max` frame. `psnr.log` has one line per frame with the MSE and PSNR of each plane.\n\n- PSNR is symmetric, but keep the distorted file first and the reference second. That is the order `ssim` and `libvmaf` expect too; [XPSNR](/reference/metrics/xpsnr/) is the exception.\n- Both inputs must have the same dimensions. If the encode was downscaled, scale it back to the reference size first: `-lavfi \"[0:v]scale=1920:1080:flags=bicubic[d];[d][1:v]psnr\"`.\n- A mismatched pixel format, such as a 10-bit encode of an 8-bit source, is converted automatically.\n- Only if one file starts at a non-zero timestamp (for example a clip cut from a longer stream), add `setpts=PTS-STARTPTS` to both inputs before the `psnr` filter.\n- Check that both files have the same frame count. FFmpeg won't complain if they don't: it repeats the last frame of the shorter input and keeps scoring until the longer one ends.\n\n## Read the numbers\n\nFFmpeg's per-plane and `average` summary figures are computed from the MSE averaged over all frames, then converted to dB. That differs slightly from averaging per-frame dB values, which some tools do, so compare numbers produced the same way. One identical frame does not make the summary infinite.\n\nCodec papers usually quote luma PSNR (`y`). FFmpeg's `average` weights the planes by pixel count, so with 4:2:0 luma makes up two-thirds of it.\n\nlibvmaf's `psnr` feature caps scores at 60 dB for 8-bit and 72 dB for 10-bit input, while FFmpeg's filter does not, so the two disagree for near-lossless encodes.\n"
}
