Repository navigation
v2.4.0
Snipwright 2.4.0
Most of this release came out of one thread. Chasing why two exports of the same project were not identical turned up a fault in the boundary decoder, and fixing that made a run of older faults visible underneath it — a recording indexed at half its length, exports that needed Quick Stream Fix when nothing was wrong with the recording, and audio description tracks quietly going missing. It also carries the HDR colour and stream-splicing work that was prepared after 2.3.0 but never published.
If you have been running Quick Stream Fix on everything, or have edited a broadcast recording with audio description, this release is worth taking.
🔁 Exporting the same project twice now produces the same file
It did not. Two exports of one project, with a restart between, came out with their re-encoded segments different while every copied segment was byte-identical. The picture was never wrong and nothing was lost — the difference needed a frame-by-frame comparison to see at all — but it meant an export could not be checked against a previous one, so there was no way to tell whether a change to the cutting code had altered the output.
The decoder that feeds the boundary re-encoder was reading with frame threading across every core, and that does not return the same pixels every time when the machine is busy. Across five exports of one Channel 4 HD recording with the application playing in the background, 10 of the 686 frames handed to the encoder decoded differently — every one of them field-coded, and no progressive frame ever varied. One such frame changes every packet to the end of its re-encoded run, so a single frame moved 125 of them.
That decoder now runs on one thread. Only the GOPs at cut points are decoded at all — 833 frames for a five-minute recording — so it costs a few seconds, not a proportional slowdown.
🎨 HDR colour is now kept across every cut
The handful of frames re-encoded at each cut point used to be written with their colour unspecified, while the rest of the file declared BT.2020 and PQ. On one 10-bit HDR10 test cut that was 199 frames carrying their colour and 78 carrying nothing, which on an HDR display shows as a flash at every join. Those frames now carry the source's colour description, and a cut file is tagged the whole way through.
🔢 Spliced streams now carry one coherent picture numbering
Writing that colour into the re-encoded frames turned out to be enough, on its own, to break the join — a lost frame and Duplicate POC in a sequence from the decoder. That was not a colour fault. It was a splicing fault that the missing colour had been hiding.
Every picture in an HEVC stream carries a number identifying it within its sequence. Segments copied from the source keep the source's own numbering, so once segments from different points in a recording sit next to each other, two pictures can claim the same number. Measured on the 10-bit test file: two pictures both claiming 44, twenty-five pictures apart.
It went unnoticed because it was masked. The boundary encoder wrote a slightly different parameter set from the source's, so a decoder re-initialised at every switch between copied and re-encoded material and cleared the earlier picture away before the colliding one arrived. Supplying the colour makes the encoder reproduce the source's parameter set exactly — the stream becomes more correct — the two stop differing, nothing re-initialises, and the collision surfaces. ffmpeg-based players tolerated the old output; a decoder that does not re-initialise the same way need not have.
Each run of pictures in the output is now renumbered so the file carries one coherent sequence: 38 latent collisions to none on the test file, with the decoded picture byte-for-byte identical. Recordings whose keyframes are IDR rather than CRA — many commercial encodes — were never affected and are unchanged. If the renumbering meets something it cannot account for, it turns itself off for the rest of that export, writes the stream exactly as before, and says so in the log.
📏 A recording could be indexed at half its real length
A 2h38m film opened as 01:19:20, with the timeline scale and every reported timing halved to match. Scene markers still landed in the right places, which made it easy to miss until an export went wrong.
Field-coded recordings carry some frames as two field-pictures, and the index merges those back into one. It used to do that by rounding every packet onto a frame grid — but an odd number of half-frame gaps anywhere in the file leaves everything after it sitting exactly half way between slots, and consecutive frames then collapse into the same slot. Frames are now paired locally, so nothing depends on where the timestamps happen to fall.
🩹 Quick Stream Fix is no longer needed for ordinary recordings
Exporting a recording straight off the tuner produced a file with a video track and nothing in it, reported as "no readable video" — so Quick Stream Fix became a routine step before cutting anything.
The recording was fine. A recording that starts part-way through a GOP, which is normal off a tuner, had every GOP's end timestamp shifted one GOP earlier, so no packet fell inside one and nothing was copied. Quick Stream Fix appeared to cure it only because the repaired copy starts on a keyframe.
Confirmed on MPEG-2 SD and on a raw 1080i H.264 film, to .ts, .mkv and .mp4, all without it. Quick Stream Fix remains the right tool for a genuinely damaged recording — a signal dropout, or an interrupted capture.
🔊 Audio description tracks are no longer dropped
A BBC One recording with a working audio description track exported without it, reported as a track that "carries no audio in this recording". It carried plenty: 141,570 packets and audible description throughout.
Whether a track was usable was decided from the channel count and sample rate in the container header. Zeroes there mean the parameters could not be worked out, which is not the same as the track being empty, and some broadcast AD streams simply do not declare them. Probing harder does not help — this one still read as "0 channels, 0 Hz" with a 100 MB probe while decoding its first packets without difficulty. Snipwright now asks the decoder, and keeps the track if it produces audio.
A second fault sat behind that one: the first export of a file walks it and caches the result, and the next export loaded that cache and skipped the walk — which is what determines those parameters in the first place. So the track survived the first export and vanished from the next. Exporting to .ts worked and the .mkv straight afterwards did not.
If you have checked such a track by ear and thought it empty, it is worth another look. UK audio description is often a receiver-mix track carrying only the narration, silent between descriptions, so skipping through one lands in silence most of the time even when it is working perfectly.
🎬 Chapters become marks on the timeline
Opening a file that already has chapters — upscaled or re-encoded material usually keeps them, and Snipwright's own exports write your marks out as chapters — showed an empty timeline. The marks had to be found in another player and re-entered by hand. Chapter starts are now added as scene markers when the file opens, with a note in the status bar saying how many were loaded.
🧩 Interlacing at cut points
The frames re-encoded at each cut are meant to be coded as fields when the source is interlaced, or players skip deinterlacing and show combing on motion. Two things stopped that happening: whether a recording counted as interlaced was decided by decoding a single frame, and the decision was made once per export when each re-encoded run opens its own encoder.
Both are fixed. A run is coded as fields when the frame that opens it is itself interlaced, taking the field order from that frame. One case remains: a run that opens progressive and switches to interlaced part way through is still coded progressive, which is no worse than before but not yet right.
✅ Every export is now checked for its length
The check compared the output's packet count against the number of frames kept. On a field-coded source those count different things, so the check was skipped altogether — which is most UK HD. For those files the only verification was whether the output was completely empty, and the frame count shown afterwards was the number of frames requested rather than the number produced. A partial export looked exactly like a good one.
The finished file's duration is now compared against the length the edit asked for. Anything more than a second out is flagged, and the log records both figures on every export.
A small caveat that is not a fault: the reported length can differ by a few hundredths of a second. That figure is the container's span from the earliest track start to the latest track end, and sound sits on a different grid from video, so a track almost never ends on the same instant. A real frame difference is always a whole number of frames — 0.04s at 25fps — so a drift of 0.03s cannot be a missing frame.
🐛 Also fixed
- Commercial detection appeared to restart part way through. It was not restarting: Comskip rescans a recording when it cannot settle on a logo, and the percentage genuinely returns to zero. The dialog now says which pass it is on.
- Every cut segment was attributed to the last scene in the log and the progress dialog on recordings that carry the broadcast clock.
- Clearing the cache in Settings cleared only one of Snipwright's two caches, so a file that had already been opened kept behaving as it did before.
- A track lost to an export failure was described as a silent one that cost nothing. It is now reported as a fault.
- The log claimed MKV audio had been converted to AAC when nothing had been converted, and claimed audio would be re-encoded for MP4 when it was copied untouched.
- The user guide said cutting a Blu-ray uses several gigabytes of RAM. That stopped being true in 2.2.0.
📺 HDR and 4K
Both are largely untested, and honestly so: UK Freeview broadcasts neither, so there is nothing off the tuner to test against. Two things are known and unfixed. HDR metadata — mastering display, MaxCLL, MaxFALL, and Dolby Vision — is lost on export, leaving a file tagged BT.2020 and PQ with no static metadata. And the single-threaded boundary decode above has been measured only on 1080p H.264; its cost on 4K HEVC is unknown.
If you record HDR or 4K off a PVR and can share a sample, that would be genuinely useful — it is the one thing standing between these being known limitations and being fixed.
Bug reports are welcome, especially with a sample recording — a short clip cut with ffmpeg -ss … -t 60 -i recording.ts -c copy sample.ts is usually enough. The full changelog is in CHANGELOG.md.