A session AVPlayer refuses is handed to the engine's own decoder (AE#561) - #582
Merged
Merged
Conversation
… decoder (AE#561) Every recovery under the native path answers the same bytes again. The #93 revive reloads the item at the position that died, and the stage-2 chain refills the same segment. Against a transient that is exactly right; against a segment Apple's parser refuses on its merits it is a loop, and the reporter's capture shows it ending the session with the replacement item dying 62 ms after the first. A failure in the CoreMedia domain is now offered to SoftwarePlaybackHost before it is made terminal: the session is rebuilt at its playhead with preferredDecodePath = .software, which decodes with libavcodec (one skipped frame rather than a dead session) and reads the demuxer directly instead of the loopback HLS, so it also steps around a local-server wedge. Once per session, because a second escalation could only repeat the first. The domain is the whole discriminator. A CoreMedia failure is a verdict on the MEDIA, which is the one thing a second decoder can disagree with; a URL-loading failure is a verdict on the SOURCE, which both paths read through the same reader, so escalating one would spend a rebuild to fail the same way seconds later. Whether the software path can serve this source at all is the existing AE#461 decodePathRefusal, so a source it cannot serve costs a refusal and the original failure rather than a second dead session. Measured on a 40 s HEVC fixture whose damaged sample sits at 20 s, against the same file healthy, with AETHER_DISABLE_NAL_SANITIZER restoring the shape the cut in 729ccaf now removes (that switch is read once from the environment and is never set in a shipped configuration): before, damaged plays to 15.87s, -19602, reload dies on the same segment, dead after, damaged -19602 at 15.88s, rebuilt on the software path at 12.00s, plays through the damaged sample to the end of the file after, healthy unchanged, nothing logged, still native shipping config the sample is cut, the session stays native, nothing escalates Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015PM3xUJB6ZQyqnmGK1fp6F
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 free
to 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 #581, which cut the unparsable sample. This is the rung underneath it, for every other way AVPlayer can refuse what it is served.
The weakness
Every recovery under the native path answers the same bytes again. The #93 revive reloads the item at the position that died, the stage-2 chain refills the same segment. Against a transient that is exactly right. Against a segment Apple's parser refuses on its merits it is a loop, and the reporter's capture shows where it ends: the replacement item dies 62 ms after the first, and the session is over.
The rung
A failure in the CoreMedia domain is offered to
SoftwarePlaybackHostbefore it is made terminal. The session is rebuilt at its playhead withpreferredDecodePath = .software, which decodes with libavcodec (one skipped frame rather than a dead session) and reads the demuxer directly rather than the loopback HLS, so it also steps around a local-server wedge. Once per session, because a second escalation could only repeat the first.The domain is the whole discriminator:
Whether the software path can serve the source at all is the existing AE#461
decodePathRefusal, already called byreloadAtCurrentPosition(applying:), so a source it cannot serve costs a refusal and the original failure rather than a second dead session. Two entry points share the decision: the host's terminal-failure classification, and the #93 gate at the moment its budget runs out on a frozen position.Measured
A 40 s HEVC fixture with one damaged sample at 20 s, against the same file healthy.
AETHER_DISABLE_NAL_SANITIZERrestores the shape #581 removed (read once from the environment, never set in a shipped configuration).-19602, reload dies on the same segment, session dead-19602at 15.88 s, rebuilt on the software path at 12.00 s, plays through the damaged sample to the endFull suite: 3216 tests in 439 suites, green. Seven new unit tests pin the decision (media domain escalates;
NSURLErrorDomain,AVFoundationErrorDomainand a nil domain do not; spent budget, a session already on software, the remote-HLS bypass and an unanswered probe all refuse; the budget is taken exactly once).🤖 Generated with Claude Code
https://claude.ai/code/session_015PM3xUJB6ZQyqnmGK1fp6F