Commit af3452d2 by andrewlewis Committed by Oliver Woodman

Make SampleSources reusable and implement SampleSourceProvider.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=126888556
parent 42d78b35
...@@ -30,18 +30,24 @@ import com.google.android.exoplayer.MediaCodecUtil.DecoderQueryException; ...@@ -30,18 +30,24 @@ import com.google.android.exoplayer.MediaCodecUtil.DecoderQueryException;
import com.google.android.exoplayer.SampleSourceProvider; import com.google.android.exoplayer.SampleSourceProvider;
import com.google.android.exoplayer.SimpleExoPlayer; import com.google.android.exoplayer.SimpleExoPlayer;
import com.google.android.exoplayer.TrackGroupArray; import com.google.android.exoplayer.TrackGroupArray;
import com.google.android.exoplayer.dash.DashSampleSource;
import com.google.android.exoplayer.drm.DrmSessionManager; import com.google.android.exoplayer.drm.DrmSessionManager;
import com.google.android.exoplayer.drm.StreamingDrmSessionManager; import com.google.android.exoplayer.drm.StreamingDrmSessionManager;
import com.google.android.exoplayer.drm.UnsupportedDrmException; import com.google.android.exoplayer.drm.UnsupportedDrmException;
import com.google.android.exoplayer.extractor.DefaultExtractorsFactory;
import com.google.android.exoplayer.extractor.ExtractorSampleSource;
import com.google.android.exoplayer.hls.HlsSampleSource;
import com.google.android.exoplayer.metadata.id3.ApicFrame; import com.google.android.exoplayer.metadata.id3.ApicFrame;
import com.google.android.exoplayer.metadata.id3.GeobFrame; import com.google.android.exoplayer.metadata.id3.GeobFrame;
import com.google.android.exoplayer.metadata.id3.Id3Frame; import com.google.android.exoplayer.metadata.id3.Id3Frame;
import com.google.android.exoplayer.metadata.id3.PrivFrame; import com.google.android.exoplayer.metadata.id3.PrivFrame;
import com.google.android.exoplayer.metadata.id3.TextInformationFrame; import com.google.android.exoplayer.metadata.id3.TextInformationFrame;
import com.google.android.exoplayer.metadata.id3.TxxxFrame; import com.google.android.exoplayer.metadata.id3.TxxxFrame;
import com.google.android.exoplayer.smoothstreaming.SmoothStreamingSampleSource;
import com.google.android.exoplayer.text.CaptionStyleCompat; import com.google.android.exoplayer.text.CaptionStyleCompat;
import com.google.android.exoplayer.text.Cue; import com.google.android.exoplayer.text.Cue;
import com.google.android.exoplayer.text.SubtitleLayout; import com.google.android.exoplayer.text.SubtitleLayout;
import com.google.android.exoplayer.upstream.BandwidthMeter;
import com.google.android.exoplayer.upstream.DataSourceFactory; import com.google.android.exoplayer.upstream.DataSourceFactory;
import com.google.android.exoplayer.upstream.DefaultDataSourceFactory; import com.google.android.exoplayer.upstream.DefaultDataSourceFactory;
import com.google.android.exoplayer.util.DebugTextViewHelper; import com.google.android.exoplayer.util.DebugTextViewHelper;
...@@ -57,6 +63,7 @@ import android.content.pm.PackageManager; ...@@ -57,6 +63,7 @@ import android.content.pm.PackageManager;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.MotionEvent; import android.view.MotionEvent;
...@@ -126,6 +133,7 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback, ...@@ -126,6 +133,7 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
private DefaultTrackSelector trackSelector; private DefaultTrackSelector trackSelector;
private TrackSelectionHelper trackSelectionHelper; private TrackSelectionHelper trackSelectionHelper;
private DebugTextViewHelper debugViewHelper; private DebugTextViewHelper debugViewHelper;
private BandwidthMeter bandwidthMeter;
private boolean playerNeedsSource; private boolean playerNeedsSource;
private long playerPosition; private long playerPosition;
...@@ -283,6 +291,7 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback, ...@@ -283,6 +291,7 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
mediaController.setAnchorView(rootView); mediaController.setAnchorView(rootView);
debugViewHelper = new DebugTextViewHelper(player, debugTextView); debugViewHelper = new DebugTextViewHelper(player, debugTextView);
debugViewHelper.start(); debugViewHelper.start();
bandwidthMeter = player.getBandwidthMeter();
playerNeedsSource = true; playerNeedsSource = true;
} }
if (playerNeedsSource) { if (playerNeedsSource) {
...@@ -311,10 +320,9 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback, ...@@ -311,10 +320,9 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
return; return;
} }
UriSampleSourceProvider[] providers = new UriSampleSourceProvider[uris.length]; SampleSourceProvider[] providers = new SampleSourceProvider[uris.length];
for (int i = 0; i < uris.length; i++) { for (int i = 0; i < uris.length; i++) {
providers[i] = new UriSampleSourceProvider(player.getBandwidthMeter(), dataSourceFactory, providers[i] = getSampleSourceProvider(uris[i], extensions[i]);
uris[i], extensions[i], mainHandler, eventLogger);
} }
SampleSourceProvider sourceProvider = providers.length == 1 ? providers[0] SampleSourceProvider sourceProvider = providers.length == 1 ? providers[0]
: new ConcatenatingSampleSourceProvider(providers); : new ConcatenatingSampleSourceProvider(providers);
...@@ -324,6 +332,28 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback, ...@@ -324,6 +332,28 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
} }
} }
private SampleSourceProvider getSampleSourceProvider(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,
eventLogger);
case Util.TYPE_DASH:
return new DashSampleSource(uri, dataSourceFactory, bandwidthMeter, mainHandler,
eventLogger);
case Util.TYPE_HLS:
return new HlsSampleSource(uri, dataSourceFactory, bandwidthMeter, mainHandler,
eventLogger);
case Util.TYPE_OTHER:
return new ExtractorSampleSource(uri, dataSourceFactory, bandwidthMeter,
new DefaultExtractorsFactory(), mainHandler, eventLogger);
default:
throw new IllegalStateException("Unsupported type: " + type);
}
}
private DrmSessionManager buildDrmSessionManager(UUID uuid, String id, String provider) private DrmSessionManager buildDrmSessionManager(UUID uuid, String id, String provider)
throws UnsupportedDrmException { throws UnsupportedDrmException {
if (Util.SDK_INT < 18) { if (Util.SDK_INT < 18) {
......
/*
* Copyright (C) 2014 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.exoplayer.demo;
import com.google.android.exoplayer.SampleSource;
import com.google.android.exoplayer.SampleSourceProvider;
import com.google.android.exoplayer.dash.DashSampleSource;
import com.google.android.exoplayer.extractor.DefaultExtractorsFactory;
import com.google.android.exoplayer.extractor.ExtractorSampleSource;
import com.google.android.exoplayer.hls.HlsSampleSource;
import com.google.android.exoplayer.smoothstreaming.SmoothStreamingSampleSource;
import com.google.android.exoplayer.upstream.BandwidthMeter;
import com.google.android.exoplayer.upstream.DataSourceFactory;
import com.google.android.exoplayer.util.Util;
import android.net.Uri;
import android.os.Handler;
import android.text.TextUtils;
/**
* Provides a {@link SampleSource} to play back media loaded from a {@link Uri}.
*/
public final class UriSampleSourceProvider implements SampleSourceProvider {
private final BandwidthMeter bandwidthMeter;
private final DataSourceFactory dataSourceFactory;
private final Uri uri;
private final String overrideExtension;
private final Handler handler;
private final EventLogger eventLogger;
/**
* Constructs a source provider for {@link SampleSource} to play back media at the specified
* URI, using the specified type.
*
* @param bandwidthMeter A bandwidth meter.
* @param dataSourceFactory A data source factory.
* @param uri The URI to play back.
* @param overrideExtension An overriding file extension used when inferring the source's type,
* or {@code null}.
* @param handler A handler to use for logging events.
* @param eventLogger An event logger.
*/
public UriSampleSourceProvider(BandwidthMeter bandwidthMeter, DataSourceFactory dataSourceFactory,
Uri uri, String overrideExtension, Handler handler, EventLogger eventLogger) {
this.bandwidthMeter = bandwidthMeter;
this.dataSourceFactory = dataSourceFactory;
this.uri = uri;
this.overrideExtension = overrideExtension;
this.handler = handler;
this.eventLogger = eventLogger;
}
@Override
public int getSourceCount() {
return 1;
}
@Override
public SampleSource createSource(int index) {
int type = inferContentType(uri, overrideExtension);
switch (type) {
case Util.TYPE_SS:
return new SmoothStreamingSampleSource(uri, dataSourceFactory, bandwidthMeter, handler,
eventLogger);
case Util.TYPE_DASH:
return new DashSampleSource(uri, dataSourceFactory, bandwidthMeter, handler, eventLogger);
case Util.TYPE_HLS:
return new HlsSampleSource(uri, dataSourceFactory, bandwidthMeter, handler, eventLogger);
case Util.TYPE_OTHER:
return new ExtractorSampleSource(uri, dataSourceFactory, bandwidthMeter,
new DefaultExtractorsFactory(), handler, eventLogger);
default:
throw new IllegalStateException("Unsupported type: " + type);
}
}
/**
* Makes a best guess to infer the type from a media {@link Uri} and an optional overriding file
* extension.
*
* @param uri The {@link Uri} of the media.
* @param fileExtension An overriding file extension.
* @return The inferred type.
*/
private static int inferContentType(Uri uri, String fileExtension) {
String lastPathSegment = !TextUtils.isEmpty(fileExtension) ? "." + fileExtension
: uri.getLastPathSegment();
return Util.inferContentType(lastPathSegment);
}
}
...@@ -83,7 +83,7 @@ public class FlacPlaybackTest extends InstrumentationTestCase { ...@@ -83,7 +83,7 @@ public class FlacPlaybackTest extends InstrumentationTestCase {
new MatroskaExtractor.Factory(), new MatroskaExtractor.Factory(),
null, null,
null); null);
player.setSource(sampleSource); player.setSourceProvider(sampleSource);
player.setPlayWhenReady(true); player.setPlayWhenReady(true);
Looper.loop(); Looper.loop();
} }
......
...@@ -83,7 +83,7 @@ public class OpusPlaybackTest extends InstrumentationTestCase { ...@@ -83,7 +83,7 @@ public class OpusPlaybackTest extends InstrumentationTestCase {
new MatroskaExtractor.Factory(), new MatroskaExtractor.Factory(),
null, null,
null); null);
player.setSource(sampleSource); player.setSourceProvider(sampleSource);
player.setPlayWhenReady(true); player.setPlayWhenReady(true);
Looper.loop(); Looper.loop();
} }
......
...@@ -102,7 +102,7 @@ public class VpxPlaybackTest extends InstrumentationTestCase { ...@@ -102,7 +102,7 @@ public class VpxPlaybackTest extends InstrumentationTestCase {
player.sendMessages(new ExoPlayer.ExoPlayerMessage(videoRenderer, player.sendMessages(new ExoPlayer.ExoPlayerMessage(videoRenderer,
LibvpxVideoTrackRenderer.MSG_SET_OUTPUT_BUFFER_RENDERER, LibvpxVideoTrackRenderer.MSG_SET_OUTPUT_BUFFER_RENDERER,
new VpxVideoSurfaceView(context))); new VpxVideoSurfaceView(context)));
player.setSource(sampleSource); player.setSourceProvider(sampleSource);
player.setPlayWhenReady(true); player.setPlayWhenReady(true);
Looper.loop(); Looper.loop();
} }
......
...@@ -236,14 +236,6 @@ public interface ExoPlayer { ...@@ -236,14 +236,6 @@ public interface ExoPlayer {
int getPlaybackState(); int getPlaybackState();
/** /**
* Sets the player's source. The player will transition to {@link #STATE_BUFFERING} until it is
* ready to play the new source.
*
* @param sampleSource The {@link SampleSource} to play.
*/
void setSource(SampleSource sampleSource);
/**
* Sets the player's source provider. The player's position will be reset to the start of the * 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 * first source and the player will transition to {@link #STATE_BUFFERING} until it is ready to
* play it. * play it.
......
...@@ -94,11 +94,6 @@ import java.util.concurrent.CopyOnWriteArraySet; ...@@ -94,11 +94,6 @@ import java.util.concurrent.CopyOnWriteArraySet;
} }
@Override @Override
public void setSource(final SampleSource sampleSource) {
setSourceProvider(new SingleSampleSourceProvider(sampleSource));
}
@Override
public void setSourceProvider(SampleSourceProvider sourceProvider) { public void setSourceProvider(SampleSourceProvider sourceProvider) {
maskingSourceIndex = 0; maskingSourceIndex = 0;
maskingPositionMs = 0; maskingPositionMs = 0;
...@@ -267,25 +262,4 @@ import java.util.concurrent.CopyOnWriteArraySet; ...@@ -267,25 +262,4 @@ import java.util.concurrent.CopyOnWriteArraySet;
} }
} }
private static final class SingleSampleSourceProvider implements SampleSourceProvider {
private final SampleSource sampleSource;
public SingleSampleSourceProvider(SampleSource sampleSource) {
this.sampleSource = sampleSource;
}
@Override
public int getSourceCount() {
return 1;
}
@Override
public SampleSource createSource(int index) {
// The source will only be created once.
return sampleSource;
}
}
} }
...@@ -314,11 +314,6 @@ public final class SimpleExoPlayer implements ExoPlayer { ...@@ -314,11 +314,6 @@ public final class SimpleExoPlayer implements ExoPlayer {
} }
@Override @Override
public void setSource(SampleSource sampleSource) {
player.setSource(sampleSource);
}
@Override
public void setSourceProvider(SampleSourceProvider sourceProvider) { public void setSourceProvider(SampleSourceProvider sourceProvider) {
player.setSourceProvider(sourceProvider); player.setSourceProvider(sourceProvider);
} }
......
...@@ -17,6 +17,7 @@ package com.google.android.exoplayer; ...@@ -17,6 +17,7 @@ package com.google.android.exoplayer;
import com.google.android.exoplayer.upstream.Allocator; import com.google.android.exoplayer.upstream.Allocator;
import com.google.android.exoplayer.upstream.DataSource; import com.google.android.exoplayer.upstream.DataSource;
import com.google.android.exoplayer.upstream.DataSourceFactory;
import com.google.android.exoplayer.upstream.DataSpec; import com.google.android.exoplayer.upstream.DataSpec;
import com.google.android.exoplayer.upstream.Loader; import com.google.android.exoplayer.upstream.Loader;
import com.google.android.exoplayer.upstream.Loader.Loadable; import com.google.android.exoplayer.upstream.Loader.Loadable;
...@@ -30,10 +31,11 @@ import java.util.Arrays; ...@@ -30,10 +31,11 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
/** /**
* A {@link SampleSource} that loads the data at a given {@link Uri} as a single sample. * 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.
*/ */
public final class SingleSampleSource implements SampleSource, TrackStream, public final class SingleSampleSource implements SampleSource, SampleSourceProvider, TrackStream,
Loader.Callback<SingleSampleSource>, Loadable { Loader.Callback<SingleSampleSource.SourceLoadable> {
/** /**
* Interface definition for a callback to be notified of {@link SingleSampleSource} events. * Interface definition for a callback to be notified of {@link SingleSampleSource} events.
...@@ -65,8 +67,7 @@ public final class SingleSampleSource implements SampleSource, TrackStream, ...@@ -65,8 +67,7 @@ public final class SingleSampleSource implements SampleSource, TrackStream,
private static final int STREAM_STATE_END_OF_STREAM = 2; private static final int STREAM_STATE_END_OF_STREAM = 2;
private final Uri uri; private final Uri uri;
private final DataSource dataSource; private final DataSourceFactory dataSourceFactory;
private final Loader loader;
private final Format format; private final Format format;
private final long durationUs; private final long durationUs;
private final int minLoadableRetryCount; private final int minLoadableRetryCount;
...@@ -75,41 +76,57 @@ public final class SingleSampleSource implements SampleSource, TrackStream, ...@@ -75,41 +76,57 @@ public final class SingleSampleSource implements SampleSource, TrackStream,
private final EventListener eventListener; private final EventListener eventListener;
private final int eventSourceId; private final int eventSourceId;
private Loader loader;
private boolean loadingFinished; private boolean loadingFinished;
private int streamState; private int streamState;
private byte[] sampleData; private byte[] sampleData;
private int sampleSize; private int sampleSize;
public SingleSampleSource(Uri uri, DataSource dataSource, Format format, long durationUs) { public SingleSampleSource(Uri uri, DataSourceFactory dataSourceFactory, Format format,
this(uri, dataSource, format, durationUs, DEFAULT_MIN_LOADABLE_RETRY_COUNT); long durationUs) {
this(uri, dataSourceFactory, format, durationUs, DEFAULT_MIN_LOADABLE_RETRY_COUNT);
} }
public SingleSampleSource(Uri uri, DataSource dataSource, Format format, long durationUs, public SingleSampleSource(Uri uri, DataSourceFactory dataSourceFactory, Format format,
int minLoadableRetryCount) { long durationUs, int minLoadableRetryCount) {
this(uri, dataSource, format, durationUs, minLoadableRetryCount, null, null, 0); this(uri, dataSourceFactory, format, durationUs, minLoadableRetryCount, null, null, 0);
} }
public SingleSampleSource(Uri uri, DataSource dataSource, Format format, long durationUs, public SingleSampleSource(Uri uri, DataSourceFactory dataSourceFactory, Format format,
int minLoadableRetryCount, Handler eventHandler, EventListener eventListener, long durationUs, int minLoadableRetryCount, Handler eventHandler, EventListener eventListener,
int eventSourceId) { int eventSourceId) {
this.uri = uri; this.uri = uri;
this.dataSource = dataSource; this.dataSourceFactory = dataSourceFactory;
this.format = format; this.format = format;
this.durationUs = durationUs; this.durationUs = durationUs;
this.minLoadableRetryCount = minLoadableRetryCount; this.minLoadableRetryCount = minLoadableRetryCount;
this.eventHandler = eventHandler; this.eventHandler = eventHandler;
this.eventListener = eventListener; this.eventListener = eventListener;
this.eventSourceId = eventSourceId; this.eventSourceId = eventSourceId;
loader = new Loader("Loader:SingleSampleSource");
tracks = new TrackGroupArray(new TrackGroup(format)); tracks = new TrackGroupArray(new TrackGroup(format));
sampleData = new byte[INITIAL_SAMPLE_SIZE]; sampleData = new byte[INITIAL_SAMPLE_SIZE];
streamState = STREAM_STATE_SEND_FORMAT;
}
// SampleSourceProvider implementation.
@Override
public int getSourceCount() {
return 1;
}
@Override
public SampleSource createSource(int index) {
Assertions.checkArgument(index == 0);
return this;
} }
// SampleSource implementation. // SampleSource implementation.
@Override @Override
public void prepare(Callback callback, Allocator allocator, long positionUs) { public void prepare(Callback callback, Allocator allocator, long positionUs) {
loader = new Loader("Loader:SingleSampleSource");
callback.onSourcePrepared(this); callback.onSourcePrepared(this);
} }
...@@ -147,7 +164,8 @@ public final class SingleSampleSource implements SampleSource, TrackStream, ...@@ -147,7 +164,8 @@ public final class SingleSampleSource implements SampleSource, TrackStream,
if (loadingFinished || loader.isLoading()) { if (loadingFinished || loader.isLoading()) {
return false; return false;
} }
loader.startLoading(this, this, minLoadableRetryCount); loader.startLoading(new SourceLoadable(uri, dataSourceFactory.createDataSource()), this,
minLoadableRetryCount);
return true; return true;
} }
...@@ -171,8 +189,14 @@ public final class SingleSampleSource implements SampleSource, TrackStream, ...@@ -171,8 +189,14 @@ public final class SingleSampleSource implements SampleSource, TrackStream,
@Override @Override
public void release() { public void release() {
if (loader != null) {
loader.release();
loader = null;
}
loadingFinished = false;
streamState = STREAM_STATE_SEND_FORMAT;
sampleData = null; sampleData = null;
loader.release(); sampleSize = 0;
} }
// TrackStream implementation. // TrackStream implementation.
...@@ -219,57 +243,26 @@ public final class SingleSampleSource implements SampleSource, TrackStream, ...@@ -219,57 +243,26 @@ public final class SingleSampleSource implements SampleSource, TrackStream,
// Loader.Callback implementation. // Loader.Callback implementation.
@Override @Override
public void onLoadCompleted(SingleSampleSource loadable, long elapsedRealtimeMs, public void onLoadCompleted(SourceLoadable loadable, long elapsedRealtimeMs,
long loadDurationMs) { long loadDurationMs) {
sampleSize = loadable.sampleSize;
sampleData = loadable.sampleData;
loadingFinished = true; loadingFinished = true;
} }
@Override @Override
public void onLoadCanceled(SingleSampleSource loadable, long elapsedRealtimeMs, public void onLoadCanceled(SourceLoadable loadable, long elapsedRealtimeMs, long loadDurationMs,
long loadDurationMs, boolean released) { boolean released) {
// Never happens. // Do nothing.
} }
@Override @Override
public int onLoadError(SingleSampleSource loadable, long elapsedRealtimeMs, public int onLoadError(SourceLoadable loadable, long elapsedRealtimeMs, long loadDurationMs,
long loadDurationMs, IOException error) { IOException error) {
notifyLoadError(error); notifyLoadError(error);
return Loader.RETRY; return Loader.RETRY;
} }
// Loadable implementation.
@Override
public void cancelLoad() {
// Never happens.
}
@Override
public boolean isLoadCanceled() {
return false;
}
@Override
public void load() throws IOException, InterruptedException {
// We always load from the beginning, so reset the sampleSize to 0.
sampleSize = 0;
try {
// Create and open the input.
dataSource.open(new DataSpec(uri));
// Load the sample data.
int result = 0;
while (result != C.RESULT_END_OF_INPUT) {
sampleSize += result;
if (sampleSize == sampleData.length) {
sampleData = Arrays.copyOf(sampleData, sampleData.length * 2);
}
result = dataSource.read(sampleData, sampleSize, sampleData.length - sampleSize);
}
} finally {
dataSource.close();
}
}
// Internal methods. // Internal methods.
private void notifyLoadError(final IOException e) { private void notifyLoadError(final IOException e) {
...@@ -283,4 +276,50 @@ public final class SingleSampleSource implements SampleSource, TrackStream, ...@@ -283,4 +276,50 @@ public final class SingleSampleSource implements SampleSource, TrackStream,
} }
} }
/* package */ static final class SourceLoadable implements Loadable {
private final Uri uri;
private final DataSource dataSource;
private int sampleSize;
private byte[] sampleData;
public SourceLoadable(Uri uri, DataSource dataSource) {
this.uri = uri;
this.dataSource = dataSource;
}
@Override
public void cancelLoad() {
// Never happens.
}
@Override
public boolean isLoadCanceled() {
return false;
}
@Override
public void load() throws IOException, InterruptedException {
// We always load from the beginning, so reset the sampleSize to 0.
sampleSize = 0;
try {
// Create and open the input.
dataSource.open(new DataSpec(uri));
// Load the sample data.
int result = 0;
while (result != C.RESULT_END_OF_INPUT) {
sampleSize += result;
if (sampleSize == sampleData.length) {
sampleData = Arrays.copyOf(sampleData, sampleData.length * 2);
}
result = dataSource.read(sampleData, sampleSize, sampleData.length - sampleSize);
}
} finally {
dataSource.close();
}
}
}
} }
...@@ -22,6 +22,7 @@ import com.google.android.exoplayer.CompositeSequenceableLoader; ...@@ -22,6 +22,7 @@ import com.google.android.exoplayer.CompositeSequenceableLoader;
import com.google.android.exoplayer.Format; import com.google.android.exoplayer.Format;
import com.google.android.exoplayer.ParserException; import com.google.android.exoplayer.ParserException;
import com.google.android.exoplayer.SampleSource; import com.google.android.exoplayer.SampleSource;
import com.google.android.exoplayer.SampleSourceProvider;
import com.google.android.exoplayer.SequenceableLoader; import com.google.android.exoplayer.SequenceableLoader;
import com.google.android.exoplayer.TrackGroup; import com.google.android.exoplayer.TrackGroup;
import com.google.android.exoplayer.TrackGroupArray; import com.google.android.exoplayer.TrackGroupArray;
...@@ -42,6 +43,7 @@ import com.google.android.exoplayer.upstream.DataSource; ...@@ -42,6 +43,7 @@ import com.google.android.exoplayer.upstream.DataSource;
import com.google.android.exoplayer.upstream.DataSourceFactory; import com.google.android.exoplayer.upstream.DataSourceFactory;
import com.google.android.exoplayer.upstream.Loader; import com.google.android.exoplayer.upstream.Loader;
import com.google.android.exoplayer.upstream.ParsingLoadable; import com.google.android.exoplayer.upstream.ParsingLoadable;
import com.google.android.exoplayer.util.Assertions;
import com.google.android.exoplayer.util.Util; import com.google.android.exoplayer.util.Util;
import android.net.Uri; import android.net.Uri;
...@@ -61,9 +63,10 @@ import java.util.Locale; ...@@ -61,9 +63,10 @@ import java.util.Locale;
import java.util.TimeZone; import java.util.TimeZone;
/** /**
* A {@link SampleSource} for DASH media. * A {@link SampleSource} for DASH media. Also acts as a {@link SampleSourceProvider} providing
* {@link DashSampleSource} instances.
*/ */
public final class DashSampleSource implements SampleSource, public final class DashSampleSource implements SampleSource, SampleSourceProvider,
SequenceableLoader.Callback<ChunkTrackStream<DashChunkSource>> { SequenceableLoader.Callback<ChunkTrackStream<DashChunkSource>> {
/** /**
...@@ -77,11 +80,14 @@ public final class DashSampleSource implements SampleSource, ...@@ -77,11 +80,14 @@ public final class DashSampleSource implements SampleSource,
private final BandwidthMeter bandwidthMeter; private final BandwidthMeter bandwidthMeter;
private final int minLoadableRetryCount; private final int minLoadableRetryCount;
private final EventDispatcher eventDispatcher; private final EventDispatcher eventDispatcher;
private final Loader loader;
private final DataSource dataSource;
private final MediaPresentationDescriptionParser manifestParser; private final MediaPresentationDescriptionParser manifestParser;
private final ManifestCallback manifestCallback; private final ManifestCallback manifestCallback;
private DataSource dataSource;
private Loader loader;
private ChunkTrackStream<DashChunkSource>[] trackStreams;
private CompositeSequenceableLoader sequenceableLoader;
private Uri manifestUri; private Uri manifestUri;
private long manifestLoadStartTimestamp; private long manifestLoadStartTimestamp;
private long manifestLoadEndTimestamp; private long manifestLoadEndTimestamp;
...@@ -96,9 +102,6 @@ public final class DashSampleSource implements SampleSource, ...@@ -96,9 +102,6 @@ public final class DashSampleSource implements SampleSource,
private TrackGroupArray trackGroups; private TrackGroupArray trackGroups;
private int[] trackGroupAdaptationSetIndices; private int[] trackGroupAdaptationSetIndices;
private ChunkTrackStream<DashChunkSource>[] trackStreams;
private CompositeSequenceableLoader sequenceableLoader;
public DashSampleSource(Uri manifestUri, DataSourceFactory dataSourceFactory, public DashSampleSource(Uri manifestUri, DataSourceFactory dataSourceFactory,
BandwidthMeter bandwidthMeter, Handler eventHandler, BandwidthMeter bandwidthMeter, Handler eventHandler,
AdaptiveSourceEventListener eventListener) { AdaptiveSourceEventListener eventListener) {
...@@ -114,18 +117,33 @@ public final class DashSampleSource implements SampleSource, ...@@ -114,18 +117,33 @@ public final class DashSampleSource implements SampleSource,
this.bandwidthMeter = bandwidthMeter; this.bandwidthMeter = bandwidthMeter;
this.minLoadableRetryCount = minLoadableRetryCount; this.minLoadableRetryCount = minLoadableRetryCount;
eventDispatcher = new EventDispatcher(eventHandler, eventListener); eventDispatcher = new EventDispatcher(eventHandler, eventListener);
dataSource = dataSourceFactory.createDataSource();
loader = new Loader("Loader:DashSampleSource");
manifestParser = new MediaPresentationDescriptionParser(); manifestParser = new MediaPresentationDescriptionParser();
manifestCallback = new ManifestCallback(); manifestCallback = new ManifestCallback();
trackStreams = newTrackStreamArray(0);
sequenceableLoader = new CompositeSequenceableLoader(trackStreams);
} }
// SampleSourceProvider implementation.
@Override
public int getSourceCount() {
return 1;
}
@Override
public SampleSource createSource(int index) {
Assertions.checkArgument(index == 0);
return this;
}
// SampleSource implementation.
@Override @Override
public void prepare(Callback callback, Allocator allocator, long positionUs) { public void prepare(Callback callback, Allocator allocator, long positionUs) {
this.callback = callback; this.callback = callback;
this.allocator = allocator; this.allocator = allocator;
trackStreams = newTrackStreamArray(0);
sequenceableLoader = new CompositeSequenceableLoader(trackStreams);
dataSource = dataSourceFactory.createDataSource();
loader = new Loader("Loader:DashSampleSource");
manifestRefreshHandler = new Handler(); manifestRefreshHandler = new Handler();
startLoadingManifest(); startLoadingManifest();
} }
...@@ -212,14 +230,32 @@ public final class DashSampleSource implements SampleSource, ...@@ -212,14 +230,32 @@ public final class DashSampleSource implements SampleSource,
@Override @Override
public void release() { public void release() {
dataSource = null;
if (loader != null) {
loader.release();
loader = null;
}
if (trackStreams != null) {
for (ChunkTrackStream<DashChunkSource> trackStream : trackStreams) {
trackStream.release();
}
trackStreams = null;
}
sequenceableLoader = null;
manifestLoadStartTimestamp = 0;
manifestLoadEndTimestamp = 0;
manifest = null;
callback = null;
allocator = null;
if (manifestRefreshHandler != null) { if (manifestRefreshHandler != null) {
manifestRefreshHandler.removeCallbacksAndMessages(null); manifestRefreshHandler.removeCallbacksAndMessages(null);
manifestRefreshHandler = null; manifestRefreshHandler = null;
} }
loader.release(); prepared = false;
for (ChunkTrackStream<DashChunkSource> trackStream : trackStreams) { durationUs = 0;
trackStream.release(); elapsedRealtimeOffset = 0;
} trackGroups = null;
trackGroupAdaptationSetIndices = null;
} }
// SequenceableLoader.Callback implementation. // SequenceableLoader.Callback implementation.
......
...@@ -21,6 +21,7 @@ import com.google.android.exoplayer.Format; ...@@ -21,6 +21,7 @@ import com.google.android.exoplayer.Format;
import com.google.android.exoplayer.FormatHolder; import com.google.android.exoplayer.FormatHolder;
import com.google.android.exoplayer.ParserException; import com.google.android.exoplayer.ParserException;
import com.google.android.exoplayer.SampleSource; import com.google.android.exoplayer.SampleSource;
import com.google.android.exoplayer.SampleSourceProvider;
import com.google.android.exoplayer.SequenceableLoader; import com.google.android.exoplayer.SequenceableLoader;
import com.google.android.exoplayer.TrackGroup; import com.google.android.exoplayer.TrackGroup;
import com.google.android.exoplayer.TrackGroupArray; import com.google.android.exoplayer.TrackGroupArray;
...@@ -47,7 +48,8 @@ import java.util.Arrays; ...@@ -47,7 +48,8 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
/** /**
* A {@link SampleSource} that extracts sample data using an {@link Extractor}. * 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 * <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 * extractors for them to the constructor. Otherwise, pass a {@link DefaultExtractorsFactory} to
...@@ -57,8 +59,8 @@ import java.util.List; ...@@ -57,8 +59,8 @@ import java.util.List;
* *
* <p>Note that the built-in extractors for AAC, MPEG TS and FLV streams do not support seeking. * <p>Note that the built-in extractors for AAC, MPEG TS and FLV streams do not support seeking.
*/ */
public final class ExtractorSampleSource implements SampleSource, ExtractorOutput, public final class ExtractorSampleSource implements SampleSource, SampleSourceProvider,
Loader.Callback<ExtractorSampleSource.ExtractingLoadable>, ExtractorOutput, Loader.Callback<ExtractorSampleSource.ExtractingLoadable>,
UpstreamFormatChangedListener { UpstreamFormatChangedListener {
/** /**
...@@ -106,13 +108,17 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu ...@@ -106,13 +108,17 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
private static final long DEFAULT_LAST_SAMPLE_DURATION_US = 10000; private static final long DEFAULT_LAST_SAMPLE_DURATION_US = 10000;
private final Uri uri; private final Uri uri;
private final DataSourceFactory dataSourceFactory;
private final BandwidthMeter bandwidthMeter;
private final ExtractorsFactory extractorsFactory;
private final int minLoadableRetryCount; private final int minLoadableRetryCount;
private final Handler eventHandler; private final Handler eventHandler;
private final EventListener eventListener; private final EventListener eventListener;
private final DataSource dataSource;
private final ConditionVariable loadCondition; private DataSource dataSource;
private final ExtractorHolder extractorHolder; private ExtractorHolder extractorHolder;
private final Loader loader; private Loader loader;
private ConditionVariable loadCondition;
private Callback callback; private Callback callback;
private Allocator allocator; private Allocator allocator;
...@@ -166,16 +172,25 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu ...@@ -166,16 +172,25 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
BandwidthMeter bandwidthMeter, ExtractorsFactory extractorsFactory, int minLoadableRetryCount, BandwidthMeter bandwidthMeter, ExtractorsFactory extractorsFactory, int minLoadableRetryCount,
Handler eventHandler, EventListener eventListener) { Handler eventHandler, EventListener eventListener) {
this.uri = uri; this.uri = uri;
this.dataSourceFactory = dataSourceFactory;
this.bandwidthMeter = bandwidthMeter;
this.extractorsFactory = extractorsFactory;
this.minLoadableRetryCount = minLoadableRetryCount; this.minLoadableRetryCount = minLoadableRetryCount;
this.eventListener = eventListener;
this.eventHandler = eventHandler; this.eventHandler = eventHandler;
dataSource = dataSourceFactory.createDataSource(bandwidthMeter); this.eventListener = eventListener;
loadCondition = new ConditionVariable(); }
extractorHolder = new ExtractorHolder(extractorsFactory.createExtractors(), this);
loader = new Loader("Loader:ExtractorSampleSource", extractorHolder); // SampleSourceProvider implementation.
pendingResetPositionUs = C.UNSET_TIME_US;
sampleQueues = new DefaultTrackOutput[0]; @Override
length = C.LENGTH_UNBOUNDED; public int getSourceCount() {
return 1;
}
@Override
public SampleSource createSource(int index) {
Assertions.checkArgument(index == 0);
return this;
} }
// SampleSource implementation. // SampleSource implementation.
...@@ -184,6 +199,15 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu ...@@ -184,6 +199,15 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
public void prepare(Callback callback, Allocator allocator, long positionUs) { public void prepare(Callback callback, Allocator allocator, long positionUs) {
this.callback = callback; this.callback = callback;
this.allocator = allocator; this.allocator = allocator;
dataSource = dataSourceFactory.createDataSource(bandwidthMeter);
extractorHolder = new ExtractorHolder(extractorsFactory.createExtractors(), this);
loader = new Loader("Loader:ExtractorSampleSource", extractorHolder);
loadCondition = new ConditionVariable();
pendingResetPositionUs = C.UNSET_TIME_US;
sampleQueues = new DefaultTrackOutput[0];
length = C.LENGTH_UNBOUNDED;
loadCondition.open(); loadCondition.open();
startLoading(); startLoading();
} }
...@@ -318,10 +342,35 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu ...@@ -318,10 +342,35 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
@Override @Override
public void release() { public void release() {
for (DefaultTrackOutput sampleQueue : sampleQueues) { dataSource = null;
sampleQueue.disable(); extractorHolder = null;
} if (loader != null) {
loader.release(); loader.release(); // Releases extractorHolder via its own reference on the loader's thread.
loader = null;
}
loadCondition = null;
callback = null;
allocator = null;
seekMap = null;
tracksBuilt = false;
prepared = false;
seenFirstTrackSelection = false;
notifyReset = false;
enabledTrackCount = 0;
if (sampleQueues != null) {
for (DefaultTrackOutput sampleQueue : sampleQueues) {
sampleQueue.disable();
}
sampleQueues = null;
}
tracks = null;
durationUs = 0;
trackEnabledStates = null;
length = 0;
lastSeekPositionUs = 0;
pendingResetPositionUs = 0;
extractedSamplesCountAtStartOfLoad = 0;
loadingFinished = false;
} }
// TrackStream methods. // TrackStream methods.
......
...@@ -22,6 +22,7 @@ import com.google.android.exoplayer.CompositeSequenceableLoader; ...@@ -22,6 +22,7 @@ import com.google.android.exoplayer.CompositeSequenceableLoader;
import com.google.android.exoplayer.Format; import com.google.android.exoplayer.Format;
import com.google.android.exoplayer.ParserException; import com.google.android.exoplayer.ParserException;
import com.google.android.exoplayer.SampleSource; import com.google.android.exoplayer.SampleSource;
import com.google.android.exoplayer.SampleSourceProvider;
import com.google.android.exoplayer.TrackGroup; import com.google.android.exoplayer.TrackGroup;
import com.google.android.exoplayer.TrackGroupArray; import com.google.android.exoplayer.TrackGroupArray;
import com.google.android.exoplayer.TrackSelection; import com.google.android.exoplayer.TrackSelection;
...@@ -38,6 +39,7 @@ import com.google.android.exoplayer.upstream.DataSource; ...@@ -38,6 +39,7 @@ import com.google.android.exoplayer.upstream.DataSource;
import com.google.android.exoplayer.upstream.DataSourceFactory; import com.google.android.exoplayer.upstream.DataSourceFactory;
import com.google.android.exoplayer.upstream.Loader; import com.google.android.exoplayer.upstream.Loader;
import com.google.android.exoplayer.upstream.ParsingLoadable; import com.google.android.exoplayer.upstream.ParsingLoadable;
import com.google.android.exoplayer.util.Assertions;
import com.google.android.exoplayer.util.MimeTypes; import com.google.android.exoplayer.util.MimeTypes;
import android.net.Uri; import android.net.Uri;
...@@ -51,9 +53,10 @@ import java.util.IdentityHashMap; ...@@ -51,9 +53,10 @@ import java.util.IdentityHashMap;
import java.util.List; import java.util.List;
/** /**
* A {@link SampleSource} for HLS streams. * A {@link SampleSource} for HLS streams. Also acts as a {@link SampleSourceProvider} providing
* {@link HlsSampleSource} instances.
*/ */
public final class HlsSampleSource implements SampleSource, public final class HlsSampleSource implements SampleSource, SampleSourceProvider,
Loader.Callback<ParsingLoadable<HlsPlaylist>>, HlsTrackStreamWrapper.Callback { Loader.Callback<ParsingLoadable<HlsPlaylist>>, HlsTrackStreamWrapper.Callback {
/** /**
...@@ -68,10 +71,11 @@ public final class HlsSampleSource implements SampleSource, ...@@ -68,10 +71,11 @@ public final class HlsSampleSource implements SampleSource,
private final EventDispatcher eventDispatcher; private final EventDispatcher eventDispatcher;
private final IdentityHashMap<TrackStream, HlsTrackStreamWrapper> trackStreamSources; private final IdentityHashMap<TrackStream, HlsTrackStreamWrapper> trackStreamSources;
private final PtsTimestampAdjusterProvider timestampAdjusterProvider; private final PtsTimestampAdjusterProvider timestampAdjusterProvider;
private final Loader manifestFetcher;
private final DataSource manifestDataSource;
private final HlsPlaylistParser manifestParser; private final HlsPlaylistParser manifestParser;
private DataSource manifestDataSource;
private Loader manifestFetcher;
private Callback callback; private Callback callback;
private Allocator allocator; private Allocator allocator;
private long preparePositionUs; private long preparePositionUs;
...@@ -100,25 +104,38 @@ public final class HlsSampleSource implements SampleSource, ...@@ -100,25 +104,38 @@ public final class HlsSampleSource implements SampleSource,
this.dataSourceFactory = dataSourceFactory; this.dataSourceFactory = dataSourceFactory;
this.bandwidthMeter = bandwidthMeter; this.bandwidthMeter = bandwidthMeter;
this.minLoadableRetryCount = minLoadableRetryCount; this.minLoadableRetryCount = minLoadableRetryCount;
eventDispatcher = new EventDispatcher(eventHandler, eventListener); eventDispatcher = new EventDispatcher(eventHandler, eventListener);
timestampAdjusterProvider = new PtsTimestampAdjusterProvider();
trackStreamSources = new IdentityHashMap<>();
manifestDataSource = dataSourceFactory.createDataSource(); trackStreamSources = new IdentityHashMap<>();
timestampAdjusterProvider = new PtsTimestampAdjusterProvider();
manifestParser = new HlsPlaylistParser(); manifestParser = new HlsPlaylistParser();
manifestFetcher = new Loader("Loader:ManifestFetcher");
} }
// SampleSourceProvider implementation.
@Override
public int getSourceCount() {
return 1;
}
@Override
public SampleSource createSource(int index) {
Assertions.checkArgument(index == 0);
return this;
}
// SampleSource implementation.
@Override @Override
public void prepare(Callback callback, Allocator allocator, long positionUs) { public void prepare(Callback callback, Allocator allocator, long positionUs) {
this.callback = callback; this.callback = callback;
this.allocator = allocator; this.allocator = allocator;
this.preparePositionUs = positionUs; preparePositionUs = positionUs;
ParsingLoadable<HlsPlaylist> loadable = new ParsingLoadable<>(manifestDataSource, manifestDataSource = dataSourceFactory.createDataSource();
manifestUri, C.DATA_TYPE_MANIFEST, manifestParser); manifestFetcher = new Loader("Loader:ManifestFetcher");
long elapsedRealtimeMs = manifestFetcher.startLoading(loadable, this, ParsingLoadable<HlsPlaylist> loadable = new ParsingLoadable<>(manifestDataSource, manifestUri,
minLoadableRetryCount); C.DATA_TYPE_MANIFEST, manifestParser);
long elapsedRealtimeMs = manifestFetcher.startLoading(loadable, this, minLoadableRetryCount);
eventDispatcher.loadStarted(loadable.dataSpec, loadable.type, elapsedRealtimeMs); eventDispatcher.loadStarted(loadable.dataSpec, loadable.type, elapsedRealtimeMs);
} }
...@@ -212,12 +229,30 @@ public final class HlsSampleSource implements SampleSource, ...@@ -212,12 +229,30 @@ public final class HlsSampleSource implements SampleSource,
@Override @Override
public void release() { public void release() {
manifestFetcher.release(); trackStreamSources.clear();
timestampAdjusterProvider.reset();
manifestDataSource = null;
if (manifestFetcher != null) {
manifestFetcher.release();
manifestFetcher = null;
}
callback = null;
allocator = null;
preparePositionUs = 0;
pendingPrepareCount = 0;
seenFirstTrackSelection = false;
durationUs = 0;
isLive = false;
trackGroups = null;
selectedTrackCounts = null;
if (trackStreamWrappers != null) { if (trackStreamWrappers != null) {
for (HlsTrackStreamWrapper trackStreamWrapper : trackStreamWrappers) { for (HlsTrackStreamWrapper trackStreamWrapper : trackStreamWrappers) {
trackStreamWrapper.release(); trackStreamWrapper.release();
} }
trackStreamWrappers = null;
} }
enabledTrackStreamWrappers = null;
sequenceableLoader = null;
} }
// Loader.Callback implementation. // Loader.Callback implementation.
......
...@@ -22,6 +22,7 @@ import com.google.android.exoplayer.CompositeSequenceableLoader; ...@@ -22,6 +22,7 @@ import com.google.android.exoplayer.CompositeSequenceableLoader;
import com.google.android.exoplayer.Format; import com.google.android.exoplayer.Format;
import com.google.android.exoplayer.ParserException; import com.google.android.exoplayer.ParserException;
import com.google.android.exoplayer.SampleSource; import com.google.android.exoplayer.SampleSource;
import com.google.android.exoplayer.SampleSourceProvider;
import com.google.android.exoplayer.SequenceableLoader; import com.google.android.exoplayer.SequenceableLoader;
import com.google.android.exoplayer.TrackGroup; import com.google.android.exoplayer.TrackGroup;
import com.google.android.exoplayer.TrackGroupArray; import com.google.android.exoplayer.TrackGroupArray;
...@@ -39,6 +40,7 @@ import com.google.android.exoplayer.upstream.DataSource; ...@@ -39,6 +40,7 @@ import com.google.android.exoplayer.upstream.DataSource;
import com.google.android.exoplayer.upstream.DataSourceFactory; import com.google.android.exoplayer.upstream.DataSourceFactory;
import com.google.android.exoplayer.upstream.Loader; import com.google.android.exoplayer.upstream.Loader;
import com.google.android.exoplayer.upstream.ParsingLoadable; import com.google.android.exoplayer.upstream.ParsingLoadable;
import com.google.android.exoplayer.util.Assertions;
import com.google.android.exoplayer.util.Util; import com.google.android.exoplayer.util.Util;
import android.net.Uri; import android.net.Uri;
...@@ -51,9 +53,10 @@ import java.util.Arrays; ...@@ -51,9 +53,10 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
/** /**
* A {@link SampleSource} for SmoothStreaming media. * A {@link SampleSource} for SmoothStreaming media. Also acts as a {@link SampleSourceProvider}
* providing {@link SmoothStreamingSampleSource} instances.
*/ */
public final class SmoothStreamingSampleSource implements SampleSource, public final class SmoothStreamingSampleSource implements SampleSource, SampleSourceProvider,
SequenceableLoader.Callback<ChunkTrackStream<SmoothStreamingChunkSource>>, SequenceableLoader.Callback<ChunkTrackStream<SmoothStreamingChunkSource>>,
Loader.Callback<ParsingLoadable<SmoothStreamingManifest>> { Loader.Callback<ParsingLoadable<SmoothStreamingManifest>> {
...@@ -70,10 +73,13 @@ public final class SmoothStreamingSampleSource implements SampleSource, ...@@ -70,10 +73,13 @@ public final class SmoothStreamingSampleSource implements SampleSource,
private final BandwidthMeter bandwidthMeter; private final BandwidthMeter bandwidthMeter;
private final int minLoadableRetryCount; private final int minLoadableRetryCount;
private final EventDispatcher eventDispatcher; private final EventDispatcher eventDispatcher;
private final Loader manifestLoader;
private final DataSource manifestDataSource;
private final SmoothStreamingManifestParser manifestParser; private final SmoothStreamingManifestParser manifestParser;
private DataSource manifestDataSource;
private Loader manifestLoader;
private ChunkTrackStream<SmoothStreamingChunkSource>[] trackStreams;
private CompositeSequenceableLoader sequenceableLoader;
private long manifestLoadStartTimestamp; private long manifestLoadStartTimestamp;
private SmoothStreamingManifest manifest; private SmoothStreamingManifest manifest;
...@@ -86,9 +92,6 @@ public final class SmoothStreamingSampleSource implements SampleSource, ...@@ -86,9 +92,6 @@ public final class SmoothStreamingSampleSource implements SampleSource,
private TrackGroupArray trackGroups; private TrackGroupArray trackGroups;
private int[] trackGroupElementIndices; private int[] trackGroupElementIndices;
private ChunkTrackStream<SmoothStreamingChunkSource>[] trackStreams;
private CompositeSequenceableLoader sequenceableLoader;
public SmoothStreamingSampleSource(Uri manifestUri, DataSourceFactory dataSourceFactory, public SmoothStreamingSampleSource(Uri manifestUri, DataSourceFactory dataSourceFactory,
BandwidthMeter bandwidthMeter, Handler eventHandler, BandwidthMeter bandwidthMeter, Handler eventHandler,
AdaptiveSourceEventListener eventListener) { AdaptiveSourceEventListener eventListener) {
...@@ -105,17 +108,32 @@ public final class SmoothStreamingSampleSource implements SampleSource, ...@@ -105,17 +108,32 @@ public final class SmoothStreamingSampleSource implements SampleSource,
this.bandwidthMeter = bandwidthMeter; this.bandwidthMeter = bandwidthMeter;
this.minLoadableRetryCount = minLoadableRetryCount; this.minLoadableRetryCount = minLoadableRetryCount;
this.eventDispatcher = new EventDispatcher(eventHandler, eventListener); this.eventDispatcher = new EventDispatcher(eventHandler, eventListener);
trackStreams = newTrackStreamArray(0);
sequenceableLoader = new CompositeSequenceableLoader(trackStreams);
manifestDataSource = dataSourceFactory.createDataSource();
manifestParser = new SmoothStreamingManifestParser(); manifestParser = new SmoothStreamingManifestParser();
manifestLoader = new Loader("Loader:Manifest");
} }
// SampleSourceProvider implementation.
@Override
public int getSourceCount() {
return 1;
}
@Override
public SampleSource createSource(int index) {
Assertions.checkArgument(index == 0);
return this;
}
// SampleSource implementation.
@Override @Override
public void prepare(Callback callback, Allocator allocator, long positionUs) { public void prepare(Callback callback, Allocator allocator, long positionUs) {
this.callback = callback; this.callback = callback;
this.allocator = allocator; this.allocator = allocator;
trackStreams = newTrackStreamArray(0);
sequenceableLoader = new CompositeSequenceableLoader(trackStreams);
manifestDataSource = dataSourceFactory.createDataSource();
manifestLoader = new Loader("Loader:Manifest");
manifestRefreshHandler = new Handler(); manifestRefreshHandler = new Handler();
startLoadingManifest(); startLoadingManifest();
} }
...@@ -202,14 +220,31 @@ public final class SmoothStreamingSampleSource implements SampleSource, ...@@ -202,14 +220,31 @@ public final class SmoothStreamingSampleSource implements SampleSource,
@Override @Override
public void release() { public void release() {
manifestDataSource = null;
if (manifestLoader != null) {
manifestLoader.release();
manifestLoader = null;
}
if (trackStreams != null) {
for (ChunkTrackStream<SmoothStreamingChunkSource> trackStream : trackStreams) {
trackStream.release();
}
trackStreams = null;
}
sequenceableLoader = null;
manifestLoadStartTimestamp = 0;
manifest = null;
callback = null;
allocator = null;
if (manifestRefreshHandler != null) { if (manifestRefreshHandler != null) {
manifestRefreshHandler.removeCallbacksAndMessages(null); manifestRefreshHandler.removeCallbacksAndMessages(null);
manifestRefreshHandler = null; manifestRefreshHandler = null;
} }
manifestLoader.release(); prepared = false;
for (ChunkTrackStream<SmoothStreamingChunkSource> trackStream : trackStreams) { durationUs = 0;
trackStream.release(); trackEncryptionBoxes = null;
} trackGroups = null;
trackGroupElementIndices = null;
} }
// SequenceableLoader.Callback implementation // SequenceableLoader.Callback implementation
......
...@@ -22,7 +22,7 @@ import com.google.android.exoplayer.ExoPlaybackException; ...@@ -22,7 +22,7 @@ import com.google.android.exoplayer.ExoPlaybackException;
import com.google.android.exoplayer.ExoPlayer; import com.google.android.exoplayer.ExoPlayer;
import com.google.android.exoplayer.MediaCodecUtil; import com.google.android.exoplayer.MediaCodecUtil;
import com.google.android.exoplayer.MediaCodecUtil.DecoderQueryException; import com.google.android.exoplayer.MediaCodecUtil.DecoderQueryException;
import com.google.android.exoplayer.SampleSource; import com.google.android.exoplayer.SampleSourceProvider;
import com.google.android.exoplayer.TrackGroup; import com.google.android.exoplayer.TrackGroup;
import com.google.android.exoplayer.TrackGroupArray; import com.google.android.exoplayer.TrackGroupArray;
import com.google.android.exoplayer.TrackRenderer; import com.google.android.exoplayer.TrackRenderer;
...@@ -44,6 +44,7 @@ import android.annotation.TargetApi; ...@@ -44,6 +44,7 @@ import android.annotation.TargetApi;
import android.net.Uri; import android.net.Uri;
import android.test.ActivityInstrumentationTestCase2; import android.test.ActivityInstrumentationTestCase2;
import android.util.Log; import android.util.Log;
import junit.framework.AssertionFailedError; import junit.framework.AssertionFailedError;
import java.util.ArrayList; import java.util.ArrayList;
...@@ -418,7 +419,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit ...@@ -418,7 +419,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
} }
@Override @Override
public SampleSource buildSource(HostActivity host, DataSourceFactory dataSourceFactory, public SampleSourceProvider buildSource(HostActivity host, DataSourceFactory dataSourceFactory,
BandwidthMeter bandwidthMeter) { BandwidthMeter bandwidthMeter) {
return new DashSampleSource(manifestUri, dataSourceFactory, bandwidthMeter, return new DashSampleSource(manifestUri, dataSourceFactory, bandwidthMeter,
MIN_LOADABLE_RETRY_COUNT, null, null); MIN_LOADABLE_RETRY_COUNT, null, null);
......
...@@ -22,7 +22,7 @@ import com.google.android.exoplayer.ExoPlaybackException; ...@@ -22,7 +22,7 @@ import com.google.android.exoplayer.ExoPlaybackException;
import com.google.android.exoplayer.ExoPlayer; import com.google.android.exoplayer.ExoPlayer;
import com.google.android.exoplayer.ExoPlayerFactory; import com.google.android.exoplayer.ExoPlayerFactory;
import com.google.android.exoplayer.Format; import com.google.android.exoplayer.Format;
import com.google.android.exoplayer.SampleSource; import com.google.android.exoplayer.SampleSourceProvider;
import com.google.android.exoplayer.SimpleExoPlayer; import com.google.android.exoplayer.SimpleExoPlayer;
import com.google.android.exoplayer.TrackSelectionPolicy; import com.google.android.exoplayer.TrackSelectionPolicy;
import com.google.android.exoplayer.audio.AudioTrack; import com.google.android.exoplayer.audio.AudioTrack;
...@@ -129,7 +129,7 @@ public abstract class ExoHostedTest implements HostedTest, ExoPlayer.EventListen ...@@ -129,7 +129,7 @@ public abstract class ExoHostedTest implements HostedTest, ExoPlayer.EventListen
player = buildExoPlayer(host, surface, trackSelector); player = buildExoPlayer(host, surface, trackSelector);
DataSourceFactory dataSourceFactory = new DefaultDataSourceFactory(host, Util DataSourceFactory dataSourceFactory = new DefaultDataSourceFactory(host, Util
.getUserAgent(host, "ExoPlayerPlaybackTests")); .getUserAgent(host, "ExoPlayerPlaybackTests"));
player.setSource(buildSource(host, dataSourceFactory, player.getBandwidthMeter())); player.setSourceProvider(buildSource(host, dataSourceFactory, player.getBandwidthMeter()));
player.addListener(this); player.addListener(this);
player.setDebugListener(this); player.setDebugListener(this);
player.setPlayWhenReady(true); player.setPlayWhenReady(true);
...@@ -288,7 +288,7 @@ public abstract class ExoHostedTest implements HostedTest, ExoPlayer.EventListen ...@@ -288,7 +288,7 @@ public abstract class ExoHostedTest implements HostedTest, ExoPlayer.EventListen
} }
@SuppressWarnings("unused") @SuppressWarnings("unused")
protected abstract SampleSource buildSource(HostActivity host, protected abstract SampleSourceProvider buildSource(HostActivity host,
DataSourceFactory dataSourceFactory, BandwidthMeter bandwidthMeter); DataSourceFactory dataSourceFactory, BandwidthMeter bandwidthMeter);
@SuppressWarnings("unused") @SuppressWarnings("unused")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment