diff --git a/demos/main/src/main/assets/media.exolist.json b/demos/main/src/main/assets/media.exolist.json index 7052e7c436..0d26f196c1 100644 --- a/demos/main/src/main/assets/media.exolist.json +++ b/demos/main/src/main/assets/media.exolist.json @@ -578,5 +578,16 @@ "ad_tag_uri": "http://vastsynthesizer.appspot.com/empty-midroll-2" } ] + }, + { + "name": "ABR", + "samples": [ + { + "name": "Random ABR - Google Glass (MP4,H264)", + "uri": "http://www.youtube.com/api/manifest/dash/id/bf5bb2419360daf1/source/youtube?as=fmp4_audio_clear,fmp4_sd_hd_clear&sparams=ip,ipbits,expire,source,id,as&ip=0.0.0.0&ipbits=0&expire=19000000000&signature=51AF5F39AB0CEC3E5497CD9C900EBFEAECCCB5C7.8506521BFC350652163895D4C26DEE124209AA9E&key=ik0", + "extension": "mpd", + "abr_algorithm": "random" + } + ] } ] diff --git a/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java b/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java index a876364a84..4765278fcb 100644 --- a/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java +++ b/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java @@ -68,6 +68,7 @@ import com.google.android.exoplayer2.source.smoothstreaming.manifest.TrackKey; import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; import com.google.android.exoplayer2.trackselection.MappingTrackSelector.MappedTrackInfo; +import com.google.android.exoplayer2.trackselection.RandomTrackSelection; import com.google.android.exoplayer2.trackselection.TrackSelection; import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.ui.DebugTextViewHelper; @@ -91,10 +92,10 @@ public class PlayerActivity extends Activity implements OnClickListener, PlaybackPreparer, PlayerControlView.VisibilityListener { public static final String DRM_SCHEME_EXTRA = "drm_scheme"; - public static final String DRM_LICENSE_URL = "drm_license_url"; - public static final String DRM_KEY_REQUEST_PROPERTIES = "drm_key_request_properties"; - public static final String DRM_MULTI_SESSION = "drm_multi_session"; - public static final String PREFER_EXTENSION_DECODERS = "prefer_extension_decoders"; + public static final String DRM_LICENSE_URL_EXTRA = "drm_license_url"; + public static final String DRM_KEY_REQUEST_PROPERTIES_EXTRA = "drm_key_request_properties"; + public static final String DRM_MULTI_SESSION_EXTRA = "drm_multi_session"; + public static final String PREFER_EXTENSION_DECODERS_EXTRA = "prefer_extension_decoders"; public static final String ACTION_VIEW = "com.google.android.exoplayer.demo.action.VIEW"; public static final String EXTENSION_EXTRA = "extension"; @@ -108,7 +109,11 @@ public class PlayerActivity extends Activity public static final String AD_TAG_URI_EXTRA = "ad_tag_uri"; - // For backwards compatibility. + public static final String ABR_ALGORITHM_EXTRA = "abr_algorithm"; + private static final String ABR_ALGORITHM_DEFAULT = "default"; + private static final String ABR_ALGORITHM_RANDOM = "random"; + + // For backwards compatibility only. private static final String DRM_SCHEME_UUID_EXTRA = "drm_scheme_uuid"; private static final DefaultBandwidthMeter BANDWIDTH_METER = new DefaultBandwidthMeter(); @@ -292,6 +297,7 @@ public class PlayerActivity extends Activity } } else { showToast(getString(R.string.unexpected_intent_action, action)); + finish(); return; } if (Util.maybeRequestReadExternalStoragePermission(this, uris)) { @@ -301,9 +307,10 @@ public class PlayerActivity extends Activity DefaultDrmSessionManager drmSessionManager = null; if (intent.hasExtra(DRM_SCHEME_EXTRA) || intent.hasExtra(DRM_SCHEME_UUID_EXTRA)) { - String drmLicenseUrl = intent.getStringExtra(DRM_LICENSE_URL); - String[] keyRequestPropertiesArray = intent.getStringArrayExtra(DRM_KEY_REQUEST_PROPERTIES); - boolean multiSession = intent.getBooleanExtra(DRM_MULTI_SESSION, false); + String drmLicenseUrl = intent.getStringExtra(DRM_LICENSE_URL_EXTRA); + String[] keyRequestPropertiesArray = + intent.getStringArrayExtra(DRM_KEY_REQUEST_PROPERTIES_EXTRA); + boolean multiSession = intent.getBooleanExtra(DRM_MULTI_SESSION_EXTRA, false); int errorStringId = R.string.error_drm_unknown; if (Util.SDK_INT < 18) { errorStringId = R.string.error_drm_not_supported; @@ -326,11 +333,25 @@ public class PlayerActivity extends Activity } if (drmSessionManager == null) { showToast(errorStringId); + finish(); return; } } - boolean preferExtensionDecoders = intent.getBooleanExtra(PREFER_EXTENSION_DECODERS, false); + TrackSelection.Factory trackSelectionFactory; + String abrAlgorithm = intent.getStringExtra(ABR_ALGORITHM_EXTRA); + if (abrAlgorithm == null || ABR_ALGORITHM_DEFAULT.equals(abrAlgorithm)) { + trackSelectionFactory = new AdaptiveTrackSelection.Factory(BANDWIDTH_METER); + } else if (ABR_ALGORITHM_RANDOM.equals(abrAlgorithm)) { + trackSelectionFactory = new RandomTrackSelection.Factory(); + } else { + showToast(R.string.error_unrecognized_abr_algorithm); + finish(); + return; + } + + boolean preferExtensionDecoders = + intent.getBooleanExtra(PREFER_EXTENSION_DECODERS_EXTRA, false); @DefaultRenderersFactory.ExtensionRendererMode int extensionRendererMode = ((DemoApplication) getApplication()).useExtensionRenderers() ? (preferExtensionDecoders ? DefaultRenderersFactory.EXTENSION_RENDERER_MODE_PREFER @@ -339,10 +360,8 @@ public class PlayerActivity extends Activity DefaultRenderersFactory renderersFactory = new DefaultRenderersFactory(this, extensionRendererMode); - TrackSelection.Factory adaptiveTrackSelectionFactory = - new AdaptiveTrackSelection.Factory(BANDWIDTH_METER); - trackSelector = new DefaultTrackSelector(adaptiveTrackSelectionFactory); - trackSelectionHelper = new TrackSelectionHelper(trackSelector, adaptiveTrackSelectionFactory); + trackSelector = new DefaultTrackSelector(trackSelectionFactory); + trackSelectionHelper = new TrackSelectionHelper(trackSelector, trackSelectionFactory); lastSeenTrackGroupArray = null; player = diff --git a/demos/main/src/main/java/com/google/android/exoplayer2/demo/SampleChooserActivity.java b/demos/main/src/main/java/com/google/android/exoplayer2/demo/SampleChooserActivity.java index 3895ad8e84..5febb949f1 100644 --- a/demos/main/src/main/java/com/google/android/exoplayer2/demo/SampleChooserActivity.java +++ b/demos/main/src/main/java/com/google/android/exoplayer2/demo/SampleChooserActivity.java @@ -45,7 +45,6 @@ import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.UUID; /** * An activity for selecting from a list of samples. @@ -178,13 +177,14 @@ public class SampleChooserActivity extends Activity { String sampleName = null; String uri = null; String extension = null; - UUID drmUuid = null; + String drmScheme = null; String drmLicenseUrl = null; String[] drmKeyRequestProperties = null; boolean drmMultiSession = false; boolean preferExtensionDecoders = false; ArrayList playlistSamples = null; String adTagUri = null; + String abrAlgorithm = null; reader.beginObject(); while (reader.hasNext()) { @@ -201,9 +201,7 @@ public class SampleChooserActivity extends Activity { break; case "drm_scheme": Assertions.checkState(!insidePlaylist, "Invalid attribute on nested item: drm_scheme"); - String drmScheme = reader.nextString(); - drmUuid = Util.getDrmUuid(drmScheme); - Assertions.checkState(drmUuid != null, "Invalid drm_scheme: " + drmScheme); + drmScheme = reader.nextString(); break; case "drm_license_url": Assertions.checkState(!insidePlaylist, @@ -242,21 +240,28 @@ public class SampleChooserActivity extends Activity { case "ad_tag_uri": adTagUri = reader.nextString(); break; + case "abr_algorithm": + Assertions.checkState( + !insidePlaylist, "Invalid attribute on nested item: abr_algorithm"); + abrAlgorithm = reader.nextString(); + break; default: throw new ParserException("Unsupported attribute name: " + name); } } reader.endObject(); - DrmInfo drmInfo = drmUuid == null ? null : new DrmInfo(drmUuid, drmLicenseUrl, - drmKeyRequestProperties, drmMultiSession); + DrmInfo drmInfo = + drmScheme == null + ? null + : new DrmInfo(drmScheme, drmLicenseUrl, drmKeyRequestProperties, drmMultiSession); if (playlistSamples != null) { UriSample[] playlistSamplesArray = playlistSamples.toArray( new UriSample[playlistSamples.size()]); - return new PlaylistSample(sampleName, preferExtensionDecoders, drmInfo, - playlistSamplesArray); + return new PlaylistSample( + sampleName, preferExtensionDecoders, abrAlgorithm, drmInfo, playlistSamplesArray); } else { - return new UriSample(sampleName, preferExtensionDecoders, drmInfo, uri, extension, - adTagUri); + return new UriSample( + sampleName, preferExtensionDecoders, abrAlgorithm, drmInfo, uri, extension, adTagUri); } } @@ -362,14 +367,17 @@ public class SampleChooserActivity extends Activity { } private static final class DrmInfo { - public final UUID drmSchemeUuid; + public final String drmScheme; public final String drmLicenseUrl; public final String[] drmKeyRequestProperties; public final boolean drmMultiSession; - public DrmInfo(UUID drmSchemeUuid, String drmLicenseUrl, - String[] drmKeyRequestProperties, boolean drmMultiSession) { - this.drmSchemeUuid = drmSchemeUuid; + public DrmInfo( + String drmScheme, + String drmLicenseUrl, + String[] drmKeyRequestProperties, + boolean drmMultiSession) { + this.drmScheme = drmScheme; this.drmLicenseUrl = drmLicenseUrl; this.drmKeyRequestProperties = drmKeyRequestProperties; this.drmMultiSession = drmMultiSession; @@ -377,31 +385,34 @@ public class SampleChooserActivity extends Activity { public void updateIntent(Intent intent) { Assertions.checkNotNull(intent); - intent.putExtra(PlayerActivity.DRM_SCHEME_EXTRA, drmSchemeUuid.toString()); - intent.putExtra(PlayerActivity.DRM_LICENSE_URL, drmLicenseUrl); - intent.putExtra(PlayerActivity.DRM_KEY_REQUEST_PROPERTIES, drmKeyRequestProperties); - intent.putExtra(PlayerActivity.DRM_MULTI_SESSION, drmMultiSession); + intent.putExtra(PlayerActivity.DRM_SCHEME_EXTRA, drmScheme); + intent.putExtra(PlayerActivity.DRM_LICENSE_URL_EXTRA, drmLicenseUrl); + intent.putExtra(PlayerActivity.DRM_KEY_REQUEST_PROPERTIES_EXTRA, drmKeyRequestProperties); + intent.putExtra(PlayerActivity.DRM_MULTI_SESSION_EXTRA, drmMultiSession); } } private abstract static class Sample { public final String name; public final boolean preferExtensionDecoders; + public final String abrAlgorithm; public final DrmInfo drmInfo; - public Sample(String name, boolean preferExtensionDecoders, DrmInfo drmInfo) { + public Sample( + String name, boolean preferExtensionDecoders, String abrAlgorithm, DrmInfo drmInfo) { this.name = name; this.preferExtensionDecoders = preferExtensionDecoders; + this.abrAlgorithm = abrAlgorithm; this.drmInfo = drmInfo; } public Intent buildIntent(Context context) { Intent intent = new Intent(context, PlayerActivity.class); - intent.putExtra(PlayerActivity.PREFER_EXTENSION_DECODERS, preferExtensionDecoders); + intent.putExtra(PlayerActivity.PREFER_EXTENSION_DECODERS_EXTRA, preferExtensionDecoders); + intent.putExtra(PlayerActivity.ABR_ALGORITHM_EXTRA, abrAlgorithm); if (drmInfo != null) { drmInfo.updateIntent(intent); } - return intent; } @@ -413,9 +424,15 @@ public class SampleChooserActivity extends Activity { public final String extension; public final String adTagUri; - public UriSample(String name, boolean preferExtensionDecoders, DrmInfo drmInfo, String uri, - String extension, String adTagUri) { - super(name, preferExtensionDecoders, drmInfo); + public UriSample( + String name, + boolean preferExtensionDecoders, + String abrAlgorithm, + DrmInfo drmInfo, + String uri, + String extension, + String adTagUri) { + super(name, preferExtensionDecoders, abrAlgorithm, drmInfo); this.uri = uri; this.extension = extension; this.adTagUri = adTagUri; @@ -436,9 +453,13 @@ public class SampleChooserActivity extends Activity { public final UriSample[] children; - public PlaylistSample(String name, boolean preferExtensionDecoders, DrmInfo drmInfo, + public PlaylistSample( + String name, + boolean preferExtensionDecoders, + String abrAlgorithm, + DrmInfo drmInfo, UriSample... children) { - super(name, preferExtensionDecoders, drmInfo); + super(name, preferExtensionDecoders, abrAlgorithm, drmInfo); this.children = children; } diff --git a/demos/main/src/main/java/com/google/android/exoplayer2/demo/TrackSelectionHelper.java b/demos/main/src/main/java/com/google/android/exoplayer2/demo/TrackSelectionHelper.java index 5fcc0cd90b..89b008dbfe 100644 --- a/demos/main/src/main/java/com/google/android/exoplayer2/demo/TrackSelectionHelper.java +++ b/demos/main/src/main/java/com/google/android/exoplayer2/demo/TrackSelectionHelper.java @@ -31,9 +31,7 @@ import com.google.android.exoplayer2.source.TrackGroup; import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.SelectionOverride; -import com.google.android.exoplayer2.trackselection.FixedTrackSelection; import com.google.android.exoplayer2.trackselection.MappingTrackSelector.MappedTrackInfo; -import com.google.android.exoplayer2.trackselection.RandomTrackSelection; import com.google.android.exoplayer2.trackselection.TrackSelection; import java.util.Arrays; @@ -43,11 +41,8 @@ import java.util.Arrays; /* package */ final class TrackSelectionHelper implements View.OnClickListener, DialogInterface.OnClickListener { - private static final TrackSelection.Factory FIXED_FACTORY = new FixedTrackSelection.Factory(); - private static final TrackSelection.Factory RANDOM_FACTORY = new RandomTrackSelection.Factory(); - private final DefaultTrackSelector selector; - private final TrackSelection.Factory adaptiveTrackSelectionFactory; + private final TrackSelection.Factory trackSelectionFactory; private MappedTrackInfo trackInfo; private int rendererIndex; @@ -58,18 +53,16 @@ import java.util.Arrays; private CheckedTextView disableView; private CheckedTextView defaultView; - private CheckedTextView enableRandomAdaptationView; private CheckedTextView[][] trackViews; /** * @param selector The track selector. - * @param adaptiveTrackSelectionFactory A factory for adaptive {@link TrackSelection}s, or null if - * the selection helper should not support adaptive tracks. + * @param trackSelectionFactory A factory for overriding {@link TrackSelection}s. */ public TrackSelectionHelper( - DefaultTrackSelector selector, TrackSelection.Factory adaptiveTrackSelectionFactory) { + DefaultTrackSelector selector, TrackSelection.Factory trackSelectionFactory) { this.selector = selector; - this.adaptiveTrackSelectionFactory = adaptiveTrackSelectionFactory; + this.trackSelectionFactory = trackSelectionFactory; } /** @@ -88,10 +81,10 @@ import java.util.Arrays; trackGroups = trackInfo.getTrackGroups(rendererIndex); trackGroupsAdaptive = new boolean[trackGroups.length]; for (int i = 0; i < trackGroups.length; i++) { - trackGroupsAdaptive[i] = adaptiveTrackSelectionFactory != null - && trackInfo.getAdaptiveSupport(rendererIndex, i, false) - != RendererCapabilities.ADAPTIVE_NOT_SUPPORTED - && trackGroups.get(i).length > 1; + trackGroupsAdaptive[i] = + trackInfo.getAdaptiveSupport(rendererIndex, i, false) + != RendererCapabilities.ADAPTIVE_NOT_SUPPORTED + && trackGroups.get(i).length > 1; } isDisabled = selector.getRendererDisabled(rendererIndex); override = selector.getSelectionOverride(rendererIndex, trackGroups); @@ -136,12 +129,10 @@ import java.util.Arrays; root.addView(defaultView); // Per-track views. - boolean haveAdaptiveTracks = false; trackViews = new CheckedTextView[trackGroups.length][]; for (int groupIndex = 0; groupIndex < trackGroups.length; groupIndex++) { TrackGroup group = trackGroups.get(groupIndex); boolean groupIsAdaptive = trackGroupsAdaptive[groupIndex]; - haveAdaptiveTracks |= groupIsAdaptive; trackViews[groupIndex] = new CheckedTextView[group.length]; for (int trackIndex = 0; trackIndex < group.length; trackIndex++) { if (trackIndex == 0) { @@ -167,17 +158,6 @@ import java.util.Arrays; } } - if (haveAdaptiveTracks) { - // View for using random adaptation. - enableRandomAdaptationView = (CheckedTextView) inflater.inflate( - android.R.layout.simple_list_item_multiple_choice, root, false); - enableRandomAdaptationView.setBackgroundResource(selectableItemBackgroundResourceId); - enableRandomAdaptationView.setText(R.string.enable_random_adaptation); - enableRandomAdaptationView.setOnClickListener(this); - root.addView(inflater.inflate(R.layout.list_divider, root, false)); - root.addView(enableRandomAdaptationView); - } - updateViews(); return view; } @@ -191,15 +171,6 @@ import java.util.Arrays; && override.containsTrack(j)); } } - if (enableRandomAdaptationView != null) { - boolean enableView = !isDisabled && override != null && override.length > 1; - enableRandomAdaptationView.setEnabled(enableView); - enableRandomAdaptationView.setFocusable(enableView); - if (enableView) { - enableRandomAdaptationView.setChecked(!isDisabled - && override.factory instanceof RandomTrackSelection.Factory); - } - } } // DialogInterface.OnClickListener @@ -224,8 +195,6 @@ import java.util.Arrays; } else if (view == defaultView) { isDisabled = false; override = null; - } else if (view == enableRandomAdaptationView) { - setOverride(override.groupIndex, override.tracks, !enableRandomAdaptationView.isChecked()); } else { isDisabled = false; @SuppressWarnings("unchecked") @@ -234,7 +203,7 @@ import java.util.Arrays; int trackIndex = tag.second; if (!trackGroupsAdaptive[groupIndex] || override == null || override.groupIndex != groupIndex) { - override = new SelectionOverride(FIXED_FACTORY, groupIndex, trackIndex); + setOverride(groupIndex, trackIndex); } else { // The group being modified is adaptive and we already have a non-null override. boolean isEnabled = ((CheckedTextView) view).isChecked(); @@ -246,13 +215,11 @@ import java.util.Arrays; override = null; isDisabled = true; } else { - setOverride(groupIndex, getTracksRemoving(override, trackIndex), - enableRandomAdaptationView.isChecked()); + setOverride(groupIndex, getTracksRemoving(override, trackIndex)); } } else { // Add the track to the override. - setOverride(groupIndex, getTracksAdding(override, trackIndex), - enableRandomAdaptationView.isChecked()); + setOverride(groupIndex, getTracksAdding(override, trackIndex)); } } } @@ -260,10 +227,8 @@ import java.util.Arrays; updateViews(); } - private void setOverride(int group, int[] tracks, boolean enableRandomAdaptation) { - TrackSelection.Factory factory = tracks.length == 1 ? FIXED_FACTORY - : (enableRandomAdaptation ? RANDOM_FACTORY : adaptiveTrackSelectionFactory); - override = new SelectionOverride(factory, group, tracks); + private void setOverride(int group, int... tracks) { + override = new SelectionOverride(trackSelectionFactory, group, tracks); } // Track array manipulation. diff --git a/demos/main/src/main/res/values/strings.xml b/demos/main/src/main/res/values/strings.xml index 43b17052fb..42ef358a1a 100644 --- a/demos/main/src/main/res/values/strings.xml +++ b/demos/main/src/main/res/values/strings.xml @@ -29,7 +29,7 @@ Unexpected intent action: %1$s - Enable random adaptation + Unrecognized ABR algorithm Protected content not supported on API levels below 18