Skip to content

sections

The ordered timeline. Required, and must contain at least one entry. Sections play back to back in declaration order, and their frame counts sum to the length of the output.

sections:
  - name: Programme
    type: progressive
    source: "{bundled}/exr/720x576/100_BARS.exr"
    duration_frames: 250
    start_frame: 0
    laserdisc: {area: programme_area}
    osd: {}
    noise: {}
    dropouts: {}
    audio: {}

Keys

Key Type Required Values Default
name string No — empty
type string Yes progressive —
source string Yes Path, optionally with an asset root token —
duration_frames int or string No Positive integer, or "all" "all"
duration_repeat int No Positive integer 1
start_frame int No ≥ 0, inside the video source 0
end_frame int No ≥ start_frame, inside the video source last source frame
cadence map No field cadence video cadence
laserdisc map No section laserdisc — disc area and biphase codes (LaserDisc projects only) absent
line_injections list No vitc only, not implemented — see section laserdisc absent
horizontal_resample string No nearest, bandlimited (horizontal mapping) nearest
chroma_line_sign list No chroma line sign regions (PAL and PAL-M) absent
luma_bandwidth map No luma bandwidth limit absent
picture_response string or map No domesday, or a map of picture response curves absent
osd map No osd absent
noise map No noise absent
dropouts map No dropouts absent
audio map No audio absent

No other key is accepted.

name

Identifies the section in the GUI list, in log messages, in validation errors, and in the {section_name} OSD token. It is not required, and names need not be unique, but a unique name for every section is considerably easier to work with.

type

Must be progressive. This is the only implemented section type: a progressive source file converted to an interlaced signal.

source

The picture content. Must resolve to an existing file that matches a supported progressive profile:

  • EXR (.exr) — single-frame scanline OpenEXR, R/G/B FLOAT, uncompressed, full-raster windows, standard-matching frame-rate and pixel-aspect metadata.
  • Video (.mkv Matroska or .mp4 MP4) — any FFmpeg-decodable codec at a constant frame rate of 25 (PAL/SECAM) or 30000/1001 (NTSC/PAL-M). Colour range, matrix, chroma format and bit depth are normalised to BT.601 10-bit 4:2:2 studio swing; field order and sample aspect mismatches are warnings.

The raster must be exactly 720×576 (PAL/SECAM) or 720×486 (NTSC/PAL-M). There is no scaling or frame-rate conversion; a source of any other size or rate is rejected. See Picture sources.

Use {bundled}/… for shipped assets and {project}/… for files beside the project. A bare relative path resolves against the working directory in the CLI but against the project directory in the GUI, so it will not behave the same in both.

duration_frames

How many output frames the section produces.

  • A positive integer — exactly that many. A still is repeated. A clip plays from start_frame; a count longer than the rest of the clip loops it, restarting at start_frame after the last frame.
  • "all" — the selected range once: [start_frame, end_frame], or [start_frame, last frame] without an end_frame. The clip's length is discovered by probing.

Omitting duration_frames means "all". The emitter always writes the key out, so a saved project shows duration_frames: all. An EXR still needs an integer: it has no length of its own.

duration_repeat

With duration_frames: "all", plays the selected range this many times. Total output frames = range length × duration_repeat; each replay restarts at start_frame.

Ignored with a fixed integer duration_frames, and a warning is emitted if you set it to anything other than 1 there. The emitter writes it only alongside duration_frames: all, so a saved project drops an ignored duration_repeat.

start_frame

The first source frame of the selected range, 0-based. Video sources only; it must be below the clip's frame count.

end_frame

The last source frame of the selected range, 0-based and inclusive. Video sources only; it must be at least start_frame and below the clip's frame count. Omit it to run to the end of the clip.

- name: Excerpt
  type: progressive
  source: "{project}/capture.mp4"
  start_frame: 1500
  end_frame: 2999        # 1 500 frames; duration derived

end_frame sets the section's length, so it cannot be combined with an integer duration_frames; leave duration_frames out (or set it to "all"), and use duration_repeat to play the range more than once. Emitted only when set.

cadence

How the section's source frames map onto output fields. Optional — omit it for the native video cadence, where each source frame becomes one frame's two fields.

- name: Feature
  type: progressive
  source: "{project}/film_23976.mkv"
  cadence:
    pattern: "2:3"
    phase: A
    continuity: restart
