mirror of
https://github.com/samsonjs/media.git
synced 2026-03-31 10:25:48 +00:00
Rename ExtractorMediaSource to ProgressiveMediaSource
It better describes what the class does. More importantly, we've had
inconsistent class names since we added offline support, for which we
added ProgressiveDownloader ("ExtractorDownloader" doesn't make any
sense). We could really do with aligning the names for clarity.
(Sorry)
PiperOrigin-RevId: 231387268
This commit is contained in:
parent
ef8335fc50
commit
45433869e5
13 changed files with 349 additions and 126 deletions
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
### dev-v2 (not yet released) ###
|
||||
|
||||
* `ExtractorMediaSource` renamed to `ProgressiveMediaSource`.
|
||||
* HLS:
|
||||
* Parse CHANNELS attribute from EXT-X-MEDIA.
|
||||
* Support for playing spherical videos on Daydream.
|
||||
|
|
|
|||
|
|
@ -35,8 +35,8 @@ import com.google.android.exoplayer2.ext.cast.CastPlayer;
|
|||
import com.google.android.exoplayer2.ext.cast.MediaItem;
|
||||
import com.google.android.exoplayer2.ext.cast.SessionAvailabilityListener;
|
||||
import com.google.android.exoplayer2.source.ConcatenatingMediaSource;
|
||||
import com.google.android.exoplayer2.source.ExtractorMediaSource;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
|
||||
import com.google.android.exoplayer2.source.dash.DashMediaSource;
|
||||
import com.google.android.exoplayer2.source.hls.HlsMediaSource;
|
||||
import com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource;
|
||||
|
|
@ -373,7 +373,7 @@ import java.util.ArrayList;
|
|||
case DemoUtil.MIME_TYPE_HLS:
|
||||
return new HlsMediaSource.Factory(DATA_SOURCE_FACTORY).createMediaSource(uri);
|
||||
case DemoUtil.MIME_TYPE_VIDEO_MP4:
|
||||
return new ExtractorMediaSource.Factory(DATA_SOURCE_FACTORY).createMediaSource(uri);
|
||||
return new ProgressiveMediaSource.Factory(DATA_SOURCE_FACTORY).createMediaSource(uri);
|
||||
default: {
|
||||
throw new IllegalStateException("Unsupported type: " + item.mimeType);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ import com.google.android.exoplayer2.ExoPlayer;
|
|||
import com.google.android.exoplayer2.ExoPlayerFactory;
|
||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||
import com.google.android.exoplayer2.ext.ima.ImaAdsLoader;
|
||||
import com.google.android.exoplayer2.source.ExtractorMediaSource;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
|
||||
import com.google.android.exoplayer2.source.ads.AdsMediaSource;
|
||||
import com.google.android.exoplayer2.source.dash.DashMediaSource;
|
||||
import com.google.android.exoplayer2.source.hls.HlsMediaSource;
|
||||
|
|
@ -125,7 +125,7 @@ import com.google.android.exoplayer2.util.Util;
|
|||
case C.TYPE_HLS:
|
||||
return new HlsMediaSource.Factory(dataSourceFactory).createMediaSource(uri);
|
||||
case C.TYPE_OTHER:
|
||||
return new ExtractorMediaSource.Factory(dataSourceFactory).createMediaSource(uri);
|
||||
return new ProgressiveMediaSource.Factory(dataSourceFactory).createMediaSource(uri);
|
||||
default:
|
||||
throw new IllegalStateException("Unsupported type: " + type);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,8 +51,8 @@ import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryExcep
|
|||
import com.google.android.exoplayer2.offline.StreamKey;
|
||||
import com.google.android.exoplayer2.source.BehindLiveWindowException;
|
||||
import com.google.android.exoplayer2.source.ConcatenatingMediaSource;
|
||||
import com.google.android.exoplayer2.source.ExtractorMediaSource;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
|
||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||
import com.google.android.exoplayer2.source.ads.AdsLoader;
|
||||
import com.google.android.exoplayer2.source.ads.AdsMediaSource;
|
||||
|
|
@ -483,7 +483,7 @@ public class PlayerActivity extends Activity
|
|||
.setStreamKeys(offlineStreamKeys)
|
||||
.createMediaSource(uri);
|
||||
case C.TYPE_OTHER:
|
||||
return new ExtractorMediaSource.Factory(dataSourceFactory).createMediaSource(uri);
|
||||
return new ProgressiveMediaSource.Factory(dataSourceFactory).createMediaSource(uri);
|
||||
default: {
|
||||
throw new IllegalStateException("Unsupported type: " + type);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@ import com.google.android.exoplayer2.ExoPlayerFactory;
|
|||
import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.Renderer;
|
||||
import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor;
|
||||
import com.google.android.exoplayer2.source.ExtractorMediaSource;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
|
||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
||||
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
|
||||
import org.junit.Before;
|
||||
|
|
@ -86,7 +86,7 @@ public class FlacPlaybackTest {
|
|||
player = ExoPlayerFactory.newInstance(context, new Renderer[] {audioRenderer}, trackSelector);
|
||||
player.addListener(this);
|
||||
MediaSource mediaSource =
|
||||
new ExtractorMediaSource.Factory(
|
||||
new ProgressiveMediaSource.Factory(
|
||||
new DefaultDataSourceFactory(context, "ExoPlayerExtFlacTest"))
|
||||
.setExtractorsFactory(MatroskaExtractor.FACTORY)
|
||||
.createMediaSource(uri);
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@ import com.google.android.exoplayer2.ExoPlayerFactory;
|
|||
import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.Renderer;
|
||||
import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor;
|
||||
import com.google.android.exoplayer2.source.ExtractorMediaSource;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
|
||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
||||
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
|
||||
import org.junit.Before;
|
||||
|
|
@ -86,7 +86,7 @@ public class OpusPlaybackTest {
|
|||
player = ExoPlayerFactory.newInstance(context, new Renderer[] {audioRenderer}, trackSelector);
|
||||
player.addListener(this);
|
||||
MediaSource mediaSource =
|
||||
new ExtractorMediaSource.Factory(
|
||||
new ProgressiveMediaSource.Factory(
|
||||
new DefaultDataSourceFactory(context, "ExoPlayerExtOpusTest"))
|
||||
.setExtractorsFactory(MatroskaExtractor.FACTORY)
|
||||
.createMediaSource(uri);
|
||||
|
|
|
|||
|
|
@ -29,8 +29,8 @@ import com.google.android.exoplayer2.ExoPlayerFactory;
|
|||
import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.Renderer;
|
||||
import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor;
|
||||
import com.google.android.exoplayer2.source.ExtractorMediaSource;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
|
||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
||||
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
|
||||
import com.google.android.exoplayer2.util.Log;
|
||||
|
|
@ -119,7 +119,7 @@ public class VpxPlaybackTest {
|
|||
player = ExoPlayerFactory.newInstance(context, new Renderer[] {videoRenderer}, trackSelector);
|
||||
player.addListener(this);
|
||||
MediaSource mediaSource =
|
||||
new ExtractorMediaSource.Factory(
|
||||
new ProgressiveMediaSource.Factory(
|
||||
new DefaultDataSourceFactory(context, "ExoPlayerExtVp9Test"))
|
||||
.setExtractorsFactory(MatroskaExtractor.FACTORY)
|
||||
.createMediaSource(uri);
|
||||
|
|
|
|||
|
|
@ -21,10 +21,10 @@ import com.google.android.exoplayer2.audio.MediaCodecAudioRenderer;
|
|||
import com.google.android.exoplayer2.metadata.MetadataRenderer;
|
||||
import com.google.android.exoplayer2.source.ClippingMediaSource;
|
||||
import com.google.android.exoplayer2.source.ConcatenatingMediaSource;
|
||||
import com.google.android.exoplayer2.source.ExtractorMediaSource;
|
||||
import com.google.android.exoplayer2.source.LoopingMediaSource;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
import com.google.android.exoplayer2.source.MergingMediaSource;
|
||||
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
|
||||
import com.google.android.exoplayer2.source.SingleSampleMediaSource;
|
||||
import com.google.android.exoplayer2.text.TextRenderer;
|
||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
||||
|
|
@ -48,7 +48,7 @@ import com.google.android.exoplayer2.video.MediaCodecVideoRenderer;
|
|||
* <li>A <b>{@link MediaSource}</b> that defines the media to be played, loads the media, and from
|
||||
* which the loaded media can be read. A MediaSource is injected via {@link
|
||||
* #prepare(MediaSource)} at the start of playback. The library modules provide default
|
||||
* implementations for regular media files ({@link ExtractorMediaSource}), DASH
|
||||
* implementations for progressive media files ({@link ProgressiveMediaSource}), DASH
|
||||
* (DashMediaSource), SmoothStreaming (SsMediaSource) and HLS (HlsMediaSource), an
|
||||
* implementation for loading single media samples ({@link SingleSampleMediaSource}) that's
|
||||
* most often used for side-loaded subtitle files, and implementations for building more
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import android.os.Handler;
|
|||
import android.support.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.Timeline;
|
||||
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
|
||||
import com.google.android.exoplayer2.extractor.Extractor;
|
||||
import com.google.android.exoplayer2.extractor.ExtractorsFactory;
|
||||
|
|
@ -32,25 +33,13 @@ import com.google.android.exoplayer2.upstream.TransferListener;
|
|||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Provides one period that loads data from a {@link Uri} and extracted using an {@link Extractor}.
|
||||
*
|
||||
* <p>If the possible input stream container formats are known, pass a factory that instantiates
|
||||
* extractors for them to the constructor. Otherwise, pass a {@link DefaultExtractorsFactory} to use
|
||||
* the default extractors. When reading a new stream, the first {@link Extractor} in the array of
|
||||
* extractors created by the factory that returns {@code true} from {@link Extractor#sniff} will be
|
||||
* used to extract samples from the input stream.
|
||||
*
|
||||
* <p>Note that the built-in extractors for AAC, MPEG PS/TS and FLV streams do not support seeking.
|
||||
*/
|
||||
/** @deprecated Use {@link ProgressiveMediaSource} instead. */
|
||||
@Deprecated
|
||||
@SuppressWarnings("deprecation")
|
||||
public final class ExtractorMediaSource extends BaseMediaSource
|
||||
implements ExtractorMediaPeriod.Listener {
|
||||
implements MediaSource.SourceInfoRefreshListener {
|
||||
|
||||
/**
|
||||
* Listener of {@link ExtractorMediaSource} events.
|
||||
*
|
||||
* @deprecated Use {@link MediaSourceEventListener}.
|
||||
*/
|
||||
/** @deprecated Use {@link MediaSourceEventListener} instead. */
|
||||
@Deprecated
|
||||
public interface EventListener {
|
||||
|
||||
|
|
@ -70,7 +59,8 @@ public final class ExtractorMediaSource extends BaseMediaSource
|
|||
|
||||
}
|
||||
|
||||
/** Factory for {@link ExtractorMediaSource}s. */
|
||||
/** Use {@link ProgressiveMediaSource.Factory} instead. */
|
||||
@Deprecated
|
||||
public static final class Factory implements AdsMediaSource.MediaSourceFactory {
|
||||
|
||||
private final DataSource.Factory dataSourceFactory;
|
||||
|
|
@ -232,23 +222,11 @@ public final class ExtractorMediaSource extends BaseMediaSource
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The default number of bytes that should be loaded between each each invocation of {@link
|
||||
* MediaPeriod.Callback#onContinueLoadingRequested(SequenceableLoader)}.
|
||||
*/
|
||||
public static final int DEFAULT_LOADING_CHECK_INTERVAL_BYTES = 1024 * 1024;
|
||||
@Deprecated
|
||||
public static final int DEFAULT_LOADING_CHECK_INTERVAL_BYTES =
|
||||
ProgressiveMediaSource.DEFAULT_LOADING_CHECK_INTERVAL_BYTES;
|
||||
|
||||
private final Uri uri;
|
||||
private final DataSource.Factory dataSourceFactory;
|
||||
private final ExtractorsFactory extractorsFactory;
|
||||
private final LoadErrorHandlingPolicy loadableLoadErrorHandlingPolicy;
|
||||
private final String customCacheKey;
|
||||
private final int continueLoadingCheckIntervalBytes;
|
||||
private final @Nullable Object tag;
|
||||
|
||||
private long timelineDurationUs;
|
||||
private boolean timelineIsSeekable;
|
||||
private @Nullable TransferListener transferListener;
|
||||
private final ProgressiveMediaSource progressiveMediaSource;
|
||||
|
||||
/**
|
||||
* @param uri The {@link Uri} of the media stream.
|
||||
|
|
@ -261,7 +239,6 @@ public final class ExtractorMediaSource extends BaseMediaSource
|
|||
* @deprecated Use {@link Factory} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("deprecation")
|
||||
public ExtractorMediaSource(
|
||||
Uri uri,
|
||||
DataSource.Factory dataSourceFactory,
|
||||
|
|
@ -284,7 +261,6 @@ public final class ExtractorMediaSource extends BaseMediaSource
|
|||
* @deprecated Use {@link Factory} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("deprecation")
|
||||
public ExtractorMediaSource(
|
||||
Uri uri,
|
||||
DataSource.Factory dataSourceFactory,
|
||||
|
|
@ -317,7 +293,6 @@ public final class ExtractorMediaSource extends BaseMediaSource
|
|||
* @deprecated Use {@link Factory} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("deprecation")
|
||||
public ExtractorMediaSource(
|
||||
Uri uri,
|
||||
DataSource.Factory dataSourceFactory,
|
||||
|
|
@ -347,93 +322,57 @@ public final class ExtractorMediaSource extends BaseMediaSource
|
|||
@Nullable String customCacheKey,
|
||||
int continueLoadingCheckIntervalBytes,
|
||||
@Nullable Object tag) {
|
||||
this.uri = uri;
|
||||
this.dataSourceFactory = dataSourceFactory;
|
||||
this.extractorsFactory = extractorsFactory;
|
||||
this.loadableLoadErrorHandlingPolicy = loadableLoadErrorHandlingPolicy;
|
||||
this.customCacheKey = customCacheKey;
|
||||
this.continueLoadingCheckIntervalBytes = continueLoadingCheckIntervalBytes;
|
||||
this.timelineDurationUs = C.TIME_UNSET;
|
||||
this.tag = tag;
|
||||
progressiveMediaSource =
|
||||
new ProgressiveMediaSource(
|
||||
uri,
|
||||
dataSourceFactory,
|
||||
extractorsFactory,
|
||||
loadableLoadErrorHandlingPolicy,
|
||||
customCacheKey,
|
||||
continueLoadingCheckIntervalBytes,
|
||||
tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Object getTag() {
|
||||
return tag;
|
||||
return progressiveMediaSource.getTag();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) {
|
||||
transferListener = mediaTransferListener;
|
||||
notifySourceInfoRefreshed(timelineDurationUs, timelineIsSeekable);
|
||||
progressiveMediaSource.prepareSource(/* listener= */ this, mediaTransferListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void maybeThrowSourceInfoRefreshError() throws IOException {
|
||||
// Do nothing.
|
||||
progressiveMediaSource.maybeThrowSourceInfoRefreshError();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator, long startPositionUs) {
|
||||
DataSource dataSource = dataSourceFactory.createDataSource();
|
||||
if (transferListener != null) {
|
||||
dataSource.addTransferListener(transferListener);
|
||||
}
|
||||
return new ExtractorMediaPeriod(
|
||||
uri,
|
||||
dataSource,
|
||||
extractorsFactory.createExtractors(),
|
||||
loadableLoadErrorHandlingPolicy,
|
||||
createEventDispatcher(id),
|
||||
this,
|
||||
allocator,
|
||||
customCacheKey,
|
||||
continueLoadingCheckIntervalBytes);
|
||||
return progressiveMediaSource.createPeriod(id, allocator, startPositionUs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releasePeriod(MediaPeriod mediaPeriod) {
|
||||
((ExtractorMediaPeriod) mediaPeriod).release();
|
||||
progressiveMediaSource.releasePeriod(mediaPeriod);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releaseSourceInternal() {
|
||||
// Do nothing.
|
||||
progressiveMediaSource.releaseSource(/* listener= */ this);
|
||||
}
|
||||
|
||||
// ExtractorMediaPeriod.Listener implementation.
|
||||
|
||||
@Override
|
||||
public void onSourceInfoRefreshed(long durationUs, boolean isSeekable) {
|
||||
// If we already have the duration from a previous source info refresh, use it.
|
||||
durationUs = durationUs == C.TIME_UNSET ? timelineDurationUs : durationUs;
|
||||
if (timelineDurationUs == durationUs && timelineIsSeekable == isSeekable) {
|
||||
// Suppress no-op source info changes.
|
||||
return;
|
||||
}
|
||||
notifySourceInfoRefreshed(durationUs, isSeekable);
|
||||
public void onSourceInfoRefreshed(
|
||||
MediaSource source, Timeline timeline, @Nullable Object manifest) {
|
||||
refreshSourceInfo(timeline, manifest);
|
||||
}
|
||||
|
||||
// Internal methods.
|
||||
|
||||
private void notifySourceInfoRefreshed(long durationUs, boolean isSeekable) {
|
||||
timelineDurationUs = durationUs;
|
||||
timelineIsSeekable = isSeekable;
|
||||
// TODO: Make timeline dynamic until its duration is known. This is non-trivial. See b/69703223.
|
||||
refreshSourceInfo(
|
||||
new SinglePeriodTimeline(
|
||||
timelineDurationUs, timelineIsSeekable, /* isDynamic= */ false, tag),
|
||||
/* manifest= */ null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps a deprecated {@link EventListener}, invoking its callback from the equivalent callback in
|
||||
* {@link MediaSourceEventListener}.
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("deprecation")
|
||||
private static final class EventListenerWrapper extends DefaultMediaSourceEventListener {
|
||||
|
||||
private final EventListener eventListener;
|
||||
|
||||
public EventListenerWrapper(EventListener eventListener) {
|
||||
|
|
|
|||
|
|
@ -54,12 +54,13 @@ import java.io.IOException;
|
|||
import java.util.Arrays;
|
||||
import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||
|
||||
/**
|
||||
* A {@link MediaPeriod} that extracts data using an {@link Extractor}.
|
||||
*/
|
||||
/* package */ final class ExtractorMediaPeriod implements MediaPeriod, ExtractorOutput,
|
||||
Loader.Callback<ExtractorMediaPeriod.ExtractingLoadable>, Loader.ReleaseCallback,
|
||||
UpstreamFormatChangedListener {
|
||||
/** A {@link MediaPeriod} that extracts data using an {@link Extractor}. */
|
||||
/* package */ final class ProgressiveMediaPeriod
|
||||
implements MediaPeriod,
|
||||
ExtractorOutput,
|
||||
Loader.Callback<ProgressiveMediaPeriod.ExtractingLoadable>,
|
||||
Loader.ReleaseCallback,
|
||||
UpstreamFormatChangedListener {
|
||||
|
||||
/**
|
||||
* Listener for information about the period.
|
||||
|
|
@ -145,7 +146,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||
"nullness:argument.type.incompatible",
|
||||
"nullness:methodref.receiver.bound.invalid"
|
||||
})
|
||||
public ExtractorMediaPeriod(
|
||||
public ProgressiveMediaPeriod(
|
||||
Uri uri,
|
||||
DataSource dataSource,
|
||||
Extractor[] extractors,
|
||||
|
|
@ -163,14 +164,15 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||
this.allocator = allocator;
|
||||
this.customCacheKey = customCacheKey;
|
||||
this.continueLoadingCheckIntervalBytes = continueLoadingCheckIntervalBytes;
|
||||
loader = new Loader("Loader:ExtractorMediaPeriod");
|
||||
loader = new Loader("Loader:ProgressiveMediaPeriod");
|
||||
extractorHolder = new ExtractorHolder(extractors);
|
||||
loadCondition = new ConditionVariable();
|
||||
maybeFinishPrepareRunnable = this::maybeFinishPrepare;
|
||||
onContinueLoadingRequestedRunnable =
|
||||
() -> {
|
||||
if (!released) {
|
||||
Assertions.checkNotNull(callback).onContinueLoadingRequested(ExtractorMediaPeriod.this);
|
||||
Assertions.checkNotNull(callback)
|
||||
.onContinueLoadingRequested(ProgressiveMediaPeriod.this);
|
||||
}
|
||||
};
|
||||
handler = new Handler();
|
||||
|
|
@ -852,23 +854,23 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||
|
||||
@Override
|
||||
public boolean isReady() {
|
||||
return ExtractorMediaPeriod.this.isReady(track);
|
||||
return ProgressiveMediaPeriod.this.isReady(track);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void maybeThrowError() throws IOException {
|
||||
ExtractorMediaPeriod.this.maybeThrowError();
|
||||
ProgressiveMediaPeriod.this.maybeThrowError();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer,
|
||||
boolean formatRequired) {
|
||||
return ExtractorMediaPeriod.this.readData(track, formatHolder, buffer, formatRequired);
|
||||
return ProgressiveMediaPeriod.this.readData(track, formatHolder, buffer, formatRequired);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int skipData(long positionUs) {
|
||||
return ExtractorMediaPeriod.this.skipData(track, positionUs);
|
||||
return ProgressiveMediaPeriod.this.skipData(track, positionUs);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,281 @@
|
|||
/*
|
||||
* Copyright (C) 2016 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 com.google.android.exoplayer2.source;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.support.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
|
||||
import com.google.android.exoplayer2.extractor.Extractor;
|
||||
import com.google.android.exoplayer2.extractor.ExtractorsFactory;
|
||||
import com.google.android.exoplayer2.source.ads.AdsMediaSource;
|
||||
import com.google.android.exoplayer2.upstream.Allocator;
|
||||
import com.google.android.exoplayer2.upstream.DataSource;
|
||||
import com.google.android.exoplayer2.upstream.DefaultLoadErrorHandlingPolicy;
|
||||
import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy;
|
||||
import com.google.android.exoplayer2.upstream.TransferListener;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Provides one period that loads data from a {@link Uri} and extracted using an {@link Extractor}.
|
||||
*
|
||||
* <p>If the possible input stream container formats are known, pass a factory that instantiates
|
||||
* extractors for them to the constructor. Otherwise, pass a {@link DefaultExtractorsFactory} to use
|
||||
* the default extractors. When reading a new stream, the first {@link Extractor} in the array of
|
||||
* extractors created by the factory that returns {@code true} from {@link Extractor#sniff} will be
|
||||
* used to extract samples from the input stream.
|
||||
*
|
||||
* <p>Note that the built-in extractors for AAC, MPEG PS/TS and FLV streams do not support seeking.
|
||||
*/
|
||||
public final class ProgressiveMediaSource extends BaseMediaSource
|
||||
implements ProgressiveMediaPeriod.Listener {
|
||||
|
||||
/** Factory for {@link ProgressiveMediaSource}s. */
|
||||
public static final class Factory implements AdsMediaSource.MediaSourceFactory {
|
||||
|
||||
private final DataSource.Factory dataSourceFactory;
|
||||
|
||||
@Nullable private ExtractorsFactory extractorsFactory;
|
||||
@Nullable private String customCacheKey;
|
||||
@Nullable private Object tag;
|
||||
private LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
||||
private int continueLoadingCheckIntervalBytes;
|
||||
private boolean isCreateCalled;
|
||||
|
||||
/**
|
||||
* Creates a new factory for {@link ProgressiveMediaSource}s.
|
||||
*
|
||||
* @param dataSourceFactory A factory for {@link DataSource}s to read the media.
|
||||
*/
|
||||
public Factory(DataSource.Factory dataSourceFactory) {
|
||||
this.dataSourceFactory = dataSourceFactory;
|
||||
loadErrorHandlingPolicy = new DefaultLoadErrorHandlingPolicy();
|
||||
continueLoadingCheckIntervalBytes = DEFAULT_LOADING_CHECK_INTERVAL_BYTES;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the factory for {@link Extractor}s to process the media stream. The default value is an
|
||||
* instance of {@link DefaultExtractorsFactory}.
|
||||
*
|
||||
* @param extractorsFactory A factory for {@link Extractor}s to process the media stream. If the
|
||||
* possible formats are known, pass a factory that instantiates extractors for those
|
||||
* formats.
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||
*/
|
||||
public Factory setExtractorsFactory(ExtractorsFactory extractorsFactory) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
this.extractorsFactory = extractorsFactory;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the custom key that uniquely identifies the original stream. Used for cache indexing.
|
||||
* The default value is {@code null}.
|
||||
*
|
||||
* @param customCacheKey A custom key that uniquely identifies the original stream. Used for
|
||||
* cache indexing.
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||
*/
|
||||
public Factory setCustomCacheKey(String customCacheKey) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
this.customCacheKey = customCacheKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a tag for the media source which will be published in the {@link
|
||||
* com.google.android.exoplayer2.Timeline} of the source as {@link
|
||||
* com.google.android.exoplayer2.Timeline.Window#tag}.
|
||||
*
|
||||
* @param tag A tag for the media source.
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||
*/
|
||||
public Factory setTag(Object tag) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
this.tag = tag;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link LoadErrorHandlingPolicy}. The default value is created by calling {@link
|
||||
* DefaultLoadErrorHandlingPolicy#DefaultLoadErrorHandlingPolicy()}.
|
||||
*
|
||||
* @param loadErrorHandlingPolicy A {@link LoadErrorHandlingPolicy}.
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||
*/
|
||||
public Factory setLoadErrorHandlingPolicy(LoadErrorHandlingPolicy loadErrorHandlingPolicy) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
this.loadErrorHandlingPolicy = loadErrorHandlingPolicy;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the number of bytes that should be loaded between each invocation of {@link
|
||||
* MediaPeriod.Callback#onContinueLoadingRequested(SequenceableLoader)}. The default value is
|
||||
* {@link #DEFAULT_LOADING_CHECK_INTERVAL_BYTES}.
|
||||
*
|
||||
* @param continueLoadingCheckIntervalBytes The number of bytes that should be loaded between
|
||||
* each invocation of {@link
|
||||
* MediaPeriod.Callback#onContinueLoadingRequested(SequenceableLoader)}.
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||
*/
|
||||
public Factory setContinueLoadingCheckIntervalBytes(int continueLoadingCheckIntervalBytes) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
this.continueLoadingCheckIntervalBytes = continueLoadingCheckIntervalBytes;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@link ProgressiveMediaSource} using the current parameters.
|
||||
*
|
||||
* @param uri The {@link Uri}.
|
||||
* @return The new {@link ProgressiveMediaSource}.
|
||||
*/
|
||||
@Override
|
||||
public ProgressiveMediaSource createMediaSource(Uri uri) {
|
||||
isCreateCalled = true;
|
||||
if (extractorsFactory == null) {
|
||||
extractorsFactory = new DefaultExtractorsFactory();
|
||||
}
|
||||
return new ProgressiveMediaSource(
|
||||
uri,
|
||||
dataSourceFactory,
|
||||
extractorsFactory,
|
||||
loadErrorHandlingPolicy,
|
||||
customCacheKey,
|
||||
continueLoadingCheckIntervalBytes,
|
||||
tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getSupportedTypes() {
|
||||
return new int[] {C.TYPE_OTHER};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The default number of bytes that should be loaded between each each invocation of {@link
|
||||
* MediaPeriod.Callback#onContinueLoadingRequested(SequenceableLoader)}.
|
||||
*/
|
||||
public static final int DEFAULT_LOADING_CHECK_INTERVAL_BYTES = 1024 * 1024;
|
||||
|
||||
private final Uri uri;
|
||||
private final DataSource.Factory dataSourceFactory;
|
||||
private final ExtractorsFactory extractorsFactory;
|
||||
private final LoadErrorHandlingPolicy loadableLoadErrorHandlingPolicy;
|
||||
@Nullable private final String customCacheKey;
|
||||
private final int continueLoadingCheckIntervalBytes;
|
||||
@Nullable private final Object tag;
|
||||
|
||||
private long timelineDurationUs;
|
||||
private boolean timelineIsSeekable;
|
||||
@Nullable private TransferListener transferListener;
|
||||
|
||||
// TODO: Make private when ExtractorMediaSource is deleted.
|
||||
/* package */ ProgressiveMediaSource(
|
||||
Uri uri,
|
||||
DataSource.Factory dataSourceFactory,
|
||||
ExtractorsFactory extractorsFactory,
|
||||
LoadErrorHandlingPolicy loadableLoadErrorHandlingPolicy,
|
||||
@Nullable String customCacheKey,
|
||||
int continueLoadingCheckIntervalBytes,
|
||||
@Nullable Object tag) {
|
||||
this.uri = uri;
|
||||
this.dataSourceFactory = dataSourceFactory;
|
||||
this.extractorsFactory = extractorsFactory;
|
||||
this.loadableLoadErrorHandlingPolicy = loadableLoadErrorHandlingPolicy;
|
||||
this.customCacheKey = customCacheKey;
|
||||
this.continueLoadingCheckIntervalBytes = continueLoadingCheckIntervalBytes;
|
||||
this.timelineDurationUs = C.TIME_UNSET;
|
||||
this.tag = tag;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Object getTag() {
|
||||
return tag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) {
|
||||
transferListener = mediaTransferListener;
|
||||
notifySourceInfoRefreshed(timelineDurationUs, timelineIsSeekable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void maybeThrowSourceInfoRefreshError() throws IOException {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator, long startPositionUs) {
|
||||
DataSource dataSource = dataSourceFactory.createDataSource();
|
||||
if (transferListener != null) {
|
||||
dataSource.addTransferListener(transferListener);
|
||||
}
|
||||
return new ProgressiveMediaPeriod(
|
||||
uri,
|
||||
dataSource,
|
||||
extractorsFactory.createExtractors(),
|
||||
loadableLoadErrorHandlingPolicy,
|
||||
createEventDispatcher(id),
|
||||
this,
|
||||
allocator,
|
||||
customCacheKey,
|
||||
continueLoadingCheckIntervalBytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releasePeriod(MediaPeriod mediaPeriod) {
|
||||
((ProgressiveMediaPeriod) mediaPeriod).release();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releaseSourceInternal() {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
// ProgressiveMediaPeriod.Listener implementation.
|
||||
|
||||
@Override
|
||||
public void onSourceInfoRefreshed(long durationUs, boolean isSeekable) {
|
||||
// If we already have the duration from a previous source info refresh, use it.
|
||||
durationUs = durationUs == C.TIME_UNSET ? timelineDurationUs : durationUs;
|
||||
if (timelineDurationUs == durationUs && timelineIsSeekable == isSeekable) {
|
||||
// Suppress no-op source info changes.
|
||||
return;
|
||||
}
|
||||
notifySourceInfoRefreshed(durationUs, isSeekable);
|
||||
}
|
||||
|
||||
// Internal methods.
|
||||
|
||||
private void notifySourceInfoRefreshed(long durationUs, boolean isSeekable) {
|
||||
timelineDurationUs = durationUs;
|
||||
timelineIsSeekable = isSeekable;
|
||||
// TODO: Make timeline dynamic until its duration is known. This is non-trivial. See b/69703223.
|
||||
refreshSourceInfo(
|
||||
new SinglePeriodTimeline(
|
||||
timelineDurationUs, timelineIsSeekable, /* isDynamic= */ false, tag),
|
||||
/* manifest= */ null);
|
||||
}
|
||||
}
|
||||
|
|
@ -138,12 +138,12 @@ public final class SingleSampleMediaSource extends BaseMediaSource {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@link ExtractorMediaSource} using the current parameters.
|
||||
* Returns a new {@link SingleSampleMediaSource} using the current parameters.
|
||||
*
|
||||
* @param uri The {@link Uri}.
|
||||
* @param format The {@link Format} of the media stream.
|
||||
* @param durationUs The duration of the media stream in microseconds.
|
||||
* @return The new {@link ExtractorMediaSource}.
|
||||
* @return The new {@link SingleSampleMediaSource}.
|
||||
*/
|
||||
public SingleSampleMediaSource createMediaSource(Uri uri, Format format, long durationUs) {
|
||||
isCreateCalled = true;
|
||||
|
|
|
|||
|
|
@ -25,13 +25,13 @@ import com.google.android.exoplayer2.C;
|
|||
import com.google.android.exoplayer2.Timeline;
|
||||
import com.google.android.exoplayer2.source.CompositeMediaSource;
|
||||
import com.google.android.exoplayer2.source.DeferredMediaPeriod;
|
||||
import com.google.android.exoplayer2.source.ExtractorMediaSource;
|
||||
import com.google.android.exoplayer2.source.MediaPeriod;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener.LoadEventInfo;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener.MediaLoadData;
|
||||
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
|
||||
import com.google.android.exoplayer2.upstream.Allocator;
|
||||
import com.google.android.exoplayer2.upstream.DataSource;
|
||||
import com.google.android.exoplayer2.upstream.DataSpec;
|
||||
|
|
@ -203,7 +203,7 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
|
|||
|
||||
/**
|
||||
* Constructs a new source that inserts ads linearly with the content specified by {@code
|
||||
* contentMediaSource}. Ad media is loaded using {@link ExtractorMediaSource}.
|
||||
* contentMediaSource}. Ad media is loaded using {@link ProgressiveMediaSource}.
|
||||
*
|
||||
* @param contentMediaSource The {@link MediaSource} providing the content to play.
|
||||
* @param dataSourceFactory Factory for data sources used to load ad media.
|
||||
|
|
@ -217,7 +217,7 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
|
|||
ViewGroup adUiViewGroup) {
|
||||
this(
|
||||
contentMediaSource,
|
||||
new ExtractorMediaSource.Factory(dataSourceFactory),
|
||||
new ProgressiveMediaSource.Factory(dataSourceFactory),
|
||||
adsLoader,
|
||||
adUiViewGroup,
|
||||
/* eventHandler= */ null,
|
||||
|
|
@ -249,7 +249,7 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
|
|||
|
||||
/**
|
||||
* Constructs a new source that inserts ads linearly with the content specified by {@code
|
||||
* contentMediaSource}. Ad media is loaded using {@link ExtractorMediaSource}.
|
||||
* contentMediaSource}. Ad media is loaded using {@link ProgressiveMediaSource}.
|
||||
*
|
||||
* @param contentMediaSource The {@link MediaSource} providing the content to play.
|
||||
* @param dataSourceFactory Factory for data sources used to load ad media.
|
||||
|
|
@ -273,7 +273,7 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
|
|||
@Nullable EventListener eventListener) {
|
||||
this(
|
||||
contentMediaSource,
|
||||
new ExtractorMediaSource.Factory(dataSourceFactory),
|
||||
new ProgressiveMediaSource.Factory(dataSourceFactory),
|
||||
adsLoader,
|
||||
adUiViewGroup,
|
||||
eventHandler,
|
||||
|
|
|
|||
Loading…
Reference in a new issue