mirror of
https://github.com/samsonjs/media.git
synced 2026-03-30 10:15:48 +00:00
Allow playback for ads buffered to end
`ImaAdsLoader` only loads ad media URLs once playback of the preceding ad (if any) has started, and this behavior is likely to be similar for other ad loader implementations due to limits on how long before an ad plays it is meant to be loaded. This is problematic for very short ads followed by an ad because the ad will load to the end but load control may not allow playback to start due to the total buffered duration being low. Fix this by allowing playback to start regardless of load control if we are waiting for an ad media period to prepare. An alternative fix would be to fake the ad progress in the `ImaAdsLoader` to trigger loading the next ad, but this would only allow one ad to load ahead (so the problem would remain for two short ads in a row followed by another ad). Issue: #8492 PiperOrigin-RevId: 353600088
This commit is contained in:
parent
6a900ab11b
commit
c37f757854
3 changed files with 57 additions and 2 deletions
|
|
@ -252,6 +252,9 @@
|
|||
skipped but only after the preload timeout rather than instantly
|
||||
([#8428](https://github.com/google/ExoPlayer/issues/8428)),
|
||||
([#7832](https://github.com/google/ExoPlayer/issues/7832)).
|
||||
* Fix a regression that caused a short ad followed by another ad to be
|
||||
skipped due to playback being stuck buffering waiting for the second ad
|
||||
to load ([#8492](https://github.com/google/ExoPlayer/issues/8492)).
|
||||
* FFmpeg extension:
|
||||
* Link the FFmpeg library statically, saving 350KB in binary size on
|
||||
average.
|
||||
|
|
|
|||
|
|
@ -1729,8 +1729,13 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||
? livePlaybackSpeedControl.getTargetLiveOffsetUs()
|
||||
: C.TIME_UNSET;
|
||||
MediaPeriodHolder loadingHolder = queue.getLoadingPeriod();
|
||||
boolean bufferedToEnd = loadingHolder.isFullyBuffered() && loadingHolder.info.isFinal;
|
||||
return bufferedToEnd
|
||||
boolean isBufferedToEnd = loadingHolder.isFullyBuffered() && loadingHolder.info.isFinal;
|
||||
// Ad loader implementations may only load ad media once playback has nearly reached the ad, but
|
||||
// it is possible for playback to be stuck buffering waiting for this. Therefore, we start
|
||||
// playback regardless of buffered duration if we are waiting for an ad media period to prepare.
|
||||
boolean isAdPendingPreparation = loadingHolder.info.id.isAd() && !loadingHolder.prepared;
|
||||
return isBufferedToEnd
|
||||
|| isAdPendingPreparation
|
||||
|| loadControl.shouldStartPlayback(
|
||||
getTotalBufferedDurationUs(),
|
||||
mediaClock.getPlaybackParameters().speed,
|
||||
|
|
|
|||
|
|
@ -4816,6 +4816,53 @@ public final class ExoPlayerTest {
|
|||
.blockUntilEnded(TIMEOUT_MS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shortAdFollowedByUnpreparedAd_playbackDoesNotGetStuck() throws Exception {
|
||||
AdPlaybackState adPlaybackState =
|
||||
FakeTimeline.createAdPlaybackState(/* adsPerAdGroup= */ 2, /* adGroupTimesUs...= */ 0);
|
||||
long shortAdDurationMs = 1_000;
|
||||
adPlaybackState =
|
||||
adPlaybackState.withAdDurationsUs(new long[][] {{shortAdDurationMs, shortAdDurationMs}});
|
||||
Timeline timeline =
|
||||
new FakeTimeline(
|
||||
new TimelineWindowDefinition(
|
||||
/* periodCount= */ 1,
|
||||
/* id= */ 0,
|
||||
/* isSeekable= */ true,
|
||||
/* isDynamic= */ false,
|
||||
/* durationUs= */ C.msToUs(10000),
|
||||
adPlaybackState));
|
||||
// Simulate the second ad not being prepared.
|
||||
FakeMediaSource mediaSource =
|
||||
new FakeMediaSource(timeline, ExoPlayerTestRunner.VIDEO_FORMAT) {
|
||||
@Override
|
||||
protected MediaPeriod createMediaPeriod(
|
||||
MediaPeriodId id,
|
||||
TrackGroupArray trackGroupArray,
|
||||
Allocator allocator,
|
||||
MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher,
|
||||
DrmSessionManager drmSessionManager,
|
||||
DrmSessionEventListener.EventDispatcher drmEventDispatcher,
|
||||
@Nullable TransferListener transferListener) {
|
||||
return new FakeMediaPeriod(
|
||||
trackGroupArray,
|
||||
allocator,
|
||||
FakeMediaPeriod.TrackDataFactory.singleSampleWithTimeUs(0),
|
||||
mediaSourceEventDispatcher,
|
||||
drmSessionManager,
|
||||
drmEventDispatcher,
|
||||
/* deferOnPrepared= */ id.adIndexInAdGroup == 1);
|
||||
}
|
||||
};
|
||||
SimpleExoPlayer player = new TestExoPlayerBuilder(context).build();
|
||||
player.setMediaSource(mediaSource);
|
||||
player.prepare();
|
||||
player.play();
|
||||
|
||||
// The player is not stuck in the buffering state.
|
||||
TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_READY);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void moveMediaItem() throws Exception {
|
||||
TimelineWindowDefinition firstWindowDefinition =
|
||||
|
|
|
|||
Loading…
Reference in a new issue