Key Type Required Values Default
pattern string No video, "2:3" video
phase string No A, B, C, D A
continuity string No restart, continue restart
  • pattern: "2:3" spreads 24000/1001 fps film frames over the 59.94 Hz fields in the 2:3 pulldown cycle A A B B B C C D D D, so four film frames fill ten fields (five frames). It needs NTSC or PAL-M and a video source at exactly 24000/1001 fps. Quote it: unquoted, 2:3 is a number to some YAML 1.1 readers.
  • phase is the cycle letter whose first field opens the section.
  • continuity: continue carries the cycle on from the previous section, which must also be "2:3", instead of starting at phase. When the previous section ended part-way through a letter, the new section's first film frame gets only the rest of it — the short or orphan field a real edit leaves. restart starts at phase, so the cadence breaks at the boundary.

duration_frames still counts output frames. With "all", the section shows every film frame of the selected range (× duration_repeat) for its full number of fields; when that is an odd number of fields, the last frame's second field repeats the last film frame. A fixed duration_frames loops the range, as for a video cadence.

Each field is drawn from its own film frame, so a frame whose fields fall in different letters (B3 and C1, say) weaves two film frames together, as real pulldown does. The OSD tokens {film_frame} and {cadence} show the mapping field by field.

A video soundtrack plays in real time from the range's first film frame: four film frames last exactly as long as five output frames, so the sound needs no resampling and is not cut to the cadence.

Laserdisc codes follow the film pictures. CAV picture numbers count film frames, four in five output frames, and the picture-number codes, picture stop and white flag go on the fields where each film frame starts. The colour sequence still follows the output frames.

Validation: "2:3" on PAL or SECAM, or on an EXR still, is an error; so is a source frame rate other than 24000/1001 under "2:3", or 24000/1001 under video, and continue on the first section or after a section that is not "2:3". phase together with continue, and phase or continuity under video, are ignored with a warning. An unknown value or key is a parse error. The emitter writes the block only when it differs from the video default.

laserdisc

Where the section sits on a LaserDisc — lead_in, programme_area or lead_out — and the biphase codes it carries. Only a project with a top-level laserdisc block may use it; omit it for a section that is not part of a disc. A section-level section_type key is a parse error that points to laserdisc.area, and a line_injections entry with type: laserdisc is a parse error that points to laserdisc.codes.

The keys, the CAV minimum durations, the ordering rules and the EFM disc-area mapping are on the section laserdisc page.

horizontal_resample

How the source raster's 720 active pixels are mapped onto the 4fsc active window (922 samples for PAL and SECAM, 52 µs). Optional.

- name: Photo
  type: progressive
  source: "{project}/media/photo.exr"
  duration_frames: 8
  horizontal_resample: bandlimited
Value Mapping
nearest (default) Each sample takes the source pixel at or to the left of its position (x · 720 / N): a zero-order hold.
bandlimited Each sample interpolates the source row with a polyphase Kaiser-windowed sinc.
  • The zero-order hold leaves images of the source spectrum up to the 4fsc Nyquist frequency. A source component at f reappears at 13.5 MHz − f, which the 4fsc sampling folds down again: a 0.25 MHz detail in a PAL picture leaves an image near 4.5 MHz, beside the colour subcarrier, where a decoder reads it as cross-colour. The hold also droops the in-band response.
  • The bandlimited kernel has its −6 dB point at the source Nyquist frequency (0.5 cycles per pixel, 6.75 MHz for a 13.5 MHz raster) with a 0.1 cycle-per-pixel transition and a 70 dB stopband. Every passband frequency's image lands in the stopband; only content within the transition band, right at the source Nyquist frequency, leaves an image (at most −6 dB).
  • Sample x reads the source at pixel position x · 720 / N − 0.5, so a pixel's value is centred on the span of samples the nearest mapping holds it for, and edges land on the same samples under both mappings.
  • Each phase of the kernel has unit DC gain, so flat areas are bit-identical to nearest. Taps that fall outside the raster repeat the edge pixel.
  • The luma, both colour-difference components and the chroma_line_sign regions are resampled together; any luma_bandwidth limit and the chroma low-pass follow.
  • nearest keeps existing projects bit-exact.

Validation: any other value is a parse error. The emitter writes the key only for bandlimited.

chroma_line_sign

Rectangles of the source picture whose U or V is multiplied by each line's PAL V-switch sign before modulation. PAL and PAL-M only. This builds the PAL decoder-stress elements of test cards such as the Philips PM5544: a bar of line-alternating ±(R−Y), and the "anti-PAL" fields whose U alternates instead.

