Commit f0f25aef by olly Committed by Oliver Woodman

Support playlists in exolist.json.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=126622342
parent 9f017d71
...@@ -330,5 +330,32 @@ ...@@ -330,5 +330,32 @@
"uri": "http://vod.leasewebcdn.com/bbb.flv?ri=1024&rs=150&start=0" "uri": "http://vod.leasewebcdn.com/bbb.flv?ri=1024&rs=150&start=0"
} }
] ]
},
{
"name": "Playlists",
"samples": [
{
"name": "Cats and dogs",
"playlist": [
{
"uri": "http://html5demos.com/assets/dizzy.mp4"
},
{
"uri": "http://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv"
}
]
},
{
"name": "Audio then Video",
"playlist": [
{
"uri": "https://storage.googleapis.com/exoplayer-test-media-1/gen-3/screens/dash-vod-single-segment/audio-141.mp4"
},
{
"uri": "http://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv"
}
]
}
]
} }
] ]
...@@ -87,15 +87,18 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback, ...@@ -87,15 +87,18 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
ExoPlayer.EventListener, SimpleExoPlayer.VideoListener, SimpleExoPlayer.CaptionListener, ExoPlayer.EventListener, SimpleExoPlayer.VideoListener, SimpleExoPlayer.CaptionListener,
SimpleExoPlayer.Id3MetadataListener, DefaultTrackSelector.EventListener { SimpleExoPlayer.Id3MetadataListener, DefaultTrackSelector.EventListener {
public static final String URIS_LIST_EXTRA = "uris";
public static final String CONTENT_EXT_EXTRA = "extension";
public static final String DRM_SCHEME_UUID_EXTRA = "drm_scheme_uuid"; public static final String DRM_SCHEME_UUID_EXTRA = "drm_scheme_uuid";
public static final String DRM_CONTENT_ID_EXTRA = "drm_content_id"; public static final String DRM_CONTENT_ID_EXTRA = "drm_content_id";
public static final String DRM_PROVIDER_EXTRA = "drm_provider"; public static final String DRM_PROVIDER_EXTRA = "drm_provider";
public static final String PREFER_EXTENSION_DECODERS = "prefer_extension_decoders"; public static final String PREFER_EXTENSION_DECODERS = "prefer_extension_decoders";
public static final String ACTION_VIEW = "com.google.android.exoplayer.demo.action.VIEW"; public static final String ACTION_VIEW = "com.google.android.exoplayer.demo.action.VIEW";
public static final String EXTENSION_EXTRA = "extension";
public static final String ACTION_VIEW_LIST = public static final String ACTION_VIEW_LIST =
"com.google.android.exoplayer.demo.action.VIEW_LIST"; "com.google.android.exoplayer.demo.action.VIEW_LIST";
public static final String URI_LIST_EXTRA = "uri_list";
public static final String EXTENSION_LIST_EXTRA = "extension_list";
private static final String TAG = "PlayerActivity"; private static final String TAG = "PlayerActivity";
...@@ -285,14 +288,20 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback, ...@@ -285,14 +288,20 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
if (playerNeedsSource) { if (playerNeedsSource) {
String action = intent.getAction(); String action = intent.getAction();
Uri[] uris; Uri[] uris;
String[] extensions;
if (ACTION_VIEW.equals(action)) { if (ACTION_VIEW.equals(action)) {
uris = new Uri[] {intent.getData()}; uris = new Uri[] {intent.getData()};
extensions = new String[] {intent.getStringExtra(EXTENSION_EXTRA)};
} else if (ACTION_VIEW_LIST.equals(action)) { } else if (ACTION_VIEW_LIST.equals(action)) {
String[] uriStrings = intent.getStringArrayExtra(URIS_LIST_EXTRA); String[] uriStrings = intent.getStringArrayExtra(URI_LIST_EXTRA);
uris = new Uri[uriStrings.length]; uris = new Uri[uriStrings.length];
for (int i = 0; i < uriStrings.length; i++) { for (int i = 0; i < uriStrings.length; i++) {
uris[i] = Uri.parse(uriStrings[i]); uris[i] = Uri.parse(uriStrings[i]);
} }
extensions = intent.getStringArrayExtra(EXTENSION_LIST_EXTRA);
if (extensions == null) {
extensions = new String[uriStrings.length];
}
} else { } else {
Log.w(TAG, "Unexpected intent action: " + action); Log.w(TAG, "Unexpected intent action: " + action);
return; return;
...@@ -305,7 +314,7 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback, ...@@ -305,7 +314,7 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
UriSampleSourceProvider[] providers = new UriSampleSourceProvider[uris.length]; UriSampleSourceProvider[] providers = new UriSampleSourceProvider[uris.length];
for (int i = 0; i < uris.length; i++) { for (int i = 0; i < uris.length; i++) {
providers[i] = new UriSampleSourceProvider(player.getBandwidthMeter(), dataSourceFactory, providers[i] = new UriSampleSourceProvider(player.getBandwidthMeter(), dataSourceFactory,
uris[i], intent.getStringExtra(CONTENT_EXT_EXTRA), mainHandler, eventLogger); uris[i], extensions[i], mainHandler, eventLogger);
} }
SampleSourceProvider sourceProvider = providers.length == 1 ? providers[0] SampleSourceProvider sourceProvider = providers.length == 1 ? providers[0]
: new ConcatenatingSampleSourceProvider(providers); : new ConcatenatingSampleSourceProvider(providers);
......
...@@ -21,6 +21,7 @@ import com.google.android.exoplayer.upstream.DataSource; ...@@ -21,6 +21,7 @@ import com.google.android.exoplayer.upstream.DataSource;
import com.google.android.exoplayer.upstream.DataSourceInputStream; 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.upstream.DefaultDataSource; import com.google.android.exoplayer.upstream.DefaultDataSource;
import com.google.android.exoplayer.util.Assertions;
import com.google.android.exoplayer.util.Util; import com.google.android.exoplayer.util.Util;
import android.app.Activity; import android.app.Activity;
...@@ -90,15 +91,7 @@ public class SampleChooserActivity extends Activity { ...@@ -90,15 +91,7 @@ public class SampleChooserActivity extends Activity {
} }
private void onSampleSelected(Sample sample) { private void onSampleSelected(Sample sample) {
Intent intent = new Intent(this, PlayerActivity.class) startActivity(sample.buildIntent(this));
.setAction(PlayerActivity.ACTION_VIEW)
.setData(Uri.parse(sample.uri))
.putExtra(PlayerActivity.CONTENT_EXT_EXTRA, sample.extension)
.putExtra(PlayerActivity.DRM_SCHEME_UUID_EXTRA, sample.drmSchemeUuid)
.putExtra(PlayerActivity.DRM_CONTENT_ID_EXTRA, sample.drmContentId)
.putExtra(PlayerActivity.DRM_PROVIDER_EXTRA, sample.drmProvider)
.putExtra(PlayerActivity.PREFER_EXTENSION_DECODERS, sample.preferExtensionDecoders);
startActivity(intent);
} }
private final class SampleListLoader extends AsyncTask<String, Void, List<SampleGroup>> { private final class SampleListLoader extends AsyncTask<String, Void, List<SampleGroup>> {
...@@ -116,7 +109,7 @@ public class SampleChooserActivity extends Activity { ...@@ -116,7 +109,7 @@ public class SampleChooserActivity extends Activity {
InputStream inputStream = new DataSourceInputStream(dataSource, dataSpec); InputStream inputStream = new DataSourceInputStream(dataSource, dataSpec);
try { try {
readSampleGroups(new JsonReader(new InputStreamReader(inputStream, "UTF-8")), result); readSampleGroups(new JsonReader(new InputStreamReader(inputStream, "UTF-8")), result);
} catch (IOException e) { } catch (Exception e) {
Log.e(TAG, "Error loading sample list: " + uri, e); Log.e(TAG, "Error loading sample list: " + uri, e);
sawError = true; sawError = true;
} finally { } finally {
...@@ -152,7 +145,7 @@ public class SampleChooserActivity extends Activity { ...@@ -152,7 +145,7 @@ public class SampleChooserActivity extends Activity {
case "samples": case "samples":
reader.beginArray(); reader.beginArray();
while (reader.hasNext()) { while (reader.hasNext()) {
samples.add(readSample(reader)); samples.add(readEntry(reader, false));
} }
reader.endArray(); reader.endArray();
break; break;
...@@ -164,7 +157,7 @@ public class SampleChooserActivity extends Activity { ...@@ -164,7 +157,7 @@ public class SampleChooserActivity extends Activity {
group.samples.addAll(samples); group.samples.addAll(samples);
} }
private Sample readSample(JsonReader reader) throws IOException { private Sample readEntry(JsonReader reader, boolean insidePlaylist) throws IOException {
String sampleName = null; String sampleName = null;
String uri = null; String uri = null;
String extension = null; String extension = null;
...@@ -172,10 +165,12 @@ public class SampleChooserActivity extends Activity { ...@@ -172,10 +165,12 @@ public class SampleChooserActivity extends Activity {
String drmContentId = null; String drmContentId = null;
String drmProvider = null; String drmProvider = null;
boolean preferExtensionDecoders = false; boolean preferExtensionDecoders = false;
ArrayList<UriSample> playlistSamples = null;
reader.beginObject(); reader.beginObject();
while (reader.hasNext()) { while (reader.hasNext()) {
switch (reader.nextName()) { String name = reader.nextName();
switch (name) {
case "name": case "name":
sampleName = reader.nextString(); sampleName = reader.nextString();
break; break;
...@@ -194,15 +189,30 @@ public class SampleChooserActivity extends Activity { ...@@ -194,15 +189,30 @@ public class SampleChooserActivity extends Activity {
case "prefer_extension_decoders": case "prefer_extension_decoders":
preferExtensionDecoders = reader.nextBoolean(); preferExtensionDecoders = reader.nextBoolean();
break; break;
case "playlist":
Assertions.checkState(!insidePlaylist, "Nested playlists are invalid");
playlistSamples = new ArrayList<>();
reader.beginArray();
while (reader.hasNext()) {
playlistSamples.add((UriSample) readEntry(reader, true));
}
reader.endArray();
break;
default:
throw new ParserException("Unsupported attribute name: " + name);
} }
} }
reader.endObject(); reader.endObject();
if (sampleName == null || uri == null) { if (playlistSamples != null) {
throw new ParserException("Invalid sample (name or uri missing)"); UriSample[] playlistSamplesArray = playlistSamples.toArray(
new UriSample[playlistSamples.size()]);
return new PlaylistSample(sampleName, drmUuid, drmContentId, drmProvider,
preferExtensionDecoders, playlistSamplesArray);
} else {
return new UriSample(sampleName, drmUuid, drmContentId, drmProvider,
preferExtensionDecoders, uri, extension);
} }
return new Sample(sampleName, uri, extension, drmUuid, drmContentId, drmProvider,
preferExtensionDecoders);
} }
private SampleGroup getGroup(String groupName, List<SampleGroup> groups) { private SampleGroup getGroup(String groupName, List<SampleGroup> groups) {
...@@ -317,27 +327,87 @@ public class SampleChooserActivity extends Activity { ...@@ -317,27 +327,87 @@ public class SampleChooserActivity extends Activity {
} }
private static class Sample { private abstract static class Sample {
public final String name; public final String name;
public final String uri; public final boolean preferExtensionDecoders;
public final String extension;
// TODO: DRM properties should be specified on UriSample only. This requires changes to
// PlayerActivity and beyond to be able to handle playlists containing multiple DRM protected
// items that have different DRM properties.
public final UUID drmSchemeUuid; public final UUID drmSchemeUuid;
public final String drmContentId; public final String drmContentId;
public final String drmProvider; public final String drmProvider;
public final boolean preferExtensionDecoders;
public Sample(String name, String uri, String extension, UUID drmSchemeUuid, public Sample(String name, UUID drmSchemeUuid, String drmContentId, String drmProvider,
String drmContentId, String drmProvider, boolean preferExtensionDecoders) { boolean preferExtensionDecoders) {
this.name = name; this.name = name;
this.uri = uri;
this.extension = extension;
this.drmSchemeUuid = drmSchemeUuid; this.drmSchemeUuid = drmSchemeUuid;
this.drmContentId = drmContentId; this.drmContentId = drmContentId;
this.drmProvider = drmProvider; this.drmProvider = drmProvider;
this.preferExtensionDecoders = preferExtensionDecoders; this.preferExtensionDecoders = preferExtensionDecoders;
} }
public abstract Intent buildIntent(Context context);
}
private static final class UriSample extends Sample {
public final String uri;
public final String extension;
public UriSample(String name, UUID drmSchemeUuid, String drmContentId, String drmProvider,
boolean preferExtensionDecoders, String uri, String extension) {
super(name, drmSchemeUuid, drmContentId, drmProvider, preferExtensionDecoders);
this.uri = uri;
this.extension = extension;
}
@Override
public Intent buildIntent(Context context) {
return new Intent(context, PlayerActivity.class)
.setAction(PlayerActivity.ACTION_VIEW)
.putExtra(PlayerActivity.DRM_SCHEME_UUID_EXTRA, drmSchemeUuid)
.putExtra(PlayerActivity.DRM_CONTENT_ID_EXTRA, drmContentId)
.putExtra(PlayerActivity.DRM_PROVIDER_EXTRA, drmProvider)
.putExtra(PlayerActivity.PREFER_EXTENSION_DECODERS, preferExtensionDecoders)
.setData(Uri.parse(uri))
.putExtra(PlayerActivity.EXTENSION_EXTRA, extension)
.setAction(PlayerActivity.ACTION_VIEW);
}
}
private static final class PlaylistSample extends Sample {
public final UriSample[] children;
public PlaylistSample(String name, UUID drmSchemeUuid, String drmContentId, String drmProvider,
boolean preferExtensionDecoders, UriSample... children) {
super(name, drmSchemeUuid, drmContentId, drmProvider, preferExtensionDecoders);
this.children = children;
}
@Override
public Intent buildIntent(Context context) {
String[] uris = new String[children.length];
String[] extensions = new String[children.length];
for (int i = 0; i < children.length; i++) {
uris[i] = children[i].uri;
extensions[i] = children[i].extension;
}
return new Intent(context, PlayerActivity.class)
.setAction(PlayerActivity.ACTION_VIEW)
.putExtra(PlayerActivity.DRM_SCHEME_UUID_EXTRA, drmSchemeUuid)
.putExtra(PlayerActivity.DRM_CONTENT_ID_EXTRA, drmContentId)
.putExtra(PlayerActivity.DRM_PROVIDER_EXTRA, drmProvider)
.putExtra(PlayerActivity.PREFER_EXTENSION_DECODERS, preferExtensionDecoders)
.putExtra(PlayerActivity.URI_LIST_EXTRA, uris)
.putExtra(PlayerActivity.EXTENSION_LIST_EXTRA, extensions)
.setAction(PlayerActivity.ACTION_VIEW_LIST);
}
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment