line_timing¶
The per-line timing error of the active picture that is left after time-base correction: each picture line is displaced horizontally by a few nanoseconds, by a different amount on every line, field and frame. Optional — omit the block for a perfectly time-base-corrected picture.
line_timing:
line_ns: 4.9 # within-field r.m.s., per line
line_correlation: 0.6 # first-order, line to line within a field
field_ns: 3.1 # r.m.s. offset common to the field
slope_ns: 3.4 # r.m.s. difference between the line's two halves
seed: 7
include_burst: false
shared: # the part recorded on the disc
line_ns: 3.0
line_correlation: 0.6
field_ns: 1.5
slope_ns: 2.0
seed: 7001
The keys of the block itself are the capture layer: the residual of one capture's player and time-base corrector, so each capture of a pressing draws its own. shared: is the pressing layer: the part recorded on the disc, identical in every capture of the pressing, as the shared noise layer is.
At 4fsc a 625-line sample is 56.4 ns and a 525-line sample 69.8 ns, so a few ns is about a tenth of a sample.
Keys¶
| Key | Type | Required | Range | Default | Description |
|---|---|---|---|---|---|
line_ns |
float | One of the figures, or shared |
0.0 to 50.0 | 0.0 | R.m.s. shift of each line within its field (the field's mean removed), in ns |
line_correlation |
float | No | 0.0 to 0.99 | 0.0 | Correlation of a line's shift and slope with the next line of the same field |
field_ns |
float | One of the figures, or shared |
0.0 to 50.0 | 0.0 | R.m.s. offset common to a whole field, in ns |
slope_ns |
float | One of the figures, or shared |
0.0 to 50.0 | 0.0 | R.m.s. difference between the shifts of the line's two halves (a velocity error), in ns |
seed |
integer | No | any | — | Fixed seed of the capture layer. Omit for a run-specific seed |
include_burst |
bool | No | true, false |
false |
Move each picture line's colour burst with the line; see The burst |
shared |
map | No | — | — | The pressing layer, below |
shared¶
| Key | Type | Required | Range | Default | Description |
|---|---|---|---|---|---|
line_ns |
float | One of the three figures | 0.0 to 50.0 | 0.0 | As above |
line_correlation |
float | No | 0.0 to 0.99 | 0.0 | As above |
field_ns |
float | One of the three figures | 0.0 to 50.0 | 0.0 | As above |
slope_ns |
float | One of the three figures | 0.0 to 50.0 | 0.0 | As above |
seed |
integer | Yes | any | — | Fixed seed of the pressing layer, so every capture shares it |
line_timing: must set at least one of line_ns, field_ns, slope_ns or shared, and shared: one of its line_ns, field_ns or slope_ns. seed at the top of the block seeds the capture layer, so it needs one of the capture figures.
Behaviour¶
| Configuration | Result |
|---|---|
| Block absent | No line timing stage; output is unchanged |
| Every figure 0.0 | No processing; output is bit-identical to the block being absent |
line_ns |
Each line takes its own shift, correlated with its neighbours by line_correlation |
field_ns |
Every line of a field takes the same extra shift |
slope_ns |
Each line's shift grows linearly along it |
shared |
A second, disc-keyed error is added to the capture layer's |
The model¶
Each layer draws, for every field of every frame:
shift(k) = F + x(k)
slope(k) = s(k)
x(k) = r · x(k−1) + √(1 − r²) · line_ns · e(k), x(0) = line_ns · e(0)
s(k) = r · s(k−1) + √(1 − r²) · slope_ns · e'(k), s(0) = slope_ns · e'(0)
F = field_ns · e''
where k counts the lines of the field, r is line_correlation, and e, e' and e'' are independent unit normals. Both processes are stationary: every line has the configured r.m.s. and the correlation between lines n apart is rⁿ (0.6, 0.36, 0.13 and 0.02 at 1, 2, 4 and 8 lines for r = 0.6). They advance over every line of the field, picture or not, so the correlation depends on the line spacing alone. The two fields of a frame, and successive frames, are independent.
Each sample n of a picture line is then read from the line at n − d(n):
with c the centre and W the width of a full active line (52 µs), so the line's two halves, whose centres are W / 2 apart, differ by slope. Positive values arrive later. The read is band-limited: a Kaiser-windowed sinc of 32 taps, the kernel of the channel's timing offset, tabulated at 512 fractional positions. Y and C move together, so a line's chroma moves with its luma, and a shift of d also delays the line's subcarrier by 2π · fsc · d against its burst.
What moves¶
Only the active window of picture lines moves: the lines and samples that carry the picture, less any line carrying a project VITS. Sync, the colour burst, the VBI and the VITS lines stay where they are, because the measured residual moves the picture relative to a burst-locked line. Samples just outside a window are read as they are, so a picture edge moves into the blanking next to it.
The burst¶
include_burst: true moves each picture line's burst too, by the same d(n) evaluated at the burst's samples. A decoder that references every line to its own burst then sees the line's chroma phase follow its burst, which is how such a decoder corrects the error. The window moved is the burst gate widened by 8 samples each side. Only C moves there: Y is flat blanking under the burst. SECAM has no burst, so include_burst is a validation error on SECAM; the rest of the block applies to SECAM too.
Seeds¶
The capture layer is keyed by its seed and the output frame position, so a capture that replays a picture draws a fresh error for it. With seed set it is identical on every run and for any --threads value; without it, each run draws a fresh seed. The pressing layer is keyed by its seed and the disc frame position (the CAV picture number when the section anchors one), so every capture of one pressing, and a replay of the same picture, carries the same recorded error. Each layer uses its own seed domain, so a capture and a pressing seed of the same value still draw independently.
Every line always draws two values, shift then slope, and every field one field offset, whether or not each figure is set, so changing one figure never moves another's values.
The picture truth¶
The picture truth is drawn from generation, so it is the unjittered picture: what a perfect time-base corrector would give, and what a mean over many frames of a real disc approximates.
Stage order¶
- Generation
- LaserVision channel and channel
- Chroma error
- Line timing
- Noise (capture layer, then shared layer)
- Dropouts
- Output
The error is applied after the channel and the chroma error, and before noise, so the noise is not shifted. Y is clamped to the same legal range as noise injection; C is centred on zero and is not clamped.
Rules¶
- Values outside their ranges, or not finite, are validation errors.
shared:without aseedis a validation error: the pressing layer must be identical in every capture of the pressing.include_burst: trueon SECAM is a validation error.- A non-numeric figure, a non-integer seed, a non-boolean
include_burst, an unknown key or an empty block is a parse error.