- name: PalStress
  type: progressive
  source: "{bundled}/exr/720x576/PAL_STRESS.exr"
  duration_frames: 8
  chroma_line_sign:
    - region: {x: 26, y: 16, width: 38, height: 544}
      v: follow_switch
    - region: {x: 656, y: 16, width: 38, height: 544}
      u: follow_switch
    - region: {x: 0, y: 100, width: 24, height: 40}
      v: follow_switch
Key Type Required Values Description
region.x, region.y int Yes ≥ 0 Top-left corner, in source pixels and rows
region.width, region.height int Yes ≥ 1, inside the raster Size, in source pixels and rows
u string No (default normal) normal, follow_switch How U is carried
v string No (default normal) normal, follow_switch How V is carried
  • The V-switch sign is +1 on lines whose V axis is transmitted as is and −1 on lines where it is inverted (ITU-R BT.1700 Annex 1 Part B Table 1 item 10f). It belongs to the line, and a given frame line's switch flips every frame (625 and 525 are odd), so a still image alone cannot express it.
  • v: follow_switch cancels the switch: the transmitted V carrier is unswitched. A PAL decoder, which removes the switch, sees V alternate line by line. A correct delay-line decoder averages it to grey; delay-line amplitude errors show as "Venetian blinds" and a non-orthogonal demodulator colours it. Because the unswitched V lands where U would be in the vertical spectrum, a 2D or Transform PAL decoder cannot tell it from U by position.
  • u: follow_switch makes U alternate with the switch (the "+V/±U anti-PAL" field).
  • Regions are tested against source pixels, before the horizontal mapping. Overlapping regions each apply their sign, so two follow_switch regions on one component cancel.
  • Lines outside every region, and every line with a +1 switch sign, are bit-identical to a section without the block.
  • The picture truth includes the alternation.

Validation: the block on an NTSC or SECAM project is an error, as is a region with a zero or negative size, one that leaves the 720×576 (PAL) or 720×486 (PAL-M) raster, or one with neither u nor v set to follow_switch. A missing region or coordinate, a non-integer coordinate, an unknown value or key is a parse error. The emitter omits components left normal.

luma_bandwidth

A low-pass on the section's picture luma, as from a player or transfer with a limited luma frequency response. Optional — omit it for the full 4fsc bandwidth.

- name: SoftPlayer
  type: progressive
  source: "{bundled}/exr/720x576/MULTIBURST.exr"
  duration_frames: 4
  luma_bandwidth:
    cutoff_mhz: 3.0
    transition_mhz: 0.4
Key Type Required Range Description
cutoff_mhz float Yes 0.5 to 2 f_sc − transition_mhz / 2 The −6 dB point, in MHz
transition_mhz float No (default 0.4) 0.1 to 2.0 Width of the transition band, centred on the cutoff, in MHz

2 f_sc is half the 4fsc sampling rate: 8.867 MHz for PAL and SECAM, 7.159 MHz for NTSC and 7.151 MHz for PAL-M.

  • The filter is a Kaiser-windowed-sinc low-pass. The passband runs to cutoff_mhz − transition_mhz / 2 with a ripple below 0.003 dB; above cutoff_mhz + transition_mhz / 2 the stopband is at least 70 dB down (designed for 70 dB; the limit promises 60 dB).
  • It filters the luma of each active picture line across the active window, after the source pixels are mapped to 4fsc samples. It therefore also removes the images that the nearest-pixel column mapping leaves above the cutoff (the band-limited mapping avoids them at any frequency, for chroma too).
  • Each line is filtered on its own. Beyond the ends of the active window the line's first and last samples are repeated, so a flat line passes unchanged and the window edges do not ring.
  • Sync, blanking, the VBI, the VITS lines and the chroma are not filtered and are bit-identical to an unlimited section.
  • OSD text is drawn after the filter, so it stays sharp.
  • The channel impairments, noise and dropouts are applied afterwards and are not band-limited.

Validation: cutoff_mhz outside its range, or transition_mhz outside 0.1–2.0, is an error. luma_bandwidth without cutoff_mhz, a non-numeric value or another key is a parse error.

picture_response

A gentle horizontal and vertical softening of the section's picture luma, as from a camera, caption generator and production chain. Optional — omit it to keep the source picture as sharp as it is. Unlike luma_bandwidth, which is a cutoff, the response is a curve: it can describe a 2 dB shelf that falls to −10 dB over a few MHz.

