Skip to content

Chroma decoder guide

The Video Sink's Decoder Type setting separates a composite video signal into luma and chroma before it is written as colour video. This guide explains the built-in decoder choices, their trade-offs, and the controls that affect them. It applies to the Video Sink's decoder_type parameter; externally installed decoder stages document their own settings.

Chroma decoding cannot correct a wrong video standard, poor time-base correction, or a bad colour burst. Set the project format and input type correctly first, then compare decoder choices on representative material.

Start here

Input First choice When to try another choice
Composite PAL or PAL-M pal2d for a quick, robust baseline Compare transform2d and transform3d when colour/luma separation matters more than render time. For still pictures on a PAL disc that change every frame (maps, text, photographs), use palstill.
Composite NTSC ntsc2d Compare ntsc3d on static or slowly changing material where extra separation is worth the cost.
Separate Y/C pal2d for PAL/PAL-M; ntsc2d for NTSC The luma and chroma are already separate, so the composite comb/Transform distinction largely does not apply.
Genuinely monochrome composite mono Use a colour decoder only when the source actually carries a colour subcarrier.

The defaults are deliberately conservative: pal2d for PAL/PAL-M and ntsc2d for NTSC. They do not need temporal context and make a useful reference render before trying the more expensive 3D modes.

Composite and Y/C input

The PAL and NTSC decoder families are not interchangeable. Use the family matching the project video format; PAL-M uses the PAL-family choices.

The choices matter most for composite input, where luma and chroma occupy the same signal and must be separated. A separate Y/C source has already done that separation:

  • transform2d, transform3d and palstill cannot operate on Y/C input. The Video Sink changes any of them to pal2d when the export starts (the Decoder Type setting itself is switched to pal2d), and decodes any Transform ranges of a multiple schedule with pal2d too. The parameter description in the stage's parameter dialog says so when the input is Y/C.
  • The NTSC decoder's Y/C path skips the 1D, 2D, and 3D comb stages and demodulates the supplied chroma channel directly. Choosing ntsc1d, ntsc2d, ntsc3d, or ntsc3dnoadapt therefore does not select a different comb filter for Y/C input.

For Y/C, use the normal pal2d or ntsc2d setting and concentrate on burst quality, chroma_gain, chroma_phase, and noise reduction instead.

PAL and PAL-M decoders

Decoder What it does Use it when Trade-off
pal2d Uses the PALcolour two-dimensional FIR filter. This is a conventional PAL decoder rather than a Transform PAL filter. You need the default baseline, a quick render, or a tolerant option for a poor or non-standard signal. Less effective luma/chroma separation than the Transform filters on material that suits them.
transform2d Uses a frequency-domain Transform PAL filter within one field. It identifies chroma by its expected frequency-domain symmetry. You want Transform PAL separation without using information from other fields. It is the first Transform mode to compare against pal2d. Slower than pal2d; its result still depends on the current field's signal quality.
transform3d Extends the Transform PAL filter across multiple fields, adding temporal information to the frequency-domain separation. You are making a quality-focused render and have checked both still and moving scenes. The most expensive PAL option and needs surrounding fields. Motion, dropouts, or unstable colour can change its artefacts relative to transform2d; compare rather than assuming it always wins.
palstill A specialist decoder for still pictures (photographs, maps, text). It decodes each frame from its own two fields as one picture: Transform PAL on the woven frame, then an edge-preserving vertical colour estimate, and the colour it cannot explain handed back to the luma. PAL projects only. Each frame is a different still picture, on screen for only that frame, as on most of the BBC Domesday discs. Not for moving video (comb-like edges) or for pictures held over many frames (transform3d does better there). About 2.6 times transform2d's decode time (44 ms a frame on one core, against 17 ms).

Transform PAL separates likely chroma before the PAL decoder reconstructs U/V. It is normally the quality-oriented path. transform3d can retain more useful colour detail on stable content, while transform2d avoids relying on temporal similarity. Neither Transform mode is available for Y/C input.

PAL Still

In short: palstill is a specialist decoder for still pictures on PAL discs: photographs, maps, diagrams and pages of text. Use it on frames that show a picture that does not move and that is on screen for only that one frame. Do not use it for moving video, or for a picture that stays on screen for many frames.

What counts as a still

A frame of video is made of two fields, captured one after the other. For this decoder, a frame is a still when:

  • nothing in the picture moves between its two fields, and
  • the frames just before and just after it show different, unrelated pictures.

