Repository navigation
Releases: JustinTArthur/vapoursynth-analog
Release list
v0.4.0
Full Changelog: v0.3.0...v0.4.0
v0.3.0
SECAM decoding, neural-network composite decoders, two new color filters, dropout reporting, and output geometry that follows the interface standards instead of the capture's own crop. That last one, the field-order tag on 525-line output, and a couple of removed options change what existing scripts produce — see Output geometry and tagging.
New decoding
- SECAM decoding, emitting
YUV440PS(4:4:0) tagged_ChromaLocationtop-left, with anAnalogSecamFirstRowComponentframe property for downstream chroma alignment. Both chroma planes are woven by row parity like luma, so separating fields selects the same field on all three — an explicit SECAM crop must span a multiple of 4 lines. resample_secamandfill_secam_by_delayturn that 4:4:0 output into a conventional raster.resample_secamrealigns the line-sequential lattice and otherwise behaves likecore.resize.<Filter>, forwardingformat,matrix,rangeand the rest;fill_secam_by_delayinstead copies each line's missing color difference from the previous line of the same field, as a receiver's delay line does, interpolating nothing. Both want woven frames, so run them before deinterlacing.- Neural-network composite decoders —
nntransform3d,ldzeug2_color_cnn,ldzeug2_luma_sepandldzeug2_luma_sep_frame— with bundled models,onnx_providerexecution-provider selection and graceful CPU fallback. macOS runs them on native CoreML (the Neural Engine on Apple silicon) and the Windows wheel on any DirectX 12 GPU through DirectML. GPU wheels on the project's package index — one--extra-index-urlchannel per vendor runtime at https://py.justinarthur.com — add Nvidia CUDA/TensorRT (Linux, Windows) and AMD MIGraphX (Linux). See the installation docs. - Newer CVBS capture formats are read alongside ld-decode/vhs-decode
.tbc:.cvbs,.cvbsy/.cvbscfor separated luma/chroma, plus the pre-1.5.0.compositeand.y/.cspellings, selected by file extension. RAW (unscaled-ADC) CVBS encodings are rejected. color_familyselectsYUV444PS(default),RGBSorGRAYSfloat output.model_precision,color_difference_precisionandbroadcast_scaling_precisionoptions. The bundlednntransform3dv2weights default to fp16: TensorRT builds a mixed-precision engine, and the CUDA and Windows wheels bundle an fp16 copy of those weights for an explicitonnx_provider="cuda"or"directml".phase_compensationnow defaults to enabled, making burst-locked chroma demodulation the default.
New filters
modernize_chromaticity(plugin and Python wrapper) converts analog-era colorimetry and photometry to modern targets (BT.709, sRGB, BT.2100 PQ/HLG, BT.2020 SDR, DCI/D65 P3, XYZ), with BT.1886 Annex 1/Appendix 1 display modelling, optional Bradford chromatic adaptation, andresize-style parameter names whose*_invalues override frame properties. Color only: no geometry conversion and no dithering. Subsampled Y'CbCr input goes through an internalresizeround trip (resample_filter_uv, bicubic by default) and keeps its subsampling on Y'CbCr output; 4:4:0 SECAM is instead routed throughresample_secam/fill_secam_by_delay. Constant-luminance output covers both2020cl(H.273 matrix 10) andchromacl(matrix 13, luma weights derived from the output primaries), each free to pair with any output transfer — H.273 Equations E-62 to E-65 define the color-difference normalizers as the transfer characteristic applied to expressions in KB/KR, so the curve is an independent axis rather than something the matrix fixes.amplify_chroma(plugin and Python wrapper), a post-decode counterpart tochroma_gain: a saturation control in the analog video domain, scaling E'Cb/E'Cr rather than an HSV/HLS saturation axis. Frames that already carry those color differences — 32-bit float Y'CbCr tagged_Matrix=4,5or6, asdecode_4fsc_videoemits — are scaled in place, and the same color differences in an integer format go through a float intermediate that names no matrix, so nothing is resampled and even 4:4:0 SECAM survives. Frames on other axes are converted through a_Matrix=6intermediate of the same subsampling and back, per frame, so previously captured video from a source plugin works too; that conversion holds the analog luma constant the way a decoder's gain does, leaving the frame's own Y' to be re-derived, and 4:4:0 is refused rather than blended. Only analog-era_Primaries(4, 5, 6, 7, or none) are accepted, so it belongs upstream ofmodernize_chromaticity.annotate_dropoutsreports where each frame's dropouts are instead of concealing them, in anAnalogDropoutSpansframe property — a flat array ofy,x_start,x_end,originper region, in the decoded clip's own pixel coordinates. It is independent ofdropout_correct, so damaged regions can be handed to another filter rather than replaced from neighbouring lines, anddropout_overcorrectwidens what gets reported just as it widens what correction overwrites. On SECAM the regions also cover the FM click concealment the decoder performed itself, distinguished byorigin.core.analog.create_dropouts_mask(vsanalog.create_dropouts_mask) rasterises those regions into a mask clip forcore.std.MaskedMergeand the otherstdmask functions, withoriginsto select which kinds of region to draw. The mask matches the clip's dimensions and precision, so subsampled output needs no special handling.vsanalog.dropout_spansreads the regions back as a list of named tuples.
Output geometry and tagging
- Output geometry now follows the interface standards instead of the source's declared crop, so a video system always decodes to the same raster. NTSC and PAL-M give 768x486 (SMPTE ST 244's digital active line, ST 170's active picture); PAL and SECAM give 948x576 (EBU Tech 3280-E and ITU-R BT.1700). Previously
.tbcsources inherited their sidecar's crop, giving 760x488 and 928x576 with the old default padding. The wider horizontal window includes the blanking transition on each side of the picture. - Removed
padding_multiple. Output is now exactly the active window on every source. Under libchromadec the option added a black border rather than widening the crop, whichstd.AddBordersdoes downstream with control over the amount, sides and color; removing it also means pixel (0, 0) is always the first active sample of the first active line. - 525-line output is now tagged bottom-field-first. ST 170's 486-line window starts on a field 2 half-line, because field 2 begins at line 264 and so its first active line (283) sits half a line above field 1's (21). The previous top-field-first tag came from the black padding row that the old default
padding_multiple=8added above the picture. 625-line output begins on a field 1 line and remains top-field-first. - Added
first_active_sample,last_active_sample,first_active_lineandlast_active_lineto crop explicitly, in the numbering of the signal standards themselves rather than of the stored raster. Samples are numbered as SMPTE ST 244 and EBU Tech 3280-E do, from the start of the digital active line, with negative values reaching back into the line blanking ahead of it; lines are the field-sequential signal line numbers of SMPTE ST 170, ITU-R BT.470 / BT.1700 and EBU Tech 3280,first_active_linenaming the window's topmost line. Both bounds are inclusive and independent; unset bounds keep the standard's value. To restore the previous crop, passfirst_active_sample=9, last_active_sample=768for NTSC or8/929for PAL. - The standard active window is now placed through each source's own horizontal alignment instead of a fixed offset, so subcarrier-locked captures — whose rows are cut at the first digital blanking sample rather than at 0H, as
ld-chroma-encoder --sc-lockedoutput is — land on the same picture as a 0H-cut.tbcwithout an explicit crop. This also fixes PAL-M, whose digital active line sits one sample further left than NTSC's. - Added
AnalogFirstActiveSample/AnalogLastActiveSample/AnalogFirstActiveLine/AnalogLastActiveLineframe properties reporting the resolved window in those same standards coordinates. - Removed
fpsnumandfpsden. They were meant to convert to a constant frame rate the waybs.VideoSourcedoes, but only ever retagged the rate and rescaled the frame count — no frame was dropped or duplicated, so raising the rate advertised frames past the end of the capture and lowering it put the tail out of reach. A 4𝑓𝑠𝑐 capture is constant-rate by construction, leaving nothing to convert; retag withcore.std.AssumeFPS, and retime after deinterlacing, where dropping a frame doesn't mean dropping two fields.
Metadata and diagnostics
- A decode asking for dropout correction or annotation now warns when the capture's
.tbc.dbsidecar carries no dropout metadata while its.tbc.jsondoes. The SQLite sidecar wins on existence alone, and releases up to 0.2.3 wrote one themselves during a decode without copying the dropouts across, so a capture decoded by an older version reports itself clean however damaged it is. Nothing writes those sidecars now; delete the.tbc.dbto decode from the JSON. - JSON metadata is processed natively — no intermediate SQLite sidecar is created for it.
- Decoder diagnostics now arrive as VapourSynth log messages instead of going straight to the process's stderr, so
core.add_log_handlercan capture, redirect or silence them. Addedset_log_levelto set the threshold (debug,info,warning,criticaloroff). Failures are unaffected — they still raise, and now carry the specific complaint from the layer that found it rather than a generic summary.
Build and packaging
- The vendored ld-decode-tools submodule is replaced by [libchroma...
v0.2.3
Fixes for vhs-decode and tape-decode-rs:
- Fix fractional IRE value input for blank/black/white in JSON to SQLite conversion. Older .db metadata sidecars will likely need to be regenerated if they were bugged from prior conversion.
- Chroma metadata sidecar is now optional in Y/C input, will fallback to using luma TBC's metadata.
Commits: v0.2.2...v0.2.3
v0.3.0a3
Full Changelog: v0.3.0a2...v0.3.0a3
Full Changelog: v0.3.0a2...v0.3.0a3
Full Changelog: v0.3.0a2...v0.3.0a3
Full Changelog: v0.3.0a2...v0.3.0a3
v0.3.0a2
v0.3.0a1
v0.2.2
v0.2.1
Revised Windows wheel should now contain the full dependency set. macOS and Linux wheels should be be unchanged from 0.2.0.
Full Changelog: v0.2.0...v0.2.1
v0.2.0
- Added a
vsanalogPython wrapper package with type-hinted signatures and an auto-loading fallback for older VapourSynth versions that predate pip-installable plugins. - Retagged wheels as independent from the CPython ABI (
none) so a single wheel can serve any compatible Python interpreter on a given platform. - More comprehensive documentation.
Commits: v0.1.1...v0.2.0
v0.1.1
New build pipeline with reasonably-packaged plugin libs plus Python sdists and wheels that can support VapourSynth's upcoming pip-installable plugin flow (the old drop-in plugin libs will still work, don't worry).
No fixes or feature changes to the plugin itself.
Full Changelog: v0.1.0...v0.1.1