Give either the name of a preset:

- name: Map
  type: progressive
  source: "{bundled}/exr/720x576/OSM_TOWN.exr"
  duration_frames: 4
  picture_response: domesday

or your own curves:

  picture_response:
    horizontal_db: [[0, 0], [2.5, -2], [4.0, -2], [4.75, -8], [5.25, -10]]
    vertical_db: [[0, 0], [0.2, 0], [0.28, -4], [0.375, -10]]
Key Type Required Range Description
horizontal_db list of [MHz, dB] One of the two MHz 0 to 2 f_sc, strictly ascending; dB −60 to +20 Response along each line
vertical_db list of [cycles/row, dB] One of the two 0 to 0.5 cycles per frame row, strictly ascending; dB −60 to +20 Response down the picture's rows

Breakpoints are joined by straight lines in dB, and the first and last values are held below the first and above the last point. A direction without a curve is not filtered.

Preset Response
domesday Programme material as mastered for LaserVision: the BBC Domesday disc's Test Card F against the bundled TESTCARD-F. Horizontally flat to 2.25 MHz, about −2.2 dB from 2.75 to 3.75 MHz, then −3.1 dB at 4.25, −8.4 dB at 4.75, −9.9 dB at 5.25 and −11 dB from 5.75 MHz. Vertically flat to 0.2 cycles per row, −4.5 dB at 0.27, −5 dB at 0.34, −10 dB at 0.38 and −10.4 dB at 0.5.
  • Both parts are linear-phase FIRs (127 taps horizontally, 31 rows vertically), frequency-sampled from the curve and Hann-windowed. They are normalised to unit gain at zero frequency, so flat areas and picture levels pass unchanged and only the shape of a curve matters.
  • The vertical part filters the rows of each progressive source picture before it is split into fields, as an interlaced camera's vertical aperture or a graphics flicker filter would. On a 2:3 cadence each film frame is filtered on its own.
  • The horizontal part filters each active line across the active window after the source pixels are mapped to 4fsc samples, and before any luma_bandwidth limit.
  • Beyond the ends of a line, and above the top or below the bottom of the picture, the edge samples and rows are repeated, so the edges of the picture do not ring.
  • Only the luma is filtered. Sync, blanking, the VBI, the VITS lines and the chroma are bit-identical to a section without the block, and OSD text is drawn afterwards and stays sharp.
  • The picture truth includes the response, so a decoder is never scored against detail that was never modulated.

The domesday figures were measured on PAL; the curves are in MHz and cycles per row and apply unchanged to NTSC and PAL-M. Measured against the bundled TESTCARD-F, the preset's band ratios match the disc's within 0.5 dB in every horizontal band from 0.5 to 5.5 MHz and in the vertical bands 1/4–5/16, 3/8–7/16 and 7/16–1/2 cycles per row. The disc's 5/16–3/8 figure (−1.6 dB) rises above both of its neighbours, which no camera aperture does; the preset is a monotonic roll-off and gives about −8 dB there.

Validation: an out-of-range or non-ascending breakpoint, or a map with neither curve, is an error. A preset name other than domesday, a curve that is not a list of numeric pairs, or another key is a parse error.

Section sub-blocks

Each has its own reference page:

Block Purpose
laserdisc Disc area and laserdisc biphase codes
osd On-screen display overlays
noise Gaussian noise injection
dropouts Random and scratch dropouts
audio Audio channel pairs

All are optional, and only blocks that are explicitly set are written back out by the emitter.

Validation summary

  • type must be progressive.
  • source must exist and match a supported profile, at the standard's raster and constant frame rate (24000/1001 for a "2:3" cadence); a video's container must match its extension and carry no crop metadata.
  • duration_frames must be a positive integer or "all".
  • start_frame ≥ 0 and end_frame ≥ start_frame, both inside the video source; end_frame never with an integer duration_frames.
  • An EXR still takes neither start_frame nor end_frame, and needs an integer duration_frames.
  • A laserdisc block needs the project's top-level laserdisc block. Disc areas follow the ordering rules, and a section with codes must set area.
  • cadence rules (above).
  • chroma_line_sign only on PAL and PAL-M, with every region inside the raster and following the switch on at least one component.
  • luma_bandwidth within its ranges (above).
  • picture_response curves within their ranges, strictly ascending (above).
  • CAV lead-in and lead-out minimum durations (warnings; see section laserdisc).