diff --git a/demo/src/main/java/com/google/android/exoplayer/demo/player/SmoothStreamingRendererBuilder.java b/demo/src/main/java/com/google/android/exoplayer/demo/player/SmoothStreamingRendererBuilder.java index 87d10e6d1b..ec4f35b019 100644 --- a/demo/src/main/java/com/google/android/exoplayer/demo/player/SmoothStreamingRendererBuilder.java +++ b/demo/src/main/java/com/google/android/exoplayer/demo/player/SmoothStreamingRendererBuilder.java @@ -92,8 +92,12 @@ public class SmoothStreamingRendererBuilder implements RendererBuilder, public void buildRenderers(DemoPlayer player, RendererBuilderCallback callback) { this.player = player; this.callback = callback; + String manifestUrl = url; + if (!manifestUrl.endsWith("/Manifest")) { + manifestUrl += "/Manifest"; + } SmoothStreamingManifestParser parser = new SmoothStreamingManifestParser(); - manifestFetcher = new ManifestFetcher(url + "/Manifest", + manifestFetcher = new ManifestFetcher(manifestUrl, new DefaultHttpDataSource(userAgent, null), parser); manifestFetcher.singleLoad(player.getMainHandler().getLooper(), this); } diff --git a/library/src/main/java/com/google/android/exoplayer/upstream/AssetDataSource.java b/library/src/main/java/com/google/android/exoplayer/upstream/AssetDataSource.java index 858c674872..84642df5a0 100644 --- a/library/src/main/java/com/google/android/exoplayer/upstream/AssetDataSource.java +++ b/library/src/main/java/com/google/android/exoplayer/upstream/AssetDataSource.java @@ -31,7 +31,7 @@ import java.io.InputStream; public final class AssetDataSource implements UriDataSource { /** - * Thrown when IOException is encountered during local asset read operation. + * Thrown when an {@link IOException} is encountered reading a local asset. */ public static final class AssetDataSourceException extends IOException { @@ -45,7 +45,7 @@ public final class AssetDataSource implements UriDataSource { private final TransferListener listener; private String uriString; - private InputStream assetInputStream; + private InputStream inputStream; private long bytesRemaining; private boolean opened; @@ -76,10 +76,11 @@ public final class AssetDataSource implements UriDataSource { } else if (path.startsWith("/")) { path = path.substring(1); } - assetInputStream = assetManager.open(path, AssetManager.ACCESS_RANDOM); - long skipped = assetInputStream.skip(dataSpec.position); + uriString = dataSpec.uri.toString(); + inputStream = assetManager.open(path, AssetManager.ACCESS_RANDOM); + long skipped = inputStream.skip(dataSpec.position); Assertions.checkState(skipped == dataSpec.position); - bytesRemaining = dataSpec.length == C.LENGTH_UNBOUNDED ? assetInputStream.available() + bytesRemaining = dataSpec.length == C.LENGTH_UNBOUNDED ? inputStream.available() : dataSpec.length; if (bytesRemaining < 0) { throw new EOFException(); @@ -102,8 +103,7 @@ public final class AssetDataSource implements UriDataSource { } else { int bytesRead = 0; try { - bytesRead = assetInputStream.read(buffer, offset, - (int) Math.min(bytesRemaining, readLength)); + bytesRead = inputStream.read(buffer, offset, (int) Math.min(bytesRemaining, readLength)); } catch (IOException e) { throw new AssetDataSourceException(e); } @@ -126,13 +126,14 @@ public final class AssetDataSource implements UriDataSource { @Override public void close() throws AssetDataSourceException { - if (assetInputStream != null) { + uriString = null; + if (inputStream != null) { try { - assetInputStream.close(); + inputStream.close(); } catch (IOException e) { throw new AssetDataSourceException(e); } finally { - assetInputStream = null; + inputStream = null; if (opened) { opened = false; if (listener != null) { diff --git a/library/src/main/java/com/google/android/exoplayer/upstream/ContentDataSource.java b/library/src/main/java/com/google/android/exoplayer/upstream/ContentDataSource.java index dd7b68d41d..6102bc2b2c 100644 --- a/library/src/main/java/com/google/android/exoplayer/upstream/ContentDataSource.java +++ b/library/src/main/java/com/google/android/exoplayer/upstream/ContentDataSource.java @@ -15,25 +15,25 @@ */ package com.google.android.exoplayer.upstream; +import com.google.android.exoplayer.C; +import com.google.android.exoplayer.util.Assertions; + import android.content.ContentResolver; import android.content.Context; import android.content.res.AssetFileDescriptor; -import com.google.android.exoplayer.C; - -import java.io.FileDescriptor; +import java.io.EOFException; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; /** - * This calll is support content uri and file uri (e.q. content:// , file://). - * {@link DataSource}. + * A content URI {@link UriDataSource}. */ public final class ContentDataSource implements UriDataSource { - static private final String TAG = "ContentDataSource"; + /** - * Thrown when IOException is encountered during local asset read operation. + * Thrown when an {@link IOException} is encountered reading from a content URI. */ public static class ContentDataSourceException extends IOException { @@ -43,11 +43,11 @@ public final class ContentDataSource implements UriDataSource { } + private final ContentResolver resolver; private final TransferListener listener; private InputStream inputStream; - private Context context; - private String uri; + private String uriString; private long bytesRemaining; private boolean opened; @@ -64,23 +64,25 @@ public final class ContentDataSource implements UriDataSource { * @param listener An optional listener. Specify {@code null} for no listener. */ public ContentDataSource(Context context, TransferListener listener) { - this.context = context; + this.resolver = context.getContentResolver(); this.listener = listener; } @Override - public long open(DataSpec dataSpec) throws IOException { + public long open(DataSpec dataSpec) throws ContentDataSourceException { try { - uri = dataSpec.uri.toString(); - inputStream = new FileInputStream(getFileDescriptor(context, dataSpec)); - inputStream.skip(dataSpec.position); + uriString = dataSpec.uri.toString(); + AssetFileDescriptor assetFd = resolver.openAssetFileDescriptor(dataSpec.uri, "r"); + inputStream = new FileInputStream(assetFd.getFileDescriptor()); + long skipped = inputStream.skip(dataSpec.position); + Assertions.checkState(skipped == dataSpec.position); bytesRemaining = dataSpec.length == C.LENGTH_UNBOUNDED ? inputStream.available() : dataSpec.length; if (bytesRemaining < 0) { - throw new IOException(); + throw new EOFException(); } } catch (IOException e) { - throw new IOException(e); + throw new ContentDataSourceException(e); } opened = true; @@ -92,7 +94,7 @@ public final class ContentDataSource implements UriDataSource { } @Override - public int read(byte[] buffer, int offset, int readLength) throws IOException { + public int read(byte[] buffer, int offset, int readLength) throws ContentDataSourceException { if (bytesRemaining == 0) { return -1; } else { @@ -100,7 +102,7 @@ public final class ContentDataSource implements UriDataSource { try { bytesRead = inputStream.read(buffer, offset, (int) Math.min(bytesRemaining, readLength)); } catch (IOException e) { - throw new IOException(e); + throw new ContentDataSourceException(e); } if (bytesRead > 0) { @@ -116,11 +118,12 @@ public final class ContentDataSource implements UriDataSource { @Override public String getUri() { - return uri; + return uriString; } @Override public void close() throws ContentDataSourceException { + uriString = null; if (inputStream != null) { try { inputStream.close(); @@ -128,8 +131,6 @@ public final class ContentDataSource implements UriDataSource { throw new ContentDataSourceException(e); } finally { inputStream = null; - uri = null; - if (opened) { opened = false; if (listener != null) { @@ -140,17 +141,4 @@ public final class ContentDataSource implements UriDataSource { } } - /** - * query the fileDescriptor from conten resolver. - * - */ - private static FileDescriptor getFileDescriptor(Context context, DataSpec dataSpec) throws IOException { - try { - ContentResolver resolver = context.getContentResolver(); - AssetFileDescriptor fd = resolver.openAssetFileDescriptor(dataSpec.uri, "r"); - return fd.getFileDescriptor(); - } catch (IOException e) { - throw new IOException(e); - } - } } diff --git a/library/src/main/java/com/google/android/exoplayer/upstream/DefaultUriDataSource.java b/library/src/main/java/com/google/android/exoplayer/upstream/DefaultUriDataSource.java index a2a683343f..e3cbb7b84d 100644 --- a/library/src/main/java/com/google/android/exoplayer/upstream/DefaultUriDataSource.java +++ b/library/src/main/java/com/google/android/exoplayer/upstream/DefaultUriDataSource.java @@ -18,6 +18,7 @@ package com.google.android.exoplayer.upstream; import com.google.android.exoplayer.util.Assertions; import android.content.Context; +import android.text.TextUtils; import java.io.IOException; @@ -26,8 +27,11 @@ import java.io.IOException; * * */ public final class DefaultUriDataSource implements UriDataSource { @@ -56,10 +60,12 @@ public final class DefaultUriDataSource implements UriDataSource { private static final String SCHEME_HTTPS = "https"; private static final String SCHEME_FILE = "file"; private static final String SCHEME_ASSET = "asset"; + private static final String SCHEME_CONTENT = "content"; private final UriDataSource httpDataSource; private final UriDataSource fileDataSource; private final UriDataSource assetDataSource; + private final UriDataSource contentDataSource; /** * {@code null} if no data source is open. Otherwise, equal to {@link #fileDataSource} if the open @@ -127,6 +133,7 @@ public final class DefaultUriDataSource implements UriDataSource { this.httpDataSource = Assertions.checkNotNull(httpDataSource); this.fileDataSource = new FileDataSource(listener); this.assetDataSource = new AssetDataSource(context, listener); + this.contentDataSource = new ContentDataSource(context, listener); } @Override @@ -136,7 +143,7 @@ public final class DefaultUriDataSource implements UriDataSource { String scheme = dataSpec.uri.getScheme(); if (SCHEME_HTTP.equals(scheme) || SCHEME_HTTPS.equals(scheme)) { dataSource = httpDataSource; - } else if (SCHEME_FILE.equals(scheme)) { + } else if (SCHEME_FILE.equals(scheme) || TextUtils.isEmpty(scheme)) { if (dataSpec.uri.getPath().startsWith("/android_asset/")) { dataSource = assetDataSource; } else { @@ -144,6 +151,8 @@ public final class DefaultUriDataSource implements UriDataSource { } } else if (SCHEME_ASSET.equals(scheme)) { dataSource = assetDataSource; + } else if (SCHEME_CONTENT.equals(scheme)) { + dataSource = contentDataSource; } else { throw new UnsupportedSchemeException(scheme); } diff --git a/library/src/main/java/com/google/android/exoplayer/upstream/FileDataSource.java b/library/src/main/java/com/google/android/exoplayer/upstream/FileDataSource.java index 68dd7e2a0c..784914a7ef 100644 --- a/library/src/main/java/com/google/android/exoplayer/upstream/FileDataSource.java +++ b/library/src/main/java/com/google/android/exoplayer/upstream/FileDataSource.java @@ -40,7 +40,7 @@ public final class FileDataSource implements UriDataSource { private final TransferListener listener; private RandomAccessFile file; - private String uri; + private String uriString; private long bytesRemaining; private boolean opened; @@ -63,7 +63,7 @@ public final class FileDataSource implements UriDataSource { @Override public long open(DataSpec dataSpec) throws FileDataSourceException { try { - uri = dataSpec.uri.toString(); + uriString = dataSpec.uri.toString(); file = new RandomAccessFile(dataSpec.uri.getPath(), "r"); file.seek(dataSpec.position); bytesRemaining = dataSpec.length == C.LENGTH_UNBOUNDED ? file.length() - dataSpec.position @@ -108,11 +108,12 @@ public final class FileDataSource implements UriDataSource { @Override public String getUri() { - return uri; + return uriString; } @Override public void close() throws FileDataSourceException { + uriString = null; if (file != null) { try { file.close(); @@ -120,8 +121,6 @@ public final class FileDataSource implements UriDataSource { throw new FileDataSourceException(e); } finally { file = null; - uri = null; - if (opened) { opened = false; if (listener != null) {