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

@ptr727 ptr727 commented Jul 14, 2026

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

Copilot AI 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
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.

Comment thread PlexCleaner/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.
Copilot AI review requested due to automatic review settings July 14, 2026 13:46

Copilot AI 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 develop Jul 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 free to 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