Finalize class naming

SampleSourceProvider -> MediaSource
SampleSource -> MediaPeriod
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=126914964
This commit is contained in:
olly 2016-07-08 08:45:19 -07:00 committed by Oliver Woodman
parent c9ec7beb92
commit 8e0354c0a6
32 changed files with 635 additions and 666 deletions

View file

@ -15,7 +15,7 @@
*/
package com.google.android.exoplayer2.demo;
import com.google.android.exoplayer2.AdaptiveSourceEventListener;
import com.google.android.exoplayer2.AdaptiveMediaSourceEventListener;
import com.google.android.exoplayer2.CodecCounters;
import com.google.android.exoplayer2.DefaultTrackSelector;
import com.google.android.exoplayer2.DefaultTrackSelector.TrackInfo;
@ -28,7 +28,7 @@ import com.google.android.exoplayer2.TrackGroupArray;
import com.google.android.exoplayer2.TrackRenderer;
import com.google.android.exoplayer2.TrackSelection;
import com.google.android.exoplayer2.drm.StreamingDrmSessionManager;
import com.google.android.exoplayer2.extractor.ExtractorSampleSource;
import com.google.android.exoplayer2.extractor.ExtractorMediaSource;
import com.google.android.exoplayer2.upstream.DataSpec;
import android.os.SystemClock;
@ -42,7 +42,7 @@ import java.util.Locale;
* Logs player events using {@link Log}.
*/
public class EventLogger implements ExoPlayer.EventListener, SimpleExoPlayer.DebugListener,
AdaptiveSourceEventListener, ExtractorSampleSource.EventListener,
AdaptiveMediaSourceEventListener, ExtractorMediaSource.EventListener,
StreamingDrmSessionManager.EventListener, DefaultTrackSelector.EventListener {
private static final String TAG = "EventLogger";
@ -78,8 +78,8 @@ public class EventLogger implements ExoPlayer.EventListener, SimpleExoPlayer.Deb
}
@Override
public void onPositionDiscontinuity(int sourceIndex, long positionMs) {
Log.d(TAG, "discontinuity [" + sourceIndex + ", " + positionMs + "]");
public void onPositionDiscontinuity(int periodIndex, long positionMs) {
Log.d(TAG, "discontinuity [" + periodIndex + ", " + positionMs + "]");
}
@Override
@ -211,14 +211,14 @@ public class EventLogger implements ExoPlayer.EventListener, SimpleExoPlayer.Deb
Log.d(TAG, "drmKeysLoaded [" + getSessionTimeString() + "]");
}
// ExtractorSampleSource.EventListener
// ExtractorMediaSource.EventListener
@Override
public void onLoadError(IOException error) {
printInternalError("loadError", error);
}
// AdaptiveSourceEventListener
// AdaptiveMediaSourceEventListener
@Override
public void onLoadStarted(DataSpec dataSpec, int dataType, int trackType, Format format,

View file

@ -17,7 +17,7 @@ package com.google.android.exoplayer2.demo;
import com.google.android.exoplayer2.AspectRatioFrameLayout;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ConcatenatingSampleSourceProvider;
import com.google.android.exoplayer2.ConcatenatingMediaSource;
import com.google.android.exoplayer2.DefaultLoadControl;
import com.google.android.exoplayer2.DefaultTrackSelectionPolicy;
import com.google.android.exoplayer2.DefaultTrackSelector;
@ -27,23 +27,23 @@ import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.ExoPlayerFactory;
import com.google.android.exoplayer2.MediaCodecTrackRenderer.DecoderInitializationException;
import com.google.android.exoplayer2.MediaCodecUtil.DecoderQueryException;
import com.google.android.exoplayer2.SampleSourceProvider;
import com.google.android.exoplayer2.MediaSource;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.TrackGroupArray;
import com.google.android.exoplayer2.dash.DashSampleSource;
import com.google.android.exoplayer2.dash.DashMediaSource;
import com.google.android.exoplayer2.drm.DrmSessionManager;
import com.google.android.exoplayer2.drm.StreamingDrmSessionManager;
import com.google.android.exoplayer2.drm.UnsupportedDrmException;
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
import com.google.android.exoplayer2.extractor.ExtractorSampleSource;
import com.google.android.exoplayer2.hls.HlsSampleSource;
import com.google.android.exoplayer2.extractor.ExtractorMediaSource;
import com.google.android.exoplayer2.hls.HlsMediaSource;
import com.google.android.exoplayer2.metadata.id3.ApicFrame;
import com.google.android.exoplayer2.metadata.id3.GeobFrame;
import com.google.android.exoplayer2.metadata.id3.Id3Frame;
import com.google.android.exoplayer2.metadata.id3.PrivFrame;
import com.google.android.exoplayer2.metadata.id3.TextInformationFrame;
import com.google.android.exoplayer2.metadata.id3.TxxxFrame;
import com.google.android.exoplayer2.smoothstreaming.SmoothStreamingSampleSource;
import com.google.android.exoplayer2.smoothstreaming.SmoothStreamingMediaSource;
import com.google.android.exoplayer2.text.CaptionStyleCompat;
import com.google.android.exoplayer2.text.Cue;
import com.google.android.exoplayer2.text.SubtitleLayout;
@ -320,34 +320,33 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
return;
}
SampleSourceProvider[] providers = new SampleSourceProvider[uris.length];
MediaSource[] mediaSources = new MediaSource[uris.length];
for (int i = 0; i < uris.length; i++) {
providers[i] = getSampleSourceProvider(uris[i], extensions[i]);
mediaSources[i] = getMediaSource(uris[i], extensions[i]);
}
SampleSourceProvider sourceProvider = providers.length == 1 ? providers[0]
: new ConcatenatingSampleSourceProvider(providers);
player.setSourceProvider(sourceProvider);
MediaSource mediaSource = mediaSources.length == 1 ? mediaSources[0]
: new ConcatenatingMediaSource(mediaSources);
player.setMediaSource(mediaSource);
playerNeedsSource = false;
updateButtonVisibilities();
}
}
private SampleSourceProvider getSampleSourceProvider(Uri uri, String overrideExtension) {
private MediaSource getMediaSource(Uri uri, String overrideExtension) {
String lastPathSegment = !TextUtils.isEmpty(overrideExtension) ? "." + overrideExtension
: uri.getLastPathSegment();
int type = Util.inferContentType(lastPathSegment);
switch (type) {
case Util.TYPE_SS:
return new SmoothStreamingSampleSource(uri, dataSourceFactory, bandwidthMeter, mainHandler,
return new SmoothStreamingMediaSource(uri, dataSourceFactory, bandwidthMeter, mainHandler,
eventLogger);
case Util.TYPE_DASH:
return new DashSampleSource(uri, dataSourceFactory, bandwidthMeter, mainHandler,
return new DashMediaSource(uri, dataSourceFactory, bandwidthMeter, mainHandler,
eventLogger);
case Util.TYPE_HLS:
return new HlsSampleSource(uri, dataSourceFactory, bandwidthMeter, mainHandler,
eventLogger);
return new HlsMediaSource(uri, dataSourceFactory, bandwidthMeter, mainHandler, eventLogger);
case Util.TYPE_OTHER:
return new ExtractorSampleSource(uri, dataSourceFactory, bandwidthMeter,
return new ExtractorMediaSource(uri, dataSourceFactory, bandwidthMeter,
new DefaultExtractorsFactory(), mainHandler, eventLogger);
default:
throw new IllegalStateException("Unsupported type: " + type);
@ -437,7 +436,7 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
}
@Override
public void onPositionDiscontinuity(int sourceIndex, long positionMs) {
public void onPositionDiscontinuity(int periodIndex, long positionMs) {
if (mediaController.isShowing()) {
// The MediaController is visible, so force it to show the updated position immediately.
mediaController.show();

View file

@ -21,7 +21,7 @@ import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.ExoPlayerFactory;
import com.google.android.exoplayer2.TrackRenderer;
import com.google.android.exoplayer2.extractor.ExtractorSampleSource;
import com.google.android.exoplayer2.extractor.ExtractorMediaSource;
import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
@ -76,14 +76,14 @@ public class FlacPlaybackTest extends InstrumentationTestCase {
new DefaultTrackSelectionPolicy(), null);
player = ExoPlayerFactory.newInstance(new TrackRenderer[] {audioRenderer}, trackSelector);
player.addListener(this);
ExtractorSampleSource sampleSource = new ExtractorSampleSource(
ExtractorMediaSource mediaSource = new ExtractorMediaSource(
uri,
new DefaultDataSourceFactory(context, "ExoPlayerExtFlacTest"),
null,
new MatroskaExtractor.Factory(),
null,
null);
player.setSourceProvider(sampleSource);
player.setMediaSource(mediaSource);
player.setPlayWhenReady(true);
Looper.loop();
}
@ -99,7 +99,7 @@ public class FlacPlaybackTest extends InstrumentationTestCase {
}
@Override
public void onPositionDiscontinuity(int sourceIndex, long positionMs) {
public void onPositionDiscontinuity(int periodIndex, long positionMs) {
// Do nothing.
}

View file

@ -21,7 +21,7 @@ import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.ExoPlayerFactory;
import com.google.android.exoplayer2.TrackRenderer;
import com.google.android.exoplayer2.extractor.ExtractorSampleSource;
import com.google.android.exoplayer2.extractor.ExtractorMediaSource;
import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
@ -76,14 +76,14 @@ public class OpusPlaybackTest extends InstrumentationTestCase {
new DefaultTrackSelectionPolicy(), null);
player = ExoPlayerFactory.newInstance(new TrackRenderer[] {audioRenderer}, trackSelector);
player.addListener(this);
ExtractorSampleSource sampleSource = new ExtractorSampleSource(
ExtractorMediaSource mediaSource = new ExtractorMediaSource(
uri,
new DefaultDataSourceFactory(context, "ExoPlayerExtOpusTest"),
null,
new MatroskaExtractor.Factory(),
null,
null);
player.setSourceProvider(sampleSource);
player.setMediaSource(mediaSource);
player.setPlayWhenReady(true);
Looper.loop();
}
@ -99,7 +99,7 @@ public class OpusPlaybackTest extends InstrumentationTestCase {
}
@Override
public void onPositionDiscontinuity(int sourceIndex, long positionMs) {
public void onPositionDiscontinuity(int periodIndex, long positionMs) {
// Do nothing.
}

View file

@ -1,12 +0,0 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.7
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.7

View file

@ -21,7 +21,7 @@ import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.ExoPlayerFactory;
import com.google.android.exoplayer2.TrackRenderer;
import com.google.android.exoplayer2.extractor.ExtractorSampleSource;
import com.google.android.exoplayer2.extractor.ExtractorMediaSource;
import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
@ -92,7 +92,7 @@ public class VpxPlaybackTest extends InstrumentationTestCase {
new DefaultTrackSelectionPolicy(), null);
player = ExoPlayerFactory.newInstance(new TrackRenderer[] {videoRenderer}, trackSelector);
player.addListener(this);
ExtractorSampleSource sampleSource = new ExtractorSampleSource(
ExtractorMediaSource mediaSource = new ExtractorMediaSource(
uri,
new DefaultDataSourceFactory(context, "ExoPlayerExtVp9Test"),
null,
@ -102,7 +102,7 @@ public class VpxPlaybackTest extends InstrumentationTestCase {
player.sendMessages(new ExoPlayer.ExoPlayerMessage(videoRenderer,
LibvpxVideoTrackRenderer.MSG_SET_OUTPUT_BUFFER_RENDERER,
new VpxVideoSurfaceView(context)));
player.setSourceProvider(sampleSource);
player.setMediaSource(mediaSource);
player.setPlayWhenReady(true);
Looper.loop();
}
@ -118,7 +118,7 @@ public class VpxPlaybackTest extends InstrumentationTestCase {
}
@Override
public void onPositionDiscontinuity(int sourceIndex, long positionMs) {
public void onPositionDiscontinuity(int periodIndex, long positionMs) {
// Do nothing.
}

View file

@ -1,12 +0,0 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.7
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.7

View file

@ -25,9 +25,9 @@ import android.os.SystemClock;
import java.io.IOException;
/**
* Interface for callbacks to be notified about events during adaptive playbacks.
* Interface for callbacks to be notified of adaptive {@link MediaSource} events.
*/
public interface AdaptiveSourceEventListener {
public interface AdaptiveMediaSourceEventListener {
/**
* Invoked when a load begins.
@ -171,14 +171,14 @@ public interface AdaptiveSourceEventListener {
Object formatEvaluatorData, long mediaTimeMs);
/**
* Dispatches events to a {@link AdaptiveSourceEventListener}.
* Dispatches events to a {@link AdaptiveMediaSourceEventListener}.
*/
final class EventDispatcher {
private final Handler handler;
private final AdaptiveSourceEventListener listener;
private final AdaptiveMediaSourceEventListener listener;
public EventDispatcher(Handler handler, AdaptiveSourceEventListener listener) {
public EventDispatcher(Handler handler, AdaptiveMediaSourceEventListener listener) {
this.handler = listener != null ? Assertions.checkNotNull(handler) : null;
this.listener = listener;
}

View file

@ -0,0 +1,58 @@
/*
* 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;
/**
* A {@link MediaSource} that concatenates multiple {@link MediaSource}s.
*/
public final class ConcatenatingMediaSource implements MediaSource {
private final MediaSource[] mediaSources;
/**
* @param mediaSources The {@link MediaSource}s to concatenate.
*/
public ConcatenatingMediaSource(MediaSource... mediaSources) {
this.mediaSources = mediaSources;
}
@Override
public int getPeriodCount() {
int sourceCount = 0;
for (MediaSource mediaSource : mediaSources) {
int count = mediaSource.getPeriodCount();
if (count == MediaSource.UNKNOWN_PERIOD_COUNT) {
return UNKNOWN_PERIOD_COUNT;
}
sourceCount += count;
}
return sourceCount;
}
@Override
public MediaPeriod createPeriod(int index) {
int sourceCount = 0;
for (MediaSource mediaSource : mediaSources) {
int count = mediaSource.getPeriodCount();
if (count == MediaSource.UNKNOWN_PERIOD_COUNT || index < sourceCount + count) {
return mediaSource.createPeriod(index - sourceCount);
}
sourceCount += count;
}
throw new IndexOutOfBoundsException();
}
}

View file

@ -1,58 +0,0 @@
/*
* 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;
/**
* A {@link SampleSourceProvider} that concatenates multiple {@link SampleSourceProvider}s.
*/
public final class ConcatenatingSampleSourceProvider implements SampleSourceProvider {
private final SampleSourceProvider[] sampleSourceProviders;
/**
* @param sampleSourcePoviders The {@link SampleSourceProvider}s to concatenate.
*/
public ConcatenatingSampleSourceProvider(SampleSourceProvider... sampleSourcePoviders) {
this.sampleSourceProviders = sampleSourcePoviders;
}
@Override
public int getSourceCount() {
int sourceCount = 0;
for (SampleSourceProvider sampleSourceProvider : sampleSourceProviders) {
int count = sampleSourceProvider.getSourceCount();
if (count == SampleSourceProvider.UNKNOWN_SOURCE_COUNT) {
return UNKNOWN_SOURCE_COUNT;
}
sourceCount += count;
}
return sourceCount;
}
@Override
public SampleSource createSource(int index) {
int sourceCount = 0;
for (SampleSourceProvider sampleSourceProvider : sampleSourceProviders) {
int count = sampleSourceProvider.getSourceCount();
if (count == SampleSourceProvider.UNKNOWN_SOURCE_COUNT || index < sourceCount + count) {
return sampleSourceProvider.createSource(index - sourceCount);
}
sourceCount += count;
}
throw new IndexOutOfBoundsException();
}
}

View file

@ -25,7 +25,7 @@ import java.io.IOException;
public final class ExoPlaybackException extends Exception {
/**
* The error occurred loading data from a {@link SampleSource}.
* The error occurred loading data from a {@link MediaSource}.
* <p>
* Call {@link #getSourceException()} to retrieve the underlying cause.
*/

View file

@ -38,11 +38,11 @@ package com.google.android.exoplayer2;
*
* <p>{@link MediaCodecAudioTrackRenderer} and {@link MediaCodecVideoTrackRenderer} can be used for
* the common cases of rendering audio and video. These components in turn require an
* <i>upstream</i> {@link SampleSource} to be injected through their constructors, where upstream
* <i>upstream</i> {@link MediaPeriod} to be injected through their constructors, where upstream
* is defined to denote a component that is closer to the source of the media. This pattern of
* upstream dependency injection is actively encouraged, since it means that the functionality of
* the player is built up through the composition of components that can easily be exchanged for
* alternate implementations. For example a {@link SampleSource} implementation may require a
* alternate implementations. For example a {@link MediaPeriod} implementation may require a
* further upstream data loading component to be injected through its constructor, with different
* implementations enabling the loading of data from various sources.
*
@ -84,8 +84,7 @@ package com.google.android.exoplayer2;
*
* <p>The possible playback state transitions are shown below. Transitions can be triggered either
* by changes in the state of the {@link TrackRenderer}s being used, or as a result of
* {@link #setSource(SampleSource)}, {@link #setSourceProvider(SampleSourceProvider)},
* {@link #stop()} or {@link #release()} being invoked.</p>
* {@link #setMediaSource(MediaSource)}, {@link #stop()} or {@link #release()} being invoked.</p>
* <p align="center"><img src="../../../../../images/exoplayer_playbackstate.png"
* alt="ExoPlayer playback state transitions"
* border="0"/></p>
@ -128,12 +127,12 @@ public interface ExoPlayer {
// TODO[playlists]: Should source-initiated resets also cause this to be invoked?
/**
* Invoked when the player's position changes due to a discontinuity (seeking or playback
* transitioning to the next source).
* transitioning to the next period).
*
* @param sourceIndex The index of the source being played.
* @param positionMs The playback position in that source, in milliseconds.
* @param periodIndex The index of the period being played.
* @param positionMs The playback position in that period, in milliseconds.
*/
void onPositionDiscontinuity(int sourceIndex, long positionMs);
void onPositionDiscontinuity(int periodIndex, long positionMs);
/**
* Invoked when an error occurs. The playback state will transition to
@ -189,7 +188,7 @@ public interface ExoPlayer {
}
/**
* The player does not have a source to load, so it is neither buffering nor ready to play.
* The player does not have a source to play, so it is neither buffering nor ready to play.
*/
int STATE_IDLE = 1;
/**
@ -236,17 +235,18 @@ public interface ExoPlayer {
int getPlaybackState();
/**
* Sets the player's source provider. The player's position will be reset to the start of the
* first source and the player will transition to {@link #STATE_BUFFERING} until it is ready to
* play it.
* Sets the {@link MediaSource} to play.
* <p>
* The player's position will be reset to the start of the source.
*
* @param sourceProvider The provider of {@link SampleSource}s to play.
* @param mediaSource The {@link MediaSource} to play.
*/
void setSourceProvider(SampleSourceProvider sourceProvider);
void setMediaSource(MediaSource mediaSource);
/**
* Sets whether playback should proceed when {@link #getPlaybackState()} == {@link #STATE_READY}.
* If the player is already in this state, then this method can be used to pause and resume
* <p>
* If the player is already in the ready state then this method can be used to pause and resume
* playback.
*
* @param playWhenReady Whether playback should proceed when ready.
@ -276,19 +276,19 @@ public interface ExoPlayer {
boolean isLoading();
/**
* Seeks to a position specified in milliseconds in the current source.
* Seeks to a position specified in milliseconds in the current period.
*
* @param positionMs The seek position.
*/
void seekTo(long positionMs);
/**
* Seeks to a position specified in milliseconds in the specified source.
* Seeks to a position specified in milliseconds in the specified period.
*
* @param sourceIndex The index of the source to seek to.
* @param positionMs The seek position relative to the start of the specified source.
* @param periodIndex The index of the period to seek to.
* @param positionMs The seek position relative to the start of the specified period.
*/
void seekTo(int sourceIndex, long positionMs);
void seekTo(int periodIndex, long positionMs);
/**
* Stops playback. Use {@code setPlayWhenReady(false)} rather than this method if the intention
@ -298,9 +298,7 @@ public interface ExoPlayer {
* {@link ExoPlayer#STATE_IDLE}. The player instance can still be used, and
* {@link ExoPlayer#release()} must still be called on the player if it's no longer required.
* <p>
* Calling this method does not reset the playback position. If this player instance will be used
* to play another video from its start, then {@code seekTo(0)} should be called after stopping
* the player and before setting the next source.
* Calling this method does not reset the playback position.
*/
void stop();
@ -337,18 +335,18 @@ public interface ExoPlayer {
long getDuration();
/**
* Gets the playback position in the current source, in milliseconds.
* Gets the playback position in the current period, in milliseconds.
*
* @return The playback position in the current source, in milliseconds.
* @return The playback position in the current period, in milliseconds.
*/
long getCurrentPosition();
/**
* Gets the index of the current source.
* Gets the index of the current period.
*
* @return The index of the current source.
* @return The index of the current period.
*/
int getCurrentSourceIndex();
int getCurrentPeriodIndex();
/**
* Gets an estimate of the absolute position in milliseconds up to which data is buffered.

View file

@ -40,14 +40,14 @@ import java.util.concurrent.CopyOnWriteArraySet;
private boolean playWhenReady;
private int playbackState;
private int pendingPlayWhenReadyAcks;
private int pendingSetSourceProviderAndSeekAcks;
private int pendingSetMediaSourceAndSeekAcks;
private boolean isLoading;
// Playback information when there is no pending seek/set source operation.
private PlaybackInfo playbackInfo;
// Playback information when there is a pending seek/set source operation.
private int maskingSourceIndex;
private int maskingPeriodIndex;
private long maskingPositionMs;
private long maskingDurationMs;
@ -94,13 +94,13 @@ import java.util.concurrent.CopyOnWriteArraySet;
}
@Override
public void setSourceProvider(SampleSourceProvider sourceProvider) {
maskingSourceIndex = 0;
public void setMediaSource(MediaSource mediaSource) {
maskingPeriodIndex = 0;
maskingPositionMs = 0;
maskingDurationMs = ExoPlayer.UNKNOWN_TIME;
pendingSetSourceProviderAndSeekAcks++;
internalPlayer.setSourceProvider(sourceProvider);
pendingSetMediaSourceAndSeekAcks++;
internalPlayer.setMediaSource(mediaSource);
for (EventListener listener : listeners) {
listener.onPositionDiscontinuity(0, 0);
}
@ -135,20 +135,20 @@ import java.util.concurrent.CopyOnWriteArraySet;
@Override
public void seekTo(long positionMs) {
seekTo(getCurrentSourceIndex(), positionMs);
seekTo(getCurrentPeriodIndex(), positionMs);
}
@Override
public void seekTo(int sourceIndex, long positionMs) {
boolean sourceChanging = sourceIndex != getCurrentSourceIndex();
maskingSourceIndex = sourceIndex;
public void seekTo(int periodIndex, long positionMs) {
boolean periodChanging = periodIndex != getCurrentPeriodIndex();
maskingPeriodIndex = periodIndex;
maskingPositionMs = positionMs;
maskingDurationMs = sourceChanging ? ExoPlayer.UNKNOWN_TIME : getDuration();
maskingDurationMs = periodChanging ? ExoPlayer.UNKNOWN_TIME : getDuration();
pendingSetSourceProviderAndSeekAcks++;
internalPlayer.seekTo(sourceIndex, positionMs * 1000);
pendingSetMediaSourceAndSeekAcks++;
internalPlayer.seekTo(periodIndex, positionMs * 1000);
for (EventListener listener : listeners) {
listener.onPositionDiscontinuity(sourceIndex, positionMs);
listener.onPositionDiscontinuity(periodIndex, positionMs);
}
}
@ -175,7 +175,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
@Override
public long getDuration() {
if (pendingSetSourceProviderAndSeekAcks == 0) {
if (pendingSetMediaSourceAndSeekAcks == 0) {
long durationUs = playbackInfo.durationUs;
return durationUs == C.UNSET_TIME_US ? ExoPlayer.UNKNOWN_TIME : durationUs / 1000;
} else {
@ -185,18 +185,18 @@ import java.util.concurrent.CopyOnWriteArraySet;
@Override
public long getCurrentPosition() {
return pendingSetSourceProviderAndSeekAcks == 0 ? playbackInfo.positionUs / 1000
return pendingSetMediaSourceAndSeekAcks == 0 ? playbackInfo.positionUs / 1000
: maskingPositionMs;
}
@Override
public int getCurrentSourceIndex() {
return pendingSetSourceProviderAndSeekAcks == 0 ? playbackInfo.sourceIndex : maskingSourceIndex;
public int getCurrentPeriodIndex() {
return pendingSetMediaSourceAndSeekAcks == 0 ? playbackInfo.periodIndex : maskingPeriodIndex;
}
@Override
public long getBufferedPosition() {
if (pendingSetSourceProviderAndSeekAcks == 0) {
if (pendingSetMediaSourceAndSeekAcks == 0) {
long bufferedPositionUs = playbackInfo.bufferedPositionUs;
return bufferedPositionUs == C.END_OF_SOURCE_US ? getDuration() : bufferedPositionUs / 1000;
} else {
@ -238,16 +238,16 @@ import java.util.concurrent.CopyOnWriteArraySet;
}
break;
}
case ExoPlayerImplInternal.MSG_SET_SOURCE_PROVIDER_ACK: // Fall through.
case ExoPlayerImplInternal.MSG_SET_MEDIA_SOURCE_ACK: // Fall through.
case ExoPlayerImplInternal.MSG_SEEK_ACK: {
pendingSetSourceProviderAndSeekAcks--;
pendingSetMediaSourceAndSeekAcks--;
break;
}
case ExoPlayerImplInternal.MSG_SOURCE_CHANGED: {
case ExoPlayerImplInternal.MSG_PERIOD_CHANGED: {
playbackInfo = (ExoPlayerImplInternal.PlaybackInfo) msg.obj;
if (pendingSetSourceProviderAndSeekAcks == 0) {
if (pendingSetMediaSourceAndSeekAcks == 0) {
for (EventListener listener : listeners) {
listener.onPositionDiscontinuity(playbackInfo.sourceIndex, 0);
listener.onPositionDiscontinuity(playbackInfo.periodIndex, 0);
}
}
break;

View file

@ -35,7 +35,7 @@ import java.util.ArrayList;
/**
* Implements the internal behavior of {@link ExoPlayerImpl}.
*/
/* package */ final class ExoPlayerImplInternal implements Handler.Callback, SampleSource.Callback,
/* package */ final class ExoPlayerImplInternal implements Handler.Callback, MediaPeriod.Callback,
InvalidationListener {
/**
@ -44,14 +44,14 @@ import java.util.ArrayList;
*/
public static final class PlaybackInfo {
public final int sourceIndex;
public final int periodIndex;
public volatile long positionUs;
public volatile long bufferedPositionUs;
public volatile long durationUs;
public PlaybackInfo(int sourceIndex) {
this.sourceIndex = sourceIndex;
public PlaybackInfo(int periodIndex) {
this.periodIndex = periodIndex;
durationUs = C.UNSET_TIME_US;
}
@ -63,19 +63,19 @@ import java.util.ArrayList;
public static final int MSG_STATE_CHANGED = 1;
public static final int MSG_LOADING_CHANGED = 2;
public static final int MSG_SET_PLAY_WHEN_READY_ACK = 3;
public static final int MSG_SET_SOURCE_PROVIDER_ACK = 4;
public static final int MSG_SET_MEDIA_SOURCE_ACK = 4;
public static final int MSG_SEEK_ACK = 5;
public static final int MSG_SOURCE_CHANGED = 6;
public static final int MSG_PERIOD_CHANGED = 6;
public static final int MSG_ERROR = 7;
// Internal messages
private static final int MSG_SET_SOURCE_PROVIDER = 0;
private static final int MSG_SET_MEDIA_SOURCE = 0;
private static final int MSG_SET_PLAY_WHEN_READY = 1;
private static final int MSG_DO_SOME_WORK = 2;
private static final int MSG_SEEK_TO = 3;
private static final int MSG_STOP = 4;
private static final int MSG_RELEASE = 5;
private static final int MSG_SOURCE_PREPARED = 6;
private static final int MSG_PERIOD_PREPARED = 6;
private static final int MSG_SOURCE_CONTINUE_LOADING_REQUESTED = 7;
private static final int MSG_TRACK_SELECTION_INVALIDATED = 8;
private static final int MSG_CUSTOM = 9;
@ -102,7 +102,7 @@ import java.util.ArrayList;
private PlaybackInfo playbackInfo;
private TrackRenderer rendererMediaClockSource;
private MediaClock rendererMediaClock;
private SampleSourceProvider sampleSourceProvider;
private MediaSource mediaSource;
private TrackRenderer[] enabledRenderers;
private boolean released;
private boolean playWhenReady;
@ -142,16 +142,16 @@ import java.util.ArrayList;
handler = new Handler(internalPlaybackThread.getLooper(), this);
}
public void setSourceProvider(SampleSourceProvider sourceProvider) {
handler.obtainMessage(MSG_SET_SOURCE_PROVIDER, sourceProvider).sendToTarget();
public void setMediaSource(MediaSource mediaSource) {
handler.obtainMessage(MSG_SET_MEDIA_SOURCE, mediaSource).sendToTarget();
}
public void setPlayWhenReady(boolean playWhenReady) {
handler.obtainMessage(MSG_SET_PLAY_WHEN_READY, playWhenReady ? 1 : 0, 0).sendToTarget();
}
public void seekTo(int sourceIndex, long positionUs) {
handler.obtainMessage(MSG_SEEK_TO, sourceIndex, -1, positionUs).sendToTarget();
public void seekTo(int periodIndex, long positionUs) {
handler.obtainMessage(MSG_SEEK_TO, periodIndex, -1, positionUs).sendToTarget();
}
public void stop() {
@ -205,15 +205,15 @@ import java.util.ArrayList;
handler.sendEmptyMessage(MSG_TRACK_SELECTION_INVALIDATED);
}
// SampleSource.Callback implementation.
// MediaPeriod.Callback implementation.
@Override
public void onSourcePrepared(SampleSource source) {
handler.obtainMessage(MSG_SOURCE_PREPARED, source).sendToTarget();
public void onPeriodPrepared(MediaPeriod source) {
handler.obtainMessage(MSG_PERIOD_PREPARED, source).sendToTarget();
}
@Override
public void onContinueLoadingRequested(SampleSource source) {
public void onContinueLoadingRequested(MediaPeriod source) {
handler.obtainMessage(MSG_SOURCE_CONTINUE_LOADING_REQUESTED, source).sendToTarget();
}
@ -223,8 +223,8 @@ import java.util.ArrayList;
public boolean handleMessage(Message msg) {
try {
switch (msg.what) {
case MSG_SET_SOURCE_PROVIDER: {
setSourceProviderInternal((SampleSourceProvider) msg.obj);
case MSG_SET_MEDIA_SOURCE: {
setMediaSourceInternal((MediaSource) msg.obj);
return true;
}
case MSG_SET_PLAY_WHEN_READY: {
@ -247,12 +247,12 @@ import java.util.ArrayList;
releaseInternal();
return true;
}
case MSG_SOURCE_PREPARED: {
timeline.handleSourcePrepared((SampleSource) msg.obj);
case MSG_PERIOD_PREPARED: {
timeline.handlePeriodPrepared((MediaPeriod) msg.obj);
return true;
}
case MSG_SOURCE_CONTINUE_LOADING_REQUESTED: {
timeline.handleContinueLoadingRequested((SampleSource) msg.obj);
timeline.handleContinueLoadingRequested((MediaPeriod) msg.obj);
return true;
}
case MSG_TRACK_SELECTION_INVALIDATED: {
@ -301,14 +301,14 @@ import java.util.ArrayList;
}
}
private void setSourceProviderInternal(SampleSourceProvider sourceProvider) {
private void setMediaSourceInternal(MediaSource mediaSource) {
try {
resetInternal();
sampleSourceProvider = sourceProvider;
this.mediaSource = mediaSource;
setState(ExoPlayer.STATE_BUFFERING);
handler.sendEmptyMessage(MSG_DO_SOME_WORK);
} finally {
eventHandler.sendEmptyMessage(MSG_SET_SOURCE_PROVIDER_ACK);
eventHandler.sendEmptyMessage(MSG_SET_MEDIA_SOURCE_ACK);
}
}
@ -348,18 +348,18 @@ import java.util.ArrayList;
}
private void updatePlaybackPositions() throws ExoPlaybackException {
SampleSource sampleSource = timeline.getSampleSource();
if (sampleSource == null) {
MediaPeriod mediaPeriod = timeline.getPeriod();
if (mediaPeriod == null) {
return;
}
// Update the duration.
if (playbackInfo.durationUs == C.UNSET_TIME_US) {
playbackInfo.durationUs = sampleSource.getDurationUs();
playbackInfo.durationUs = mediaPeriod.getDurationUs();
}
// Update the playback position.
long positionUs = sampleSource.readDiscontinuity();
long positionUs = mediaPeriod.readDiscontinuity();
if (positionUs != C.UNSET_TIME_US) {
resetInternalPosition(positionUs);
} else {
@ -369,7 +369,7 @@ import java.util.ArrayList;
} else {
internalPositionUs = standaloneMediaClock.getPositionUs();
}
positionUs = internalPositionUs - timeline.playingSource.offsetUs;
positionUs = internalPositionUs - timeline.playingPeriod.offsetUs;
}
playbackInfo.positionUs = positionUs;
elapsedRealtimeUs = SystemClock.elapsedRealtime() * 1000;
@ -379,7 +379,7 @@ import java.util.ArrayList;
if (enabledRenderers.length == 0) {
bufferedPositionUs = C.END_OF_SOURCE_US;
} else {
bufferedPositionUs = sampleSource.getBufferedPositionUs();
bufferedPositionUs = mediaPeriod.getBufferedPositionUs();
}
playbackInfo.bufferedPositionUs = bufferedPositionUs;
}
@ -387,10 +387,10 @@ import java.util.ArrayList;
private void doSomeWork() throws ExoPlaybackException, IOException {
long operationStartTimeMs = SystemClock.elapsedRealtime();
timeline.updateSources();
if (timeline.getSampleSource() == null) {
timeline.updatePeriods();
if (timeline.getPeriod() == null) {
// We're still waiting for the first source to be prepared.
timeline.maybeThrowSourcePrepareError();
timeline.maybeThrowPeriodPrepareError();
scheduleNextOperation(MSG_DO_SOME_WORK, operationStartTimeMs, PREPARING_SOURCE_INTERVAL_MS);
return;
}
@ -416,7 +416,7 @@ import java.util.ArrayList;
}
if (!allRenderersReadyOrEnded) {
timeline.maybeThrowSourcePrepareError();
timeline.maybeThrowPeriodPrepareError();
}
if (allRenderersEnded && (playbackInfo.durationUs == C.UNSET_TIME_US
@ -460,9 +460,9 @@ import java.util.ArrayList;
}
}
private void seekToInternal(int sourceIndex, long seekPositionUs) throws ExoPlaybackException {
private void seekToInternal(int periodIndex, long seekPositionUs) throws ExoPlaybackException {
try {
if (sourceIndex == playbackInfo.sourceIndex
if (periodIndex == playbackInfo.periodIndex
&& (seekPositionUs / 1000) == (playbackInfo.positionUs / 1000)) {
// Seek position equals the current position to the nearest millisecond. Do nothing.
return;
@ -471,17 +471,17 @@ import java.util.ArrayList;
stopRenderers();
rebuffering = false;
seekPositionUs = timeline.seekTo(sourceIndex, seekPositionUs);
if (sourceIndex != playbackInfo.sourceIndex) {
playbackInfo = new PlaybackInfo(sourceIndex);
seekPositionUs = timeline.seekTo(periodIndex, seekPositionUs);
if (periodIndex != playbackInfo.periodIndex) {
playbackInfo = new PlaybackInfo(periodIndex);
playbackInfo.positionUs = seekPositionUs;
eventHandler.obtainMessage(MSG_SOURCE_CHANGED, playbackInfo).sendToTarget();
eventHandler.obtainMessage(MSG_PERIOD_CHANGED, playbackInfo).sendToTarget();
} else {
playbackInfo.positionUs = seekPositionUs;
}
updatePlaybackPositions();
if (sampleSourceProvider != null) {
if (mediaSource != null) {
setState(ExoPlayer.STATE_BUFFERING);
handler.sendEmptyMessage(MSG_DO_SOME_WORK);
}
@ -490,9 +490,9 @@ import java.util.ArrayList;
}
}
private void resetInternalPosition(long sourcePositionUs) throws ExoPlaybackException {
long sourceOffsetUs = timeline.playingSource == null ? 0 : timeline.playingSource.offsetUs;
internalPositionUs = sourceOffsetUs + sourcePositionUs;
private void resetInternalPosition(long periodPositionUs) throws ExoPlaybackException {
long sourceOffsetUs = timeline.playingPeriod == null ? 0 : timeline.playingPeriod.offsetUs;
internalPositionUs = sourceOffsetUs + periodPositionUs;
standaloneMediaClock.setPositionUs(internalPositionUs);
for (TrackRenderer renderer : enabledRenderers) {
renderer.reset(internalPositionUs);
@ -529,7 +529,7 @@ import java.util.ArrayList;
}
}
enabledRenderers = new TrackRenderer[0];
sampleSourceProvider = null;
mediaSource = null;
timeline.reset();
loadControl.reset();
setIsLoading(false);
@ -540,7 +540,7 @@ import java.util.ArrayList;
for (ExoPlayerMessage message : messages) {
message.target.handleMessage(message.messageType, message.message);
}
if (sampleSourceProvider != null) {
if (mediaSource != null) {
// The message may have caused something to change that now requires us to do work.
handler.sendEmptyMessage(MSG_DO_SOME_WORK);
}
@ -559,7 +559,7 @@ import java.util.ArrayList;
}
private void reselectTracksInternal() throws ExoPlaybackException {
if (timeline.getSampleSource() == null) {
if (timeline.getPeriod() == null) {
// We don't have tracks yet, so we don't care.
return;
}
@ -569,7 +569,7 @@ import java.util.ArrayList;
}
/**
* Keeps track of the {@link Source}s of media being played in the timeline.
* Keeps track of the {@link Period}s of media being played in the timeline.
*/
private final class Timeline {
@ -578,107 +578,107 @@ import java.util.ArrayList;
public boolean isReady;
public boolean isEnded;
private Source playingSource;
private Source readingSource;
private Source loadingSource;
private Period playingPeriod;
private Period readingPeriod;
private Period loadingPeriod;
private int pendingSourceIndex;
private long playingSourceEndPositionUs;
private int pendingPeriodIndex;
private long playingPeriodEndPositionUs;
public Timeline(TrackRenderer[] renderers) {
this.renderers = renderers;
playingSourceEndPositionUs = C.UNSET_TIME_US;
playingPeriodEndPositionUs = C.UNSET_TIME_US;
}
public SampleSource getSampleSource() throws ExoPlaybackException {
return playingSource == null ? null : playingSource.sampleSource;
public MediaPeriod getPeriod() throws ExoPlaybackException {
return playingPeriod == null ? null : playingPeriod.mediaPeriod;
}
public boolean haveSufficientBuffer(boolean rebuffering) {
if (loadingSource == null) {
if (loadingPeriod == null) {
return false;
}
long positionUs = internalPositionUs - loadingSource.offsetUs;
long bufferedPositionUs = !loadingSource.prepared ? 0
: loadingSource.sampleSource.getBufferedPositionUs();
long positionUs = internalPositionUs - loadingPeriod.offsetUs;
long bufferedPositionUs = !loadingPeriod.prepared ? 0
: loadingPeriod.mediaPeriod.getBufferedPositionUs();
if (bufferedPositionUs == C.END_OF_SOURCE_US) {
int sourceCount = sampleSourceProvider.getSourceCount();
if (sourceCount != SampleSourceProvider.UNKNOWN_SOURCE_COUNT
&& loadingSource.index == sourceCount - 1) {
int periodCount = mediaSource.getPeriodCount();
if (periodCount != MediaSource.UNKNOWN_PERIOD_COUNT
&& loadingPeriod.index == periodCount - 1) {
return true;
}
bufferedPositionUs = loadingSource.sampleSource.getDurationUs();
bufferedPositionUs = loadingPeriod.mediaPeriod.getDurationUs();
}
return loadControl.shouldStartPlayback(bufferedPositionUs - positionUs, rebuffering);
}
public void maybeThrowSourcePrepareError() throws IOException {
if (loadingSource != null && !loadingSource.prepared
&& (readingSource == null || readingSource.nextSource == loadingSource)) {
public void maybeThrowPeriodPrepareError() throws IOException {
if (loadingPeriod != null && !loadingPeriod.prepared
&& (readingPeriod == null || readingPeriod.nextPeriod == loadingPeriod)) {
for (TrackRenderer renderer : enabledRenderers) {
if (!renderer.hasReadStreamToEnd()) {
return;
}
}
loadingSource.sampleSource.maybeThrowPrepareError();
loadingPeriod.mediaPeriod.maybeThrowPrepareError();
}
}
public void updateSources() throws ExoPlaybackException, IOException {
// TODO[playlists]: Let sample source providers invalidate sources that are already loaded.
public void updatePeriods() throws ExoPlaybackException, IOException {
// TODO[playlists]: Let MediaSource invalidate periods that are already loaded.
// Update the loading source.
int sourceCount = sampleSourceProvider.getSourceCount();
if (loadingSource == null
|| (loadingSource.isFullyBuffered() && loadingSource.index
- (playingSource != null ? playingSource.index : 0) < MAXIMUM_BUFFER_AHEAD_SOURCES)) {
// Try and obtain the next source to start loading.
int sourceIndex = loadingSource == null ? pendingSourceIndex : loadingSource.index + 1;
if (sourceCount == SampleSourceProvider.UNKNOWN_SOURCE_COUNT || sourceIndex < sourceCount) {
// Attempt to create the next source.
SampleSource sampleSource = sampleSourceProvider.createSource(sourceIndex);
if (sampleSource != null) {
Source newSource = new Source(renderers, trackSelector, sampleSource, sourceIndex);
if (loadingSource != null) {
loadingSource.setNextSource(newSource);
// Update the loading period.
int periodCount = mediaSource.getPeriodCount();
if (loadingPeriod == null
|| (loadingPeriod.isFullyBuffered() && loadingPeriod.index
- (playingPeriod != null ? playingPeriod.index : 0) < MAXIMUM_BUFFER_AHEAD_SOURCES)) {
// Try and obtain the next period to start loading.
int periodIndex = loadingPeriod == null ? pendingPeriodIndex : loadingPeriod.index + 1;
if (periodCount == MediaSource.UNKNOWN_PERIOD_COUNT || periodIndex < periodCount) {
// Attempt to create the next period.
MediaPeriod mediaPeriod = mediaSource.createPeriod(periodIndex);
if (mediaPeriod != null) {
Period newPeriod = new Period(renderers, trackSelector, mediaPeriod, periodIndex);
if (loadingPeriod != null) {
loadingPeriod.setNextPeriod(newPeriod);
}
loadingSource = newSource;
long startPositionUs = playingSource == null ? playbackInfo.positionUs : 0;
loadingPeriod = newPeriod;
long startPositionUs = playingPeriod == null ? playbackInfo.positionUs : 0;
setIsLoading(true);
loadingSource.sampleSource.prepare(ExoPlayerImplInternal.this,
loadingPeriod.mediaPeriod.prepare(ExoPlayerImplInternal.this,
loadControl.getAllocator(), startPositionUs);
}
}
}
if (loadingSource == null || loadingSource.isFullyBuffered()) {
if (loadingPeriod == null || loadingPeriod.isFullyBuffered()) {
setIsLoading(false);
} else if (loadingSource != null && loadingSource.needsContinueLoading) {
} else if (loadingPeriod != null && loadingPeriod.needsContinueLoading) {
maybeContinueLoading();
}
if (playingSource == null) {
// We're waiting for the first source to be prepared.
if (playingPeriod == null) {
// We're waiting for the first period to be prepared.
return;
}
// Update the playing and reading sources.
if (playingSourceEndPositionUs == C.UNSET_TIME_US && playingSource.isFullyBuffered()) {
playingSourceEndPositionUs = playingSource.offsetUs
+ playingSource.sampleSource.getDurationUs();
// Update the playing and reading periods.
if (playingPeriodEndPositionUs == C.UNSET_TIME_US && playingPeriod.isFullyBuffered()) {
playingPeriodEndPositionUs = playingPeriod.offsetUs
+ playingPeriod.mediaPeriod.getDurationUs();
}
while (playingSource != readingSource && playingSource.nextSource != null
&& internalPositionUs >= playingSource.nextSource.offsetUs) {
while (playingPeriod != readingPeriod && playingPeriod.nextPeriod != null
&& internalPositionUs >= playingPeriod.nextPeriod.offsetUs) {
// All enabled renderers' streams have been read to the end, and the playback position
// reached the end of the playing source, so advance playback to the next source.
playingSource.release();
setPlayingSource(playingSource.nextSource);
playbackInfo = new PlaybackInfo(playingSource.index);
// reached the end of the playing period, so advance playback to the next period.
playingPeriod.release();
setPlayingPeriod(playingPeriod.nextPeriod);
playbackInfo = new PlaybackInfo(playingPeriod.index);
updatePlaybackPositions();
eventHandler.obtainMessage(MSG_SOURCE_CHANGED, playbackInfo).sendToTarget();
eventHandler.obtainMessage(MSG_PERIOD_CHANGED, playbackInfo).sendToTarget();
}
updateTimelineState();
if (readingSource == null) {
if (readingPeriod == null) {
// The renderers have their final TrackStreams.
return;
}
@ -687,104 +687,104 @@ import java.util.ArrayList;
return;
}
}
if (readingSource.nextSource != null && readingSource.nextSource.prepared) {
TrackSelectionArray oldTrackSelections = readingSource.trackSelections;
readingSource = readingSource.nextSource;
TrackSelectionArray newTrackSelections = readingSource.trackSelections;
TrackGroupArray groups = readingSource.sampleSource.getTrackGroups();
if (readingPeriod.nextPeriod != null && readingPeriod.nextPeriod.prepared) {
TrackSelectionArray oldTrackSelections = readingPeriod.trackSelections;
readingPeriod = readingPeriod.nextPeriod;
TrackSelectionArray newTrackSelections = readingPeriod.trackSelections;
TrackGroupArray groups = readingPeriod.mediaPeriod.getTrackGroups();
for (int i = 0; i < renderers.length; i++) {
TrackRenderer renderer = renderers[i];
TrackSelection oldSelection = oldTrackSelections.get(i);
TrackSelection newSelection = newTrackSelections.get(i);
if (oldSelection != null) {
if (newSelection != null) {
// Replace the renderer's TrackStream so the transition to playing the next source can
// Replace the renderer's TrackStream so the transition to playing the next period can
// be seamless.
Format[] formats = new Format[newSelection.length];
for (int j = 0; j < formats.length; j++) {
formats[j] = groups.get(newSelection.group).getFormat(newSelection.getTrack(j));
}
renderer.replaceTrackStream(formats, readingSource.trackStreams[i],
readingSource.offsetUs);
renderer.replaceTrackStream(formats, readingPeriod.trackStreams[i],
readingPeriod.offsetUs);
} else {
// The renderer will be disabled when transitioning to playing the next source. Mark
// The renderer will be disabled when transitioning to playing the next period. Mark
// the TrackStream as final to play out any remaining data.
renderer.setCurrentTrackStreamIsFinal();
}
}
}
} else if (sourceCount != SampleSourceProvider.UNKNOWN_SOURCE_COUNT
&& readingSource.index == sourceCount - 1) {
readingSource = null;
// This is the last source, so signal the renderers to read the end of the stream.
} else if (periodCount != MediaSource.UNKNOWN_PERIOD_COUNT
&& readingPeriod.index == periodCount - 1) {
readingPeriod = null;
// This is the last period, so signal the renderers to read the end of the stream.
for (TrackRenderer renderer : enabledRenderers) {
renderer.setCurrentTrackStreamIsFinal();
}
}
}
public void handleSourcePrepared(SampleSource source) throws ExoPlaybackException {
if (loadingSource == null || loadingSource.sampleSource != source) {
public void handlePeriodPrepared(MediaPeriod period) throws ExoPlaybackException {
if (loadingPeriod == null || loadingPeriod.mediaPeriod != period) {
// Stale event.
return;
}
long startPositionUs = playingSource == null ? playbackInfo.positionUs : 0;
loadingSource.handlePrepared(startPositionUs, loadControl);
if (playingSource == null) {
// This is the first prepared source, so start playing it.
readingSource = loadingSource;
setPlayingSource(readingSource);
long startPositionUs = playingPeriod == null ? playbackInfo.positionUs : 0;
loadingPeriod.handlePrepared(startPositionUs, loadControl);
if (playingPeriod == null) {
// This is the first prepared period, so start playing it.
readingPeriod = loadingPeriod;
setPlayingPeriod(readingPeriod);
updateTimelineState();
}
maybeContinueLoading();
}
public void handleContinueLoadingRequested(SampleSource source) {
if (loadingSource == null || loadingSource.sampleSource != source) {
public void handleContinueLoadingRequested(MediaPeriod period) {
if (loadingPeriod == null || loadingPeriod.mediaPeriod != period) {
return;
}
maybeContinueLoading();
}
private void maybeContinueLoading() {
long nextLoadPositionUs = loadingSource.sampleSource.getNextLoadPositionUs();
long nextLoadPositionUs = loadingPeriod.mediaPeriod.getNextLoadPositionUs();
if (nextLoadPositionUs != C.END_OF_SOURCE_US) {
long positionUs = internalPositionUs - loadingSource.offsetUs;
long positionUs = internalPositionUs - loadingPeriod.offsetUs;
long bufferedDurationUs = nextLoadPositionUs - positionUs;
boolean continueLoading = loadControl.shouldContinueLoading(bufferedDurationUs);
setIsLoading(continueLoading);
if (continueLoading) {
loadingSource.needsContinueLoading = false;
loadingSource.sampleSource.continueLoading(positionUs);
loadingPeriod.needsContinueLoading = false;
loadingPeriod.mediaPeriod.continueLoading(positionUs);
} else {
loadingSource.needsContinueLoading = true;
loadingPeriod.needsContinueLoading = true;
}
} else {
setIsLoading(false);
}
}
public long seekTo(int sourceIndex, long seekPositionUs) throws ExoPlaybackException {
// Clear the timeline, but keep the requested source if it is already prepared.
Source source = playingSource;
Source newPlayingSource = null;
while (source != null) {
if (source.index == sourceIndex && source.prepared) {
newPlayingSource = source;
public long seekTo(int periodIndex, long seekPositionUs) throws ExoPlaybackException {
// Clear the timeline, but keep the requested period if it is already prepared.
Period period = playingPeriod;
Period newPlayingPeriod = null;
while (period != null) {
if (period.index == periodIndex && period.prepared) {
newPlayingPeriod = period;
} else {
source.release();
period.release();
}
source = source.nextSource;
period = period.nextPeriod;
}
if (newPlayingSource != null) {
newPlayingSource.nextSource = null;
setPlayingSource(newPlayingSource);
if (newPlayingPeriod != null) {
newPlayingPeriod.nextPeriod = null;
setPlayingPeriod(newPlayingPeriod);
updateTimelineState();
readingSource = playingSource;
loadingSource = playingSource;
if (playingSource.hasEnabledTracks) {
seekPositionUs = playingSource.sampleSource.seekToUs(seekPositionUs);
readingPeriod = playingPeriod;
loadingPeriod = playingPeriod;
if (playingPeriod.hasEnabledTracks) {
seekPositionUs = playingPeriod.mediaPeriod.seekToUs(seekPositionUs);
}
resetInternalPosition(seekPositionUs);
maybeContinueLoading();
@ -794,51 +794,51 @@ import java.util.ArrayList;
renderer.disable();
}
enabledRenderers = new TrackRenderer[0];
playingSource = null;
readingSource = null;
loadingSource = null;
pendingSourceIndex = sourceIndex;
playingPeriod = null;
readingPeriod = null;
loadingPeriod = null;
pendingPeriodIndex = periodIndex;
resetInternalPosition(seekPositionUs);
}
return seekPositionUs;
}
public void reselectTracks() throws ExoPlaybackException {
// Reselect tracks on each source in turn, until the selection changes.
Source source = playingSource;
boolean selectionsChangedForReadSource = true;
// Reselect tracks on each period in turn, until the selection changes.
Period period = playingPeriod;
boolean selectionsChangedForReadPeriod = true;
while (true) {
if (source == null || !source.prepared) {
// The reselection did not change any prepared sources.
if (period == null || !period.prepared) {
// The reselection did not change any prepared periods.
return;
}
if (source.selectTracks()) {
if (period.selectTracks()) {
break;
}
if (source == readingSource) {
// The track reselection didn't affect any source that has been read.
selectionsChangedForReadSource = false;
if (period == readingPeriod) {
// The track reselection didn't affect any period that has been read.
selectionsChangedForReadPeriod = false;
}
source = source.nextSource;
period = period.nextPeriod;
}
if (selectionsChangedForReadSource) {
// Release everything after the playing source because a renderer may have read data from a
if (selectionsChangedForReadPeriod) {
// Release everything after the playing period because a renderer may have read data from a
// track whose selection has now changed.
source = playingSource.nextSource;
while (source != null) {
source.release();
source = source.nextSource;
period = playingPeriod.nextPeriod;
while (period != null) {
period.release();
period = period.nextPeriod;
}
playingSource.nextSource = null;
readingSource = playingSource;
loadingSource = playingSource;
playingSourceEndPositionUs = C.UNSET_TIME_US;
playingPeriod.nextPeriod = null;
readingPeriod = playingPeriod;
loadingPeriod = playingPeriod;
playingPeriodEndPositionUs = C.UNSET_TIME_US;
// Update streams for the new selection, recreating all streams if reading ahead.
boolean recreateStreams = readingSource != playingSource;
TrackSelectionArray playingSourceOldTrackSelections = playingSource.sourceTrackSelections;
playingSource.updateSourceTrackSelection(playbackInfo.positionUs, loadControl,
boolean recreateStreams = readingPeriod != playingPeriod;
TrackSelectionArray playingPeriodOldTrackSelections = playingPeriod.periodTrackSelections;
playingPeriod.updatePeriodTrackSelection(playbackInfo.positionUs, loadControl,
recreateStreams);
int enabledRendererCount = 0;
@ -846,8 +846,8 @@ import java.util.ArrayList;
for (int i = 0; i < renderers.length; i++) {
TrackRenderer renderer = renderers[i];
rendererWasEnabledFlags[i] = renderer.getState() != TrackRenderer.STATE_DISABLED;
TrackSelection oldSelection = playingSourceOldTrackSelections.get(i);
TrackSelection newSelection = playingSource.trackSelections.get(i);
TrackSelection oldSelection = playingPeriodOldTrackSelections.get(i);
TrackSelection newSelection = playingPeriod.trackSelections.get(i);
if (newSelection != null) {
enabledRendererCount++;
}
@ -868,52 +868,52 @@ import java.util.ArrayList;
renderer.disable();
}
}
trackSelector.onSelectionActivated(playingSource.trackSelectionData);
trackSelector.onSelectionActivated(playingPeriod.trackSelectionData);
enableRenderers(rendererWasEnabledFlags, enabledRendererCount);
} else {
// Release and re-prepare/buffer sources after the one whose selection changed.
loadingSource = source;
source = loadingSource.nextSource;
while (source != null) {
source.release();
source = source.nextSource;
// Release and re-prepare/buffer periods after the one whose selection changed.
loadingPeriod = period;
period = loadingPeriod.nextPeriod;
while (period != null) {
period.release();
period = period.nextPeriod;
}
loadingSource.nextSource = null;
long positionUs = Math.max(0, internalPositionUs - loadingSource.offsetUs);
loadingSource.updateSourceTrackSelection(positionUs, loadControl, false);
loadingPeriod.nextPeriod = null;
long positionUs = Math.max(0, internalPositionUs - loadingPeriod.offsetUs);
loadingPeriod.updatePeriodTrackSelection(positionUs, loadControl, false);
}
maybeContinueLoading();
}
public void reset() {
Source source = playingSource != null ? playingSource : loadingSource;
while (source != null) {
source.release();
source = source.nextSource;
Period period = playingPeriod != null ? playingPeriod : loadingPeriod;
while (period != null) {
period.release();
period = period.nextPeriod;
}
isReady = false;
isEnded = false;
playingSource = null;
readingSource = null;
loadingSource = null;
playingSourceEndPositionUs = C.UNSET_TIME_US;
pendingSourceIndex = 0;
playingPeriod = null;
readingPeriod = null;
loadingPeriod = null;
playingPeriodEndPositionUs = C.UNSET_TIME_US;
pendingPeriodIndex = 0;
playbackInfo = new PlaybackInfo(0);
eventHandler.obtainMessage(MSG_SOURCE_CHANGED, playbackInfo).sendToTarget();
eventHandler.obtainMessage(MSG_PERIOD_CHANGED, playbackInfo).sendToTarget();
}
private void setPlayingSource(Source source) throws ExoPlaybackException {
private void setPlayingPeriod(Period period) throws ExoPlaybackException {
int enabledRendererCount = 0;
boolean[] rendererWasEnabledFlags = new boolean[renderers.length];
for (int i = 0; i < renderers.length; i++) {
TrackRenderer renderer = renderers[i];
rendererWasEnabledFlags[i] = renderer.getState() != TrackRenderer.STATE_DISABLED;
TrackSelection newSelection = source.trackSelections.get(i);
TrackSelection newSelection = period.trackSelections.get(i);
if (newSelection != null) {
// The renderer should be enabled when playing the new source.
// The renderer should be enabled when playing the new period.
enabledRendererCount++;
} else if (rendererWasEnabledFlags[i]) {
// The renderer should be disabled when playing the new source.
// The renderer should be disabled when playing the new period.
if (renderer == rendererMediaClockSource) {
// Sync standaloneMediaClock so that it can take over timing responsibilities.
standaloneMediaClock.setPositionUs(rendererMediaClock.getPositionUs());
@ -925,29 +925,29 @@ import java.util.ArrayList;
}
}
trackSelector.onSelectionActivated(source.trackSelectionData);
playingSource = source;
playingSourceEndPositionUs = C.UNSET_TIME_US;
trackSelector.onSelectionActivated(period.trackSelectionData);
playingPeriod = period;
playingPeriodEndPositionUs = C.UNSET_TIME_US;
enableRenderers(rendererWasEnabledFlags, enabledRendererCount);
}
private void updateTimelineState() {
isReady = playingSourceEndPositionUs == C.UNSET_TIME_US
|| internalPositionUs < playingSourceEndPositionUs
|| (playingSource.nextSource != null && playingSource.nextSource.prepared);
int sourceCount = sampleSourceProvider.getSourceCount();
isEnded = sourceCount != SampleSourceProvider.UNKNOWN_SOURCE_COUNT
&& playingSource.index == sourceCount - 1;
isReady = playingPeriodEndPositionUs == C.UNSET_TIME_US
|| internalPositionUs < playingPeriodEndPositionUs
|| (playingPeriod.nextPeriod != null && playingPeriod.nextPeriod.prepared);
int periodCount = mediaSource.getPeriodCount();
isEnded = periodCount != MediaSource.UNKNOWN_PERIOD_COUNT
&& playingPeriod.index == periodCount - 1;
}
private void enableRenderers(boolean[] rendererWasEnabledFlags, int enabledRendererCount)
throws ExoPlaybackException {
enabledRenderers = new TrackRenderer[enabledRendererCount];
enabledRendererCount = 0;
TrackGroupArray trackGroups = playingSource.sampleSource.getTrackGroups();
TrackGroupArray trackGroups = playingPeriod.mediaPeriod.getTrackGroups();
for (int i = 0; i < renderers.length; i++) {
TrackRenderer renderer = renderers[i];
TrackSelection newSelection = playingSource.trackSelections.get(i);
TrackSelection newSelection = playingPeriod.trackSelections.get(i);
if (newSelection != null) {
enabledRenderers[enabledRendererCount++] = renderer;
if (renderer.getState() == TrackRenderer.STATE_DISABLED) {
@ -961,8 +961,8 @@ import java.util.ArrayList;
formats[j] = trackGroups.get(newSelection.group).getFormat(newSelection.getTrack(j));
}
// Enable the renderer.
renderer.enable(formats, playingSource.trackStreams[i], internalPositionUs, joining,
playingSource.offsetUs);
renderer.enable(formats, playingPeriod.trackStreams[i], internalPositionUs, joining,
playingPeriod.offsetUs);
MediaClock mediaClock = renderer.getMediaClock();
if (mediaClock != null) {
if (rendererMediaClock != null) {
@ -984,58 +984,58 @@ import java.util.ArrayList;
}
/**
* Represents a {@link SampleSource} with information required to play it as part of a timeline.
* Represents a {@link MediaPeriod} with information required to play it as part of a timeline.
*/
private static final class Source {
private static final class Period {
private final TrackRenderer[] renderers;
private final TrackSelector trackSelector;
public final SampleSource sampleSource;
public final MediaPeriod mediaPeriod;
public final int index;
public final TrackStream[] trackStreams;
public boolean prepared;
public boolean hasEnabledTracks;
public long offsetUs;
public Source nextSource;
public Period nextPeriod;
public boolean needsContinueLoading;
private Object trackSelectionData;
private TrackSelectionArray trackSelections;
private TrackSelectionArray sourceTrackSelections;
private TrackSelectionArray periodTrackSelections;
public Source(TrackRenderer[] renderers, TrackSelector trackSelector, SampleSource sampleSource,
public Period(TrackRenderer[] renderers, TrackSelector trackSelector, MediaPeriod mediaPeriod,
int index) {
this.renderers = renderers;
this.trackSelector = trackSelector;
this.sampleSource = sampleSource;
this.mediaPeriod = mediaPeriod;
this.index = index;
trackStreams = new TrackStream[renderers.length];
}
public void setNextSource(Source nextSource) {
this.nextSource = nextSource;
nextSource.offsetUs = offsetUs + sampleSource.getDurationUs();
public void setNextPeriod(Period nextPeriod) {
this.nextPeriod = nextPeriod;
nextPeriod.offsetUs = offsetUs + mediaPeriod.getDurationUs();
}
public boolean isFullyBuffered() {
return prepared && (!hasEnabledTracks
|| sampleSource.getBufferedPositionUs() == C.END_OF_SOURCE_US);
|| mediaPeriod.getBufferedPositionUs() == C.END_OF_SOURCE_US);
}
public void handlePrepared(long positionUs, LoadControl loadControl)
throws ExoPlaybackException {
prepared = true;
selectTracks();
updateSourceTrackSelection(positionUs, loadControl, false);
updatePeriodTrackSelection(positionUs, loadControl, false);
}
public boolean selectTracks() throws ExoPlaybackException {
Pair<TrackSelectionArray, Object> result =
trackSelector.selectTracks(renderers, sampleSource.getTrackGroups());
trackSelector.selectTracks(renderers, mediaPeriod.getTrackGroups());
TrackSelectionArray newTrackSelections = result.first;
if (newTrackSelections.equals(sourceTrackSelections)) {
if (newTrackSelections.equals(periodTrackSelections)) {
return false;
}
trackSelections = newTrackSelections;
@ -1043,14 +1043,14 @@ import java.util.ArrayList;
return true;
}
public void updateSourceTrackSelection(long positionUs, LoadControl loadControl,
public void updatePeriodTrackSelection(long positionUs, LoadControl loadControl,
boolean forceRecreateStreams) throws ExoPlaybackException {
// Populate lists of streams that are being disabled/newly enabled.
ArrayList<TrackStream> oldStreams = new ArrayList<>();
ArrayList<TrackSelection> newSelections = new ArrayList<>();
for (int i = 0; i < trackSelections.length; i++) {
TrackSelection oldSelection =
sourceTrackSelections == null ? null : sourceTrackSelections.get(i);
periodTrackSelections == null ? null : periodTrackSelections.get(i);
TrackSelection newSelection = trackSelections.get(i);
if (forceRecreateStreams || !Util.areEqual(oldSelection, newSelection)) {
if (oldSelection != null) {
@ -1062,9 +1062,9 @@ import java.util.ArrayList;
}
}
// Disable streams on the source and get new streams for updated/newly-enabled tracks.
TrackStream[] newStreams = sampleSource.selectTracks(oldStreams, newSelections, positionUs);
sourceTrackSelections = trackSelections;
// Disable streams on the period and get new streams for updated/newly-enabled tracks.
TrackStream[] newStreams = mediaPeriod.selectTracks(oldStreams, newSelections, positionUs);
periodTrackSelections = trackSelections;
hasEnabledTracks = false;
for (int i = 0; i < trackSelections.length; i++) {
TrackSelection selection = trackSelections.get(i);
@ -1082,15 +1082,15 @@ import java.util.ArrayList;
}
// The track selection has changed.
loadControl.onTrackSelections(renderers, sampleSource.getTrackGroups(), trackSelections);
loadControl.onTrackSelections(renderers, mediaPeriod.getTrackGroups(), trackSelections);
}
public void release() {
try {
sampleSource.release();
mediaPeriod.release();
} catch (RuntimeException e) {
// There's nothing we can do.
Log.e(TAG, "Source release failed.", e);
Log.e(TAG, "Period release failed.", e);
}
}

View file

@ -652,7 +652,7 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
}
/**
* Invoked when a new format is read from the upstream {@link SampleSource}.
* Invoked when a new format is read from the upstream {@link MediaPeriod}.
*
* @param newFormat The new format.
* @throws ExoPlaybackException If an error occurs reinitializing the {@link MediaCodec}.

View file

@ -21,67 +21,67 @@ import java.io.IOException;
import java.util.List;
/**
* A source of media.
* A source of a single period of media.
*/
public interface SampleSource extends SequenceableLoader {
public interface MediaPeriod extends SequenceableLoader {
/**
* A callback to be notified of {@link SampleSource} events.
* A callback to be notified of {@link MediaPeriod} events.
*/
interface Callback extends SequenceableLoader.Callback<SampleSource> {
interface Callback extends SequenceableLoader.Callback<MediaPeriod> {
/**
* Invoked by the source when preparation completes.
* Invoked when preparation completes.
* <p>
* May be called from any thread. After invoking this method, the source can expect
* {@link #selectTracks(List, List, long)} to be invoked when the initial track selection.
* May be called from any thread. After invoking this method, the {@link MediaPeriod} can expect
* for {@link #selectTracks(List, List, long)} to be invoked with the initial track selection.
*
* @param source The prepared source.
* @param mediaPeriod The prepared {@link MediaPeriod}.
*/
void onSourcePrepared(SampleSource source);
void onPeriodPrepared(MediaPeriod mediaPeriod);
}
/**
* Starts preparation of the source.
* Starts preparation of the period.
* <p>
* {@link Callback#onSourcePrepared(SampleSource)} is invoked when preparation completes. If
* {@link Callback#onPeriodPrepared(MediaPeriod)} is invoked when preparation completes. If
* preparation fails, {@link #maybeThrowPrepareError()} will throw an {@link IOException} if
* invoked.
*
* @param callback A callback to receive updates from the source.
* @param callback A callback to receive updates from the period.
* @param allocator An {@link Allocator} from which to obtain media buffer allocations.
* @param positionUs The player's current playback position.
*/
void prepare(Callback callback, Allocator allocator, long positionUs);
/**
* Throws an error that's preventing the source from becoming prepared. Does nothing if no such
* Throws an error that's preventing the period from becoming prepared. Does nothing if no such
* error exists.
* <p>
* This method should only be called before the source has completed preparation.
* This method should only be called before the period has completed preparation.
*
* @throws IOException The underlying error.
*/
void maybeThrowPrepareError() throws IOException;
/**
* Returns the duration of the source in microseconds, or {@link C#UNSET_TIME_US} if not known.
* Returns the duration of the period in microseconds, or {@link C#UNSET_TIME_US} if not known.
* <p>
* If {@link #getBufferedPositionUs()} returns {@link C#END_OF_SOURCE_US}, the duration is
* guaranteed to be known.
* <p>
* This method should only be called after the source has been prepared.
* This method should only be called after the period has been prepared.
*
* @return The duration of the source in microseconds, or {@link C#UNSET_TIME_US} if the duration
* @return The duration of the period in microseconds, or {@link C#UNSET_TIME_US} if the duration
* is not known.
*/
long getDurationUs();
/**
* Returns the {@link TrackGroup}s exposed by the source.
* Returns the {@link TrackGroup}s exposed by the period.
* <p>
* This method should only be called after the source has been prepared.
* This method should only be called after the period has been prepared.
*
* @return The {@link TrackGroup}s.
*/
@ -95,7 +95,7 @@ public interface SampleSource extends SequenceableLoader {
* must have a {@link TrackSelection#group} index distinct from those of currently enabled tracks,
* except for those being unselected.
* <p>
* This method should only be called after the source has been prepared.
* This method should only be called after the period has been prepared.
*
* @param oldStreams {@link TrackStream}s corresponding to tracks being unselected. May be empty
* but must not be null.
@ -111,7 +111,7 @@ public interface SampleSource extends SequenceableLoader {
* Attempts to read a discontinuity.
* <p>
* After this method has returned a value other than {@link C#UNSET_TIME_US}, all
* {@link TrackStream}s provided by the source are guaranteed to start from a key frame.
* {@link TrackStream}s provided by the period are guaranteed to start from a key frame.
*
* @return If a discontinuity was read then the playback position in microseconds after the
* discontinuity. Else {@link C#UNSET_TIME_US}.
@ -131,20 +131,20 @@ public interface SampleSource extends SequenceableLoader {
/**
* Attempts to seek to the specified position in microseconds.
* <p>
* After this method has been called, all {@link TrackStream}s provided by the source are
* After this method has been called, all {@link TrackStream}s provided by the period are
* guaranteed to start from a key frame.
* <p>
* This method should only be called when at least one track is selected.
*
* @param positionUs The seek position in microseconds.
* @return The actual position to which the source was seeked, in microseconds.
* @return The actual position to which the period was seeked, in microseconds.
*/
long seekToUs(long positionUs);
/**
* Releases the source.
* Releases the period.
* <p>
* This method should be called when the source is no longer required. It may be called in any
* This method should be called when the period is no longer required. It may be called in any
* state.
*/
void release();

View file

@ -0,0 +1,45 @@
/*
* 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;
/**
* A source of media consisting of one or more {@link MediaPeriod}s.
*/
public interface MediaSource {
/**
* Returned by {@link #getPeriodCount()} if the number of periods is not known.
*/
int UNKNOWN_PERIOD_COUNT = -1;
/**
* Returns the number of periods in the source, or {@link #UNKNOWN_PERIOD_COUNT} if the number
* of periods is not yet known.
*/
int getPeriodCount();
/**
* Returns a {@link MediaPeriod} corresponding to the period at the specified index, or
* {@code null} if the period at the specified index is not yet available.
*
* @param index The index of the period. Must be less than {@link #getPeriodCount()} unless the
* period count is {@link #UNKNOWN_PERIOD_COUNT}.
* @return A {@link MediaPeriod}, or {@code null} if the source at the specified index is not yet
* available.
*/
MediaPeriod createPeriod(int index);
}

View file

@ -24,13 +24,14 @@ import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.List;
// TODO: Make this a MediaSource
/**
* Combines multiple {@link SampleSource} instances.
* Merges multiple {@link MediaPeriod} instances.
*/
public final class MultiSampleSource implements SampleSource, SampleSource.Callback {
public final class MultiMediaPeriod implements MediaPeriod, MediaPeriod.Callback {
private final SampleSource[] sources;
private final IdentityHashMap<TrackStream, SampleSource> trackStreamSources;
private final MediaPeriod[] periods;
private final IdentityHashMap<TrackStream, MediaPeriod> trackStreamPeriods;
private final int[] selectedTrackCounts;
private Callback callback;
@ -39,28 +40,28 @@ public final class MultiSampleSource implements SampleSource, SampleSource.Callb
private TrackGroupArray trackGroups;
private boolean seenFirstTrackSelection;
private SampleSource[] enabledSources;
private MediaPeriod[] enabledPeriods;
private SequenceableLoader sequenceableLoader;
public MultiSampleSource(SampleSource... sources) {
this.sources = sources;
pendingChildPrepareCount = sources.length;
trackStreamSources = new IdentityHashMap<>();
selectedTrackCounts = new int[sources.length];
public MultiMediaPeriod(MediaPeriod... periods) {
this.periods = periods;
pendingChildPrepareCount = periods.length;
trackStreamPeriods = new IdentityHashMap<>();
selectedTrackCounts = new int[periods.length];
}
@Override
public void prepare(Callback callback, Allocator allocator, long positionUs) {
this.callback = callback;
for (SampleSource source : sources) {
source.prepare(this, allocator, positionUs);
for (MediaPeriod period : periods) {
period.prepare(this, allocator, positionUs);
}
}
@Override
public void maybeThrowPrepareError() throws IOException {
for (SampleSource source : sources) {
source.maybeThrowPrepareError();
for (MediaPeriod period : periods) {
period.maybeThrowPrepareError();
}
}
@ -78,25 +79,25 @@ public final class MultiSampleSource implements SampleSource, SampleSource.Callb
public TrackStream[] selectTracks(List<TrackStream> oldStreams,
List<TrackSelection> newSelections, long positionUs) {
TrackStream[] newStreams = new TrackStream[newSelections.size()];
// Select tracks for each source.
int enabledSourceCount = 0;
for (int i = 0; i < sources.length; i++) {
selectedTrackCounts[i] += selectTracks(sources[i], oldStreams, newSelections, positionUs,
// Select tracks for each period.
int enabledPeriodCount = 0;
for (int i = 0; i < periods.length; i++) {
selectedTrackCounts[i] += selectTracks(periods[i], oldStreams, newSelections, positionUs,
newStreams, seenFirstTrackSelection);
if (selectedTrackCounts[i] > 0) {
enabledSourceCount++;
enabledPeriodCount++;
}
}
seenFirstTrackSelection = true;
// Update the enabled sources.
enabledSources = new SampleSource[enabledSourceCount];
enabledSourceCount = 0;
for (int i = 0; i < sources.length; i++) {
// Update the enabled periods.
enabledPeriods = new MediaPeriod[enabledPeriodCount];
enabledPeriodCount = 0;
for (int i = 0; i < periods.length; i++) {
if (selectedTrackCounts[i] > 0) {
enabledSources[enabledSourceCount++] = sources[i];
enabledPeriods[enabledPeriodCount++] = periods[i];
}
}
sequenceableLoader = new CompositeSequenceableLoader(enabledSources);
sequenceableLoader = new CompositeSequenceableLoader(enabledPeriods);
return newStreams;
}
@ -112,18 +113,18 @@ public final class MultiSampleSource implements SampleSource, SampleSource.Callb
@Override
public long readDiscontinuity() {
long positionUs = enabledSources[0].readDiscontinuity();
long positionUs = enabledPeriods[0].readDiscontinuity();
if (positionUs != C.UNSET_TIME_US) {
// It must be possible to seek additional sources to the new position.
for (int i = 1; i < enabledSources.length; i++) {
if (enabledSources[i].seekToUs(positionUs) != positionUs) {
// It must be possible to seek additional periods to the new position.
for (int i = 1; i < enabledPeriods.length; i++) {
if (enabledPeriods[i].seekToUs(positionUs) != positionUs) {
throw new IllegalStateException("Children seeked to different positions");
}
}
}
// Additional sources are not allowed to report discontinuities.
for (int i = 1; i < enabledSources.length; i++) {
if (enabledSources[i].readDiscontinuity() != C.UNSET_TIME_US) {
// Additional periods are not allowed to report discontinuities.
for (int i = 1; i < enabledPeriods.length; i++) {
if (enabledPeriods[i].readDiscontinuity() != C.UNSET_TIME_US) {
throw new IllegalStateException("Child reported discontinuity");
}
}
@ -133,8 +134,8 @@ public final class MultiSampleSource implements SampleSource, SampleSource.Callb
@Override
public long getBufferedPositionUs() {
long bufferedPositionUs = Long.MAX_VALUE;
for (SampleSource source : enabledSources) {
long rendererBufferedPositionUs = source.getBufferedPositionUs();
for (MediaPeriod period : enabledPeriods) {
long rendererBufferedPositionUs = period.getBufferedPositionUs();
if (rendererBufferedPositionUs != C.END_OF_SOURCE_US) {
bufferedPositionUs = Math.min(bufferedPositionUs, rendererBufferedPositionUs);
}
@ -144,10 +145,10 @@ public final class MultiSampleSource implements SampleSource, SampleSource.Callb
@Override
public long seekToUs(long positionUs) {
positionUs = enabledSources[0].seekToUs(positionUs);
// Additional sources must seek to the same position.
for (int i = 1; i < enabledSources.length; i++) {
if (enabledSources[i].seekToUs(positionUs) != positionUs) {
positionUs = enabledPeriods[0].seekToUs(positionUs);
// Additional periods must seek to the same position.
for (int i = 1; i < enabledPeriods.length; i++) {
if (enabledPeriods[i].seekToUs(positionUs) != positionUs) {
throw new IllegalStateException("Children seeked to different positions");
}
}
@ -156,42 +157,42 @@ public final class MultiSampleSource implements SampleSource, SampleSource.Callb
@Override
public void release() {
for (SampleSource source : sources) {
source.release();
for (MediaPeriod period : periods) {
period.release();
}
}
// SampleSource.Callback implementation
// MediaPeriod.Callback implementation
@Override
public void onSourcePrepared(SampleSource ignored) {
public void onPeriodPrepared(MediaPeriod ignored) {
if (--pendingChildPrepareCount > 0) {
return;
}
durationUs = 0;
int totalTrackGroupCount = 0;
for (SampleSource source : sources) {
totalTrackGroupCount += source.getTrackGroups().length;
for (MediaPeriod period : periods) {
totalTrackGroupCount += period.getTrackGroups().length;
if (durationUs != C.UNSET_TIME_US) {
long sourceDurationUs = source.getDurationUs();
durationUs = sourceDurationUs == C.UNSET_TIME_US
? C.UNSET_TIME_US : Math.max(durationUs, sourceDurationUs);
long periodDurationUs = period.getDurationUs();
durationUs = periodDurationUs == C.UNSET_TIME_US
? C.UNSET_TIME_US : Math.max(durationUs, periodDurationUs);
}
}
TrackGroup[] trackGroupArray = new TrackGroup[totalTrackGroupCount];
int trackGroupIndex = 0;
for (SampleSource source : sources) {
int sourceTrackGroupCount = source.getTrackGroups().length;
for (int j = 0; j < sourceTrackGroupCount; j++) {
trackGroupArray[trackGroupIndex++] = source.getTrackGroups().get(j);
for (MediaPeriod period : periods) {
int periodTrackGroupCount = period.getTrackGroups().length;
for (int j = 0; j < periodTrackGroupCount; j++) {
trackGroupArray[trackGroupIndex++] = period.getTrackGroups().get(j);
}
}
trackGroups = new TrackGroupArray(trackGroupArray);
callback.onSourcePrepared(this);
callback.onPeriodPrepared(this);
}
@Override
public void onContinueLoadingRequested(SampleSource ignored) {
public void onContinueLoadingRequested(MediaPeriod ignored) {
if (trackGroups == null) {
// Still preparing.
return;
@ -201,27 +202,27 @@ public final class MultiSampleSource implements SampleSource, SampleSource.Callb
// Internal methods.
private int selectTracks(SampleSource source, List<TrackStream> allOldStreams,
private int selectTracks(MediaPeriod period, List<TrackStream> allOldStreams,
List<TrackSelection> allNewSelections, long positionUs, TrackStream[] allNewStreams,
boolean seenFirstTrackSelection) {
// Get the subset of the old streams for the source.
// Get the subset of the old streams for the period.
ArrayList<TrackStream> oldStreams = new ArrayList<>();
for (int i = 0; i < allOldStreams.size(); i++) {
TrackStream stream = allOldStreams.get(i);
if (trackStreamSources.get(stream) == source) {
trackStreamSources.remove(stream);
if (trackStreamPeriods.get(stream) == period) {
trackStreamPeriods.remove(stream);
oldStreams.add(stream);
}
}
// Get the subset of the new selections for the source.
// Get the subset of the new selections for the period.
ArrayList<TrackSelection> newSelections = new ArrayList<>();
int[] newSelectionOriginalIndices = new int[allNewSelections.size()];
for (int i = 0; i < allNewSelections.size(); i++) {
TrackSelection selection = allNewSelections.get(i);
Pair<SampleSource, Integer> sourceAndGroup = getSourceAndGroup(selection.group);
if (sourceAndGroup.first == source) {
Pair<MediaPeriod, Integer> periodAndGroup = getPeriodAndGroup(selection.group);
if (periodAndGroup.first == period) {
newSelectionOriginalIndices[newSelections.size()] = i;
newSelections.add(new TrackSelection(sourceAndGroup.second, selection.getTracks()));
newSelections.add(new TrackSelection(periodAndGroup.second, selection.getTracks()));
}
}
// Do nothing if nothing has changed, except during the first selection.
@ -229,22 +230,22 @@ public final class MultiSampleSource implements SampleSource, SampleSource.Callb
return 0;
}
// Perform the selection.
TrackStream[] newStreams = source.selectTracks(oldStreams, newSelections, positionUs);
TrackStream[] newStreams = period.selectTracks(oldStreams, newSelections, positionUs);
for (int j = 0; j < newStreams.length; j++) {
allNewStreams[newSelectionOriginalIndices[j]] = newStreams[j];
trackStreamSources.put(newStreams[j], source);
trackStreamPeriods.put(newStreams[j], period);
}
return newSelections.size() - oldStreams.size();
}
private Pair<SampleSource, Integer> getSourceAndGroup(int group) {
private Pair<MediaPeriod, Integer> getPeriodAndGroup(int group) {
int totalTrackGroupCount = 0;
for (SampleSource source : sources) {
int sourceTrackGroupCount = source.getTrackGroups().length;
if (group < totalTrackGroupCount + sourceTrackGroupCount) {
return Pair.create(source, group - totalTrackGroupCount);
for (MediaPeriod period : periods) {
int periodTrackGroupCount = period.getTrackGroups().length;
if (group < totalTrackGroupCount + periodTrackGroupCount) {
return Pair.create(period, group - totalTrackGroupCount);
}
totalTrackGroupCount += sourceTrackGroupCount;
totalTrackGroupCount += periodTrackGroupCount;
}
throw new IndexOutOfBoundsException();
}

View file

@ -1,46 +0,0 @@
/*
* 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;
// TODO[playlists]: Rename this and maybe change the interface once we support multi-period DASH.
/**
* Provides a sequence of {@link SampleSource}s to play back.
*/
public interface SampleSourceProvider {
/**
* Returned by {@link #getSourceCount()} if the number of sources is not known.
*/
int UNKNOWN_SOURCE_COUNT = -1;
/**
* Returns the number of sources in the sequence, or {@link #UNKNOWN_SOURCE_COUNT} if the number
* of sources is not yet known.
*/
int getSourceCount();
/**
* Returns a new {@link SampleSource} providing media at the specified index in the sequence, or
* {@code null} if the source at the specified index is not yet available.
*
* @param index The index of the source to create, which must be less than the count returned by
* {@link #getSourceCount()}.
* @return A new {@link SampleSource}, or {@code null} if the source at the specified index is not
* yet available.
*/
SampleSource createSource(int index);
}

View file

@ -314,8 +314,8 @@ public final class SimpleExoPlayer implements ExoPlayer {
}
@Override
public void setSourceProvider(SampleSourceProvider sourceProvider) {
player.setSourceProvider(sourceProvider);
public void setMediaSource(MediaSource mediaSource) {
player.setMediaSource(mediaSource);
}
@Override
@ -344,8 +344,8 @@ public final class SimpleExoPlayer implements ExoPlayer {
}
@Override
public void seekTo(int sourceIndex, long positionMs) {
player.seekTo(sourceIndex, positionMs);
public void seekTo(int periodIndex, long positionMs) {
player.seekTo(periodIndex, positionMs);
}
@Override
@ -379,8 +379,8 @@ public final class SimpleExoPlayer implements ExoPlayer {
}
@Override
public int getCurrentSourceIndex() {
return player.getCurrentSourceIndex();
public int getCurrentPeriodIndex() {
return player.getCurrentPeriodIndex();
}
@Override

View file

@ -31,21 +31,20 @@ import java.util.Arrays;
import java.util.List;
/**
* A {@link SampleSource} that loads the data at a given {@link Uri} as a single sample. Also acts
* as a {@link SampleSourceProvider} providing {@link SingleSampleSource} instances.
* Loads data at a given {@link Uri} as a single sample belonging to a single {@link MediaPeriod}.
*/
public final class SingleSampleSource implements SampleSource, SampleSourceProvider, TrackStream,
Loader.Callback<SingleSampleSource.SourceLoadable> {
public final class SingleSampleMediaSource implements MediaPeriod, MediaSource, TrackStream,
Loader.Callback<SingleSampleMediaSource.SourceLoadable> {
/**
* Interface definition for a callback to be notified of {@link SingleSampleSource} events.
* Interface definition for a callback to be notified of {@link SingleSampleMediaSource} events.
*/
public interface EventListener {
/**
* Invoked when an error occurs loading media data.
*
* @param sourceId The id of the reporting {@link SampleSource}.
* @param sourceId The id of the reporting {@link SingleSampleMediaSource}.
* @param e The cause of the failure.
*/
void onLoadError(int sourceId, IOException e);
@ -83,17 +82,17 @@ public final class SingleSampleSource implements SampleSource, SampleSourceProvi
private byte[] sampleData;
private int sampleSize;
public SingleSampleSource(Uri uri, DataSourceFactory dataSourceFactory, Format format,
public SingleSampleMediaSource(Uri uri, DataSourceFactory dataSourceFactory, Format format,
long durationUs) {
this(uri, dataSourceFactory, format, durationUs, DEFAULT_MIN_LOADABLE_RETRY_COUNT);
}
public SingleSampleSource(Uri uri, DataSourceFactory dataSourceFactory, Format format,
public SingleSampleMediaSource(Uri uri, DataSourceFactory dataSourceFactory, Format format,
long durationUs, int minLoadableRetryCount) {
this(uri, dataSourceFactory, format, durationUs, minLoadableRetryCount, null, null, 0);
}
public SingleSampleSource(Uri uri, DataSourceFactory dataSourceFactory, Format format,
public SingleSampleMediaSource(Uri uri, DataSourceFactory dataSourceFactory, Format format,
long durationUs, int minLoadableRetryCount, Handler eventHandler, EventListener eventListener,
int eventSourceId) {
this.uri = uri;
@ -109,25 +108,25 @@ public final class SingleSampleSource implements SampleSource, SampleSourceProvi
streamState = STREAM_STATE_SEND_FORMAT;
}
// SampleSourceProvider implementation.
// MediaSource implementation.
@Override
public int getSourceCount() {
public int getPeriodCount() {
return 1;
}
@Override
public SampleSource createSource(int index) {
public MediaPeriod createPeriod(int index) {
Assertions.checkArgument(index == 0);
return this;
}
// SampleSource implementation.
// MediaPeriod implementation.
@Override
public void prepare(Callback callback, Allocator allocator, long positionUs) {
loader = new Loader("Loader:SingleSampleSource");
callback.onSourcePrepared(this);
loader = new Loader("Loader:SingleSampleMediaSource");
callback.onPeriodPrepared(this);
}
@Override

View file

@ -20,9 +20,9 @@ import com.google.android.exoplayer2.util.Assertions;
import java.util.Arrays;
/**
* Defines a group of tracks exposed by a {@link SampleSource}.
* Defines a group of tracks exposed by a {@link MediaPeriod}.
* <p>
* A {@link SampleSource} is only able to provide one {@link TrackStream} corresponding to a group
* A {@link MediaPeriod} is only able to provide one {@link TrackStream} corresponding to a group
* at any given time. If {@link #adaptive} is true this {@link TrackStream} can adapt between
* multiple tracks within the group. If {@link #adaptive} is false then it's only possible to
* consume one track from the group at a given time.

View file

@ -18,7 +18,7 @@ package com.google.android.exoplayer2;
import java.util.Arrays;
/**
* An array of {@link TrackGroup}s exposed by a {@link SampleSource}.
* An array of {@link TrackGroup}s exposed by a {@link MediaPeriod}.
*/
public final class TrackGroupArray {

View file

@ -15,7 +15,7 @@
*/
package com.google.android.exoplayer2.chunk;
import com.google.android.exoplayer2.AdaptiveSourceEventListener.EventDispatcher;
import com.google.android.exoplayer2.AdaptiveMediaSourceEventListener.EventDispatcher;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.DecoderInputBuffer;
import com.google.android.exoplayer2.Format;

View file

@ -15,14 +15,14 @@
*/
package com.google.android.exoplayer2.dash;
import com.google.android.exoplayer2.AdaptiveSourceEventListener;
import com.google.android.exoplayer2.AdaptiveSourceEventListener.EventDispatcher;
import com.google.android.exoplayer2.AdaptiveMediaSourceEventListener;
import com.google.android.exoplayer2.AdaptiveMediaSourceEventListener.EventDispatcher;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.CompositeSequenceableLoader;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.MediaPeriod;
import com.google.android.exoplayer2.MediaSource;
import com.google.android.exoplayer2.ParserException;
import com.google.android.exoplayer2.SampleSource;
import com.google.android.exoplayer2.SampleSourceProvider;
import com.google.android.exoplayer2.SequenceableLoader;
import com.google.android.exoplayer2.TrackGroup;
import com.google.android.exoplayer2.TrackGroupArray;
@ -63,10 +63,9 @@ import java.util.Locale;
import java.util.TimeZone;
/**
* A {@link SampleSource} for DASH media. Also acts as a {@link SampleSourceProvider} providing
* {@link DashSampleSource} instances.
* A DASH {@link MediaSource}.
*/
public final class DashSampleSource implements SampleSource, SampleSourceProvider,
public final class DashMediaSource implements MediaPeriod, MediaSource,
SequenceableLoader.Callback<ChunkTrackStream<DashChunkSource>> {
/**
@ -74,7 +73,7 @@ public final class DashSampleSource implements SampleSource, SampleSourceProvide
*/
public static final int DEFAULT_MIN_LOADABLE_RETRY_COUNT = 3;
private static final String TAG = "DashSampleSource";
private static final String TAG = "DashMediaSource";
private final DataSourceFactory dataSourceFactory;
private final BandwidthMeter bandwidthMeter;
@ -102,16 +101,16 @@ public final class DashSampleSource implements SampleSource, SampleSourceProvide
private TrackGroupArray trackGroups;
private int[] trackGroupAdaptationSetIndices;
public DashSampleSource(Uri manifestUri, DataSourceFactory dataSourceFactory,
public DashMediaSource(Uri manifestUri, DataSourceFactory dataSourceFactory,
BandwidthMeter bandwidthMeter, Handler eventHandler,
AdaptiveSourceEventListener eventListener) {
AdaptiveMediaSourceEventListener eventListener) {
this(manifestUri, dataSourceFactory, bandwidthMeter, DEFAULT_MIN_LOADABLE_RETRY_COUNT,
eventHandler, eventListener);
}
public DashSampleSource(Uri manifestUri, DataSourceFactory dataSourceFactory,
public DashMediaSource(Uri manifestUri, DataSourceFactory dataSourceFactory,
BandwidthMeter bandwidthMeter, int minLoadableRetryCount, Handler eventHandler,
AdaptiveSourceEventListener eventListener) {
AdaptiveMediaSourceEventListener eventListener) {
this.manifestUri = manifestUri;
this.dataSourceFactory = dataSourceFactory;
this.bandwidthMeter = bandwidthMeter;
@ -121,20 +120,20 @@ public final class DashSampleSource implements SampleSource, SampleSourceProvide
manifestCallback = new ManifestCallback();
}
// SampleSourceProvider implementation.
// MediaSource implementation.
@Override
public int getSourceCount() {
public int getPeriodCount() {
return 1;
}
@Override
public SampleSource createSource(int index) {
public MediaPeriod createPeriod(int index) {
Assertions.checkArgument(index == 0);
return this;
}
// SampleSource implementation.
// MediaPeriod implementation.
@Override
public void prepare(Callback callback, Allocator allocator, long positionUs) {
@ -143,7 +142,7 @@ public final class DashSampleSource implements SampleSource, SampleSourceProvide
trackStreams = newTrackStreamArray(0);
sequenceableLoader = new CompositeSequenceableLoader(trackStreams);
dataSource = dataSourceFactory.createDataSource();
loader = new Loader("Loader:DashSampleSource");
loader = new Loader("Loader:DashMediaSource");
manifestRefreshHandler = new Handler();
startLoadingManifest();
}
@ -373,7 +372,7 @@ public final class DashSampleSource implements SampleSource, SampleSourceProvide
private void finishPrepare() {
prepared = true;
callback.onSourcePrepared(this);
callback.onPeriodPrepared(this);
scheduleManifestRefresh();
}
@ -467,7 +466,7 @@ public final class DashSampleSource implements SampleSource, SampleSourceProvide
@Override
public void onLoadCanceled(ParsingLoadable<MediaPresentationDescription> loadable,
long elapsedRealtimeMs, long loadDurationMs, boolean released) {
DashSampleSource.this.onLoadCanceled(loadable, elapsedRealtimeMs, loadDurationMs);
DashMediaSource.this.onLoadCanceled(loadable, elapsedRealtimeMs, loadDurationMs);
}
@Override
@ -489,7 +488,7 @@ public final class DashSampleSource implements SampleSource, SampleSourceProvide
@Override
public void onLoadCanceled(ParsingLoadable<Long> loadable, long elapsedRealtimeMs,
long loadDurationMs, boolean released) {
DashSampleSource.this.onLoadCanceled(loadable, elapsedRealtimeMs, loadDurationMs);
DashMediaSource.this.onLoadCanceled(loadable, elapsedRealtimeMs, loadDurationMs);
}
@Override

View file

@ -19,9 +19,9 @@ import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.DecoderInputBuffer;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.FormatHolder;
import com.google.android.exoplayer2.MediaPeriod;
import com.google.android.exoplayer2.MediaSource;
import com.google.android.exoplayer2.ParserException;
import com.google.android.exoplayer2.SampleSource;
import com.google.android.exoplayer2.SampleSourceProvider;
import com.google.android.exoplayer2.SequenceableLoader;
import com.google.android.exoplayer2.TrackGroup;
import com.google.android.exoplayer2.TrackGroupArray;
@ -48,10 +48,10 @@ import java.util.Arrays;
import java.util.List;
/**
* A {@link SampleSource} that extracts sample data using an {@link Extractor}. Also acts as a
* {@link SampleSourceProvider} providing {@link ExtractorSampleSource} instances.
*
* <p>If the possible input stream container formats are known, pass a factory that instantiates
* Provides a single {@link MediaPeriod} whose data is loaded 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
@ -59,12 +59,12 @@ import java.util.List;
*
* <p>Note that the built-in extractors for AAC, MPEG TS and FLV streams do not support seeking.
*/
public final class ExtractorSampleSource implements SampleSource, SampleSourceProvider,
ExtractorOutput, Loader.Callback<ExtractorSampleSource.ExtractingLoadable>,
public final class ExtractorMediaSource implements MediaPeriod, MediaSource,
ExtractorOutput, Loader.Callback<ExtractorMediaSource.ExtractingLoadable>,
UpstreamFormatChangedListener {
/**
* Interface definition for a callback to be notified of {@link ExtractorSampleSource} events.
* Interface definition for a callback to be notified of {@link ExtractorMediaSource} events.
*/
public interface EventListener {
@ -150,7 +150,7 @@ public final class ExtractorSampleSource implements SampleSource, SampleSourcePr
* Otherwise, pass a {@link DefaultExtractorsFactory} to use default extractors.
* @param eventListener A listener of events. May be null if delivery of events is not required.
*/
public ExtractorSampleSource(Uri uri, DataSourceFactory dataSourceFactory,
public ExtractorMediaSource(Uri uri, DataSourceFactory dataSourceFactory,
BandwidthMeter bandwidthMeter, ExtractorsFactory extractorsFactory, Handler eventHandler,
EventListener eventListener) {
this(uri, dataSourceFactory, bandwidthMeter, extractorsFactory,
@ -168,7 +168,7 @@ public final class ExtractorSampleSource implements SampleSource, SampleSourcePr
* if a loading error occurs.
* @param eventListener A listener of events. May be null if delivery of events is not required.
*/
public ExtractorSampleSource(Uri uri, DataSourceFactory dataSourceFactory,
public ExtractorMediaSource(Uri uri, DataSourceFactory dataSourceFactory,
BandwidthMeter bandwidthMeter, ExtractorsFactory extractorsFactory, int minLoadableRetryCount,
Handler eventHandler, EventListener eventListener) {
this.uri = uri;
@ -180,20 +180,20 @@ public final class ExtractorSampleSource implements SampleSource, SampleSourcePr
this.eventListener = eventListener;
}
// SampleSourceProvider implementation.
// MediaSource implementation.
@Override
public int getSourceCount() {
public int getPeriodCount() {
return 1;
}
@Override
public SampleSource createSource(int index) {
public MediaPeriod createPeriod(int index) {
Assertions.checkArgument(index == 0);
return this;
}
// SampleSource implementation.
// MediaPeriod implementation.
@Override
public void prepare(Callback callback, Allocator allocator, long positionUs) {
@ -202,7 +202,7 @@ public final class ExtractorSampleSource implements SampleSource, SampleSourcePr
dataSource = dataSourceFactory.createDataSource(bandwidthMeter);
extractorHolder = new ExtractorHolder(extractorsFactory.createExtractors(), this);
loader = new Loader("Loader:ExtractorSampleSource", extractorHolder);
loader = new Loader("Loader:ExtractorMediaSource", extractorHolder);
loadCondition = new ConditionVariable();
pendingResetPositionUs = C.UNSET_TIME_US;
sampleQueues = new DefaultTrackOutput[0];
@ -483,7 +483,7 @@ public final class ExtractorSampleSource implements SampleSource, SampleSourcePr
}
tracks = new TrackGroupArray(trackArray);
prepared = true;
callback.onSourcePrepared(this);
callback.onPeriodPrepared(this);
}
private void copyLengthFromLoader(ExtractingLoadable loadable) {
@ -584,17 +584,17 @@ public final class ExtractorSampleSource implements SampleSource, SampleSourcePr
@Override
public boolean isReady() {
return ExtractorSampleSource.this.isReady(track);
return ExtractorMediaSource.this.isReady(track);
}
@Override
public void maybeThrowError() throws IOException {
ExtractorSampleSource.this.maybeThrowError();
ExtractorMediaSource.this.maybeThrowError();
}
@Override
public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer) {
return ExtractorSampleSource.this.readData(track, formatHolder, buffer);
return ExtractorMediaSource.this.readData(track, formatHolder, buffer);
}
}
@ -670,7 +670,7 @@ public final class ExtractorSampleSource implements SampleSource, SampleSourcePr
if (input.getPosition() > position + CONTINUE_LOADING_CHECK_INTERVAL_BYTES) {
position = input.getPosition();
loadCondition.close();
callback.onContinueLoadingRequested(ExtractorSampleSource.this);
callback.onContinueLoadingRequested(ExtractorMediaSource.this);
}
}
} finally {

View file

@ -15,14 +15,14 @@
*/
package com.google.android.exoplayer2.hls;
import com.google.android.exoplayer2.AdaptiveSourceEventListener;
import com.google.android.exoplayer2.AdaptiveSourceEventListener.EventDispatcher;
import com.google.android.exoplayer2.AdaptiveMediaSourceEventListener;
import com.google.android.exoplayer2.AdaptiveMediaSourceEventListener.EventDispatcher;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.CompositeSequenceableLoader;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.MediaPeriod;
import com.google.android.exoplayer2.MediaSource;
import com.google.android.exoplayer2.ParserException;
import com.google.android.exoplayer2.SampleSource;
import com.google.android.exoplayer2.SampleSourceProvider;
import com.google.android.exoplayer2.TrackGroup;
import com.google.android.exoplayer2.TrackGroupArray;
import com.google.android.exoplayer2.TrackSelection;
@ -53,10 +53,9 @@ import java.util.IdentityHashMap;
import java.util.List;
/**
* A {@link SampleSource} for HLS streams. Also acts as a {@link SampleSourceProvider} providing
* {@link HlsSampleSource} instances.
* An HLS {@link MediaSource}.
*/
public final class HlsSampleSource implements SampleSource, SampleSourceProvider,
public final class HlsMediaSource implements MediaPeriod, MediaSource,
Loader.Callback<ParsingLoadable<HlsPlaylist>>, HlsTrackStreamWrapper.Callback {
/**
@ -90,16 +89,16 @@ public final class HlsSampleSource implements SampleSource, SampleSourceProvider
private HlsTrackStreamWrapper[] enabledTrackStreamWrappers;
private CompositeSequenceableLoader sequenceableLoader;
public HlsSampleSource(Uri manifestUri, DataSourceFactory dataSourceFactory,
public HlsMediaSource(Uri manifestUri, DataSourceFactory dataSourceFactory,
BandwidthMeter bandwidthMeter, Handler eventHandler,
AdaptiveSourceEventListener eventListener) {
AdaptiveMediaSourceEventListener eventListener) {
this(manifestUri, dataSourceFactory, bandwidthMeter, DEFAULT_MIN_LOADABLE_RETRY_COUNT,
eventHandler, eventListener);
}
public HlsSampleSource(Uri manifestUri, DataSourceFactory dataSourceFactory,
public HlsMediaSource(Uri manifestUri, DataSourceFactory dataSourceFactory,
BandwidthMeter bandwidthMeter, int minLoadableRetryCount, Handler eventHandler,
AdaptiveSourceEventListener eventListener) {
AdaptiveMediaSourceEventListener eventListener) {
this.manifestUri = manifestUri;
this.dataSourceFactory = dataSourceFactory;
this.bandwidthMeter = bandwidthMeter;
@ -111,20 +110,20 @@ public final class HlsSampleSource implements SampleSource, SampleSourceProvider
manifestParser = new HlsPlaylistParser();
}
// SampleSourceProvider implementation.
// MediaSource implementation.
@Override
public int getSourceCount() {
public int getPeriodCount() {
return 1;
}
@Override
public SampleSource createSource(int index) {
public MediaPeriod createPeriod(int index) {
Assertions.checkArgument(index == 0);
return this;
}
// SampleSource implementation.
// MediaPeriod implementation.
@Override
public void prepare(Callback callback, Allocator allocator, long positionUs) {
@ -314,7 +313,7 @@ public final class HlsSampleSource implements SampleSource, SampleSourceProvider
}
}
trackGroups = new TrackGroupArray(trackGroupArray);
callback.onSourcePrepared(this);
callback.onPeriodPrepared(this);
}
@Override

View file

@ -15,7 +15,7 @@
*/
package com.google.android.exoplayer2.hls;
import com.google.android.exoplayer2.AdaptiveSourceEventListener.EventDispatcher;
import com.google.android.exoplayer2.AdaptiveMediaSourceEventListener.EventDispatcher;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.DecoderInputBuffer;
import com.google.android.exoplayer2.Format;

View file

@ -15,14 +15,14 @@
*/
package com.google.android.exoplayer2.smoothstreaming;
import com.google.android.exoplayer2.AdaptiveSourceEventListener;
import com.google.android.exoplayer2.AdaptiveSourceEventListener.EventDispatcher;
import com.google.android.exoplayer2.AdaptiveMediaSourceEventListener;
import com.google.android.exoplayer2.AdaptiveMediaSourceEventListener.EventDispatcher;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.CompositeSequenceableLoader;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.MediaPeriod;
import com.google.android.exoplayer2.MediaSource;
import com.google.android.exoplayer2.ParserException;
import com.google.android.exoplayer2.SampleSource;
import com.google.android.exoplayer2.SampleSourceProvider;
import com.google.android.exoplayer2.SequenceableLoader;
import com.google.android.exoplayer2.TrackGroup;
import com.google.android.exoplayer2.TrackGroupArray;
@ -53,10 +53,9 @@ import java.util.Arrays;
import java.util.List;
/**
* A {@link SampleSource} for SmoothStreaming media. Also acts as a {@link SampleSourceProvider}
* providing {@link SmoothStreamingSampleSource} instances.
* A SmoothStreaming {@link MediaSource}.
*/
public final class SmoothStreamingSampleSource implements SampleSource, SampleSourceProvider,
public final class SmoothStreamingMediaSource implements MediaPeriod, MediaSource,
SequenceableLoader.Callback<ChunkTrackStream<SmoothStreamingChunkSource>>,
Loader.Callback<ParsingLoadable<SmoothStreamingManifest>> {
@ -92,16 +91,16 @@ public final class SmoothStreamingSampleSource implements SampleSource, SampleSo
private TrackGroupArray trackGroups;
private int[] trackGroupElementIndices;
public SmoothStreamingSampleSource(Uri manifestUri, DataSourceFactory dataSourceFactory,
public SmoothStreamingMediaSource(Uri manifestUri, DataSourceFactory dataSourceFactory,
BandwidthMeter bandwidthMeter, Handler eventHandler,
AdaptiveSourceEventListener eventListener) {
AdaptiveMediaSourceEventListener eventListener) {
this(manifestUri, dataSourceFactory, bandwidthMeter, DEFAULT_MIN_LOADABLE_RETRY_COUNT,
eventHandler, eventListener);
}
public SmoothStreamingSampleSource(Uri manifestUri, DataSourceFactory dataSourceFactory,
public SmoothStreamingMediaSource(Uri manifestUri, DataSourceFactory dataSourceFactory,
BandwidthMeter bandwidthMeter, int minLoadableRetryCount, Handler eventHandler,
AdaptiveSourceEventListener eventListener) {
AdaptiveMediaSourceEventListener eventListener) {
this.manifestUri = Util.toLowerInvariant(manifestUri.getLastPathSegment()).equals("manifest")
? manifestUri : Uri.withAppendedPath(manifestUri, "Manifest");
this.dataSourceFactory = dataSourceFactory;
@ -111,20 +110,20 @@ public final class SmoothStreamingSampleSource implements SampleSource, SampleSo
manifestParser = new SmoothStreamingManifestParser();
}
// SampleSourceProvider implementation.
// MediaSource implementation.
@Override
public int getSourceCount() {
public int getPeriodCount() {
return 1;
}
@Override
public SampleSource createSource(int index) {
public MediaPeriod createPeriod(int index) {
Assertions.checkArgument(index == 0);
return this;
}
// SampleSource implementation.
// MediaPeriod implementation.
@Override
public void prepare(Callback callback, Allocator allocator, long positionUs) {
@ -273,7 +272,7 @@ public final class SmoothStreamingSampleSource implements SampleSource, SampleSo
new TrackEncryptionBox(true, INITIALIZATION_VECTOR_SIZE, keyId)};
}
prepared = true;
callback.onSourcePrepared(this);
callback.onPeriodPrepared(this);
} else {
for (ChunkTrackStream<SmoothStreamingChunkSource> trackStream : trackStreams) {
trackStream.getChunkSource().updateManifest(manifest);

View file

@ -81,7 +81,7 @@ public final class DebugTextViewHelper implements Runnable, ExoPlayer.EventListe
}
private void updateTextView() {
textView.setText(getPlayerStateString() + getPlayerSourceIndexString() + getBandwidthString()
textView.setText(getPlayerStateString() + getPlayerPeriodIndexString() + getBandwidthString()
+ getVideoString() + getAudioString());
}
@ -107,8 +107,8 @@ public final class DebugTextViewHelper implements Runnable, ExoPlayer.EventListe
return text;
}
private String getPlayerSourceIndexString() {
return " source:" + player.getCurrentSourceIndex();
private String getPlayerPeriodIndexString() {
return " period:" + player.getCurrentPeriodIndex();
}
private String getBandwidthString() {
@ -169,7 +169,7 @@ public final class DebugTextViewHelper implements Runnable, ExoPlayer.EventListe
}
@Override
public void onPositionDiscontinuity(int sourceIndex, long positionMs) {
public void onPositionDiscontinuity(int periodIndex, long positionMs) {
updateTextView();
}

View file

@ -22,13 +22,13 @@ import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.MediaCodecUtil;
import com.google.android.exoplayer2.MediaCodecUtil.DecoderQueryException;
import com.google.android.exoplayer2.SampleSourceProvider;
import com.google.android.exoplayer2.MediaSource;
import com.google.android.exoplayer2.TrackGroup;
import com.google.android.exoplayer2.TrackGroupArray;
import com.google.android.exoplayer2.TrackRenderer;
import com.google.android.exoplayer2.TrackSelection;
import com.google.android.exoplayer2.TrackSelectionPolicy;
import com.google.android.exoplayer2.dash.DashSampleSource;
import com.google.android.exoplayer2.dash.DashMediaSource;
import com.google.android.exoplayer2.playbacktests.util.ActionSchedule;
import com.google.android.exoplayer2.playbacktests.util.CodecCountersUtil;
import com.google.android.exoplayer2.playbacktests.util.ExoHostedTest;
@ -418,9 +418,9 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
}
@Override
public SampleSourceProvider buildSource(HostActivity host, DataSourceFactory dataSourceFactory,
public MediaSource buildSource(HostActivity host, DataSourceFactory dataSourceFactory,
BandwidthMeter bandwidthMeter) {
return new DashSampleSource(manifestUri, dataSourceFactory, bandwidthMeter,
return new DashMediaSource(manifestUri, dataSourceFactory, bandwidthMeter,
MIN_LOADABLE_RETRY_COUNT, null, null);
}

View file

@ -22,7 +22,7 @@ import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.ExoPlayerFactory;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.SampleSourceProvider;
import com.google.android.exoplayer2.MediaSource;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.TrackSelectionPolicy;
import com.google.android.exoplayer2.audio.AudioTrack;
@ -128,7 +128,7 @@ public abstract class ExoHostedTest implements HostedTest, ExoPlayer.EventListen
player = buildExoPlayer(host, surface, trackSelector);
DataSourceFactory dataSourceFactory = new DefaultDataSourceFactory(host, Util
.getUserAgent(host, "ExoPlayerPlaybackTests"));
player.setSourceProvider(buildSource(host, dataSourceFactory, player.getBandwidthMeter()));
player.setMediaSource(buildSource(host, dataSourceFactory, player.getBandwidthMeter()));
player.addListener(this);
player.setDebugListener(this);
player.setPlayWhenReady(true);
@ -210,7 +210,7 @@ public abstract class ExoHostedTest implements HostedTest, ExoPlayer.EventListen
}
@Override
public final void onPositionDiscontinuity(int sourceIndex, long positionMs) {
public final void onPositionDiscontinuity(int periodIndex, long positionMs) {
// Do nothing.
}
@ -287,8 +287,8 @@ public abstract class ExoHostedTest implements HostedTest, ExoPlayer.EventListen
}
@SuppressWarnings("unused")
protected abstract SampleSourceProvider buildSource(HostActivity host,
DataSourceFactory dataSourceFactory, BandwidthMeter bandwidthMeter);
protected abstract MediaSource buildSource(HostActivity host, DataSourceFactory dataSourceFactory,
BandwidthMeter bandwidthMeter);
@SuppressWarnings("unused")
protected void onPlayerErrorInternal(ExoPlaybackException error) {