diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/ProgressiveMediaPeriod.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/ProgressiveMediaPeriod.java index 4f3386caa70..aa849af06a7 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/ProgressiveMediaPeriod.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/ProgressiveMediaPeriod.java @@ -236,14 +236,15 @@ public ProgressiveMediaPeriod( this.progressiveMediaExtractor = progressiveMediaExtractor; this.singleSampleDurationUs = singleSampleDurationUs; loadCondition = new ConditionVariable(); + handler = Util.createHandlerForCurrentLooper(); maybeFinishPrepareRunnable = this::maybeFinishPrepare; onContinueLoadingRequestedRunnable = () -> { if (!released) { + handler.post(maybeFinishPrepareRunnable); checkNotNull(callback).onContinueLoadingRequested(ProgressiveMediaPeriod.this); } }; - handler = Util.createHandlerForCurrentLooper(); sampleQueueTrackIds = new TrackId[0]; sampleQueues = new SampleQueue[0]; controlledTrackOutputs = new ControlledTrackOutput[0]; @@ -725,6 +726,7 @@ public void onLoadCompleted( /* mediaStartTimeUs= */ loadable.seekTimeUs, durationUs); loadingFinished = true; + handler.post(maybeFinishPrepareRunnable); checkNotNull(callback).onContinueLoadingRequested(this); } @@ -907,7 +909,35 @@ private void maybeFinishPrepare() { } for (SampleQueue sampleQueue : sampleQueues) { if (sampleQueue.getUpstreamFormat() == null) { - return; + if (loadingFinished) { + // File fully exhausted; this track never produced any data. + } else if (!loadCondition.isOpen()) { + // Loading is paused (e.g. DefaultLoadControl byte budget full). Only assign a + // placeholder if at least one real video and one real audio track have already + // been seen, confirming this is an extra PMT-declared stream that carries no data + // rather than a legitimate track whose format packet hasn't arrived yet. + boolean haveVideo = false; + boolean haveAudio = false; + for (SampleQueue q : sampleQueues) { + Format f = q.getUpstreamFormat(); + if (f == null) { + continue; + } + if (MimeTypes.isVideo(f.sampleMimeType)) { + haveVideo = true; + } else if (MimeTypes.isAudio(f.sampleMimeType)) { + haveAudio = true; + } + } + if (!haveVideo || !haveAudio) { + return; + } + } else { + // Actively loading; a format may still arrive from the loading thread. + return; + } + Log.i(TAG, "Empty declared track — assigning placeholder (loadingFinished=" + loadingFinished + "). PATCHED_BUILD_OK"); + sampleQueue.format(new Format.Builder().build()); } } loadCondition.close();