Scope setts to audio DTS and verify A/V sync in the repair gate - #840
Merged
Conversation
Two refinements to the lossless timestamp repair: - Attempt setts only when every non-monotonic DTS is on an audio stream. setts is audio-only (a video setts would reorder B-frames), so a video or subtitle DTS is skipped straight to RepairFailed with no wasted rewrite. DtsInfo records each stream's codec type to decide this. This also fixes a latent false positive: DtsInfo fell back to PTS when a packet had no DTS, but Matroska video stores no DTS and its display PTS is legitimately non-monotonic for B-frames; assess only real DTS now. - The gate compared only the payload hash, which proves the samples are unchanged but not their timing. Also compare each stream's start and duration and reject a repair that shifts any stream beyond the A/V-sync tolerance, so a timestamp nudge can never drift audio out of sync. Validated on the corpus: audio-DTS files (Eureka, Ghosted) repair and the sync gate accepts them; video-DTS (Love Island, 50 First Dates) and post-decode (Diplo) skip setts and stay RepairFailed.
There was a problem hiding this comment.
Pull request overview
This PR tightens the lossless DTS timestamp-repair path by (1) only attempting setts when the detected non-monotonic DTS is audio-only, and (2) extending the regression gate to verify that stream timing (start/duration) is preserved within an A/V-sync tolerance after the timestamp rewrite.
Changes:
- Gate
settsrepair onDtsInfo.NonMonotonicIsAudioOnly(avoid attempting an audio-only rewrite when the non-monotonic stream is video/subtitle or when analysis is inconclusive). - Extend the timestamp-repair regression gate to validate per-stream
start_timeanddurationviaffprobewithin a 40ms tolerance. - Add JSON-schema + tests for stream timing parsing; update release notes wording in
HISTORY.md.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| PlexCleanerTests/StreamTimingsProbeTests.cs | Adds coverage for parsing ffprobe stream timing JSON and missing timings behavior. |
| PlexCleanerTests/DtsInfoTests.cs | Adds tests for audio-only vs mixed vs video non-monotonic DTS classification. |
| PlexCleaner/ProcessFile.cs | Gates setts attempt on audio-only DTS and adds timing-based A/V sync validation to the regression gate. |
| PlexCleaner/FfProbeTool.cs | Adds GetStreamTimings to query per-stream start_time/duration as JSON. |
| PlexCleaner/FfMpegToolJsonSchema.cs | Introduces StreamTimingsProbe/StreamTiming schema for ffprobe output parsing. |
| PlexCleaner/DtsInfo.cs | Tracks stream codec_type and ignores packets without real DTS to avoid false positives. |
| HISTORY.md | Updates release notes to reflect audio-only repair scope and new sync gate. |
Uh oh!
There was an error while loading. Please reload this page.
WithinSyncTolerance passed whenever either side was NaN, so an asymmetric missing start_time or duration slipped through unverified. Pass only when both sides are NaN (symmetric, uncomparable); a value on just one side now fails the gate.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #836/#837, from the regression review.
1. Audio-scope the setts attempt.
settsis applied-bsf:a(audio only) - a videosettswould reorder B-frames - so it can only repair an audio-stream DTS.DtsInfonow records each stream'scodec_typeand exposesNonMonotonicIsAudioOnly; a video/subtitle DTS, or a post-decode break with no demux target, skips straight toRepairFailedwith no wasted rewrite + re-verify.This also fixes a latent false positive:
DtsInfofell back to PTS when a packet had no DTS, but Matroska video stores no DTS and its display PTS is legitimately non-monotonic for B-frames, so video was being flagged as non-monotonic. It was harmless before (setts ran regardless) but the audio-only gate exposed it.DtsInfonow assesses only packets that carry a real DTS.2. Verify A/V sync in the gate. The streamhash gate proved the coded packets are byte-identical but said nothing about timing - and
settschanges timestamps. The gate now also compares each stream'sstart_timeandduration(viaffprobe) and rejects a repair that shifts any stream beyond a 40 ms A/V-sync tolerance, so a nudge can never drift audio out of sync. (The #827 design called for this A/V-offset check; the first implementation dropped it.)Corpus validation (local build, ffmpeg 8.0.1): Eureka + Ghosted (audio DTS) ->
Repairing->Timestamp repair succeeded->Repaired, sync gate accepts; Love Island + 50 First Dates (video DTS) and Diplo (post-decode) ->RepairFailed, setts skipped.213 tests pass (added
DtsInfoaudio-only cases and a timings-parse test); build, format, markdownlint clean.🤖 Generated with Claude Code