mirror of
https://github.com/samsonjs/media.git
synced 2026-04-01 10:35:48 +00:00
Make all DataSource implementations implement getUri.
In V2 we'll at some point start using DataSource factories for creating DataSource instances. If there are two DataSource interfaces this gets unnecessarily awkward. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=118470751
This commit is contained in:
parent
d869a8d2fa
commit
6cc507aac0
31 changed files with 256 additions and 215 deletions
|
|
@ -31,10 +31,11 @@ import com.google.android.exoplayer.drm.MediaDrmCallback;
|
|||
import com.google.android.exoplayer.upstream.BandwidthMeter;
|
||||
import com.google.android.exoplayer.upstream.DataSource;
|
||||
import com.google.android.exoplayer.upstream.DefaultAllocator;
|
||||
import com.google.android.exoplayer.upstream.DefaultUriDataSource;
|
||||
import com.google.android.exoplayer.upstream.DefaultDataSource;
|
||||
import com.google.android.exoplayer.util.ManifestFetcher;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
|
||||
/**
|
||||
|
|
@ -68,16 +69,16 @@ public class DashSourceBuilder implements SourceBuilder {
|
|||
@Override
|
||||
public SampleSource buildRenderers(DemoPlayer player) {
|
||||
MediaPresentationDescriptionParser parser = new MediaPresentationDescriptionParser();
|
||||
DefaultUriDataSource manifestDataSource = new DefaultUriDataSource(context, userAgent);
|
||||
ManifestFetcher<MediaPresentationDescription> manifestFetcher = new ManifestFetcher<>(url,
|
||||
manifestDataSource, parser);
|
||||
DefaultDataSource manifestDataSource = new DefaultDataSource(context, userAgent);
|
||||
ManifestFetcher<MediaPresentationDescription> manifestFetcher = new ManifestFetcher<>(
|
||||
Uri.parse(url), manifestDataSource, parser);
|
||||
|
||||
Handler mainHandler = player.getMainHandler();
|
||||
BandwidthMeter bandwidthMeter = player.getBandwidthMeter();
|
||||
LoadControl loadControl = new DefaultLoadControl(new DefaultAllocator(BUFFER_SEGMENT_SIZE));
|
||||
|
||||
// Build the video renderer.
|
||||
DataSource videoDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);
|
||||
DataSource videoDataSource = new DefaultDataSource(context, bandwidthMeter, userAgent);
|
||||
ChunkSource videoChunkSource = new DashChunkSource(manifestFetcher, AdaptationSet.TYPE_VIDEO,
|
||||
videoDataSource, new AdaptiveEvaluator(bandwidthMeter), LIVE_EDGE_LATENCY_MS,
|
||||
0, mainHandler, player, DemoPlayer.TYPE_VIDEO);
|
||||
|
|
@ -85,7 +86,7 @@ public class DashSourceBuilder implements SourceBuilder {
|
|||
VIDEO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player, DemoPlayer.TYPE_VIDEO);
|
||||
|
||||
// Build the audio renderer.
|
||||
DataSource audioDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);
|
||||
DataSource audioDataSource = new DefaultDataSource(context, bandwidthMeter, userAgent);
|
||||
ChunkSource audioChunkSource = new DashChunkSource(manifestFetcher, AdaptationSet.TYPE_AUDIO,
|
||||
audioDataSource, null, LIVE_EDGE_LATENCY_MS, 0, mainHandler, player, DemoPlayer.TYPE_AUDIO);
|
||||
ChunkSampleSource audioSampleSource = new ChunkSampleSource(audioChunkSource, loadControl,
|
||||
|
|
@ -93,7 +94,7 @@ public class DashSourceBuilder implements SourceBuilder {
|
|||
DemoPlayer.TYPE_AUDIO);
|
||||
|
||||
// Build the text renderer.
|
||||
DataSource textDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);
|
||||
DataSource textDataSource = new DefaultDataSource(context, bandwidthMeter, userAgent);
|
||||
ChunkSource textChunkSource = new DashChunkSource(manifestFetcher, AdaptationSet.TYPE_TEXT,
|
||||
textDataSource, null, LIVE_EDGE_LATENCY_MS, 0, mainHandler, player, DemoPlayer.TYPE_TEXT);
|
||||
ChunkSampleSource textSampleSource = new ChunkSampleSource(textChunkSource, loadControl,
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ import com.google.android.exoplayer.extractor.ExtractorSampleSource;
|
|||
import com.google.android.exoplayer.upstream.Allocator;
|
||||
import com.google.android.exoplayer.upstream.DataSource;
|
||||
import com.google.android.exoplayer.upstream.DefaultAllocator;
|
||||
import com.google.android.exoplayer.upstream.DefaultUriDataSource;
|
||||
import com.google.android.exoplayer.upstream.DefaultDataSource;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
|
|
@ -48,8 +48,7 @@ public class ExtractorSourceBuilder implements SourceBuilder {
|
|||
@Override
|
||||
public SampleSource buildRenderers(DemoPlayer player) {
|
||||
Allocator allocator = new DefaultAllocator(BUFFER_SEGMENT_SIZE);
|
||||
DataSource dataSource = new DefaultUriDataSource(context, player.getBandwidthMeter(),
|
||||
userAgent);
|
||||
DataSource dataSource = new DefaultDataSource(context, player.getBandwidthMeter(), userAgent);
|
||||
return new ExtractorSampleSource(uri, dataSource, allocator,
|
||||
BUFFER_SEGMENT_COUNT * BUFFER_SEGMENT_SIZE, player.getMainHandler(), player, 0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,10 +29,11 @@ import com.google.android.exoplayer.hls.PtsTimestampAdjusterProvider;
|
|||
import com.google.android.exoplayer.upstream.BandwidthMeter;
|
||||
import com.google.android.exoplayer.upstream.DataSource;
|
||||
import com.google.android.exoplayer.upstream.DefaultAllocator;
|
||||
import com.google.android.exoplayer.upstream.DefaultUriDataSource;
|
||||
import com.google.android.exoplayer.upstream.DefaultDataSource;
|
||||
import com.google.android.exoplayer.util.ManifestFetcher;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
|
||||
/**
|
||||
|
|
@ -59,8 +60,8 @@ public class HlsSourceBuilder implements SourceBuilder {
|
|||
@Override
|
||||
public SampleSource buildRenderers(DemoPlayer player) {
|
||||
HlsPlaylistParser parser = new HlsPlaylistParser();
|
||||
DefaultUriDataSource manifestDataSource = new DefaultUriDataSource(context, userAgent);
|
||||
ManifestFetcher<HlsPlaylist> manifestFetcher = new ManifestFetcher<>(url,
|
||||
DefaultDataSource manifestDataSource = new DefaultDataSource(context, userAgent);
|
||||
ManifestFetcher<HlsPlaylist> manifestFetcher = new ManifestFetcher<>(Uri.parse(url),
|
||||
manifestDataSource, parser);
|
||||
|
||||
Handler mainHandler = player.getMainHandler();
|
||||
|
|
@ -68,20 +69,20 @@ public class HlsSourceBuilder implements SourceBuilder {
|
|||
LoadControl loadControl = new DefaultLoadControl(new DefaultAllocator(BUFFER_SEGMENT_SIZE));
|
||||
PtsTimestampAdjusterProvider timestampAdjusterProvider = new PtsTimestampAdjusterProvider();
|
||||
|
||||
DataSource defaultDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);
|
||||
DataSource defaultDataSource = new DefaultDataSource(context, bandwidthMeter, userAgent);
|
||||
HlsChunkSource defaultChunkSource = new HlsChunkSource(manifestFetcher,
|
||||
HlsChunkSource.TYPE_DEFAULT, defaultDataSource, timestampAdjusterProvider,
|
||||
new FormatEvaluator.AdaptiveEvaluator(bandwidthMeter));
|
||||
HlsSampleSource defaultSampleSource = new HlsSampleSource(defaultChunkSource, loadControl,
|
||||
MAIN_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player, DemoPlayer.TYPE_VIDEO);
|
||||
|
||||
DataSource audioDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);
|
||||
DataSource audioDataSource = new DefaultDataSource(context, bandwidthMeter, userAgent);
|
||||
HlsChunkSource audioChunkSource = new HlsChunkSource(manifestFetcher, HlsChunkSource.TYPE_AUDIO,
|
||||
audioDataSource, timestampAdjusterProvider, null);
|
||||
HlsSampleSource audioSampleSource = new HlsSampleSource(audioChunkSource, loadControl,
|
||||
AUDIO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player, DemoPlayer.TYPE_AUDIO);
|
||||
|
||||
DataSource subtitleDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);
|
||||
DataSource subtitleDataSource = new DefaultDataSource(context, bandwidthMeter, userAgent);
|
||||
HlsChunkSource subtitleChunkSource = new HlsChunkSource(manifestFetcher,
|
||||
HlsChunkSource.TYPE_SUBTITLE, subtitleDataSource, timestampAdjusterProvider, null);
|
||||
HlsSampleSource subtitleSampleSource = new HlsSampleSource(subtitleChunkSource, loadControl,
|
||||
|
|
|
|||
|
|
@ -30,12 +30,13 @@ import com.google.android.exoplayer.smoothstreaming.SmoothStreamingManifestParse
|
|||
import com.google.android.exoplayer.upstream.BandwidthMeter;
|
||||
import com.google.android.exoplayer.upstream.DataSource;
|
||||
import com.google.android.exoplayer.upstream.DefaultAllocator;
|
||||
import com.google.android.exoplayer.upstream.DefaultDataSource;
|
||||
import com.google.android.exoplayer.upstream.DefaultHttpDataSource;
|
||||
import com.google.android.exoplayer.upstream.DefaultUriDataSource;
|
||||
import com.google.android.exoplayer.util.ManifestFetcher;
|
||||
import com.google.android.exoplayer.util.Util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
|
||||
/**
|
||||
|
|
@ -66,14 +67,14 @@ public class SmoothStreamingSourceBuilder implements SourceBuilder {
|
|||
@Override
|
||||
public SampleSource buildRenderers(DemoPlayer player) {
|
||||
SmoothStreamingManifestParser parser = new SmoothStreamingManifestParser();
|
||||
ManifestFetcher<SmoothStreamingManifest> manifestFetcher = new ManifestFetcher<>(url,
|
||||
ManifestFetcher<SmoothStreamingManifest> manifestFetcher = new ManifestFetcher<>(Uri.parse(url),
|
||||
new DefaultHttpDataSource(userAgent, null), parser);
|
||||
Handler mainHandler = player.getMainHandler();
|
||||
BandwidthMeter bandwidthMeter = player.getBandwidthMeter();
|
||||
LoadControl loadControl = new DefaultLoadControl(new DefaultAllocator(BUFFER_SEGMENT_SIZE));
|
||||
|
||||
// Build the video renderer.
|
||||
DataSource videoDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);
|
||||
DataSource videoDataSource = new DefaultDataSource(context, bandwidthMeter, userAgent);
|
||||
ChunkSource videoChunkSource = new SmoothStreamingChunkSource(manifestFetcher,
|
||||
SmoothStreamingManifest.StreamElement.TYPE_VIDEO,
|
||||
videoDataSource, new AdaptiveEvaluator(bandwidthMeter), LIVE_EDGE_LATENCY_MS);
|
||||
|
|
@ -82,7 +83,7 @@ public class SmoothStreamingSourceBuilder implements SourceBuilder {
|
|||
DemoPlayer.TYPE_VIDEO);
|
||||
|
||||
// Build the audio renderer.
|
||||
DataSource audioDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);
|
||||
DataSource audioDataSource = new DefaultDataSource(context, bandwidthMeter, userAgent);
|
||||
ChunkSource audioChunkSource = new SmoothStreamingChunkSource(manifestFetcher,
|
||||
SmoothStreamingManifest.StreamElement.TYPE_AUDIO, audioDataSource, null,
|
||||
LIVE_EDGE_LATENCY_MS);
|
||||
|
|
@ -90,7 +91,7 @@ public class SmoothStreamingSourceBuilder implements SourceBuilder {
|
|||
AUDIO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player, DemoPlayer.TYPE_AUDIO);
|
||||
|
||||
// Build the text renderer.
|
||||
DataSource textDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);
|
||||
DataSource textDataSource = new DefaultDataSource(context, bandwidthMeter, userAgent);
|
||||
ChunkSource textChunkSource = new SmoothStreamingChunkSource(manifestFetcher,
|
||||
SmoothStreamingManifest.StreamElement.TYPE_TEXT, textDataSource, null,
|
||||
LIVE_EDGE_LATENCY_MS);
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package com.google.android.exoplayer.dash.mpd;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.test.InstrumentationTestCase;
|
||||
|
||||
import java.io.IOException;
|
||||
|
|
@ -34,7 +35,7 @@ public class MediaPresentationDescriptionParserTest extends InstrumentationTestC
|
|||
InputStream inputStream =
|
||||
getInstrumentation().getContext().getResources().getAssets().open(SAMPLE_MPD_1);
|
||||
// Simple test to ensure that the sample manifest parses without throwing any exceptions.
|
||||
parser.parse("https://example.com/test.mpd", inputStream);
|
||||
parser.parse(Uri.parse("https://example.com/test.mpd"), inputStream);
|
||||
}
|
||||
|
||||
public void testParseMediaPresentationDescriptionWithUnknownMimeType() throws IOException {
|
||||
|
|
@ -43,7 +44,7 @@ public class MediaPresentationDescriptionParserTest extends InstrumentationTestC
|
|||
.open(SAMPLE_MPD_2_UNKNOWN_MIME_TYPE);
|
||||
// Simple test to ensure that the sample manifest with an unknown mime type parses without
|
||||
// throwing any exceptions.
|
||||
parser.parse("https://example.com/test.mpd", inputStream);
|
||||
parser.parse(Uri.parse("https://example.com/test.mpd"), inputStream);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ package com.google.android.exoplayer.hls;
|
|||
|
||||
import com.google.android.exoplayer.C;
|
||||
|
||||
import android.net.Uri;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
|
|
@ -30,7 +32,7 @@ import java.util.List;
|
|||
public class HlsMasterPlaylistParserTest extends TestCase {
|
||||
|
||||
public void testParseMasterPlaylist() {
|
||||
String playlistUrl = "https://example.com/test.m3u8";
|
||||
Uri playlistUri = Uri.parse("https://example.com/test.m3u8");
|
||||
String playlistString = "#EXTM3U\n"
|
||||
+ "\n"
|
||||
+ "#EXT-X-STREAM-INF:BANDWIDTH=1280000,CODECS=\"mp4a.40.2,avc1.66.30\",RESOLUTION=304x128\n"
|
||||
|
|
@ -50,7 +52,7 @@ public class HlsMasterPlaylistParserTest extends TestCase {
|
|||
ByteArrayInputStream inputStream = new ByteArrayInputStream(
|
||||
playlistString.getBytes(Charset.forName(C.UTF8_NAME)));
|
||||
try {
|
||||
HlsPlaylist playlist = new HlsPlaylistParser().parse(playlistUrl, inputStream);
|
||||
HlsPlaylist playlist = new HlsPlaylistParser().parse(playlistUri, inputStream);
|
||||
assertNotNull(playlist);
|
||||
assertEquals(HlsPlaylist.TYPE_MASTER, playlist.type);
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ package com.google.android.exoplayer.hls;
|
|||
|
||||
import com.google.android.exoplayer.C;
|
||||
|
||||
import android.net.Uri;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
|
|
@ -32,7 +34,7 @@ import java.util.Locale;
|
|||
public class HlsMediaPlaylistParserTest extends TestCase {
|
||||
|
||||
public void testParseMediaPlaylist() {
|
||||
String playlistUrl = "https://example.com/test.m3u8";
|
||||
Uri playlistUri = Uri.parse("https://example.com/test.m3u8");
|
||||
String playlistString = "#EXTM3U\n"
|
||||
+ "#EXT-X-VERSION:3\n"
|
||||
+ "#EXT-X-TARGETDURATION:8\n"
|
||||
|
|
@ -66,7 +68,7 @@ public class HlsMediaPlaylistParserTest extends TestCase {
|
|||
InputStream inputStream = new ByteArrayInputStream(
|
||||
playlistString.getBytes(Charset.forName(C.UTF8_NAME)));
|
||||
try {
|
||||
HlsPlaylist playlist = new HlsPlaylistParser().parse(playlistUrl, inputStream);
|
||||
HlsPlaylist playlist = new HlsPlaylistParser().parse(playlistUri, inputStream);
|
||||
assertNotNull(playlist);
|
||||
assertEquals(HlsPlaylist.TYPE_MEDIA, playlist.type);
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package com.google.android.exoplayer.smoothstreaming;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.test.InstrumentationTestCase;
|
||||
|
||||
import java.io.IOException;
|
||||
|
|
@ -34,11 +35,11 @@ public class SmoothStreamingManifestParserTest extends InstrumentationTestCase {
|
|||
// SystemID UUID in the manifest is not wrapped in braces.
|
||||
InputStream inputStream1 =
|
||||
getInstrumentation().getContext().getResources().getAssets().open(SAMPLE_ISMC_1);
|
||||
parser.parse("https://example.com/test.ismc", inputStream1);
|
||||
parser.parse(Uri.parse("https://example.com/test.ismc"), inputStream1);
|
||||
// Simple test to ensure that the sample manifest parses without throwing any exceptions.
|
||||
// SystemID UUID in the manifest is wrapped in braces.
|
||||
InputStream inputStream2 =
|
||||
getInstrumentation().getContext().getResources().getAssets().open(SAMPLE_ISMC_2);
|
||||
parser.parse("https://example.com/test.ismc", inputStream2);
|
||||
parser.parse(Uri.parse("https://example.com/test.ismc"), inputStream2);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ import com.google.android.exoplayer.upstream.DataSource;
|
|||
import com.google.android.exoplayer.upstream.DataSpec;
|
||||
import com.google.android.exoplayer.util.Assertions;
|
||||
|
||||
import android.net.Uri;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
|
|
@ -44,6 +46,7 @@ public final class FakeDataSource implements DataSource {
|
|||
private final boolean simulateUnknownLength;
|
||||
private final long totalLength;
|
||||
|
||||
private Uri uri;
|
||||
private boolean opened;
|
||||
private int currentSegmentIndex;
|
||||
private long bytesRemaining;
|
||||
|
|
@ -63,6 +66,7 @@ public final class FakeDataSource implements DataSource {
|
|||
Assertions.checkState(!opened);
|
||||
// DataSpec requires a matching close call even if open fails.
|
||||
opened = true;
|
||||
uri = dataSpec.uri;
|
||||
// If the source knows that the request is unsatisfiable then fail.
|
||||
if (dataSpec.position >= totalLength) {
|
||||
throw new IOException("Unsatisfiable position");
|
||||
|
|
@ -94,18 +98,6 @@ public final class FakeDataSource implements DataSource {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
Assertions.checkState(opened);
|
||||
opened = false;
|
||||
if (currentSegmentIndex < segments.size()) {
|
||||
Segment current = segments.get(currentSegmentIndex);
|
||||
if (current.isErrorSegment() && current.exceptionThrown) {
|
||||
current.exceptionCleared = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] buffer, int offset, int readLength) throws IOException {
|
||||
Assertions.checkState(opened);
|
||||
|
|
@ -138,6 +130,24 @@ public final class FakeDataSource implements DataSource {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uri getUri() {
|
||||
return uri;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
Assertions.checkState(opened);
|
||||
opened = false;
|
||||
uri = null;
|
||||
if (currentSegmentIndex < segments.size()) {
|
||||
Segment current = segments.get(currentSegmentIndex);
|
||||
if (current.isErrorSegment() && current.exceptionThrown) {
|
||||
current.exceptionCleared = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class Segment {
|
||||
|
||||
public final IOException exception;
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ package com.google.android.exoplayer.dash.mpd;
|
|||
|
||||
import com.google.android.exoplayer.util.ManifestFetcher.RedirectingManifest;
|
||||
|
||||
import android.net.Uri;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
|
|
@ -39,13 +41,13 @@ public class MediaPresentationDescription implements RedirectingManifest {
|
|||
|
||||
public final UtcTimingElement utcTiming;
|
||||
|
||||
public final String location;
|
||||
public final Uri location;
|
||||
|
||||
private final List<Period> periods;
|
||||
|
||||
public MediaPresentationDescription(long availabilityStartTime, long duration, long minBufferTime,
|
||||
boolean dynamic, long minUpdatePeriod, long timeShiftBufferDepth, UtcTimingElement utcTiming,
|
||||
String location, List<Period> periods) {
|
||||
Uri location, List<Period> periods) {
|
||||
this.availabilityStartTime = availabilityStartTime;
|
||||
this.duration = duration;
|
||||
this.minBufferTime = minBufferTime;
|
||||
|
|
@ -58,7 +60,7 @@ public class MediaPresentationDescription implements RedirectingManifest {
|
|||
}
|
||||
|
||||
@Override
|
||||
public final String getNextManifestUri() {
|
||||
public final Uri getNextManifestUri() {
|
||||
return location;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import com.google.android.exoplayer.util.ParserUtil;
|
|||
import com.google.android.exoplayer.util.UriUtil;
|
||||
import com.google.android.exoplayer.util.Util;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Base64;
|
||||
import android.util.Log;
|
||||
|
|
@ -88,7 +89,7 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
|
|||
// MPD parsing.
|
||||
|
||||
@Override
|
||||
public MediaPresentationDescription parse(String connectionUrl, InputStream inputStream)
|
||||
public MediaPresentationDescription parse(Uri uri, InputStream inputStream)
|
||||
throws IOException, ParserException {
|
||||
try {
|
||||
XmlPullParser xpp = xmlParserFactory.newPullParser();
|
||||
|
|
@ -98,7 +99,7 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
|
|||
throw new ParserException(
|
||||
"inputStream does not contain a valid media presentation description");
|
||||
}
|
||||
return parseMediaPresentationDescription(xpp, connectionUrl);
|
||||
return parseMediaPresentationDescription(xpp, uri.toString());
|
||||
} catch (XmlPullParserException e) {
|
||||
throw new ParserException(e);
|
||||
} catch (ParseException e) {
|
||||
|
|
@ -116,7 +117,7 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
|
|||
long minUpdateTimeMs = (dynamic) ? parseDuration(xpp, "minimumUpdatePeriod", -1) : -1;
|
||||
long timeShiftBufferDepthMs = (dynamic) ? parseDuration(xpp, "timeShiftBufferDepth", -1) : -1;
|
||||
UtcTimingElement utcTiming = null;
|
||||
String location = null;
|
||||
Uri location = null;
|
||||
|
||||
List<Period> periods = new ArrayList<>();
|
||||
long nextPeriodStartMs = dynamic ? -1 : 0;
|
||||
|
|
@ -132,7 +133,7 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
|
|||
} else if (ParserUtil.isStartTag(xpp, "UTCTiming")) {
|
||||
utcTiming = parseUtcTiming(xpp);
|
||||
} else if (ParserUtil.isStartTag(xpp, "Location")) {
|
||||
location = xpp.nextText();
|
||||
location = Uri.parse(xpp.nextText());
|
||||
} else if (ParserUtil.isStartTag(xpp, "Period") && !seenEarlyAccessPeriod) {
|
||||
Pair<Period, Long> periodWithDurationMs = parsePeriod(xpp, baseUrl, nextPeriodStartMs);
|
||||
Period period = periodWithDurationMs.first;
|
||||
|
|
@ -172,7 +173,7 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
|
|||
protected MediaPresentationDescription buildMediaPresentationDescription(
|
||||
long availabilityStartTime, long durationMs, long minBufferTimeMs, boolean dynamic,
|
||||
long minUpdateTimeMs, long timeShiftBufferDepthMs, UtcTimingElement utcTiming,
|
||||
String location, List<Period> periods) {
|
||||
Uri location, List<Period> periods) {
|
||||
return new MediaPresentationDescription(availabilityStartTime, durationMs, minBufferTimeMs,
|
||||
dynamic, minUpdateTimeMs, timeShiftBufferDepthMs, utcTiming, location, periods);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,13 +16,14 @@
|
|||
package com.google.android.exoplayer.dash.mpd;
|
||||
|
||||
import com.google.android.exoplayer.ParserException;
|
||||
import com.google.android.exoplayer.upstream.DataSource;
|
||||
import com.google.android.exoplayer.upstream.Loader;
|
||||
import com.google.android.exoplayer.upstream.Loader.Loadable;
|
||||
import com.google.android.exoplayer.upstream.UriDataSource;
|
||||
import com.google.android.exoplayer.upstream.UriLoadable;
|
||||
import com.google.android.exoplayer.util.Assertions;
|
||||
import com.google.android.exoplayer.util.Util;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.os.SystemClock;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
|
|
@ -64,7 +65,7 @@ public final class UtcTimingElementResolver implements Loader.Callback {
|
|||
void onTimestampError(UtcTimingElement utcTiming, IOException e);
|
||||
}
|
||||
|
||||
private final UriDataSource uriDataSource;
|
||||
private final DataSource dataSource;
|
||||
private final UtcTimingElement timingElement;
|
||||
private final long timingElementElapsedRealtime;
|
||||
private final UtcTimingCallback callback;
|
||||
|
|
@ -75,23 +76,22 @@ public final class UtcTimingElementResolver implements Loader.Callback {
|
|||
/**
|
||||
* Resolves a {@link UtcTimingElement}.
|
||||
*
|
||||
* @param uriDataSource A source to use should loading from a URI be necessary.
|
||||
* @param dataSource A {@link DataSource} to use should loading from a {@link Uri} be necessary.
|
||||
* @param timingElement The element to resolve.
|
||||
* @param timingElementElapsedRealtime The {@link SystemClock#elapsedRealtime()} timestamp at
|
||||
* which the element was obtained. Used if the element contains a timestamp directly.
|
||||
* @param callback The callback to invoke on resolution or failure.
|
||||
*/
|
||||
public static void resolveTimingElement(UriDataSource uriDataSource,
|
||||
UtcTimingElement timingElement, long timingElementElapsedRealtime,
|
||||
UtcTimingCallback callback) {
|
||||
UtcTimingElementResolver resolver = new UtcTimingElementResolver(uriDataSource, timingElement,
|
||||
public static void resolveTimingElement(DataSource dataSource, UtcTimingElement timingElement,
|
||||
long timingElementElapsedRealtime, UtcTimingCallback callback) {
|
||||
UtcTimingElementResolver resolver = new UtcTimingElementResolver(dataSource, timingElement,
|
||||
timingElementElapsedRealtime, callback);
|
||||
resolver.resolve();
|
||||
}
|
||||
|
||||
private UtcTimingElementResolver(UriDataSource uriDataSource, UtcTimingElement timingElement,
|
||||
private UtcTimingElementResolver(DataSource dataSource, UtcTimingElement timingElement,
|
||||
long timingElementElapsedRealtime, UtcTimingCallback callback) {
|
||||
this.uriDataSource = uriDataSource;
|
||||
this.dataSource = dataSource;
|
||||
this.timingElement = Assertions.checkNotNull(timingElement);
|
||||
this.timingElementElapsedRealtime = timingElementElapsedRealtime;
|
||||
this.callback = Assertions.checkNotNull(callback);
|
||||
|
|
@ -124,7 +124,7 @@ public final class UtcTimingElementResolver implements Loader.Callback {
|
|||
|
||||
private void resolveHttp(UriLoadable.Parser<Long> parser) {
|
||||
singleUseLoader = new Loader("utctiming");
|
||||
singleUseLoadable = new UriLoadable<>(timingElement.value, uriDataSource, parser);
|
||||
singleUseLoadable = new UriLoadable<>(Uri.parse(timingElement.value), dataSource, parser);
|
||||
singleUseLoader.startLoading(singleUseLoadable, this);
|
||||
}
|
||||
|
||||
|
|
@ -153,8 +153,7 @@ public final class UtcTimingElementResolver implements Loader.Callback {
|
|||
private static class XsDateTimeParser implements UriLoadable.Parser<Long> {
|
||||
|
||||
@Override
|
||||
public Long parse(String connectionUrl, InputStream inputStream) throws ParserException,
|
||||
IOException {
|
||||
public Long parse(Uri uri, InputStream inputStream) throws ParserException, IOException {
|
||||
String firstLine = new BufferedReader(new InputStreamReader(inputStream)).readLine();
|
||||
try {
|
||||
return Util.parseXsDateTime(firstLine);
|
||||
|
|
@ -168,8 +167,7 @@ public final class UtcTimingElementResolver implements Loader.Callback {
|
|||
private static class Iso8601Parser implements UriLoadable.Parser<Long> {
|
||||
|
||||
@Override
|
||||
public Long parse(String connectionUrl, InputStream inputStream) throws ParserException,
|
||||
IOException {
|
||||
public Long parse(Uri uri, InputStream inputStream) throws ParserException, IOException {
|
||||
String firstLine = new BufferedReader(new InputStreamReader(inputStream)).readLine();
|
||||
try {
|
||||
// TODO: It may be necessary to handle timestamp offsets from UTC.
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ import com.google.android.exoplayer.upstream.DataSourceInputStream;
|
|||
import com.google.android.exoplayer.upstream.DataSpec;
|
||||
import com.google.android.exoplayer.util.Assertions;
|
||||
|
||||
import android.net.Uri;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
|
|
@ -105,4 +107,9 @@ import javax.crypto.spec.SecretKeySpec;
|
|||
return bytesRead;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uri getUri() {
|
||||
return upstream.getUri();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -656,7 +656,7 @@ public class HlsChunkSource {
|
|||
DataSpec dataSpec = new DataSpec(mediaPlaylistUri, 0, C.LENGTH_UNBOUNDED, null,
|
||||
DataSpec.FLAG_ALLOW_GZIP);
|
||||
return new MediaPlaylistChunk(dataSource, dataSpec, variants[variantIndex].format, scratchSpace,
|
||||
playlistParser, variantIndex, mediaPlaylistUri.toString());
|
||||
playlistParser, variantIndex, mediaPlaylistUri);
|
||||
}
|
||||
|
||||
private EncryptionKeyChunk newEncryptionKeyChunk(Uri keyUri, String iv, int variantIndex) {
|
||||
|
|
@ -735,23 +735,23 @@ public class HlsChunkSource {
|
|||
public final int variantIndex;
|
||||
|
||||
private final HlsPlaylistParser playlistParser;
|
||||
private final String playlistUrl;
|
||||
private final Uri playlistUri;
|
||||
|
||||
private HlsMediaPlaylist result;
|
||||
|
||||
public MediaPlaylistChunk(DataSource dataSource, DataSpec dataSpec, Format format,
|
||||
byte[] scratchSpace, HlsPlaylistParser playlistParser, int variantIndex,
|
||||
String playlistUrl) {
|
||||
Uri playlistUri) {
|
||||
super(dataSource, dataSpec, Chunk.TYPE_MANIFEST, Chunk.TRIGGER_UNSPECIFIED, format,
|
||||
Chunk.NO_PARENT_ID, scratchSpace);
|
||||
this.variantIndex = variantIndex;
|
||||
this.playlistParser = playlistParser;
|
||||
this.playlistUrl = playlistUrl;
|
||||
this.playlistUri = playlistUri;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void consume(byte[] data, int limit) throws IOException {
|
||||
result = (HlsMediaPlaylist) playlistParser.parse(playlistUrl,
|
||||
result = (HlsMediaPlaylist) playlistParser.parse(playlistUri,
|
||||
new ByteArrayInputStream(data, 0, limit));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ import com.google.android.exoplayer.hls.HlsMediaPlaylist.Segment;
|
|||
import com.google.android.exoplayer.upstream.UriLoadable;
|
||||
import com.google.android.exoplayer.util.MimeTypes;
|
||||
|
||||
import android.net.Uri;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
|
@ -107,8 +109,7 @@ public final class HlsPlaylistParser implements UriLoadable.Parser<HlsPlaylist>
|
|||
// HlsParserUtil.compileBooleanAttrPattern(DEFAULT_ATTR);
|
||||
|
||||
@Override
|
||||
public HlsPlaylist parse(String connectionUrl, InputStream inputStream)
|
||||
throws IOException, ParserException {
|
||||
public HlsPlaylist parse(Uri uri, InputStream inputStream) throws IOException, ParserException {
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
|
||||
Queue<String> extraLines = new LinkedList<>();
|
||||
String line;
|
||||
|
|
@ -119,7 +120,7 @@ public final class HlsPlaylistParser implements UriLoadable.Parser<HlsPlaylist>
|
|||
// Do nothing.
|
||||
} else if (line.startsWith(STREAM_INF_TAG)) {
|
||||
extraLines.add(line);
|
||||
return parseMasterPlaylist(new LineIterator(extraLines, reader), connectionUrl);
|
||||
return parseMasterPlaylist(new LineIterator(extraLines, reader), uri.toString());
|
||||
} else if (line.startsWith(TARGET_DURATION_TAG)
|
||||
|| line.startsWith(MEDIA_SEQUENCE_TAG)
|
||||
|| line.startsWith(MEDIA_DURATION_TAG)
|
||||
|
|
@ -129,7 +130,7 @@ public final class HlsPlaylistParser implements UriLoadable.Parser<HlsPlaylist>
|
|||
|| line.equals(DISCONTINUITY_SEQUENCE_TAG)
|
||||
|| line.equals(ENDLIST_TAG)) {
|
||||
extraLines.add(line);
|
||||
return parseMediaPlaylist(new LineIterator(extraLines, reader), connectionUrl);
|
||||
return parseMediaPlaylist(new LineIterator(extraLines, reader), uri.toString());
|
||||
} else {
|
||||
extraLines.add(line);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import com.google.android.exoplayer.util.CodecSpecificDataUtil;
|
|||
import com.google.android.exoplayer.util.MimeTypes;
|
||||
import com.google.android.exoplayer.util.Util;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Base64;
|
||||
import android.util.Pair;
|
||||
|
|
@ -61,13 +62,13 @@ public class SmoothStreamingManifestParser implements UriLoadable.Parser<SmoothS
|
|||
}
|
||||
|
||||
@Override
|
||||
public SmoothStreamingManifest parse(String connectionUrl, InputStream inputStream)
|
||||
public SmoothStreamingManifest parse(Uri uri, InputStream inputStream)
|
||||
throws IOException, ParserException {
|
||||
try {
|
||||
XmlPullParser xmlParser = xmlParserFactory.newPullParser();
|
||||
xmlParser.setInput(inputStream, null);
|
||||
SmoothStreamMediaParser smoothStreamMediaParser =
|
||||
new SmoothStreamMediaParser(null, connectionUrl);
|
||||
new SmoothStreamMediaParser(null, uri.toString());
|
||||
return (SmoothStreamingManifest) smoothStreamMediaParser.parse(xmlParser);
|
||||
} catch (XmlPullParserException e) {
|
||||
throw new ParserException(e);
|
||||
|
|
|
|||
|
|
@ -19,15 +19,16 @@ import com.google.android.exoplayer.C;
|
|||
|
||||
import android.content.Context;
|
||||
import android.content.res.AssetManager;
|
||||
import android.net.Uri;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* A local asset {@link UriDataSource}.
|
||||
* A local asset {@link DataSource}.
|
||||
*/
|
||||
public final class AssetDataSource implements UriDataSource {
|
||||
public final class AssetDataSource implements DataSource {
|
||||
|
||||
/**
|
||||
* Thrown when an {@link IOException} is encountered reading a local asset.
|
||||
|
|
@ -43,7 +44,7 @@ public final class AssetDataSource implements UriDataSource {
|
|||
private final AssetManager assetManager;
|
||||
private final TransferListener listener;
|
||||
|
||||
private String uriString;
|
||||
private Uri uri;
|
||||
private InputStream inputStream;
|
||||
private long bytesRemaining;
|
||||
private boolean opened;
|
||||
|
|
@ -68,14 +69,13 @@ public final class AssetDataSource implements UriDataSource {
|
|||
@Override
|
||||
public long open(DataSpec dataSpec) throws AssetDataSourceException {
|
||||
try {
|
||||
uriString = dataSpec.uri.toString();
|
||||
String path = dataSpec.uri.getPath();
|
||||
uri = dataSpec.uri;
|
||||
String path = uri.getPath();
|
||||
if (path.startsWith("/android_asset/")) {
|
||||
path = path.substring(15);
|
||||
} else if (path.startsWith("/")) {
|
||||
path = path.substring(1);
|
||||
}
|
||||
uriString = dataSpec.uri.toString();
|
||||
inputStream = assetManager.open(path, AssetManager.ACCESS_RANDOM);
|
||||
long skipped = inputStream.skip(dataSpec.position);
|
||||
if (skipped < dataSpec.position) {
|
||||
|
|
@ -133,13 +133,13 @@ public final class AssetDataSource implements UriDataSource {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getUri() {
|
||||
return uriString;
|
||||
public Uri getUri() {
|
||||
return uri;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws AssetDataSourceException {
|
||||
uriString = null;
|
||||
uri = null;
|
||||
if (inputStream != null) {
|
||||
try {
|
||||
inputStream.close();
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ package com.google.android.exoplayer.upstream;
|
|||
import com.google.android.exoplayer.C;
|
||||
import com.google.android.exoplayer.util.Assertions;
|
||||
|
||||
import android.net.Uri;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
|
|
@ -26,6 +28,8 @@ import java.io.IOException;
|
|||
public final class ByteArrayDataSource implements DataSource {
|
||||
|
||||
private final byte[] data;
|
||||
|
||||
private Uri uri;
|
||||
private int readPosition;
|
||||
private int remainingBytes;
|
||||
|
||||
|
|
@ -40,6 +44,7 @@ public final class ByteArrayDataSource implements DataSource {
|
|||
|
||||
@Override
|
||||
public long open(DataSpec dataSpec) throws IOException {
|
||||
uri = dataSpec.uri;
|
||||
readPosition = (int) dataSpec.position;
|
||||
remainingBytes = (int) ((dataSpec.length == C.LENGTH_UNBOUNDED)
|
||||
? (data.length - dataSpec.position) : dataSpec.length);
|
||||
|
|
@ -50,11 +55,6 @@ public final class ByteArrayDataSource implements DataSource {
|
|||
return remainingBytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] buffer, int offset, int length) throws IOException {
|
||||
if (remainingBytes == 0) {
|
||||
|
|
@ -66,5 +66,16 @@ public final class ByteArrayDataSource implements DataSource {
|
|||
remainingBytes -= length;
|
||||
return length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uri getUri() {
|
||||
return uri;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
uri = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import com.google.android.exoplayer.C;
|
|||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.res.AssetFileDescriptor;
|
||||
import android.net.Uri;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.FileInputStream;
|
||||
|
|
@ -27,9 +28,9 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* A content URI {@link UriDataSource}.
|
||||
* A content URI {@link DataSource}.
|
||||
*/
|
||||
public final class ContentDataSource implements UriDataSource {
|
||||
public final class ContentDataSource implements DataSource {
|
||||
|
||||
/**
|
||||
* Thrown when an {@link IOException} is encountered reading from a content URI.
|
||||
|
|
@ -45,8 +46,8 @@ public final class ContentDataSource implements UriDataSource {
|
|||
private final ContentResolver resolver;
|
||||
private final TransferListener listener;
|
||||
|
||||
private Uri uri;
|
||||
private InputStream inputStream;
|
||||
private String uriString;
|
||||
private long bytesRemaining;
|
||||
private boolean opened;
|
||||
|
||||
|
|
@ -70,8 +71,8 @@ public final class ContentDataSource implements UriDataSource {
|
|||
@Override
|
||||
public long open(DataSpec dataSpec) throws ContentDataSourceException {
|
||||
try {
|
||||
uriString = dataSpec.uri.toString();
|
||||
AssetFileDescriptor assetFd = resolver.openAssetFileDescriptor(dataSpec.uri, "r");
|
||||
uri = dataSpec.uri;
|
||||
AssetFileDescriptor assetFd = resolver.openAssetFileDescriptor(uri, "r");
|
||||
inputStream = new FileInputStream(assetFd.getFileDescriptor());
|
||||
long skipped = inputStream.skip(dataSpec.position);
|
||||
if (skipped < dataSpec.position) {
|
||||
|
|
@ -130,13 +131,13 @@ public final class ContentDataSource implements UriDataSource {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getUri() {
|
||||
return uriString;
|
||||
public Uri getUri() {
|
||||
return uri;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws ContentDataSourceException {
|
||||
uriString = null;
|
||||
uri = null;
|
||||
if (inputStream != null) {
|
||||
try {
|
||||
inputStream.close();
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ package com.google.android.exoplayer.upstream;
|
|||
|
||||
import com.google.android.exoplayer.C;
|
||||
|
||||
import android.net.Uri;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
|
|
@ -43,16 +45,6 @@ public interface DataSource {
|
|||
*/
|
||||
long open(DataSpec dataSpec) throws IOException;
|
||||
|
||||
/**
|
||||
* Closes the {@link DataSource}.
|
||||
* <p>
|
||||
* Note: This method will be called even if the corresponding call to {@link #open(DataSpec)}
|
||||
* threw an {@link IOException}. See {@link #open(DataSpec)} for more details.
|
||||
*
|
||||
* @throws IOException If an error occurs closing the source.
|
||||
*/
|
||||
void close() throws IOException;
|
||||
|
||||
/**
|
||||
* Reads up to {@code length} bytes of data and stores them into {@code buffer}, starting at
|
||||
* index {@code offset}.
|
||||
|
|
@ -69,4 +61,25 @@ public interface DataSource {
|
|||
*/
|
||||
int read(byte[] buffer, int offset, int readLength) throws IOException;
|
||||
|
||||
/**
|
||||
* When the source is open, returns the {@link Uri} from which data is being read.
|
||||
* <p>
|
||||
* The returned {@link Uri} will be identical to the one passed {@link #open(DataSpec)} in the
|
||||
* {@link DataSpec} unless redirection has occurred. If redirection has occurred, the {@link Uri}
|
||||
* after redirection is returned.
|
||||
*
|
||||
* @return When the source is open, the {@link Uri} from which data is being read. Null otherwise.
|
||||
*/
|
||||
Uri getUri();
|
||||
|
||||
/**
|
||||
* Closes the {@link DataSource}.
|
||||
* <p>
|
||||
* Note: This method will be called even if the corresponding call to {@link #open(DataSpec)}
|
||||
* threw an {@link IOException}. See {@link #open(DataSpec)} for more details.
|
||||
*
|
||||
* @throws IOException If an error occurs closing the source.
|
||||
*/
|
||||
void close() throws IOException;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,11 +19,12 @@ import com.google.android.exoplayer.util.Assertions;
|
|||
import com.google.android.exoplayer.util.Util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* A {@link UriDataSource} that supports multiple URI schemes. The supported schemes are:
|
||||
* A {@link DataSource} 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).
|
||||
|
|
@ -34,34 +35,34 @@ import java.io.IOException;
|
|||
* <li>content: For fetching data from a content URI (e.g. content://authority/path/123).
|
||||
* </ul>
|
||||
*/
|
||||
public final class DefaultUriDataSource implements UriDataSource {
|
||||
public final class DefaultDataSource implements DataSource {
|
||||
|
||||
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;
|
||||
private final DataSource httpDataSource;
|
||||
private final DataSource fileDataSource;
|
||||
private final DataSource assetDataSource;
|
||||
private final DataSource contentDataSource;
|
||||
|
||||
/**
|
||||
* {@code null} if no data source is open. Otherwise, equal to {@link #fileDataSource} if the open
|
||||
* data source is a file, or {@link #httpDataSource} otherwise.
|
||||
*/
|
||||
private UriDataSource dataSource;
|
||||
private DataSource dataSource;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* using {@link #DefaultDataSource(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.
|
||||
*/
|
||||
public DefaultUriDataSource(Context context, String userAgent) {
|
||||
public DefaultDataSource(Context context, String userAgent) {
|
||||
this(context, null, userAgent, false);
|
||||
}
|
||||
|
||||
|
|
@ -70,14 +71,14 @@ public final class DefaultUriDataSource implements UriDataSource {
|
|||
* <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
|
||||
* using {@link #DefaultDataSource(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) {
|
||||
public DefaultDataSource(Context context, TransferListener listener, String userAgent) {
|
||||
this(context, listener, userAgent, false);
|
||||
}
|
||||
|
||||
|
|
@ -90,7 +91,7 @@ public final class DefaultUriDataSource implements UriDataSource {
|
|||
* @param allowCrossProtocolRedirects Whether cross-protocol redirects (i.e. redirects from HTTP
|
||||
* to HTTPS and vice versa) are enabled when fetching remote data..
|
||||
*/
|
||||
public DefaultUriDataSource(Context context, TransferListener listener, String userAgent,
|
||||
public DefaultDataSource(Context context, TransferListener listener, String userAgent,
|
||||
boolean allowCrossProtocolRedirects) {
|
||||
this(context, listener,
|
||||
new DefaultHttpDataSource(userAgent, null, listener,
|
||||
|
|
@ -103,10 +104,10 @@ public final class DefaultUriDataSource implements UriDataSource {
|
|||
*
|
||||
* @param context A context.
|
||||
* @param listener An optional {@link TransferListener}.
|
||||
* @param httpDataSource {@link UriDataSource} to use for non-file URIs.
|
||||
* @param httpDataSource {@link DataSource} to use for non-file URIs.
|
||||
*/
|
||||
public DefaultUriDataSource(Context context, TransferListener listener,
|
||||
UriDataSource httpDataSource) {
|
||||
public DefaultDataSource(Context context, TransferListener listener,
|
||||
DataSource httpDataSource) {
|
||||
this.httpDataSource = Assertions.checkNotNull(httpDataSource);
|
||||
this.fileDataSource = new FileDataSource(listener);
|
||||
this.assetDataSource = new AssetDataSource(context, listener);
|
||||
|
|
@ -141,7 +142,7 @@ public final class DefaultUriDataSource implements UriDataSource {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getUri() {
|
||||
public Uri getUri() {
|
||||
return dataSource == null ? null : dataSource.getUri();
|
||||
}
|
||||
|
||||
|
|
@ -20,6 +20,7 @@ import com.google.android.exoplayer.util.Assertions;
|
|||
import com.google.android.exoplayer.util.Predicate;
|
||||
import com.google.android.exoplayer.util.Util;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
|
|
@ -149,8 +150,8 @@ public class DefaultHttpDataSource implements HttpDataSource {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getUri() {
|
||||
return connection == null ? null : connection.getURL().toString();
|
||||
public Uri getUri() {
|
||||
return connection == null ? null : Uri.parse(connection.getURL().toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -17,14 +17,16 @@ package com.google.android.exoplayer.upstream;
|
|||
|
||||
import com.google.android.exoplayer.C;
|
||||
|
||||
import android.net.Uri;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
/**
|
||||
* A local file {@link UriDataSource}.
|
||||
* A local file {@link DataSource}.
|
||||
*/
|
||||
public final class FileDataSource implements UriDataSource {
|
||||
public final class FileDataSource implements DataSource {
|
||||
|
||||
/**
|
||||
* Thrown when IOException is encountered during local file read operation.
|
||||
|
|
@ -40,7 +42,7 @@ public final class FileDataSource implements UriDataSource {
|
|||
private final TransferListener listener;
|
||||
|
||||
private RandomAccessFile file;
|
||||
private String uriString;
|
||||
private Uri uri;
|
||||
private long bytesRemaining;
|
||||
private boolean opened;
|
||||
|
||||
|
|
@ -63,7 +65,7 @@ public final class FileDataSource implements UriDataSource {
|
|||
@Override
|
||||
public long open(DataSpec dataSpec) throws FileDataSourceException {
|
||||
try {
|
||||
uriString = dataSpec.uri.toString();
|
||||
uri = dataSpec.uri;
|
||||
file = new RandomAccessFile(dataSpec.uri.getPath(), "r");
|
||||
file.seek(dataSpec.position);
|
||||
bytesRemaining = dataSpec.length == C.LENGTH_UNBOUNDED ? file.length() - dataSpec.position
|
||||
|
|
@ -107,13 +109,13 @@ public final class FileDataSource implements UriDataSource {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getUri() {
|
||||
return uriString;
|
||||
public Uri getUri() {
|
||||
return uri;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws FileDataSourceException {
|
||||
uriString = null;
|
||||
uri = null;
|
||||
if (file != null) {
|
||||
try {
|
||||
file.close();
|
||||
|
|
|
|||
|
|
@ -25,9 +25,9 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* An HTTP specific extension to {@link UriDataSource}.
|
||||
* An HTTP specific extension to {@link DataSource}.
|
||||
*/
|
||||
public interface HttpDataSource extends UriDataSource {
|
||||
public interface HttpDataSource extends DataSource {
|
||||
|
||||
/**
|
||||
* A {@link Predicate} that rejects content types often used for pay-walls.
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ package com.google.android.exoplayer.upstream;
|
|||
|
||||
import com.google.android.exoplayer.util.Assertions;
|
||||
|
||||
import android.net.Uri;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
|
|
@ -50,6 +52,11 @@ public final class PriorityDataSource implements DataSource {
|
|||
return upstream.read(buffer, offset, max);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uri getUri() {
|
||||
return upstream.getUri();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
upstream.close();
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ package com.google.android.exoplayer.upstream;
|
|||
import com.google.android.exoplayer.C;
|
||||
import com.google.android.exoplayer.util.Assertions;
|
||||
|
||||
import android.net.Uri;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
|
|
@ -59,6 +61,11 @@ public final class TeeDataSource implements DataSource {
|
|||
return num;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uri getUri() {
|
||||
return upstream.getUri();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ package com.google.android.exoplayer.upstream;
|
|||
|
||||
import com.google.android.exoplayer.C;
|
||||
|
||||
import android.net.Uri;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
|
|
@ -27,7 +29,7 @@ import java.net.MulticastSocket;
|
|||
/**
|
||||
* A UDP {@link DataSource}.
|
||||
*/
|
||||
public final class UdpDataSource implements UriDataSource {
|
||||
public final class UdpDataSource implements DataSource {
|
||||
|
||||
/**
|
||||
* Thrown when an error is encountered when trying to read from a {@link UdpDataSource}.
|
||||
|
|
@ -52,7 +54,7 @@ public final class UdpDataSource implements UriDataSource {
|
|||
private final TransferListener listener;
|
||||
private final DatagramPacket packet;
|
||||
|
||||
private DataSpec dataSpec;
|
||||
private Uri uri;
|
||||
private DatagramSocket socket;
|
||||
private MulticastSocket multicastSocket;
|
||||
private InetAddress address;
|
||||
|
|
@ -81,9 +83,9 @@ public final class UdpDataSource implements UriDataSource {
|
|||
|
||||
@Override
|
||||
public long open(DataSpec dataSpec) throws UdpDataSourceException {
|
||||
this.dataSpec = dataSpec;
|
||||
String host = dataSpec.uri.getHost();
|
||||
int port = dataSpec.uri.getPort();
|
||||
uri = dataSpec.uri;
|
||||
String host = uri.getHost();
|
||||
int port = uri.getPort();
|
||||
|
||||
try {
|
||||
address = InetAddress.getByName(host);
|
||||
|
|
@ -129,8 +131,14 @@ public final class UdpDataSource implements UriDataSource {
|
|||
return bytesToRead;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uri getUri() {
|
||||
return uri;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
uri = null;
|
||||
if (multicastSocket != null) {
|
||||
try {
|
||||
multicastSocket.leaveGroup(address);
|
||||
|
|
@ -154,9 +162,4 @@ public final class UdpDataSource implements UriDataSource {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUri() {
|
||||
return dataSpec == null ? null : dataSpec.uri.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* 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.upstream;
|
||||
|
||||
/**
|
||||
* A component that provides media data from a URI.
|
||||
*/
|
||||
public interface UriDataSource extends DataSource {
|
||||
|
||||
/**
|
||||
* When the source is open, returns the URI from which data is being read.
|
||||
* <p>
|
||||
* If redirection occurred, the URI after redirection is the one returned.
|
||||
*
|
||||
* @return When the source is open, the URI from which data is being read. Null otherwise.
|
||||
*/
|
||||
String getUri();
|
||||
|
||||
}
|
||||
|
|
@ -38,32 +38,32 @@ public final class UriLoadable<T> implements Loadable {
|
|||
/**
|
||||
* Parses an object from a response.
|
||||
*
|
||||
* @param connectionUrl The source of the response, after any redirection.
|
||||
* @param uri The source of the response, after any redirection.
|
||||
* @param inputStream An {@link InputStream} from which the response data can be read.
|
||||
* @return The parsed object.
|
||||
* @throws ParserException If an error occurs parsing the data.
|
||||
* @throws IOException If an error occurs reading data from the stream.
|
||||
*/
|
||||
T parse(String connectionUrl, InputStream inputStream) throws ParserException, IOException;
|
||||
T parse(Uri uri, InputStream inputStream) throws ParserException, IOException;
|
||||
|
||||
}
|
||||
|
||||
private final DataSpec dataSpec;
|
||||
private final UriDataSource uriDataSource;
|
||||
private final DataSource dataSource;
|
||||
private final Parser<T> parser;
|
||||
|
||||
private volatile T result;
|
||||
private volatile boolean isCanceled;
|
||||
|
||||
/**
|
||||
* @param url The url from which the object should be loaded.
|
||||
* @param uriDataSource A {@link UriDataSource} to use when loading the data.
|
||||
* @param uri The {@link Uri} from which the object should be loaded.
|
||||
* @param dataSource A {@link DataSource} to use when loading the data.
|
||||
* @param parser Parses the object from the response.
|
||||
*/
|
||||
public UriLoadable(String url, UriDataSource uriDataSource, Parser<T> parser) {
|
||||
this.uriDataSource = uriDataSource;
|
||||
public UriLoadable(Uri uri, DataSource dataSource, Parser<T> parser) {
|
||||
this.dataSource = dataSource;
|
||||
this.parser = parser;
|
||||
dataSpec = new DataSpec(Uri.parse(url), DataSpec.FLAG_ALLOW_GZIP);
|
||||
dataSpec = new DataSpec(uri, DataSpec.FLAG_ALLOW_GZIP);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -87,10 +87,10 @@ public final class UriLoadable<T> implements Loadable {
|
|||
|
||||
@Override
|
||||
public final void load() throws IOException, InterruptedException {
|
||||
DataSourceInputStream inputStream = new DataSourceInputStream(uriDataSource, dataSpec);
|
||||
DataSourceInputStream inputStream = new DataSourceInputStream(dataSource, dataSpec);
|
||||
try {
|
||||
inputStream.open();
|
||||
result = parser.parse(uriDataSource.getUri(), inputStream);
|
||||
result = parser.parse(dataSource.getUri(), inputStream);
|
||||
} finally {
|
||||
inputStream.close();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -166,8 +166,14 @@ public final class CacheDataSource implements DataSource {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uri getUri() {
|
||||
return currentDataSource == upstreamDataSource ? currentDataSource.getUri() : uri;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
uri = null;
|
||||
notifyBytesRead();
|
||||
try {
|
||||
closeCurrentSource();
|
||||
|
|
|
|||
|
|
@ -15,14 +15,14 @@
|
|||
*/
|
||||
package com.google.android.exoplayer.util;
|
||||
|
||||
import com.google.android.exoplayer.upstream.DataSource;
|
||||
import com.google.android.exoplayer.upstream.Loader;
|
||||
import com.google.android.exoplayer.upstream.Loader.Loadable;
|
||||
import com.google.android.exoplayer.upstream.UriDataSource;
|
||||
import com.google.android.exoplayer.upstream.UriLoadable;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.os.SystemClock;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Pair;
|
||||
|
||||
import java.io.IOException;
|
||||
|
|
@ -62,19 +62,19 @@ public class ManifestFetcher<T> implements Loader.Callback {
|
|||
public interface RedirectingManifest {
|
||||
|
||||
/**
|
||||
* Returns the URI from which subsequent manifests should be requested, or null to continue
|
||||
* using the current URI.
|
||||
* Returns the {@link Uri} from which subsequent manifests should be requested, or null to
|
||||
* continue using the current {@link Uri}.
|
||||
*/
|
||||
public String getNextManifestUri();
|
||||
public Uri getNextManifestUri();
|
||||
|
||||
}
|
||||
|
||||
private final UriLoadable.Parser<T> parser;
|
||||
private final UriDataSource uriDataSource;
|
||||
private final DataSource dataSource;
|
||||
private final Handler eventHandler;
|
||||
private final EventListener eventListener;
|
||||
|
||||
/* package */ volatile String manifestUri;
|
||||
private volatile Uri manifestUri;
|
||||
|
||||
private int enabledCount;
|
||||
private Loader loader;
|
||||
|
|
@ -90,38 +90,37 @@ public class ManifestFetcher<T> implements Loader.Callback {
|
|||
private volatile long manifestLoadCompleteTimestamp;
|
||||
|
||||
/**
|
||||
* @param manifestUri The manifest location.
|
||||
* @param uriDataSource The {@link UriDataSource} to use when loading the manifest.
|
||||
* @param manifestUri The manifest {@link Uri}.
|
||||
* @param dataSource The {@link DataSource} to use when loading the manifest.
|
||||
* @param parser A parser to parse the loaded manifest data.
|
||||
*/
|
||||
public ManifestFetcher(String manifestUri, UriDataSource uriDataSource,
|
||||
UriLoadable.Parser<T> parser) {
|
||||
this(manifestUri, uriDataSource, parser, null, null);
|
||||
public ManifestFetcher(Uri manifestUri, DataSource dataSource, UriLoadable.Parser<T> parser) {
|
||||
this(manifestUri, dataSource, parser, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param manifestUri The manifest location.
|
||||
* @param uriDataSource The {@link UriDataSource} to use when loading the manifest.
|
||||
* @param manifestUri The manifest {@link Uri}.
|
||||
* @param dataSource The {@link DataSource} to use when loading the manifest.
|
||||
* @param parser A parser to parse the loaded manifest data.
|
||||
* @param eventHandler A handler to use when delivering events to {@code eventListener}. May be
|
||||
* null if delivery of events is not required.
|
||||
* @param eventListener A listener of events. May be null if delivery of events is not required.
|
||||
*/
|
||||
public ManifestFetcher(String manifestUri, UriDataSource uriDataSource,
|
||||
UriLoadable.Parser<T> parser, Handler eventHandler, EventListener eventListener) {
|
||||
public ManifestFetcher(Uri manifestUri, DataSource dataSource, UriLoadable.Parser<T> parser,
|
||||
Handler eventHandler, EventListener eventListener) {
|
||||
this.parser = parser;
|
||||
this.manifestUri = manifestUri;
|
||||
this.uriDataSource = uriDataSource;
|
||||
this.dataSource = dataSource;
|
||||
this.eventHandler = eventHandler;
|
||||
this.eventListener = eventListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the manifest location.
|
||||
* Updates the manifest {@link Uri}.
|
||||
*
|
||||
* @param manifestUri The manifest location.
|
||||
* @param manifestUri The manifest {@link Uri}.
|
||||
*/
|
||||
public void updateManifestUri(String manifestUri) {
|
||||
public void updateManifestUri(Uri manifestUri) {
|
||||
this.manifestUri = manifestUri;
|
||||
}
|
||||
|
||||
|
|
@ -205,7 +204,7 @@ public class ManifestFetcher<T> implements Loader.Callback {
|
|||
loader = new Loader("manifestLoader");
|
||||
}
|
||||
if (!loader.isLoading()) {
|
||||
currentLoadable = new UriLoadable<>(manifestUri, uriDataSource, parser);
|
||||
currentLoadable = new UriLoadable<>(manifestUri, dataSource, parser);
|
||||
currentLoadStartTimestamp = SystemClock.elapsedRealtime();
|
||||
loader.startLoading(currentLoadable, this);
|
||||
notifyManifestRefreshStarted();
|
||||
|
|
@ -227,9 +226,9 @@ public class ManifestFetcher<T> implements Loader.Callback {
|
|||
|
||||
if (manifest instanceof RedirectingManifest) {
|
||||
RedirectingManifest redirectingManifest = (RedirectingManifest) manifest;
|
||||
String nextLocation = redirectingManifest.getNextManifestUri();
|
||||
if (!TextUtils.isEmpty(nextLocation)) {
|
||||
manifestUri = nextLocation;
|
||||
Uri nextUri = redirectingManifest.getNextManifestUri();
|
||||
if (nextUri != null) {
|
||||
manifestUri = nextUri;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -255,12 +254,6 @@ public class ManifestFetcher<T> implements Loader.Callback {
|
|||
notifyManifestError(loadException);
|
||||
}
|
||||
|
||||
/* package */ void onSingleFetchCompleted(T result, long loadStartTimestamp) {
|
||||
manifest = result;
|
||||
manifestLoadStartTimestamp = loadStartTimestamp;
|
||||
manifestLoadCompleteTimestamp = SystemClock.elapsedRealtime();
|
||||
}
|
||||
|
||||
private long getRetryDelayMillis(long errorCount) {
|
||||
return Math.min((errorCount - 1) * 1000, 5000);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue