Skip to content

Scope setts to audio DTS and verify A/V sync in the repair gate - #840

Merged
ptr727 merged 2 commits into
developfrom
fix/setts-audio-scope-and-sync-gate
Jul 14, 2026
Merged

Scope setts to audio DTS and verify A/V sync in the repair gate#840
ptr727 merged 2 commits into
developfrom
fix/setts-audio-scope-and-sync-gate

Conversation

@ptr727

Copy link
Copy Markdown
Owner

Follow-up to #836/#837, from the regression review.

1. Audio-scope the setts attempt.setts is applied -bsf:a (audio only) - a video setts would reorder B-frames - so it can only repair an audio-stream DTS. DtsInfo now records each stream's codec_type and exposes NonMonotonicIsAudioOnly; a video/subtitle DTS, or a post-decode break with no demux target, skips straight to RepairFailed with no wasted rewrite + re-verify.

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, so video was being flagged as non-monotonic. It was harmless before (setts ran regardless) but the audio-only gate exposed it. DtsInfo now 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 setts changes timestamps. The gate now also compares each stream's start_time and duration (via ffprobe) 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 DtsInfo audio-only cases and a timings-parse test); build, format, markdownlint clean.

🤖 Generated with Claude Code

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.
CopilotAI review requested due to automatic review settings July 14, 2026 13:40

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 setts repair on DtsInfo.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_time and duration via ffprobe within 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
FileDescription
PlexCleanerTests/StreamTimingsProbeTests.csAdds coverage for parsing ffprobe stream timing JSON and missing timings behavior.
PlexCleanerTests/DtsInfoTests.csAdds tests for audio-only vs mixed vs video non-monotonic DTS classification.
PlexCleaner/ProcessFile.csGates setts attempt on audio-only DTS and adds timing-based A/V sync validation to the regression gate.
PlexCleaner/FfProbeTool.csAdds GetStreamTimings to query per-stream start_time/duration as JSON.
PlexCleaner/FfMpegToolJsonSchema.csIntroduces StreamTimingsProbe/StreamTiming schema for ffprobe output parsing.
PlexCleaner/DtsInfo.csTracks stream codec_type and ignores packets without real DTS to avoid false positives.
HISTORY.mdUpdates release notes to reflect audio-only repair scope and new sync gate.

Comment threadPlexCleaner/ProcessFile.cs Outdated
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.
CopilotAI review requested due to automatic review settings July 14, 2026 13:46

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.

@ptr727
ptr727 merged commit cceb70b into developJul 14, 2026
15 checks passed
@ptr727
ptr727 deleted the fix/setts-audio-scope-and-sync-gate branch July 14, 2026 13:54
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@ptr727