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/BFLOAT, uncompressed, full-raster windows, standard-matching frame-rate and pixel-aspect metadata. - Video (
.mkvMatroska or.mp4MP4) — 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 atstart_frameafter the last frame. "all"— the selected range once: [start_frame,end_frame], or [start_frame, last frame] without anend_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 cycleA 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:3is a number to some YAML 1.1 readers.phaseis the cycle letter whose first field opens the section.continuity: continuecarries the cycle on from the previous section, which must also be"2:3", instead of starting atphase. 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.restartstarts atphase, 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
bandlimitedkernel 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_signregions are resampled together; anyluma_bandwidthlimit and the chroma low-pass follow. nearestkeeps 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_switchcancels 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_switchmakes 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_switchregions 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; abovecutoff_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_bandwidthlimit. - 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¶
typemust beprogressive.sourcemust 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_framesmust be a positive integer or"all".start_frame≥ 0 andend_frame≥start_frame, both inside the video source;end_framenever with an integerduration_frames.- An EXR still takes neither
start_framenorend_frame, and needs an integerduration_frames. - A
laserdiscblock needs the project's top-levellaserdiscblock. Disc areas follow the ordering rules, and a section withcodesmust setarea. cadencerules (above).chroma_line_signonly on PAL and PAL-M, with every region inside the raster and following the switch on at least one component.luma_bandwidthwithin its ranges (above).picture_responsecurves within their ranges, strictly ascending (above).- CAV lead-in and lead-out minimum durations (warnings; see section
laserdisc).