Merge pull request #123 from stoyicker:wrapping_media_source

PiperOrigin-RevId: 476376463
This commit is contained in:
Marc Baechinger 2022-09-30 18:15:30 +00:00
commit cac8c4f6e9
7 changed files with 263 additions and 89 deletions

View File

@ -25,6 +25,8 @@
AudioTrack offload state. AudioTrack offload state.
([#134](https://github.com/androidx/media/issues/134)). ([#134](https://github.com/androidx/media/issues/134)).
* Make `AudioTrackBufferSizeProvider` a public interface. * Make `AudioTrackBufferSizeProvider` a public interface.
* Add `WrappingMediaSource` to simplify wrapping a single `MediaSource`
([#7279](https://github.com/google/ExoPlayer/issues/7279)).
* Metadata: * Metadata:
* `MetadataRenderer` can now be configured to render metadata as soon as * `MetadataRenderer` can now be configured to render metadata as soon as
they are available. Create an instance with they are available. Create an instance with

View File

@ -200,6 +200,13 @@ public abstract class BaseMediaSource implements MediaSource {
drmEventDispatcher.removeEventListener(eventListener); drmEventDispatcher.removeEventListener(eventListener);
} }
@SuppressWarnings("deprecation") // Overriding deprecated method to make it final.
@Override
public final void prepareSource(
MediaSourceCaller caller, @Nullable TransferListener mediaTransferListener) {
prepareSource(caller, mediaTransferListener, PlayerId.UNSET);
}
@Override @Override
public final void prepareSource( public final void prepareSource(
MediaSourceCaller caller, MediaSourceCaller caller,

View File

@ -22,12 +22,10 @@ import static java.lang.annotation.ElementType.TYPE_USE;
import androidx.annotation.IntDef; import androidx.annotation.IntDef;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.common.MediaItem;
import androidx.media3.common.Timeline; import androidx.media3.common.Timeline;
import androidx.media3.common.util.Assertions; import androidx.media3.common.util.Assertions;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util; import androidx.media3.common.util.Util;
import androidx.media3.datasource.TransferListener;
import androidx.media3.exoplayer.upstream.Allocator; import androidx.media3.exoplayer.upstream.Allocator;
import java.io.IOException; import java.io.IOException;
import java.lang.annotation.Documented; import java.lang.annotation.Documented;
@ -41,7 +39,7 @@ import java.util.ArrayList;
* positions. The wrapped source must consist of a single period. * positions. The wrapped source must consist of a single period.
*/ */
@UnstableApi @UnstableApi
public final class ClippingMediaSource extends CompositeMediaSource<Void> { public final class ClippingMediaSource extends WrappingMediaSource {
/** Thrown when a {@link ClippingMediaSource} cannot clip its wrapped source. */ /** Thrown when a {@link ClippingMediaSource} cannot clip its wrapped source. */
public static final class IllegalClippingException extends IOException { public static final class IllegalClippingException extends IOException {
@ -87,7 +85,6 @@ public final class ClippingMediaSource extends CompositeMediaSource<Void> {
} }
} }
private final MediaSource mediaSource;
private final long startUs; private final long startUs;
private final long endUs; private final long endUs;
private final boolean enableInitialDiscontinuity; private final boolean enableInitialDiscontinuity;
@ -183,8 +180,8 @@ public final class ClippingMediaSource extends CompositeMediaSource<Void> {
boolean enableInitialDiscontinuity, boolean enableInitialDiscontinuity,
boolean allowDynamicClippingUpdates, boolean allowDynamicClippingUpdates,
boolean relativeToDefaultPosition) { boolean relativeToDefaultPosition) {
super(Assertions.checkNotNull(mediaSource));
Assertions.checkArgument(startPositionUs >= 0); Assertions.checkArgument(startPositionUs >= 0);
this.mediaSource = Assertions.checkNotNull(mediaSource);
startUs = startPositionUs; startUs = startPositionUs;
endUs = endPositionUs; endUs = endPositionUs;
this.enableInitialDiscontinuity = enableInitialDiscontinuity; this.enableInitialDiscontinuity = enableInitialDiscontinuity;
@ -194,17 +191,6 @@ public final class ClippingMediaSource extends CompositeMediaSource<Void> {
window = new Timeline.Window(); window = new Timeline.Window();
} }
@Override
public MediaItem getMediaItem() {
return mediaSource.getMediaItem();
}
@Override
protected void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) {
super.prepareSourceInternal(mediaTransferListener);
prepareChildSource(/* id= */ null, mediaSource);
}
@Override @Override
public void maybeThrowSourceInfoRefreshError() throws IOException { public void maybeThrowSourceInfoRefreshError() throws IOException {
if (clippingError != null) { if (clippingError != null) {
@ -242,7 +228,7 @@ public final class ClippingMediaSource extends CompositeMediaSource<Void> {
} }
@Override @Override
protected void onChildSourceInfoRefreshed(Void id, MediaSource mediaSource, Timeline timeline) { protected void onChildSourceInfoRefreshed(Timeline timeline) {
if (clippingError != null) { if (clippingError != null) {
return; return;
} }

View File

@ -17,12 +17,10 @@ package androidx.media3.exoplayer.source;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.common.MediaItem;
import androidx.media3.common.Player; import androidx.media3.common.Player;
import androidx.media3.common.Timeline; import androidx.media3.common.Timeline;
import androidx.media3.common.util.Assertions; import androidx.media3.common.util.Assertions;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.datasource.TransferListener;
import androidx.media3.exoplayer.AbstractConcatenatedTimeline; import androidx.media3.exoplayer.AbstractConcatenatedTimeline;
import androidx.media3.exoplayer.ExoPlayer; import androidx.media3.exoplayer.ExoPlayer;
import androidx.media3.exoplayer.source.ShuffleOrder.UnshuffledShuffleOrder; import androidx.media3.exoplayer.source.ShuffleOrder.UnshuffledShuffleOrder;
@ -43,9 +41,8 @@ import java.util.Map;
*/ */
@Deprecated @Deprecated
@UnstableApi @UnstableApi
public final class LoopingMediaSource extends CompositeMediaSource<Void> { public final class LoopingMediaSource extends WrappingMediaSource {
private final MaskingMediaSource maskingMediaSource;
private final int loopCount; private final int loopCount;
private final Map<MediaPeriodId, MediaPeriodId> childMediaPeriodIdToMediaPeriodId; private final Map<MediaPeriodId, MediaPeriodId> childMediaPeriodIdToMediaPeriodId;
private final Map<MediaPeriod, MediaPeriodId> mediaPeriodToChildMediaPeriodId; private final Map<MediaPeriod, MediaPeriodId> mediaPeriodToChildMediaPeriodId;
@ -67,21 +64,17 @@ public final class LoopingMediaSource extends CompositeMediaSource<Void> {
* @param loopCount The desired number of loops. Must be strictly positive. * @param loopCount The desired number of loops. Must be strictly positive.
*/ */
public LoopingMediaSource(MediaSource childSource, int loopCount) { public LoopingMediaSource(MediaSource childSource, int loopCount) {
super(new MaskingMediaSource(childSource, /* useLazyPreparation= */ false));
Assertions.checkArgument(loopCount > 0); Assertions.checkArgument(loopCount > 0);
this.maskingMediaSource = new MaskingMediaSource(childSource, /* useLazyPreparation= */ false);
this.loopCount = loopCount; this.loopCount = loopCount;
childMediaPeriodIdToMediaPeriodId = new HashMap<>(); childMediaPeriodIdToMediaPeriodId = new HashMap<>();
mediaPeriodToChildMediaPeriodId = new HashMap<>(); mediaPeriodToChildMediaPeriodId = new HashMap<>();
} }
@Override
public MediaItem getMediaItem() {
return maskingMediaSource.getMediaItem();
}
@Override @Override
@Nullable @Nullable
public Timeline getInitialTimeline() { public Timeline getInitialTimeline() {
MaskingMediaSource maskingMediaSource = (MaskingMediaSource) mediaSource;
return loopCount != Integer.MAX_VALUE return loopCount != Integer.MAX_VALUE
? new LoopingTimeline(maskingMediaSource.getTimeline(), loopCount) ? new LoopingTimeline(maskingMediaSource.getTimeline(), loopCount)
: new InfinitelyLoopingTimeline(maskingMediaSource.getTimeline()); : new InfinitelyLoopingTimeline(maskingMediaSource.getTimeline());
@ -92,29 +85,23 @@ public final class LoopingMediaSource extends CompositeMediaSource<Void> {
return false; return false;
} }
@Override
protected void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) {
super.prepareSourceInternal(mediaTransferListener);
prepareChildSource(/* id= */ null, maskingMediaSource);
}
@Override @Override
public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator, long startPositionUs) { public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator, long startPositionUs) {
if (loopCount == Integer.MAX_VALUE) { if (loopCount == Integer.MAX_VALUE) {
return maskingMediaSource.createPeriod(id, allocator, startPositionUs); return mediaSource.createPeriod(id, allocator, startPositionUs);
} }
Object childPeriodUid = LoopingTimeline.getChildPeriodUidFromConcatenatedUid(id.periodUid); Object childPeriodUid = LoopingTimeline.getChildPeriodUidFromConcatenatedUid(id.periodUid);
MediaPeriodId childMediaPeriodId = id.copyWithPeriodUid(childPeriodUid); MediaPeriodId childMediaPeriodId = id.copyWithPeriodUid(childPeriodUid);
childMediaPeriodIdToMediaPeriodId.put(childMediaPeriodId, id); childMediaPeriodIdToMediaPeriodId.put(childMediaPeriodId, id);
MediaPeriod mediaPeriod = MediaPeriod mediaPeriod =
maskingMediaSource.createPeriod(childMediaPeriodId, allocator, startPositionUs); mediaSource.createPeriod(childMediaPeriodId, allocator, startPositionUs);
mediaPeriodToChildMediaPeriodId.put(mediaPeriod, childMediaPeriodId); mediaPeriodToChildMediaPeriodId.put(mediaPeriod, childMediaPeriodId);
return mediaPeriod; return mediaPeriod;
} }
@Override @Override
public void releasePeriod(MediaPeriod mediaPeriod) { public void releasePeriod(MediaPeriod mediaPeriod) {
maskingMediaSource.releasePeriod(mediaPeriod); mediaSource.releasePeriod(mediaPeriod);
@Nullable @Nullable
MediaPeriodId childMediaPeriodId = mediaPeriodToChildMediaPeriodId.remove(mediaPeriod); MediaPeriodId childMediaPeriodId = mediaPeriodToChildMediaPeriodId.remove(mediaPeriod);
if (childMediaPeriodId != null) { if (childMediaPeriodId != null) {
@ -123,7 +110,7 @@ public final class LoopingMediaSource extends CompositeMediaSource<Void> {
} }
@Override @Override
protected void onChildSourceInfoRefreshed(Void id, MediaSource mediaSource, Timeline timeline) { protected void onChildSourceInfoRefreshed(Timeline timeline) {
Timeline loopingTimeline = Timeline loopingTimeline =
loopCount != Integer.MAX_VALUE loopCount != Integer.MAX_VALUE
? new LoopingTimeline(timeline, loopCount) ? new LoopingTimeline(timeline, loopCount)
@ -133,8 +120,7 @@ public final class LoopingMediaSource extends CompositeMediaSource<Void> {
@Override @Override
@Nullable @Nullable
protected MediaPeriodId getMediaPeriodIdForChildMediaPeriodId( protected MediaPeriodId getMediaPeriodIdForChildMediaPeriodId(MediaPeriodId mediaPeriodId) {
Void id, MediaPeriodId mediaPeriodId) {
return loopCount != Integer.MAX_VALUE return loopCount != Integer.MAX_VALUE
? childMediaPeriodIdToMediaPeriodId.get(mediaPeriodId) ? childMediaPeriodIdToMediaPeriodId.get(mediaPeriodId)
: mediaPeriodId; : mediaPeriodId;

View File

@ -28,7 +28,6 @@ import androidx.media3.common.Timeline.Window;
import androidx.media3.common.util.Assertions; import androidx.media3.common.util.Assertions;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util; import androidx.media3.common.util.Util;
import androidx.media3.datasource.TransferListener;
import androidx.media3.exoplayer.upstream.Allocator; import androidx.media3.exoplayer.upstream.Allocator;
import org.checkerframework.checker.nullness.qual.RequiresNonNull; import org.checkerframework.checker.nullness.qual.RequiresNonNull;
@ -37,9 +36,8 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
* structure is known. * structure is known.
*/ */
@UnstableApi @UnstableApi
public final class MaskingMediaSource extends CompositeMediaSource<Void> { public final class MaskingMediaSource extends WrappingMediaSource {
private final MediaSource mediaSource;
private final boolean useLazyPreparation; private final boolean useLazyPreparation;
private final Timeline.Window window; private final Timeline.Window window;
private final Timeline.Period period; private final Timeline.Period period;
@ -59,7 +57,7 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> {
* initial preparations are triggered only when the player starts buffering the media. * initial preparations are triggered only when the player starts buffering the media.
*/ */
public MaskingMediaSource(MediaSource mediaSource, boolean useLazyPreparation) { public MaskingMediaSource(MediaSource mediaSource, boolean useLazyPreparation) {
this.mediaSource = mediaSource; super(mediaSource);
this.useLazyPreparation = useLazyPreparation && mediaSource.isSingleWindow(); this.useLazyPreparation = useLazyPreparation && mediaSource.isSingleWindow();
window = new Timeline.Window(); window = new Timeline.Window();
period = new Timeline.Period(); period = new Timeline.Period();
@ -80,19 +78,13 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> {
} }
@Override @Override
public void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) { public void prepareSourceInternal() {
super.prepareSourceInternal(mediaTransferListener);
if (!useLazyPreparation) { if (!useLazyPreparation) {
hasStartedPreparing = true; hasStartedPreparing = true;
prepareChildSource(/* id= */ null, mediaSource); prepareChildSource();
} }
} }
@Override
public MediaItem getMediaItem() {
return mediaSource.getMediaItem();
}
@Override @Override
@SuppressWarnings("MissingSuperCall") @SuppressWarnings("MissingSuperCall")
public void maybeThrowSourceInfoRefreshError() { public void maybeThrowSourceInfoRefreshError() {
@ -115,7 +107,7 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> {
unpreparedMaskingMediaPeriod = mediaPeriod; unpreparedMaskingMediaPeriod = mediaPeriod;
if (!hasStartedPreparing) { if (!hasStartedPreparing) {
hasStartedPreparing = true; hasStartedPreparing = true;
prepareChildSource(/* id= */ null, mediaSource); prepareChildSource();
} }
} }
return mediaPeriod; return mediaPeriod;
@ -137,8 +129,7 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> {
} }
@Override @Override
protected void onChildSourceInfoRefreshed( protected void onChildSourceInfoRefreshed(Timeline newTimeline) {
Void id, MediaSource mediaSource, Timeline newTimeline) {
@Nullable MediaPeriodId idForMaskingPeriodPreparation = null; @Nullable MediaPeriodId idForMaskingPeriodPreparation = null;
if (isPrepared) { if (isPrepared) {
timeline = timeline.cloneWithUpdatedTimeline(newTimeline); timeline = timeline.cloneWithUpdatedTimeline(newTimeline);
@ -208,8 +199,7 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> {
@Override @Override
@Nullable @Nullable
protected MediaPeriodId getMediaPeriodIdForChildMediaPeriodId( protected MediaPeriodId getMediaPeriodIdForChildMediaPeriodId(MediaPeriodId mediaPeriodId) {
Void id, MediaPeriodId mediaPeriodId) {
return mediaPeriodId.copyWithPeriodUid(getExternalPeriodUid(mediaPeriodId.periodUid)); return mediaPeriodId.copyWithPeriodUid(getExternalPeriodUid(mediaPeriodId.periodUid));
} }
@ -304,11 +294,6 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> {
return new MaskingTimeline(timeline, replacedInternalWindowUid, replacedInternalPeriodUid); return new MaskingTimeline(timeline, replacedInternalWindowUid, replacedInternalPeriodUid);
} }
/** Returns the wrapped timeline. */
public Timeline getTimeline() {
return timeline;
}
@Override @Override
public Window getWindow(int windowIndex, Window window, long defaultPositionProjectionUs) { public Window getWindow(int windowIndex, Window window, long defaultPositionProjectionUs) {
timeline.getWindow(windowIndex, window, defaultPositionProjectionUs); timeline.getWindow(windowIndex, window, defaultPositionProjectionUs);

View File

@ -0,0 +1,231 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.media3.exoplayer.source;
import androidx.annotation.Nullable;
import androidx.media3.common.MediaItem;
import androidx.media3.common.Timeline;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.datasource.TransferListener;
import androidx.media3.exoplayer.analytics.PlayerId;
import androidx.media3.exoplayer.upstream.Allocator;
/**
* An abstract {@link MediaSource} wrapping a single child {@link MediaSource}.
*
* <p>The implementation may want to override the following methods as needed:
*
* <ul>
* <li>{@link #getMediaItem()}: Amend the {@link MediaItem} for this media source. This is only
* used before the child source is prepared.
* <li>{@link #onChildSourceInfoRefreshed(Timeline)}: Called whenever the child source's {@link
* Timeline} changed. This {@link Timeline} can be amended if needed, for example using {@link
* ForwardingTimeline}. The {@link Timeline} for the wrapping source needs to be published
* with {@link #refreshSourceInfo(Timeline)}.
* <li>{@link #createPeriod}/{@link #releasePeriod}: These methods create and release {@link
* MediaPeriod} instances. They typically forward to the wrapped media source and optionally
* wrap the returned {@link MediaPeriod}.
* </ul>
*
* <p>Other methods like {@link #prepareSourceInternal}, {@link #enableInternal}, {@link
* #disableInternal} or {@link #releaseSourceInternal} only need to be overwritten if required for
* resource management.
*/
@UnstableApi
public abstract class WrappingMediaSource extends CompositeMediaSource<Void> {
private static final Void CHILD_SOURCE_ID = null;
/** The wrapped child {@link MediaSource}. */
protected final MediaSource mediaSource;
/**
* Creates the wrapping {@link MediaSource}.
*
* @param mediaSource The wrapped child {@link MediaSource}.
*/
protected WrappingMediaSource(MediaSource mediaSource) {
this.mediaSource = mediaSource;
}
@Override
protected final void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) {
super.prepareSourceInternal(mediaTransferListener);
prepareSourceInternal();
}
/**
* Starts source preparation and enables the source, see {@link #prepareSource(MediaSourceCaller,
* TransferListener, PlayerId)}. This method is called at most once until the next call to {@link
* #releaseSourceInternal()}.
*/
protected void prepareSourceInternal() {
prepareChildSource();
}
@Nullable
@Override
public Timeline getInitialTimeline() {
return mediaSource.getInitialTimeline();
}
@Override
public boolean isSingleWindow() {
return mediaSource.isSingleWindow();
}
/**
* Returns the {@link MediaItem} for this media source.
*
* <p>This method can be overridden to amend the {@link MediaItem} of the child source. It is only
* used before the child source is prepared.
*
* @see MediaSource#getMediaItem()
*/
@Override
public MediaItem getMediaItem() {
return mediaSource.getMediaItem();
}
/**
* Creates the requested {@link MediaPeriod}.
*
* <p>This method typically forwards to the wrapped media source and optionally wraps the returned
* {@link MediaPeriod}.
*
* @see MediaSource#createPeriod(MediaPeriodId, Allocator, long)
*/
@Override
public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator, long startPositionUs) {
return mediaSource.createPeriod(id, allocator, startPositionUs);
}
/**
* Releases a {@link MediaPeriod}.
*
* <p>This method typically forwards to the wrapped media source and optionally unwraps the
* provided {@link MediaPeriod}.
*
* @see MediaSource#releasePeriod(MediaPeriod)
*/
@Override
public void releasePeriod(MediaPeriod mediaPeriod) {
mediaSource.releasePeriod(mediaPeriod);
}
@Override
protected final void onChildSourceInfoRefreshed(
Void id, MediaSource mediaSource, Timeline timeline) {
onChildSourceInfoRefreshed(timeline);
}
/**
* Called when the child source info has been refreshed.
*
* <p>This {@link Timeline} can be amended if needed, for example using {@link
* ForwardingTimeline}. The {@link Timeline} for the wrapping source needs to be published with
* {@link #refreshSourceInfo(Timeline)}.
*
* @param timeline The timeline of the child source.
*/
protected void onChildSourceInfoRefreshed(Timeline timeline) {
refreshSourceInfo(timeline);
}
@Override
protected final int getWindowIndexForChildWindowIndex(Void id, int windowIndex) {
return getWindowIndexForChildWindowIndex(windowIndex);
}
/**
* Returns the window index in the wrapping source corresponding to the specified window index in
* a child source. The default implementation does not change the window index.
*
* @param windowIndex A window index of the child source.
* @return The corresponding window index in the wrapping source.
*/
protected int getWindowIndexForChildWindowIndex(int windowIndex) {
return windowIndex;
}
@Nullable
@Override
protected final MediaPeriodId getMediaPeriodIdForChildMediaPeriodId(
Void id, MediaPeriodId mediaPeriodId) {
return getMediaPeriodIdForChildMediaPeriodId(mediaPeriodId);
}
/**
* Returns the {@link MediaPeriodId} in the wrapping source corresponding to the specified {@link
* MediaPeriodId} in a child source. The default implementation does not change the media period
* id.
*
* @param mediaPeriodId A {@link MediaPeriodId} of the child source.
* @return The corresponding {@link MediaPeriodId} in the wrapping source. Null if no
* corresponding media period id can be determined.
*/
@Nullable
protected MediaPeriodId getMediaPeriodIdForChildMediaPeriodId(MediaPeriodId mediaPeriodId) {
return mediaPeriodId;
}
@Override
protected final long getMediaTimeForChildMediaTime(Void id, long mediaTimeMs) {
return getMediaTimeForChildMediaTime(mediaTimeMs);
}
/**
* Returns the media time in the {@link MediaPeriod} of the wrapping source corresponding to the
* specified media time in the {@link MediaPeriod} of the child source. The default implementation
* does not change the media time.
*
* @param mediaTimeMs A media time in the {@link MediaPeriod} of the child source, in
* milliseconds.
* @return The corresponding media time in the {@link MediaPeriod} of the wrapping source, in
* milliseconds.
*/
protected long getMediaTimeForChildMediaTime(long mediaTimeMs) {
return mediaTimeMs;
}
/**
* Prepares the wrapped child source.
*
* <p>{@link #onChildSourceInfoRefreshed(Timeline)} will be called when the child source updates
* its timeline.
*
* <p>If sources aren't explicitly released with {@link #releaseChildSource()} they will be
* released in {@link #releaseSourceInternal()}.
*/
protected final void prepareChildSource() {
prepareChildSource(CHILD_SOURCE_ID, mediaSource);
}
/** Enables the child source. */
protected final void enableChildSource() {
enableChildSource(CHILD_SOURCE_ID);
}
/** Disables the child source. */
protected final void disableChildSource() {
disableChildSource(CHILD_SOURCE_ID);
}
/** Releases the child source. */
protected final void releaseChildSource() {
releaseChildSource(CHILD_SOURCE_ID);
}
}

View File

@ -118,7 +118,6 @@ import androidx.media3.exoplayer.analytics.AnalyticsListener;
import androidx.media3.exoplayer.drm.DrmSessionEventListener; import androidx.media3.exoplayer.drm.DrmSessionEventListener;
import androidx.media3.exoplayer.drm.DrmSessionManager; import androidx.media3.exoplayer.drm.DrmSessionManager;
import androidx.media3.exoplayer.source.ClippingMediaSource; import androidx.media3.exoplayer.source.ClippingMediaSource;
import androidx.media3.exoplayer.source.CompositeMediaSource;
import androidx.media3.exoplayer.source.ConcatenatingMediaSource; import androidx.media3.exoplayer.source.ConcatenatingMediaSource;
import androidx.media3.exoplayer.source.MaskingMediaSource; import androidx.media3.exoplayer.source.MaskingMediaSource;
import androidx.media3.exoplayer.source.MediaPeriod; import androidx.media3.exoplayer.source.MediaPeriod;
@ -128,6 +127,7 @@ import androidx.media3.exoplayer.source.MediaSourceEventListener;
import androidx.media3.exoplayer.source.ShuffleOrder; import androidx.media3.exoplayer.source.ShuffleOrder;
import androidx.media3.exoplayer.source.SinglePeriodTimeline; import androidx.media3.exoplayer.source.SinglePeriodTimeline;
import androidx.media3.exoplayer.source.TrackGroupArray; import androidx.media3.exoplayer.source.TrackGroupArray;
import androidx.media3.exoplayer.source.WrappingMediaSource;
import androidx.media3.exoplayer.source.ads.ServerSideAdInsertionMediaSource; import androidx.media3.exoplayer.source.ads.ServerSideAdInsertionMediaSource;
import androidx.media3.exoplayer.trackselection.DefaultTrackSelector; import androidx.media3.exoplayer.trackselection.DefaultTrackSelector;
import androidx.media3.exoplayer.upstream.Allocation; import androidx.media3.exoplayer.upstream.Allocation;
@ -3942,33 +3942,15 @@ public final class ExoPlayerTest {
new TimelineWindowDefinition( new TimelineWindowDefinition(
/* isSeekable= */ true, /* isDynamic= */ false, /* durationUs= */ 10_000_000)); /* isSeekable= */ true, /* isDynamic= */ false, /* durationUs= */ 10_000_000));
final ConcatenatingMediaSource underlyingSource = new ConcatenatingMediaSource(); final ConcatenatingMediaSource underlyingSource = new ConcatenatingMediaSource();
CompositeMediaSource<Void> delegatingMediaSource = WrappingMediaSource delegatingMediaSource =
new CompositeMediaSource<Void>() { new WrappingMediaSource(underlyingSource) {
@Override @Override
public void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) { public void prepareSourceInternal() {
super.prepareSourceInternal(mediaTransferListener);
underlyingSource.addMediaSource( underlyingSource.addMediaSource(
new FakeMediaSource(fakeTimeline, ExoPlayerTestRunner.VIDEO_FORMAT)); new FakeMediaSource(fakeTimeline, ExoPlayerTestRunner.VIDEO_FORMAT));
underlyingSource.addMediaSource( underlyingSource.addMediaSource(
new FakeMediaSource(fakeTimeline, ExoPlayerTestRunner.VIDEO_FORMAT)); new FakeMediaSource(fakeTimeline, ExoPlayerTestRunner.VIDEO_FORMAT));
prepareChildSource(null, underlyingSource); super.prepareSourceInternal();
}
@Override
public MediaPeriod createPeriod(
MediaPeriodId id, Allocator allocator, long startPositionUs) {
return underlyingSource.createPeriod(id, allocator, startPositionUs);
}
@Override
public void releasePeriod(MediaPeriod mediaPeriod) {
underlyingSource.releasePeriod(mediaPeriod);
}
@Override
protected void onChildSourceInfoRefreshed(
Void id, MediaSource mediaSource, Timeline timeline) {
refreshSourceInfo(timeline);
} }
@Override @Override
@ -3976,11 +3958,6 @@ public final class ExoPlayerTest {
return false; return false;
} }
@Override
public MediaItem getMediaItem() {
return underlyingSource.getMediaItem();
}
@Override @Override
@Nullable @Nullable
public Timeline getInitialTimeline() { public Timeline getInitialTimeline() {