This is how the BBC Domesday discs store most of their maps, photographs and text pages: one picture per frame, each followed straight away by the next. Videodisc picture archives, slide collections and catalogue discs are often made the same way.

Which decoder for which kind of frame

What the frame shows Best decoder Why
A still, shown for just this one frame palstill It gets the most out of the one frame there is.
A picture held on screen for several frames transform3d It can combine the repeated copies, which palstill cannot.
Moving video, including film transform3d (or transform2d) Consecutive frames are related, which transform3d uses. palstill expects the picture to keep still, so interlaced motion comes out with jagged, comb-like edges.

Poor results on moving video or held pictures are expected, not a fault: those frames are meant for another decoder. A disc that mixes the three kinds of material can use a different decoder for each, chosen automatically where the Stacker can tell them apart (see Different decoders for different frames).

What it improves

Compared with pal2d and transform2d on stills, palstill gives:

  • sharper, more accurate colour, with fewer smeared or shifted colour edges;
  • far less false colour (coloured fringes and rainbow patterns) on fine detail such as text, map lines and hatching;
  • crisper map lines and lettering;
  • no row of dots ("||||") along sharp edges between strong colours, such as green against magenta.

It is slower: about 2.6 times the decode time of transform2d.

How it works

palstill treats the frame's two fields as one picture. In the woven frame each line sits between two lines of the other field, and PAL's colour carrier is arranged so that the colour and the luma's fine detail are far easier to tell apart there than within one field. In particular, at a sharp edge between green and magenta, transform2d mistakes part of the colour for luma and leaves a row of dots ("||||"). palstill does not.

After separating the colour it estimates U and V down each column with a fit that keeps colour edges sharp, but smooths the colour where the luma has fine detail that could leak into it. The colour it cannot explain goes back to the luma, which sharpens map lines and lettering.

On videosynth's test stills (with the Domesday capture noise, scored against the source picture):

Still Measure pal2d transform2d palstill
Photograph (butterfly) ΔE 2.60 2.44 1.77
Town map ΔE 5.44 4.83 3.48
Rural map ΔE 4.91 4.85 3.35
Text card cross-colour 4.57 % 2.53 % 1.25 %
Luma zone plate cross-colour 12.29 % 3.57 % 2.47 %
Test Card F cross-colour 1.69 % 0.93 % 0.36 %
Green/magenta edges ΔE 15.90 20.47 3.81

Its limits:

  • Motion. It assumes the picture is the same in both fields. Where it moves between them, the woven frame is combed and so is the decode. Use it for stills, and decode held pictures and motion with another decoder through a schedule (below).
  • Single-line colour. Colour stripes one line high are beyond what any smooth colour estimate follows, and are softened.
  • The line-alternating error. A player or master that leaks V into U, or shifts the colour against the burst, makes alternate lines differ in hue. pal2d averages the two lines, but palstill keeps vertical colour detail and has to correct it. On Domesday discs most of the error is a turn of the colour that belongs to each still, and the decoder measures and corrects that turn on every frame by itself, from the frame's own flat colour. A frame with too little flat colour is left uncorrected. A leak of V into U from the player is not corrected. It is small on the discs measured, but it shows on held colour bars.
  • Clean, stacked sources. On a low-noise stack of several captures, transform2d can be slightly more accurate on dense maps and on photographs with fine luma detail (by about 0.2 ΔE). On a single capture palstill is ahead on both.
  • No burst. A frame whose burst is under a quarter of the nominal level decodes as monochrome: no colour, and the composite as its luma.
  • PAL composite only: not PAL-M and not Y/C.

transform_threshold applies to it as to the Transform modes; simple_pal does not.

Simple PAL

simple_pal applies only to transform2d and transform3d. It replaces the normal PALcolour two-dimensional U/V post-filter with a one-dimensional UV filter.

  • Leave it off for the normal Transform PAL result.
  • Turn it on only when the source's PAL phase is stable and preserving vertical colour detail is more important than phase-error tolerance.
  • Turn it back off if adjacent lines acquire different hues (Hanover bars) or the colour becomes less stable.

It is not a faster substitute for pal2d, and it has no effect with that decoder.

Transform threshold

