Add ability to play filtered manifests in PlayerActivity
------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=189796293
This commit is contained in:
parent
dfa31f02e3
commit
764d18f68f
@ -21,9 +21,9 @@ import android.content.pm.PackageManager;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
import android.os.Parcelable;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
@ -58,9 +58,14 @@ import com.google.android.exoplayer2.source.ads.AdsLoader;
|
|||||||
import com.google.android.exoplayer2.source.ads.AdsMediaSource;
|
import com.google.android.exoplayer2.source.ads.AdsMediaSource;
|
||||||
import com.google.android.exoplayer2.source.dash.DashMediaSource;
|
import com.google.android.exoplayer2.source.dash.DashMediaSource;
|
||||||
import com.google.android.exoplayer2.source.dash.DefaultDashChunkSource;
|
import com.google.android.exoplayer2.source.dash.DefaultDashChunkSource;
|
||||||
|
import com.google.android.exoplayer2.source.dash.manifest.FilteringDashManifestParser;
|
||||||
|
import com.google.android.exoplayer2.source.dash.manifest.RepresentationKey;
|
||||||
import com.google.android.exoplayer2.source.hls.HlsMediaSource;
|
import com.google.android.exoplayer2.source.hls.HlsMediaSource;
|
||||||
|
import com.google.android.exoplayer2.source.hls.playlist.FilteringHlsPlaylistParser;
|
||||||
import com.google.android.exoplayer2.source.smoothstreaming.DefaultSsChunkSource;
|
import com.google.android.exoplayer2.source.smoothstreaming.DefaultSsChunkSource;
|
||||||
import com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource;
|
import com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource;
|
||||||
|
import com.google.android.exoplayer2.source.smoothstreaming.manifest.FilteringSsManifestParser;
|
||||||
|
import com.google.android.exoplayer2.source.smoothstreaming.manifest.TrackKey;
|
||||||
import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection;
|
import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection;
|
||||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
||||||
import com.google.android.exoplayer2.trackselection.MappingTrackSelector.MappedTrackInfo;
|
import com.google.android.exoplayer2.trackselection.MappingTrackSelector.MappedTrackInfo;
|
||||||
@ -73,11 +78,13 @@ import com.google.android.exoplayer2.upstream.DataSource;
|
|||||||
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
|
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
|
||||||
import com.google.android.exoplayer2.upstream.HttpDataSource;
|
import com.google.android.exoplayer2.upstream.HttpDataSource;
|
||||||
import com.google.android.exoplayer2.util.EventLogger;
|
import com.google.android.exoplayer2.util.EventLogger;
|
||||||
|
import com.google.android.exoplayer2.util.ParcelableArray;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.net.CookieHandler;
|
import java.net.CookieHandler;
|
||||||
import java.net.CookieManager;
|
import java.net.CookieManager;
|
||||||
import java.net.CookiePolicy;
|
import java.net.CookiePolicy;
|
||||||
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
/** An activity that plays media using {@link SimpleExoPlayer}. */
|
/** An activity that plays media using {@link SimpleExoPlayer}. */
|
||||||
@ -92,11 +99,14 @@ public class PlayerActivity extends Activity
|
|||||||
|
|
||||||
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 EXTENSION_EXTRA = "extension";
|
||||||
|
public static final String MANIFEST_FILTER_EXTRA = "manifest_filter";
|
||||||
|
|
||||||
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 URI_LIST_EXTRA = "uri_list";
|
||||||
public static final String EXTENSION_LIST_EXTRA = "extension_list";
|
public static final String EXTENSION_LIST_EXTRA = "extension_list";
|
||||||
|
public static final String MANIFEST_FILTER_LIST_EXTRA = "manifest_filter_list";
|
||||||
|
|
||||||
public static final String AD_TAG_URI_EXTRA = "ad_tag_uri";
|
public static final String AD_TAG_URI_EXTRA = "ad_tag_uri";
|
||||||
|
|
||||||
// For backwards compatibility.
|
// For backwards compatibility.
|
||||||
@ -318,9 +328,11 @@ public class PlayerActivity extends Activity
|
|||||||
String action = intent.getAction();
|
String action = intent.getAction();
|
||||||
Uri[] uris;
|
Uri[] uris;
|
||||||
String[] extensions;
|
String[] extensions;
|
||||||
|
Parcelable[] manifestFilters;
|
||||||
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)};
|
extensions = new String[] {intent.getStringExtra(EXTENSION_EXTRA)};
|
||||||
|
manifestFilters = new Parcelable[] {intent.getParcelableExtra(MANIFEST_FILTER_EXTRA)};
|
||||||
} else if (ACTION_VIEW_LIST.equals(action)) {
|
} else if (ACTION_VIEW_LIST.equals(action)) {
|
||||||
String[] uriStrings = intent.getStringArrayExtra(URI_LIST_EXTRA);
|
String[] uriStrings = intent.getStringArrayExtra(URI_LIST_EXTRA);
|
||||||
uris = new Uri[uriStrings.length];
|
uris = new Uri[uriStrings.length];
|
||||||
@ -331,6 +343,7 @@ public class PlayerActivity extends Activity
|
|||||||
if (extensions == null) {
|
if (extensions == null) {
|
||||||
extensions = new String[uriStrings.length];
|
extensions = new String[uriStrings.length];
|
||||||
}
|
}
|
||||||
|
manifestFilters = intent.getParcelableArrayExtra(MANIFEST_FILTER_LIST_EXTRA);
|
||||||
} else {
|
} else {
|
||||||
showToast(getString(R.string.unexpected_intent_action, action));
|
showToast(getString(R.string.unexpected_intent_action, action));
|
||||||
return;
|
return;
|
||||||
@ -341,7 +354,9 @@ public class PlayerActivity extends Activity
|
|||||||
}
|
}
|
||||||
MediaSource[] mediaSources = new MediaSource[uris.length];
|
MediaSource[] mediaSources = new MediaSource[uris.length];
|
||||||
for (int i = 0; i < uris.length; i++) {
|
for (int i = 0; i < uris.length; i++) {
|
||||||
mediaSources[i] = buildMediaSource(uris[i], extensions[i]);
|
ParcelableArray<?> manifestFilter = (ParcelableArray<?>) manifestFilters[i];
|
||||||
|
List<?> filter = manifestFilter != null ? manifestFilter.asList() : null;
|
||||||
|
mediaSources[i] = buildMediaSource(uris[i], extensions[i], filter);
|
||||||
}
|
}
|
||||||
mediaSource =
|
mediaSource =
|
||||||
mediaSources.length == 1 ? mediaSources[0] : new ConcatenatingMediaSource(mediaSources);
|
mediaSources.length == 1 ? mediaSources[0] : new ConcatenatingMediaSource(mediaSources);
|
||||||
@ -372,22 +387,32 @@ public class PlayerActivity extends Activity
|
|||||||
updateButtonVisibilities();
|
updateButtonVisibilities();
|
||||||
}
|
}
|
||||||
|
|
||||||
private MediaSource buildMediaSource(Uri uri, String overrideExtension) {
|
private MediaSource buildMediaSource(Uri uri) {
|
||||||
@ContentType int type = TextUtils.isEmpty(overrideExtension) ? Util.inferContentType(uri)
|
return buildMediaSource(uri, null, null);
|
||||||
: Util.inferContentType("." + overrideExtension);
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private MediaSource buildMediaSource(
|
||||||
|
Uri uri, @Nullable String overrideExtension, @Nullable List<?> manifestFilter) {
|
||||||
|
@ContentType int type = Util.inferContentType(uri, overrideExtension);
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case C.TYPE_DASH:
|
case C.TYPE_DASH:
|
||||||
return new DashMediaSource.Factory(
|
return new DashMediaSource.Factory(
|
||||||
new DefaultDashChunkSource.Factory(mediaDataSourceFactory),
|
new DefaultDashChunkSource.Factory(mediaDataSourceFactory),
|
||||||
buildDataSourceFactory(false))
|
buildDataSourceFactory(false))
|
||||||
|
.setManifestParser(
|
||||||
|
new FilteringDashManifestParser((List<RepresentationKey>) manifestFilter))
|
||||||
.createMediaSource(uri);
|
.createMediaSource(uri);
|
||||||
case C.TYPE_SS:
|
case C.TYPE_SS:
|
||||||
return new SsMediaSource.Factory(
|
return new SsMediaSource.Factory(
|
||||||
new DefaultSsChunkSource.Factory(mediaDataSourceFactory),
|
new DefaultSsChunkSource.Factory(mediaDataSourceFactory),
|
||||||
buildDataSourceFactory(false))
|
buildDataSourceFactory(false))
|
||||||
|
.setManifestParser(new FilteringSsManifestParser((List<TrackKey>) manifestFilter))
|
||||||
.createMediaSource(uri);
|
.createMediaSource(uri);
|
||||||
case C.TYPE_HLS:
|
case C.TYPE_HLS:
|
||||||
return new HlsMediaSource.Factory(mediaDataSourceFactory).createMediaSource(uri);
|
return new HlsMediaSource.Factory(mediaDataSourceFactory)
|
||||||
|
.setPlaylistParser(new FilteringHlsPlaylistParser((List<String>) manifestFilter))
|
||||||
|
.createMediaSource(uri);
|
||||||
case C.TYPE_OTHER:
|
case C.TYPE_OTHER:
|
||||||
return new ExtractorMediaSource.Factory(mediaDataSourceFactory).createMediaSource(uri);
|
return new ExtractorMediaSource.Factory(mediaDataSourceFactory).createMediaSource(uri);
|
||||||
default: {
|
default: {
|
||||||
@ -483,7 +508,7 @@ public class PlayerActivity extends Activity
|
|||||||
new AdsMediaSource.MediaSourceFactory() {
|
new AdsMediaSource.MediaSourceFactory() {
|
||||||
@Override
|
@Override
|
||||||
public MediaSource createMediaSource(Uri uri) {
|
public MediaSource createMediaSource(Uri uri) {
|
||||||
return PlayerActivity.this.buildMediaSource(uri, /* overrideExtension= */ null);
|
return PlayerActivity.this.buildMediaSource(uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 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.exoplayer2.util;
|
||||||
|
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/** A {@link android.os.Parcelable} wrapper around an array. */
|
||||||
|
public final class ParcelableArray<V extends Parcelable> implements Parcelable {
|
||||||
|
|
||||||
|
@SuppressWarnings("rawtypes") // V cannot be obtained from static context
|
||||||
|
public static final Creator<ParcelableArray> CREATOR =
|
||||||
|
new Creator<ParcelableArray>() {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public ParcelableArray createFromParcel(Parcel in) {
|
||||||
|
ClassLoader classLoader = ParcelableArray.class.getClassLoader();
|
||||||
|
Parcelable[] elements = in.readParcelableArray(classLoader);
|
||||||
|
return new ParcelableArray(elements);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ParcelableArray[] newArray(int size) {
|
||||||
|
return new ParcelableArray[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private final V[] elements;
|
||||||
|
|
||||||
|
public ParcelableArray(V[] elements) {
|
||||||
|
this.elements = elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns an unmodifiable list containing all elements. */
|
||||||
|
public List<V> asList() {
|
||||||
|
return Collections.unmodifiableList(Arrays.asList(elements));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
|
dest.writeParcelableArray(elements, flags);
|
||||||
|
}
|
||||||
|
}
|
@ -1093,6 +1093,20 @@ public final class Util {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes a best guess to infer the type from a {@link Uri}.
|
||||||
|
*
|
||||||
|
* @param uri The {@link Uri}.
|
||||||
|
* @param overrideExtension If not null, used to infer the type.
|
||||||
|
* @return The content type.
|
||||||
|
*/
|
||||||
|
@C.ContentType
|
||||||
|
public static int inferContentType(Uri uri, String overrideExtension) {
|
||||||
|
return TextUtils.isEmpty(overrideExtension)
|
||||||
|
? inferContentType(uri)
|
||||||
|
: inferContentType("." + overrideExtension);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes a best guess to infer the type from a {@link Uri}.
|
* Makes a best guess to infer the type from a {@link Uri}.
|
||||||
*
|
*
|
||||||
|
@ -16,10 +16,11 @@
|
|||||||
package com.google.android.exoplayer2.source.dash.manifest;
|
package com.google.android.exoplayer2.source.dash.manifest;
|
||||||
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import com.google.android.exoplayer2.upstream.ParsingLoadable.Parser;
|
import com.google.android.exoplayer2.upstream.ParsingLoadable.Parser;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A parser of media presentation description files which includes only the representations
|
* A parser of media presentation description files which includes only the representations
|
||||||
@ -28,16 +29,20 @@ import java.util.ArrayList;
|
|||||||
public final class FilteringDashManifestParser implements Parser<DashManifest> {
|
public final class FilteringDashManifestParser implements Parser<DashManifest> {
|
||||||
|
|
||||||
private final DashManifestParser dashManifestParser;
|
private final DashManifestParser dashManifestParser;
|
||||||
private final ArrayList<RepresentationKey> filter;
|
private final List<RepresentationKey> filter;
|
||||||
|
|
||||||
/** @param filter The representation keys that should be retained in the parsed manifests. */
|
/**
|
||||||
public FilteringDashManifestParser(ArrayList<RepresentationKey> filter) {
|
* @param filter The representation keys that should be retained in the parsed manifests. If null,
|
||||||
|
* all representation are retained.
|
||||||
|
*/
|
||||||
|
public FilteringDashManifestParser(@Nullable List<RepresentationKey> filter) {
|
||||||
this.dashManifestParser = new DashManifestParser();
|
this.dashManifestParser = new DashManifestParser();
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DashManifest parse(Uri uri, InputStream inputStream) throws IOException {
|
public DashManifest parse(Uri uri, InputStream inputStream) throws IOException {
|
||||||
return dashManifestParser.parse(uri, inputStream).copy(filter);
|
DashManifest manifest = dashManifestParser.parse(uri, inputStream);
|
||||||
|
return filter != null ? manifest.copy(filter) : manifest;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
package com.google.android.exoplayer2.source.hls.playlist;
|
package com.google.android.exoplayer2.source.hls.playlist;
|
||||||
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import com.google.android.exoplayer2.upstream.ParsingLoadable.Parser;
|
import com.google.android.exoplayer2.upstream.ParsingLoadable.Parser;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@ -27,8 +28,11 @@ public final class FilteringHlsPlaylistParser implements Parser<HlsPlaylist> {
|
|||||||
private final HlsPlaylistParser hlsPlaylistParser;
|
private final HlsPlaylistParser hlsPlaylistParser;
|
||||||
private final List<String> filter;
|
private final List<String> filter;
|
||||||
|
|
||||||
/** @param filter The urls to renditions that should be retained in the parsed playlists. */
|
/**
|
||||||
public FilteringHlsPlaylistParser(List<String> filter) {
|
* @param filter The urls to renditions that should be retained in the parsed playlists. If null,
|
||||||
|
* all renditions are retained.
|
||||||
|
*/
|
||||||
|
public FilteringHlsPlaylistParser(@Nullable List<String> filter) {
|
||||||
this.hlsPlaylistParser = new HlsPlaylistParser();
|
this.hlsPlaylistParser = new HlsPlaylistParser();
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
}
|
}
|
||||||
@ -37,7 +41,8 @@ public final class FilteringHlsPlaylistParser implements Parser<HlsPlaylist> {
|
|||||||
public HlsPlaylist parse(Uri uri, InputStream inputStream) throws IOException {
|
public HlsPlaylist parse(Uri uri, InputStream inputStream) throws IOException {
|
||||||
HlsPlaylist hlsPlaylist = hlsPlaylistParser.parse(uri, inputStream);
|
HlsPlaylist hlsPlaylist = hlsPlaylistParser.parse(uri, inputStream);
|
||||||
if (hlsPlaylist instanceof HlsMasterPlaylist) {
|
if (hlsPlaylist instanceof HlsMasterPlaylist) {
|
||||||
return ((HlsMasterPlaylist) hlsPlaylist).copy(filter);
|
HlsMasterPlaylist masterPlaylist = (HlsMasterPlaylist) hlsPlaylist;
|
||||||
|
return filter != null ? masterPlaylist.copy(filter) : masterPlaylist;
|
||||||
} else {
|
} else {
|
||||||
return hlsPlaylist;
|
return hlsPlaylist;
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
package com.google.android.exoplayer2.source.smoothstreaming.manifest;
|
package com.google.android.exoplayer2.source.smoothstreaming.manifest;
|
||||||
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import com.google.android.exoplayer2.upstream.ParsingLoadable.Parser;
|
import com.google.android.exoplayer2.upstream.ParsingLoadable.Parser;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@ -29,14 +30,18 @@ public final class FilteringSsManifestParser implements Parser<SsManifest> {
|
|||||||
private final SsManifestParser ssManifestParser;
|
private final SsManifestParser ssManifestParser;
|
||||||
private final List<TrackKey> filter;
|
private final List<TrackKey> filter;
|
||||||
|
|
||||||
/** @param filter The track keys that should be retained in the parsed manifests. */
|
/**
|
||||||
public FilteringSsManifestParser(List<TrackKey> filter) {
|
* @param filter The track keys that should be retained in the parsed manifests. If null, all
|
||||||
|
* tracks are retained.
|
||||||
|
*/
|
||||||
|
public FilteringSsManifestParser(@Nullable List<TrackKey> filter) {
|
||||||
this.ssManifestParser = new SsManifestParser();
|
this.ssManifestParser = new SsManifestParser();
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SsManifest parse(Uri uri, InputStream inputStream) throws IOException {
|
public SsManifest parse(Uri uri, InputStream inputStream) throws IOException {
|
||||||
return ssManifestParser.parse(uri, inputStream).copy(filter);
|
SsManifest manifest = ssManifestParser.parse(uri, inputStream);
|
||||||
|
return filter != null ? manifest.copy(filter) : manifest;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user