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