transform_threshold controls how closely two reflected frequency components must match before Transform PAL keeps them as chroma. The range is 0.0 to 1.0 and the default is 0.4. Higher values are more selective: fewer components qualify as chroma. It is offered only for transform2d, transform3d, palstill and multiple.

Leave it at the default unless a comparison exposes a specific problem:

  • Raise it cautiously when noise or picture detail is being classified as chroma, producing false colour.
  • Lower it cautiously when valid, fine chroma is being rejected.

Check saturation, coloured edges, and fine repeating detail after every change; this is a similarity test, not a general quality control.

SECAM decoder

SECAM sources are stored as PAL: the CVBS format and ld-decode-family TBCs have no SECAM system, and SECAM shares the 625-line, 50 Hz structure and the PAL 4fsc sampling. Select secam in a PAL project to decode them; it is not offered in PAL-M or NTSC projects, and the decoder refuses any source that is not 625-line PAL.

Decoder What it does Use it when Trade-off
secam Band-pass separates the subcarrier, undoes the high-frequency "bell" precorrection, FM-demodulates each line, converts frequency to D'R or D'B, undoes the low-frequency precorrection, and takes the missing colour difference from the neighbouring lines of the same field (ITU-R BT.1700 Annex 1 Part C). The source is SECAM, e.g. a SECAM capture stored as PAL, like from the vhs-decode project. Or a videosynth project with chroma_encoding: SECAM (which is not implemented yet, but might be available in a future release). Luma loses the 3.3–5.4 MHz band where the SECAM subcarrier sits; fine luma detail in that band shows as false colour unless secam_cross_colour_suppression is enabled; vertical colour resolution is halved, as in any SECAM receiver.

Which lines carry D'R and which D'B is detected per field from the undeviated subcarrier on the back porch (line identification, BT.1700 Part C item 13): 4.40625 MHz on D'R lines, 4.25 MHz on D'B lines. A field without a usable reference is decoded without colour.

With secam_field_identification (on by default) the decision is taken from the field identification lines instead (frame lines 7–15 and 320–328, BT.1700 Part C item 13): their trapezoid starts at the rest frequency just after line blanking and settles at +350 kHz on D'R lines and −350 kHz on D'B lines. Only lines with that ramp shape count, so picture or data content on those lines cannot pose as identification signals. This also decodes sources whose back-porch reference is missing or damaged. Fields without usable identification signals — only sources that keep the vertical interval carry them, and they are often stripped in programme exchange — fall back to the back-porch reference. Turn it off to rely on the back-porch reference alone.

Cross-colour — fine luma detail at the subcarrier frequency decoding as colour — can be reduced in three ways (see the switch below). Chroma is taken through a tight 3.75–4.95 MHz band-pass, while luma has its own wider 3.3–5.4 MHz band-stop so no subcarrier residue remains in the picture. Where the demodulated subcarrier envelope departs from the field's typical level by more than a factor of 1.3 (fully suppressed at 1.8), or its frequency leaves the 3.9–4.756 MHz range SECAM allows, the colour there is faded out, because an intact FM subcarrier has a constant envelope and stays within that range. Finally the decoded colour difference is band-limited to 1.3 MHz.

The first two measures are switched by secam_cross_colour_suppression, which is off by default: the decoder then uses the plain wide band-pass, keeping genuine colour on very fine detail but showing cross-colour. Turn it on when fine luma detail produces false colour; the 1.3 MHz band limit always applies.

SECAM temporal chroma

Every SECAM line carries only one colour difference, D'R or D'B, so the other one has to come from somewhere else. A frame has 625 lines, an odd number, so every line swaps between D'R and D'B from one frame to the next. Taking the missing component from the lines above and below therefore locates a horizontal colour edge only to within one line, and in alternate frames on opposite sides: strongly red or blue edges visibly jump up and down by a line every two fields (for example on a 75 % bars-over-red test pattern).

secam_temporal_chroma (on by default) removes this: where the luma shows the picture has not changed since the previous frame, the missing component is taken from the same line of that frame, which carried it. Moving areas fall back to the neighbouring lines. Turn it off if motion produces colour trails, or to halve the SECAM decoding time.

chroma_gain scales the decoded colour and noise_reduction applies as usual; chroma_phase has no meaning for FM chroma and is ignored.

NTSC decoders

