Commit 675c7738 by Oliver Woodman

Let DefaultUriDataSource load assets.

parent f474afbf
......@@ -233,19 +233,19 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
audioCapabilities);
case DemoUtil.TYPE_M4A: // There are no file format differences between M4A and MP4.
case DemoUtil.TYPE_MP4:
return new ExtractorRendererBuilder(userAgent, contentUri, debugTextView,
return new ExtractorRendererBuilder(this, userAgent, contentUri, debugTextView,
new Mp4Extractor());
case DemoUtil.TYPE_MP3:
return new ExtractorRendererBuilder(userAgent, contentUri, debugTextView,
return new ExtractorRendererBuilder(this, userAgent, contentUri, debugTextView,
new Mp3Extractor());
case DemoUtil.TYPE_TS:
return new ExtractorRendererBuilder(userAgent, contentUri, debugTextView,
return new ExtractorRendererBuilder(this, userAgent, contentUri, debugTextView,
new TsExtractor(0, audioCapabilities));
case DemoUtil.TYPE_AAC:
return new ExtractorRendererBuilder(userAgent, contentUri, debugTextView,
return new ExtractorRendererBuilder(this, userAgent, contentUri, debugTextView,
new AdtsExtractor());
case DemoUtil.TYPE_WEBM:
return new ExtractorRendererBuilder(userAgent, contentUri, debugTextView,
return new ExtractorRendererBuilder(this, userAgent, contentUri, debugTextView,
new WebmExtractor());
default:
throw new IllegalStateException("Unsupported type: " + contentType);
......
......@@ -130,7 +130,7 @@ public class DashRendererBuilder implements RendererBuilder,
this.player = player;
this.callback = callback;
MediaPresentationDescriptionParser parser = new MediaPresentationDescriptionParser();
manifestDataSource = new DefaultUriDataSource(userAgent, null);
manifestDataSource = new DefaultUriDataSource(context, userAgent);
manifestFetcher = new ManifestFetcher<MediaPresentationDescription>(url, manifestDataSource,
parser);
manifestFetcher.singleLoad(player.getMainHandler().getLooper(), this);
......@@ -232,10 +232,10 @@ public class DashRendererBuilder implements RendererBuilder,
videoRenderer = null;
debugRenderer = null;
} else {
DataSource videoDataSource = new DefaultUriDataSource(userAgent, bandwidthMeter);
ChunkSource videoChunkSource = new DashChunkSource(manifestFetcher, videoAdaptationSetIndex,
videoRepresentationIndices, videoDataSource, new AdaptiveEvaluator(bandwidthMeter),
LIVE_EDGE_LATENCY_MS, elapsedRealtimeOffset);
DataSource videoDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);
ChunkSource videoChunkSource = new DashChunkSource(manifestFetcher,
videoAdaptationSetIndex, videoRepresentationIndices, videoDataSource,
new AdaptiveEvaluator(bandwidthMeter), LIVE_EDGE_LATENCY_MS, elapsedRealtimeOffset);
ChunkSampleSource videoSampleSource = new ChunkSampleSource(videoChunkSource, loadControl,
VIDEO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, true, mainHandler, player,
DemoPlayer.TYPE_VIDEO);
......@@ -249,7 +249,7 @@ public class DashRendererBuilder implements RendererBuilder,
List<ChunkSource> audioChunkSourceList = new ArrayList<ChunkSource>();
List<String> audioTrackNameList = new ArrayList<String>();
if (audioAdaptationSet != null) {
DataSource audioDataSource = new DefaultUriDataSource(userAgent, bandwidthMeter);
DataSource audioDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);
FormatEvaluator audioEvaluator = new FormatEvaluator.FixedEvaluator();
List<Representation> audioRepresentations = audioAdaptationSet.representations;
List<String> codecs = new ArrayList<String>();
......@@ -304,7 +304,7 @@ public class DashRendererBuilder implements RendererBuilder,
}
// Build the text chunk sources.
DataSource textDataSource = new DefaultUriDataSource(userAgent, bandwidthMeter);
DataSource textDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);
FormatEvaluator textEvaluator = new FormatEvaluator.FixedEvaluator();
List<ChunkSource> textChunkSourceList = new ArrayList<ChunkSource>();
List<String> textTrackNameList = new ArrayList<String>();
......
......@@ -25,6 +25,7 @@ import com.google.android.exoplayer.extractor.ExtractorSampleSource;
import com.google.android.exoplayer.upstream.DataSource;
import com.google.android.exoplayer.upstream.DefaultUriDataSource;
import android.content.Context;
import android.media.MediaCodec;
import android.net.Uri;
import android.widget.TextView;
......@@ -36,13 +37,15 @@ public class ExtractorRendererBuilder implements RendererBuilder {
private static final int BUFFER_SIZE = 10 * 1024 * 1024;
private final Context context;
private final String userAgent;
private final Uri uri;
private final TextView debugTextView;
private final Extractor extractor;
public ExtractorRendererBuilder(String userAgent, Uri uri, TextView debugTextView,
Extractor extractor) {
public ExtractorRendererBuilder(Context context, String userAgent, Uri uri,
TextView debugTextView, Extractor extractor) {
this.context = context;
this.userAgent = userAgent;
this.uri = uri;
this.debugTextView = debugTextView;
......@@ -52,7 +55,7 @@ public class ExtractorRendererBuilder implements RendererBuilder {
@Override
public void buildRenderers(DemoPlayer player, RendererBuilderCallback callback) {
// Build the video and audio renderers.
DataSource dataSource = new DefaultUriDataSource(userAgent, null);
DataSource dataSource = new DefaultUriDataSource(context, userAgent);
ExtractorSampleSource sampleSource = new ExtractorSampleSource(uri, dataSource, extractor, 2,
BUFFER_SIZE);
MediaCodecVideoTrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(sampleSource,
......
......@@ -76,8 +76,8 @@ public class HlsRendererBuilder implements RendererBuilder, ManifestCallback<Hls
this.player = player;
this.callback = callback;
HlsPlaylistParser parser = new HlsPlaylistParser();
ManifestFetcher<HlsPlaylist> playlistFetcher =
new ManifestFetcher<HlsPlaylist>(url, new DefaultUriDataSource(userAgent, null), parser);
ManifestFetcher<HlsPlaylist> playlistFetcher = new ManifestFetcher<HlsPlaylist>(url,
new DefaultUriDataSource(context, userAgent), parser);
playlistFetcher.singleLoad(player.getMainHandler().getLooper(), this);
}
......@@ -103,7 +103,7 @@ public class HlsRendererBuilder implements RendererBuilder, ManifestCallback<Hls
}
}
DataSource dataSource = new DefaultUriDataSource(userAgent, bandwidthMeter);
DataSource dataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);
HlsChunkSource chunkSource = new HlsChunkSource(dataSource, url, manifest, bandwidthMeter,
variantIndices, HlsChunkSource.ADAPTIVE_MODE_SPLICE, audioCapabilities);
HlsSampleSource sampleSource = new HlsSampleSource(chunkSource, true, 3, REQUESTED_BUFFER_SIZE,
......
......@@ -160,7 +160,7 @@ public class SmoothStreamingRendererBuilder implements RendererBuilder,
videoRenderer = null;
debugRenderer = null;
} else {
DataSource videoDataSource = new DefaultUriDataSource(userAgent, bandwidthMeter);
DataSource videoDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);
ChunkSource videoChunkSource = new SmoothStreamingChunkSource(manifestFetcher,
videoStreamElementIndex, videoTrackIndices, videoDataSource,
new AdaptiveEvaluator(bandwidthMeter), LIVE_EDGE_LATENCY_MS);
......@@ -184,7 +184,7 @@ public class SmoothStreamingRendererBuilder implements RendererBuilder,
} else {
audioTrackNames = new String[audioStreamElementCount];
ChunkSource[] audioChunkSources = new ChunkSource[audioStreamElementCount];
DataSource audioDataSource = new DefaultUriDataSource(userAgent, bandwidthMeter);
DataSource audioDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);
FormatEvaluator audioFormatEvaluator = new FormatEvaluator.FixedEvaluator();
audioStreamElementCount = 0;
for (int i = 0; i < manifest.streamElements.length; i++) {
......@@ -215,7 +215,7 @@ public class SmoothStreamingRendererBuilder implements RendererBuilder,
} else {
textTrackNames = new String[textStreamElementCount];
ChunkSource[] textChunkSources = new ChunkSource[textStreamElementCount];
DataSource ttmlDataSource = new DefaultUriDataSource(userAgent, bandwidthMeter);
DataSource ttmlDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);
FormatEvaluator ttmlFormatEvaluator = new FormatEvaluator.FixedEvaluator();
textStreamElementCount = 0;
for (int i = 0; i < manifest.streamElements.length; i++) {
......
......@@ -18,6 +18,7 @@ package com.google.android.exoplayer.upstream;
import com.google.android.exoplayer.C;
import com.google.android.exoplayer.util.Assertions;
import android.content.Context;
import android.content.res.AssetManager;
import java.io.EOFException;
......@@ -32,7 +33,7 @@ public final class AssetDataSource implements UriDataSource {
/**
* Thrown when IOException is encountered during local asset read operation.
*/
public static class AssetDataSourceException extends IOException {
public static final class AssetDataSourceException extends IOException {
public AssetDataSourceException(IOException cause) {
super(cause);
......@@ -51,8 +52,8 @@ public final class AssetDataSource implements UriDataSource {
/**
* Constructs a new {@link DataSource} that retrieves data from a local asset.
*/
public AssetDataSource(AssetManager assetManager) {
this(assetManager, null);
public AssetDataSource(Context context) {
this(context, null);
}
/**
......@@ -60,8 +61,8 @@ public final class AssetDataSource implements UriDataSource {
*
* @param listener An optional listener. Specify {@code null} for no listener.
*/
public AssetDataSource(AssetManager assetManager, TransferListener listener) {
this.assetManager = assetManager;
public AssetDataSource(Context context, TransferListener listener) {
this.assetManager = context.getAssets();
this.listener = listener;
}
......
......@@ -17,17 +17,49 @@ package com.google.android.exoplayer.upstream;
import com.google.android.exoplayer.util.Assertions;
import android.content.Context;
import java.io.IOException;
/**
* A data source that fetches data from a local or remote {@link DataSpec}.
* A {@link UriDataSource} that supports multiple URI schemes. The supported schemes are:
*
* <ul>
* <li>http(s): For fetching data over HTTP and HTTPS (e.g. https://www.something.com/media.mp4).
* <li>file: For fetching data from a local file (e.g. file:///path/to/media/media.mp4).
* <li>asset: For fetching data from an asset in the application's apk (e.g. asset:///media.mp4).
* </ul>
*/
public final class DefaultUriDataSource implements UriDataSource {
private static final String FILE_URI_SCHEME = "file";
/**
* Thrown when a {@link DefaultUriDataSource} is opened for a URI with an unsupported scheme.
*/
public static final class UnsupportedSchemeException extends IOException {
/**
* The unsupported scheme.
*/
public final String scheme;
/**
* @param scheme The unsupported scheme.
*/
public UnsupportedSchemeException(String scheme) {
super("Unsupported URI scheme: " + scheme);
this.scheme = scheme;
}
}
private static final String SCHEME_HTTP = "http";
private static final String SCHEME_HTTPS = "https";
private static final String SCHEME_FILE = "file";
private static final String SCHEME_ASSET = "asset";
private final UriDataSource fileDataSource;
private final UriDataSource httpDataSource;
private final UriDataSource fileDataSource;
private final UriDataSource assetDataSource;
/**
* {@code null} if no data source is open. Otherwise, equal to {@link #fileDataSource} if the open
......@@ -36,54 +68,86 @@ public final class DefaultUriDataSource implements UriDataSource {
private UriDataSource dataSource;
/**
* Constructs a new data source that delegates to a {@link FileDataSource} for file URIs and a
* {@link DefaultHttpDataSource} for other URIs.
* Constructs a new instance.
* <p>
* The constructed instance will not follow cross-protocol redirects (i.e. redirects from HTTP to
* HTTPS or vice versa) when fetching remote data. Cross-protocol redirects can be enabled by
* using the {@link #DefaultUriDataSource(String, TransferListener, boolean)} constructor and
* passing {@code true} as the final argument.
* using {@link #DefaultUriDataSource(Context, TransferListener, String, boolean)} and passing
* {@code true} as the final argument.
*
* @param context A context.
* @param userAgent The User-Agent string that should be used when requesting remote data.
* @param transferListener An optional listener.
*/
public DefaultUriDataSource(String userAgent, TransferListener transferListener) {
this(userAgent, transferListener, false);
public DefaultUriDataSource(Context context, String userAgent) {
this(context, null, userAgent, false);
}
/**
* Constructs a new data source that delegates to a {@link FileDataSource} for file URIs and a
* {@link DefaultHttpDataSource} for other URIs.
* Constructs a new instance.
* <p>
* The constructed instance will not follow cross-protocol redirects (i.e. redirects from HTTP to
* HTTPS or vice versa) when fetching remote data. Cross-protocol redirects can be enabled by
* using {@link #DefaultUriDataSource(Context, TransferListener, String, boolean)} and passing
* {@code true} as the final argument.
*
* @param context A context.
* @param listener An optional {@link TransferListener}.
* @param userAgent The User-Agent string that should be used when requesting remote data.
*/
public DefaultUriDataSource(Context context, TransferListener listener, String userAgent) {
this(context, listener, userAgent, false);
}
/**
* Constructs a new instance, optionally configured to follow cross-protocol redirects.
*
* @param context A context.
* @param listener An optional {@link TransferListener}.
* @param userAgent The User-Agent string that should be used when requesting remote data.
* @param transferListener An optional listener.
* @param allowCrossProtocolRedirects Whether cross-protocol redirects (i.e. redirects from HTTP
* to HTTPS and vice versa) are enabled when fetching remote data..
*/
public DefaultUriDataSource(String userAgent, TransferListener transferListener,
public DefaultUriDataSource(Context context, TransferListener listener, String userAgent,
boolean allowCrossProtocolRedirects) {
this(new FileDataSource(transferListener),
new DefaultHttpDataSource(userAgent, null, transferListener,
this(context, listener,
new DefaultHttpDataSource(userAgent, null, listener,
DefaultHttpDataSource.DEFAULT_CONNECT_TIMEOUT_MILLIS,
DefaultHttpDataSource.DEFAULT_READ_TIMEOUT_MILLIS, allowCrossProtocolRedirects));
}
/**
* Constructs a new data source using {@code fileDataSource} for file URIs, and
* {@code httpDataSource} for non-file URIs.
* Constructs a new instance, using a provided {@link HttpDataSource} for fetching remote data.
*
* @param fileDataSource {@link UriDataSource} to use for file URIs.
* @param context A context.
* @param listener An optional {@link TransferListener}.
* @param httpDataSource {@link UriDataSource} to use for non-file URIs.
*/
public DefaultUriDataSource(UriDataSource fileDataSource, UriDataSource httpDataSource) {
this.fileDataSource = Assertions.checkNotNull(fileDataSource);
public DefaultUriDataSource(Context context, TransferListener listener,
UriDataSource httpDataSource) {
this.httpDataSource = Assertions.checkNotNull(httpDataSource);
this.fileDataSource = new FileDataSource(listener);
this.assetDataSource = new AssetDataSource(context, listener);
}
@Override
public long open(DataSpec dataSpec) throws IOException {
Assertions.checkState(dataSource == null);
dataSource = FILE_URI_SCHEME.equals(dataSpec.uri.getScheme()) ? fileDataSource : httpDataSource;
// Choose the correct source for the scheme.
String scheme = dataSpec.uri.getScheme();
if (SCHEME_HTTP.equals(scheme) || SCHEME_HTTPS.equals(scheme)) {
dataSource = httpDataSource;
} else if (SCHEME_FILE.equals(scheme)) {
if (dataSpec.uri.getPath().startsWith("/android_asset/")) {
dataSource = assetDataSource;
} else {
dataSource = fileDataSource;
}
} else if (SCHEME_ASSET.equals(scheme)) {
dataSource = assetDataSource;
} else {
throw new UnsupportedSchemeException(scheme);
}
// Open the source and return.
return dataSource.open(dataSpec);
}
......
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