Support content:// URIs, and some cleanup/consistency tweaks.

- There's definitely potential for more code sharing in these
classes, but deferring for now.
- Also made no-scheme default to file://, and allowed smoothstreaming
URLs to be specified with or without the /Manifest suffix.
This commit is contained in:
Oliver Woodman 2015-05-19 14:14:53 +01:00
parent a9c977a79e
commit 6ae97ced3a
5 changed files with 53 additions and 52 deletions

View File

@ -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<SmoothStreamingManifest>(url + "/Manifest",
manifestFetcher = new ManifestFetcher<SmoothStreamingManifest>(manifestUrl,
new DefaultHttpDataSource(userAgent, null), parser);
manifestFetcher.singleLoad(player.getMainHandler().getLooper(), this);
}

View File

@ -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) {

View File

@ -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);
}
}
}

View File

@ -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;
*
* <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>file: For fetching data from a local file (e.g. file:///path/to/media/media.mp4, or just
* /path/to/media/media.mp4 because the implementation assumes that a URI without a scheme is a
* local file URI).
* <li>asset: For fetching data from an asset in the application's apk (e.g. asset:///media.mp4).
* <li>content: For fetching data from a content URI (e.g. content://authority/path/123).
* </ul>
*/
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);
}

View File

@ -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) {