Decoder What it does Use it when Trade-off
ntsc1d Uses a line-local band-pass separation. It cannot distinguish luma detail at the subcarrier frequency from chroma very well. Diagnostic renders, rapid comparisons, or a fallback when no spatial/temporal comparison is wanted. Usually the weakest colour quality: dot crawl and cross-colour/luma leakage are expected.
ntsc2d Uses an adaptive three-line comb within the field, comparing the neighbouring lines before blending them. The general starting point and the current NTSC default. It gives a substantial improvement over 1D without temporal processing. Cannot use matching information from adjacent fields or frames.
ntsc3d Builds on the 1D and 2D results, then adaptively selects the best matching candidate from nearby lines, fields, and frames. Static or slowly changing content, animation, and quality-focused renders where the additional compute cost is acceptable. Requires surrounding frames and is slower. The adaptive chooser is designed to avoid bad temporal matches, but moving material must still be checked for artefacts.
ntsc3dnoadapt Performs 3D separation against the previous frame without the adaptive candidate selection. Controlled comparisons, debugging, or unusually stable content where you intentionally want the fixed previous-frame behaviour. Motion or a bad previous frame can turn luma differences into colour artefacts. It is not the normal quality choice.

The 3D mode does not blindly average whole frames. For each sample, the adaptive mode evaluates spatial and temporal candidates and can retain the 2D result when it is the better match. ntsc3dnoadapt disables that protection and always uses the previous-frame candidate.

NTSC 3D controls

Both controls are offered only in NTSC projects, range from 0.0 to 10.0, and default to 1.0.

adapt_threshold applies only to ntsc3d. Higher values strengthen the candidate selector's bias toward non-1D candidates, including candidates from nearby fields and frames. Keep the default 1.0 initially. Lower it if a comparison suggests that motion is being treated as temporally similar; increase it only when representative moving material remains clean and the extra temporal separation is visibly useful.

chroma_weight is an advanced implementation control, not a saturation control. In the current adaptive implementation it scales the same spatial/temporal candidate preference used by adapt_threshold, so raising it has the same effect as raising adapt_threshold: line, field and frame candidates are favoured more strongly over the same-line 1D ones. It is best left at its default 1.0 unless you are comparing renders on both static and moving material. It has no practical effect with ntsc3dnoadapt, because that mode bypasses candidate selection and always chooses the previous frame.

Shared controls

Control Applies to What it changes Practical guidance
chroma_gain PAL, SECAM and NTSC colour decoders Multiplies the decoded chroma components, changing saturation. Range 0.0–10.0, default 1.0. Start at 1.0. Adjust only after decoder selection; it cannot fix false colour or bad separation.
chroma_phase PAL and NTSC colour decoders (ignored by secam) Rotates the chroma reference, changing hue. Range −180 to 180 degrees, default 0.0. Use small, global corrections after confirming the input standard. It cannot repair hue errors that vary across the picture.
noise_reduction All built-in decoder paths Range 0.0–12.0 dB. Picture that stays the same from frame to frame is averaged over successive frames, while moving picture, cuts and a disc of stills (every frame a different picture) are smoothed within each frame instead, unless noise_reduction_mode is still_only. Default 0.0 is off. On film and video, start at 6 and raise it while the still areas stay free of trails behind slow, low-contrast movement; noise_reduction_motion below 1 protects such movement. On a disc of stills every frame gets the within-frame filter only, which tops out near 6 dB, so a higher setting changes nothing there.
noise_reduction_mode All built-in decoder paths, when noise_reduction is above 0 full (default) or still_only. still_only keeps the averaging over frames where the picture is held and drops the within-frame filter, so moving picture, cuts and single-frame stills are left as decoded. Use still_only on a disc of stills whose stills you want untouched: held title and test cards are still cleaned. Fed from a Stacker with still_frame_stacking, it averages only the frames the Stacker found repeated.
noise_reduction_motion All built-in decoder paths, when noise_reduction is above 0 Multiplies the motion thresholds that decide what counts as still picture. Range 0.5–4.0, default 1.0. Above 1 treats more change as still (more averaging, more risk of trails); below 1 the reverse. Leave at 1.0; lower it if slow, low-contrast movement leaves trails.
ntsc_phase_comp NTSC colour decoders (offered only in NTSC projects) Measures the burst phase on each line and uses it while demodulating chroma. Enabled by default. Keep it on unless an A/B comparison on the actual source shows more stable colour without it; it is especially relevant when NTSC phase alignment varies.

