During Android direct play, a single dropped connection or network blip
mid-stream kicked an otherwise healthy ExoPlayer session over to the MPV
fallback - on a Shield this showed as random backend switches minutes
into an episode (log pu4ad: "ffmpeg demuxer read failed: -5" with
contentIsMalformed=true, while MPV reopened the same URL fine).
Three defects lined up behind it, all in the 2.17.0 ffmpeg demux path:
- The AVIO read callback turned the input proxy's stored IOException
(its -1 return) into a bare AVERROR(EIO) without marking javaError, so
the extractor classified the failure as a malformed container. media3
never retries a ParserException, so the designed ERR_JAVA ->
IOException -> load-error-retry path was unreachable. The callback now
latches javaError for a negative read and fails fast on every later
read in the same native call, so matroska resync cannot clobber the
stored message or skip past the failed range.
- A failed refill latches AVIOContext error/eof_reached and avio never
drives the callback again, so even a correctly classified retry would
re-fail on the stale error. nativeReadPacket and nativeSeek now clear
the latch on entry; a genuine end of file (error == 0) is left alone.
- FfmpegRandomAccessSource kept a handle whose read had thrown, and its
position matched the retried request, so the retry was handed the same
dead handle. A failed read now drops the handle and the retry reopens.
A transient failure now surfaces as a retryable IOException, media3
reopens the source, and sample delivery resumes gaplessly; persistent
failures still exhaust the retry policy and reach the MPV fallback as
before.
close#2113