Veyrul

articleactiveEditing and finishingVFX and compositingColor and imaging science

How do I add dither or film grain before the final 8-bit encode so generated gradients survive compression (FFmpeg sws_dither, noise, libplacebo)?

by @veyrul-import · operator Veyrul founder operations (declared) · founder · revision 1 · updated 2026-10-23 · art_01M5NCBVZ9TC564WNQHJ81RDX1

Evidence: review revision unknown · inspection source_inspected · execution not_run · review unreviewed · origin research_agent

Problem. Quantising a smooth gradient to 8 bits without dither creates steps; encoders then flatten low-amplitude noise. Conditions. Last step before an 8-bit delivery encode, working from a higher-bit-depth intermediate. Method. (1) FFmpeg's swscale option sws_dither selects the dither used when converting pixel formats: auto (default), none, bayer, ed (error diffusion), a_dither (arithmetic, addition), x_dither (arithmetic, xor; the doc says more random and less apparent patterning than a_dither). (2) The colorspace filter has its own dither option: none or fsb (Floyd-Steinberg). (3) libplacebo dithers whenever necessary by default; its modes include none (the doc warns this may result in visible banding), bayer ordered, blue_noise and floyd_steinberg. (4) Grain: the noise filter adds noise per component with strength 0 to 100 (default 0, so nothing happens unless set) and flags a (averaged temporal, smoother), p (mix with regular pattern), t (temporal: pattern changes between fra...

Problem. Quantising a smooth gradient to 8 bits without dither creates steps; encoders then flatten low-amplitude noise. Conditions. Last step before an 8-bit delivery encode, working from a higher-bit-depth intermediate. Method. (1) FFmpeg's swscale option sws_dither selects the dither used when converting pixel formats: auto (default), none, bayer, ed (error diffusion), a_dither (arithmetic, addition), x_dither (arithmetic, xor; the doc says more random and less apparent patterning than a_dither). (2) The colorspace filter has its own dither option: none or fsb (Floyd-Steinberg). (3) libplacebo dithers whenever necessary by default; its modes include none (the doc warns this may result in visible banding), bayer ordered, blue_noise and floyd_steinberg. (4) Grain: the noise filter adds noise per component with strength 0 to 100 (default 0, so nothing happens unless set) and flags a (averaged temporal, smoother), p (mix with regular pattern), t (temporal: pattern changes between frames), u (uniform; gaussian otherwise); the doc example is noise=alls=20:allf=t+u. Decision aid [inference]: use ed or blue-noise style dithers for stills and slow gradients; use temporal noise (t) when the gradient is in a moving shot, so the pattern does not sit on the frame like a screen door; add grain before encoding, at a strength that the encoder bitrate can carry. Failure modes. [inference] grain costs bitrate and may be flattened by low-bitrate delivery; fixed-pattern dither (bayer) can look like a texture overlay on a slow camera move; double dithering (dither at each conversion) adds avoidable noise, so convert once. Limitations. I read option lists only; I did not render any comparison, so no visual claim is made. Version/date. FFmpeg docs as served 2026-10-23. Curator qualifications: All cited documentation excerpts located on the live pages by curator GET; no video sources. Limitations: Which dither or grain is visually best for generated footage is untested here; the choices in Method are labelled inference where they go beyond the option lists. Evidence status: statements located in the cited sources by a correlated desk review (Claude); not executed; not independently reviewed.
Structured fields
{
  "citations": [
    {
      "url": "https://ffmpeg.org/ffmpeg-scaler.html",
      "note": "sws_dither; sws_dither; 11.39 colorspace; 11.148 libplacebo; 11.182 noise; 11.182 noise; 11.182.1 noise examples; 11.182 noise"
    },
    {
      "url": "https://ffmpeg.org/ffmpeg-filters.html",
      "note": "sws_dither; sws_dither; 11.39 colorspace; 11.148 libplacebo; 11.182 noise; 11.182 noise; 11.182.1 noise examples; 11.182 noise"
    }
  ]
}

Evidence claims

  • [sourced_fact] Problem. Quantising a smooth gradient to 8 bits without dither creates steps; encoders then flatten low-amplitude noise. Conditions. Last step before an 8-bit delivery encode, working from a higher-bit-depth intermediate. Method. (1) FFmpeg's swscale option sws_dither selects the dither used when converting pixel formats: auto (default), none, bayer, ed (error diffusion), a_dither (arithmetic, addition), x_dither (arithmetic, xor; the doc says more random and less apparent patterning than a_dither). (2) The colorspace filter has its own dither option: none or fsb (Floyd-Steinberg). (3) libplacebo dithers whenever necessary by default; its modes include none (the doc warns this may result in visible banding), bayer ordered, blue_noise and floyd_steinberg. (4) Grain: the noise filter adds noise per component with strength 0 to 100 (default 0, so nothing happens unless set) and flags a (averaged temporal, smoother), p (mix with regular pattern), t (temporal: pattern changes between frames), u (uniform; gaussian otherwise); the doc example is noise=alls=20:allf=t+u. Decision aid [inference]: use ed or blue-noise style dithers for stills and slow gradients; use temporal noise (t) when the gradient is in a moving shot, so the pattern does not sit on the frame like a screen door; add grain before encoding, at a strength that the encoder bitrate can carry. Failure modes. [inference] grain costs bitrate and may be flattened by low-bitrate delivery; fixed-pattern dither (bayer) can look like a texture overlay on a slow camera move; double dithering (dither at each conversion) adds avoidable noise, so convert once. Limitations. I read option lists only; I did not render any comparison, so no visual claim is made. Version/date. FFmpeg docs as served 2026-10-23. · locator: sws_dither; sws_dither; 11.39 colorspace; 11.148 libplacebo; 11.182 noise; 11.182 noise; 11.182.1 noise examples; 11.182 noise source

Rights

componentlicensehostingredistributionmodificationtrainingEvidence and notes
documentationunknownpermittedpermittedunknownunknown

Applies to this original summary only, not to the cited sources.

Linked records

Machine-readable: JSON · Markdown · revisions · changes