Repository navigation
Warn When a HandBrake Rewrite Drops Embedded Closed Captions - #1160
Conversation
HandBrake runs without subtitles and only the original subtitle tracks are merged back, so closed captions embedded in the video stream do not survive a deinterlace or the HandBrake fallback of a re-encode repair. Nothing reported the loss. ConvertUsingHandBrake() now scans for embedded closed captions before the HandBrake run and logs a warning when the video carries them, or when the scan fails. The scan always runs, since the sidecar states that skip it do not imply one ran with RemoveClosedCaptions off, and it records no ScannedCaptions state mid-rewrite. Closes #1157 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A signal-ended or cancelled caption scan counted in ToolErrorScope, so a repair that then failed left its state unchanged and kept the file, repeating the whole repair every run. The scan now runs in its own scope, and the two VerifyToolErrorTests no longer need a fake ffprobe. The scan is skipped when ScannedCaptions or ClearedCaptions is set, since those flags do record a real scan or a removal. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 17 minutes. View limit details
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. |
|
A recorded local strict-review pass covers head |
PR Summary by QodoWarn when HandBrake rewrites drop embedded closed captions
AI Description
Diagram
High-Level Assessment
Files changed (4)
|
Code Review by Qodo🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)
Great, no issues found!Qodo reviewed your code and found no material issues that require reviewTip of the day💡 Did you know, you can show, collapse, or hide each part of a finding: code, evidence, and all |
There was a problem hiding this comment.
🟡 Changes recommended
The only remaining active finding is a nit in Docs/ClosedCaptions.md at line 190, where the first sentence does not clearly say when HandBrake rewrites video during deinterlacing and the paragraph omits the warning that a failed scan may drop Closed Captions.
1 open issue
What changed in this PR
This PR makes a known HandBrake side effect visible. HandBrake runs with no subtitles, and MkvMerge merges back only the original subtitle tracks. Embedded EIA-608/CTA-708 closed captions are part of the video stream, not a track, so a HandBrake rewrite drops them. The drop was already documented, but nothing reported it. The PR keeps the drop and adds a warning before each HandBrake run. It also documents the behavior in the history and closed captions docs.
Changes:
ConvertUsingHandBrake()now calls a newReportClosedCaptionsDropped()before the HandBrake run. It logs a warning when the video has captions, or an "unknown" warning when the scan fails. A failed scan never blocks the rewrite, and a cancelled scan returns.- The check is skipped when the file already records a scan or a caption removal. It runs in its own tool error scope, so a failed caption scan does not count as a repair failure. It also does not write the scan state to the sidecar mid-rewrite.
FindClosedCaptionTracks()gets arecordScanparameter (defaulttrue). The new check passesfalse.- New tests cover captions present, absent, and a failed or killed scan. They also cover the skip when a scan or removal is already recorded.
| File | Description |
|---|---|
| PlexCleanerTests/ReplaceOriginalTests.cs | Adds tests for the caption warning cases, the unknown-scan case, and the skip when a scan is already recorded. |
| PlexCleaner/ProcessFile.cs | Adds the closed caption check before HandBrake runs and the recordScan parameter that keeps the sidecar unchanged. |
| HISTORY.md | Adds a 3.23 entry noting that HandBrake drops embedded captions and that a warning is now logged. |
| Docs/ClosedCaptions.md | Adds a "HandBrake Rewrites" section explaining the drop, the warning, and when the scan is skipped. |
Review effort: Lite
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
A recorded local strict-review pass covers head |

Summary
HandBrake runs with
--subtitle none, and MkvMerge merges back only the original's subtitle tracks. EIA-608/CTA-708 closed captions embedded in the video stream are not a track, so a HandBrake rewrite drops them and nothing reported it. Both HandBrake callers reach this:DeInterlace(), and the HandBrake fallback of the re-encode repair since #1152 routed it throughConvertUsingHandBrake(). Issue: #1157.The drop is kept, the documented behavior since the HandBrake subtitle workaround, and made visible:
ConvertUsingHandBrake()calls a newReportClosedCaptionsDropped()before the HandBrake run. It scans for embedded closed captions with the existingFindClosedCaptionTracks(). It logsHandBrake drops the Closed Captions in the video streamwhen the video carries them, andUnknown if HandBrake drops Closed Captionswhen the scan fails. A failed scan never blocks the rewrite, and a cancelled one returns.VerifiedandVerifyFailedskips of a conditional scan, since those states do not imply a scan ran withRemoveClosedCaptionsoff, which is exactly when the captions are still there. It is skipped whenScannedCaptionsorClearedCaptionsrecords a real scan or a removal, so aprocessrun that just scanned the file does not decode it again.FindClosedCaptionTracks()takes arecordScanparameter, defaulttrue. This caller passesfalse, so a clean scan does not writeScannedCaptionsto the sidecar in the middle of a rewrite.ToolErrorScope. A killed, cancelled, or unlaunchable scan therefore does not count as a repair tool error, which would otherwise leave a failed repair withoutRepairFailedand repeat it every run.Docs/ClosedCaptions.md"HandBrake Rewrites" state the drop and the warning.With
RemoveClosedCaptionson, the default,processremoves the captions before either step runs. So the exposure is that option off, or thedeinterlaceandreencodecommands run directly.Verification
dotnet test: 491 passed.DeInterlace_ClosedCaptions_WarnsWithoutRecordingScancovers captions present (the warning), absent (no warning), and a failed or signal-killed caption probe (the unknown warning). Each case assertsScannedCaptionsstays clear and the outer tool-error count stays 0.DeInterlace_CaptionsAlreadyScanned_SkipsScancovers the skip for both states.Negative control: without the scan's own scope, the signal-killed case and 6 existing
VerifyToolErrorTestsfail, the tests whose fakes leave ffprobe out.Real media in
ptr727/plexcleaner:latest(FFmpeg 8.1.2, HandBrake 1.11.2), this branch published framework-dependent per OPERATIONS.md. The inputs are synthetic:synthesize.py hdr10-cc(HEVC with CC608 SEI) and atestsrc2H.264 clip, each given a Matroska field-order flag sodeinterlacetakes the HandBrake path.closed_captionsbeforeclosed_captionsafterHandBrake drops the Closed Captions in the video stream : Format: "hevc"ReMuxed, DeInterlacedReMuxed, DeInterlacedLocal strict review: two frontier passes. The first raised three findings, all introduced and all fixed in 2b33763: the repair tool-error accounting, the redundant scan on a known state, and an ambiguous doc sentence, plus two sentence-length lint hits. The second pass over the full diff found nothing.
🤖 Generated with Claude Code