mono does not use chroma gain or phase. Its current Video Sink configuration passes the composite signal through as luma; it does not enable a separate chroma-removal notch filter. It is therefore intended for monochrome sources or diagnosis, not simply as a way to desaturate a colour composite source.

Noise reduction limits

  • The frame-to-frame average is recursive: each output frame carries part of the one before it. Movement too faint to be told apart from noise, such as a slow fade or a dim edge drifting across a dark background, is averaged as if it were still, so it lags slightly behind for a few frames. Lower noise_reduction_motion if a trail is visible.
  • The within-frame filter reaches just under 6 dB. Above that setting, still areas keep getting cleaner while moving areas, cuts and stills stay where they were, so on busy footage the moving parts of the picture look noisier than the still parts.
  • The within-frame filter takes its noise level from the picture itself, so a densely detailed still, such as a map or a page of fine print, reads as noisier than it is and loses a little of its finest low-contrast lines.
  • For other kinds of noise reduction, the FFmpeg denoisers (for example hqdn3d or nlmeans) remain available through video_filter in FFmpeg output mode, with or without this control.

Different decoders for different frames

Some sources mix material that suits different decoders. A LaserDisc such as Domesday has motion sequences, where transform3d separates best, alongside long runs of single-frame stills, where palstill (or transform2d) avoids blending information from the unrelated pictures either side.

Set Decoder Type to multiple and give the ranges in Decoder Schedule:

transform3d, 1001-1500:transform2d, 2001-2400:transform2d
  • Each entry is first-last:decoder, or first:decoder for one frame. Frame numbers are those of the frames fed to the Video Sink, 1-based as in the preview.
  • A decoder without a range — transform3d above — decodes every frame the ranges do not list. Without one, every frame must be inside a range, or the export is refused before it starts.
  • Entries may come in any order, but ranges cannot overlap and at most one decoder may be given without a range. The parameter dialog accepts only the decoders the Decoder Type list offers for the project (not multiple). A schedule that cannot be parsed keeps the node's status yellow, and a decoder that does not suit the source (for example in a hand-edited project file) is refused when the export starts, before anything is written.
  • Each frame is decoded exactly as an export with its decoder alone would decode it, including that decoder's surrounding-field context. The preview shows each frame with its scheduled decoder.
  • The decoder-specific controls (transform_threshold, simple_pal, the SECAM and NTSC 3D settings) stay available and apply to every range using that decoder. noise_reduction runs over the whole output, across range boundaries.

Use the preview to find where the material changes, then check a few frames either side of each boundary in the export.

On a disc stacked with the Stacker's still_frame_stacking, the schedule can follow the pictures instead of hand-written ranges:

palstill, held:transform3d

The Stacker reports, frame by frame, how long each picture is held, from the repeats it stacks. held: decodes a frame with its decoder only where the picture is held for at least as many frames either side as that decoder reads (4 for transform3d), so the 3D filter never mixes two pictures, and every other frame, single-frame stills included, takes the default. Ranges still win, so a range can overrule it where the Stacker's view is wrong.

That default also takes any motion the Stacker does not report as held. Give film and video motion a range with transform3d: consecutive frames of moving footage are related, and transform3d uses them. Left with palstill:

  • Film, whose two fields are one instant, is not combed, but loses what transform3d gains from the neighbouring frames.
  • Slow interlaced motion (2 samples a field) costs it little.
  • Faster interlaced motion: by 8 samples a field it is level with transform2d and worse in its worst places, and by 24 it is the worst of the 2D decoders.

On the Domesday sides this matters mostly on National B, a third of which is video motion; give such stretches, and any film sequences, a transform3d range.

A repeatable comparison

  1. Keep the source, Video Parameters, output format, and all tuning controls unchanged; begin with noise_reduction at 0.0.
  2. Render a short section containing fine coloured detail, sharp luma edges, a still shot, and motion. A decoder that is best on a title card may be poor on moving live footage.
  3. Compare pal2d against both Transform modes for PAL/PAL-M (and palstill on single-frame stills), or ntsc2d against ntsc3d for NTSC. Check for false colour, dot crawl, colour bleed, and lost detail at the same locations.
  4. Choose the decoder first. Then correct global saturation and hue with chroma_gain and chroma_phase, and add the minimum necessary noise_reduction.
  5. Record the chosen decoder and non-default controls in the project. A different capture of the same programme can need a different choice.