{
  "schemaVersion": 1,
  "contentVersion": "ca42e61ede0a24f789d7287a0001244ad22f4abf",
  "id": "docs/tools/filtering/graining",
  "collection": "docs",
  "title": "Graining",
  "description": "Adding grain back after filtering, either as pixels with vs-jetpack or FFmpeg, or as AV1 film grain synthesis in SVT-AV1 and aomenc.",
  "canonicalUrl": "https://encode.wiki/tools/filtering/graining/",
  "apiUrl": "https://encode.wiki/api/v1/documents/docs/tools/filtering/graining.json",
  "markdownUrl": "https://encode.wiki/api/v1/markdown/docs/tools/filtering/graining.md",
  "status": "current",
  "tags": [
    "migrated"
  ],
  "license": "CC BY-SA 4.0",
  "dates": {
    "lastVerified": "2026-10-08T00:00:00.000Z"
  },
  "authors": [],
  "sources": [
    {
      "title": "SVT-AV1 v4.2.0 parameter reference",
      "url": "https://gitlab.com/AOMediaCodec/SVT-AV1/-/blob/v4.2.0/Docs/Parameters.md",
      "accessedAt": "2026-10-08T00:00:00.000Z"
    },
    {
      "title": "FFmpeg noise filter documentation",
      "url": "https://ffmpeg.org/ffmpeg-filters.html#noise",
      "accessedAt": "2026-10-08T00:00:00.000Z"
    },
    {
      "title": "vs-jetpack v2.2.6",
      "url": "https://github.com/Jaded-Encoding-Thaumaturgy/vs-jetpack/tree/v2.2.6",
      "accessedAt": "2026-10-08T00:00:00.000Z"
    }
  ],
  "provenance": {
    "originUrl": "https://github.com/av1-community-contributors/codec-wiki/blob/37c3317fd058b23c71a87679bed5619a98f77752/docs/filtering/graining.mdx",
    "originCommit": "37c3317fd058b23c71a87679bed5619a98f77752",
    "migratedAt": "2026-08-21T00:00:00.000Z",
    "modified": true,
    "originPath": "docs/filtering/graining.mdx"
  },
  "headings": [
    {
      "depth": 2,
      "text": "Why add grain",
      "anchor": "why-add-grain"
    },
    {
      "depth": 2,
      "text": "Adding grain as pixels",
      "anchor": "adding-grain-as-pixels"
    },
    {
      "depth": 2,
      "text": "AV1 film grain synthesis",
      "anchor": "av1-film-grain-synthesis"
    }
  ],
  "sections": [
    {
      "id": "_preamble",
      "title": "Page introduction",
      "depth": 0,
      "canonicalUrl": "https://encode.wiki/tools/filtering/graining/",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/tools/filtering/graining/_preamble.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/tools/filtering/graining/_preamble.md",
      "checksum": "0d4fb2c50e8bde6cef0f42b815b9f8ca1a2c3aefe52d09ad920b5be02fdca1e4",
      "bytes": 1142
    },
    {
      "id": "why-add-grain",
      "title": "Why add grain",
      "depth": 2,
      "anchor": "why-add-grain",
      "canonicalUrl": "https://encode.wiki/tools/filtering/graining/#why-add-grain",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/tools/filtering/graining/why-add-grain.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/tools/filtering/graining/why-add-grain.md",
      "checksum": "1f1e003cc5bd6010046ea12768cc155a584d693db109695dce22d1f72a825fa1",
      "bytes": 588
    },
    {
      "id": "adding-grain-as-pixels",
      "title": "Adding grain as pixels",
      "depth": 2,
      "anchor": "adding-grain-as-pixels",
      "canonicalUrl": "https://encode.wiki/tools/filtering/graining/#adding-grain-as-pixels",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/tools/filtering/graining/adding-grain-as-pixels.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/tools/filtering/graining/adding-grain-as-pixels.md",
      "checksum": "11b6a5e7bb25c8ed51ff661ec2a3f5ba087b03c6afee37152ea58a5ac54a970d",
      "bytes": 997
    },
    {
      "id": "av1-film-grain-synthesis",
      "title": "AV1 film grain synthesis",
      "depth": 2,
      "anchor": "av1-film-grain-synthesis",
      "canonicalUrl": "https://encode.wiki/tools/filtering/graining/#av1-film-grain-synthesis",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/tools/filtering/graining/av1-film-grain-synthesis.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/tools/filtering/graining/av1-film-grain-synthesis.md",
      "checksum": "2fdce17aa0114e5e814f2ede81c289c5c2a7db52334d200bfc9c1114e2778355",
      "bytes": 2842
    }
  ],
  "outboundReferences": [
    "/tools/filtering/deband/",
    "/tools/filtering/denoise/",
    "/tools/filtering/vapoursynth/",
    "/tools/software-encoders/svt-av1/"
  ],
  "checksum": "544a94c46e85950d1ec2f15518262d7270a4cac9c4d747a42996a6fcb75ad2b0",
  "contentFormat": "markdown",
  "markdown": "Grain is a texture, and there are three separate things you might do with it:\n\n| Approach                 | What happens                                                                                            | Cost                                                                      |\n| ------------------------ | ------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- |\n| Keep the source grain    | The encoder codes the noise as it is                                                                    | A lot of bitrate on grainy sources                                        |\n| Add grain as pixels      | You add noise in the filter chain, and the encoder codes it                                             | Bitrate, since the added noise has to be coded like any other             |\n| AV1 film grain synthesis | The encoder writes a small grain model into the stream, and the decoder generates matching grain on playback | Little bitrate, and the grain is statistical rather than the original pixels |\n\n## Why add grain\n\nAfter [denoising](/tools/filtering/denoise/) or [debanding](/tools/filtering/deband/) the picture can look plastic, and smooth gradients are exactly what an encoder re-quantises into [bands](/tools/filtering/deband/). A little fresh grain restores texture and breaks up banding. Adding grain also gives you a way to reintroduce a film look in an encoder such as x264 or x265 that can't signal synthetic grain, at the price of the bitrate to encode it.\n\nGrain is added near the end of the chain, after everything else and before the final dither to the output bit depth.\n\n## Adding grain as pixels\n\nIn VapourSynth, `Grainer` from `vsdeband` (part of [vs-jetpack](/tools/filtering/vapoursynth/)) offers several noise types, including Gaussian, Perlin, Simplex and Poisson:\n\n```python\nfrom vsdeband import Grainer\n\nclip = Grainer.GAUSS(clip, strength=0.5, luma_scaling=10)\n```\n\n`strength` can be a pair for luma and chroma. `luma_scaling` reduces grain in brighter areas. `static=True` repeats one grain pattern on every frame, `temporal` smooths the grain across frames, and `scale` makes it coarser. Pixel values near the limits of the legal range are protected by default.\n\nIn FFmpeg, the `noise` filter is the simple option. `alls` is the strength on all planes, `t` makes the pattern change every frame (without it the same noise repeats on every frame), and `u` makes it uniform instead of Gaussian:\n\n```sh\nffmpeg -i input.mkv -vf \"noise=alls=3:allf=t+u\" -c:v libx264 -crf 18 output.mkv\n```\n\nCoarse grain is expensive to encode, so add no more than the look needs.\n\n## AV1 film grain synthesis\n\nAV1 can signal a grain model in the bitstream and have the decoder add the grain. The encoder estimates the grain by comparing the source with a denoised copy and writes the model into the stream; the decoder applies grain on top of the decoded picture. What gets encoded differs: aomenc encodes the denoised frames by default, while SVT-AV1 by default encodes the original source and only adds the model (`--film-grain-denoise 0`). On a heavy-grain source this can save a large share of the bitrate.\n\n**SVT-AV1** enables it with `--film-grain`:\n\n```sh\nSvtAv1EncApp -i input.y4m --crf 30 --preset 6 --film-grain 8 -b output.ivf\n```\n\n| Option                      | Meaning                                                                                                                                                              |\n| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `--film-grain 0-50`         | 0 is off; 1-50 is the level of denoising for film grain.                                                                                                             |\n| `--film-grain-denoise 0/1`  | With 0 (the default) the source is not denoised and the grain data is still written to the stream; with 1 the source is denoised at the level set by `--film-grain`. |\n| `--fgs-table FILE`          | Path to a pre-generated film grain table to use for synthesis.                                                                                                       |\n| `--adaptive-film-grain 0/1` | Vary the grain block size with resolution; on by default.                                                                                                            |\n\n**aomenc** has `--denoise-noise-level` (0-50, where 0 disables denoising), `--enable-dnl-denoising` and `--film-grain-table` for a grain table file.\n\nSome practical points:\n\n- Grain synthesis happens in the decoder. dav1d applies it by default (its `--filmgrain` option can turn it off), but a player or hardware decoder that ignores grain data will show a clean image.\n- The grain is a statistical match to the original, not a copy of it. That is the intent, and the reason full-reference metrics score a grain-synthesised encode lower than a plain one even when it looks closer to the source; compare by eye, or with grain disabled.\n- Don't stack sources of grain. If you use synthesis, don't also add pixel grain to the input, and if you add pixel grain, turn denoising and synthesis off.\n- Stronger denoising removes more detail along with the grain; compare faces and textures against the source.\n\nSee [SVT-AV1](/tools/software-encoders/svt-av1/) for the encoder's other options.\n"
}
