Commit 1323dd63 by bachinger Committed by Ian Baker

Remove Sample from SampleChooserActivity

Unmarshal from json to MediaItem instead of Sample. Further the playlist
of MediaItems is converted to Intent extras which are read by the
PlayerActivity.

PiperOrigin-RevId: 308141231
parent 7c3b461b
......@@ -15,6 +15,8 @@
*/
package com.google.android.exoplayer2.demo;
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
import android.content.Context;
import android.content.DialogInterface;
import android.net.Uri;
......@@ -23,8 +25,8 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.FragmentManager;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.RenderersFactory;
import com.google.android.exoplayer2.demo.Sample.UriSample;
import com.google.android.exoplayer2.offline.Download;
import com.google.android.exoplayer2.offline.DownloadCursor;
import com.google.android.exoplayer2.offline.DownloadHelper;
......@@ -82,8 +84,8 @@ public class DownloadTracker {
listeners.remove(listener);
}
public boolean isDownloaded(Uri uri) {
Download download = downloads.get(uri);
public boolean isDownloaded(MediaItem mediaItem) {
Download download = downloads.get(checkNotNull(mediaItem.playbackProperties).sourceUri);
return download != null && download.state != Download.STATE_FAILED;
}
......@@ -93,8 +95,8 @@ public class DownloadTracker {
}
public void toggleDownload(
FragmentManager fragmentManager, UriSample sample, RenderersFactory renderersFactory) {
Download download = downloads.get(sample.uri);
FragmentManager fragmentManager, MediaItem mediaItem, RenderersFactory renderersFactory) {
Download download = downloads.get(checkNotNull(mediaItem.playbackProperties).sourceUri);
if (download != null) {
DownloadService.sendRemoveDownload(
context, DemoDownloadService.class, download.request.id, /* foreground= */ false);
......@@ -104,9 +106,7 @@ public class DownloadTracker {
}
startDownloadDialogHelper =
new StartDownloadDialogHelper(
fragmentManager,
getDownloadHelper(sample.uri, sample.extension, renderersFactory),
sample);
fragmentManager, getDownloadHelper(mediaItem, renderersFactory), mediaItem);
}
}
......@@ -121,18 +121,24 @@ public class DownloadTracker {
}
}
private DownloadHelper getDownloadHelper(
Uri uri, String extension, RenderersFactory renderersFactory) {
int type = Util.inferContentType(uri, extension);
private DownloadHelper getDownloadHelper(MediaItem mediaItem, RenderersFactory renderersFactory) {
MediaItem.PlaybackProperties playbackProperties = checkNotNull(mediaItem.playbackProperties);
@C.ContentType
int type =
Util.inferContentTypeWithMimeType(
playbackProperties.sourceUri, playbackProperties.mimeType);
switch (type) {
case C.TYPE_DASH:
return DownloadHelper.forDash(context, uri, dataSourceFactory, renderersFactory);
return DownloadHelper.forDash(
context, playbackProperties.sourceUri, dataSourceFactory, renderersFactory);
case C.TYPE_SS:
return DownloadHelper.forSmoothStreaming(context, uri, dataSourceFactory, renderersFactory);
return DownloadHelper.forSmoothStreaming(
context, playbackProperties.sourceUri, dataSourceFactory, renderersFactory);
case C.TYPE_HLS:
return DownloadHelper.forHls(context, uri, dataSourceFactory, renderersFactory);
return DownloadHelper.forHls(
context, playbackProperties.sourceUri, dataSourceFactory, renderersFactory);
case C.TYPE_OTHER:
return DownloadHelper.forProgressive(context, uri);
return DownloadHelper.forProgressive(context, playbackProperties.sourceUri);
default:
throw new IllegalStateException("Unsupported type: " + type);
}
......@@ -166,16 +172,16 @@ public class DownloadTracker {
private final FragmentManager fragmentManager;
private final DownloadHelper downloadHelper;
private final UriSample sample;
private final MediaItem mediaItem;
private TrackSelectionDialog trackSelectionDialog;
private MappedTrackInfo mappedTrackInfo;
public StartDownloadDialogHelper(
FragmentManager fragmentManager, DownloadHelper downloadHelper, UriSample sample) {
FragmentManager fragmentManager, DownloadHelper downloadHelper, MediaItem mediaItem) {
this.fragmentManager = fragmentManager;
this.downloadHelper = downloadHelper;
this.sample = sample;
this.mediaItem = mediaItem;
downloadHelper.prepare(this);
}
......@@ -270,7 +276,8 @@ public class DownloadTracker {
}
private DownloadRequest buildDownloadRequest() {
return downloadHelper.getDownloadRequest(Util.getUtf8Bytes(sample.name));
return downloadHelper.getDownloadRequest(
Util.getUtf8Bytes(checkNotNull(mediaItem.mediaMetadata.title)));
}
}
}
......@@ -16,6 +16,7 @@
package com.google.android.exoplayer2.demo;
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
import static com.google.android.exoplayer2.util.Assertions.checkState;
import android.content.Intent;
import android.net.Uri;
......@@ -23,6 +24,7 @@ import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.offline.DownloadRequest;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.Util;
import java.util.ArrayList;
......@@ -32,9 +34,24 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
/** Util to read from an intent. */
/** Util to read from and populate an intent. */
public class IntentUtil {
/** A tag to hold custom playback configuration attributes. */
public static class Tag {
/** Whether the stream is a live stream. */
public final boolean isLive;
/** The spherical stereo mode or null. */
@Nullable public final String sphericalStereoMode;
/** Creates an instance. */
public Tag(boolean isLive, @Nullable String sphericalStereoMode) {
this.isLive = isLive;
this.sphericalStereoMode = sphericalStereoMode;
}
}
// Actions.
public static final String ACTION_VIEW = "com.google.android.exoplayer.demo.action.VIEW";
......@@ -57,8 +74,10 @@ public class IntentUtil {
// Media item configuration extras.
public static final String URI_EXTRA = "uri";
public static final String EXTENSION_EXTRA = "extension";
public static final String IS_LIVE_EXTRA = "is_live";
public static final String MIME_TYPE_EXTRA = "mime_type";
// For backwards compatibility only.
public static final String EXTENSION_EXTRA = "extension";
public static final String DRM_SCHEME_EXTRA = "drm_scheme";
public static final String DRM_LICENSE_URL_EXTRA = "drm_license_url";
......@@ -100,15 +119,56 @@ public class IntentUtil {
return mediaItems;
}
/** Populates the intent with the given list of {@link MediaItem media items}. */
public static void addToIntent(List<MediaItem> mediaItems, Intent intent) {
Assertions.checkArgument(!mediaItems.isEmpty());
if (mediaItems.size() == 1) {
MediaItem.PlaybackProperties playbackProperties =
checkNotNull(mediaItems.get(0).playbackProperties);
intent.setAction(IntentUtil.ACTION_VIEW).setData(playbackProperties.sourceUri);
addPlaybackPropertiesToIntent(playbackProperties, intent, /* extrasKeySuffix= */ "");
} else {
intent.setAction(IntentUtil.ACTION_VIEW_LIST);
for (int i = 0; i < mediaItems.size(); i++) {
MediaItem.PlaybackProperties playbackProperties =
checkNotNull(mediaItems.get(i).playbackProperties);
intent.putExtra(IntentUtil.URI_EXTRA + ("_" + i), playbackProperties.sourceUri.toString());
addPlaybackPropertiesToIntent(playbackProperties, intent, /* extrasKeySuffix= */ "_" + i);
}
}
}
/** Makes a best guess to infer the MIME type from a {@link Uri} and an optional extension. */
@Nullable
public static String inferAdaptiveStreamMimeType(Uri uri, @Nullable String extension) {
@C.ContentType int contentType = Util.inferContentType(uri, extension);
switch (contentType) {
case C.TYPE_DASH:
return MimeTypes.APPLICATION_MPD;
case C.TYPE_HLS:
return MimeTypes.APPLICATION_M3U8;
case C.TYPE_SS:
return MimeTypes.APPLICATION_SS;
case C.TYPE_OTHER:
default:
return null;
}
}
private static MediaItem createMediaItemFromIntent(
Uri uri, Intent intent, String extrasKeySuffix, @Nullable DownloadRequest downloadRequest) {
String extension = intent.getStringExtra(EXTENSION_EXTRA + extrasKeySuffix);
String mimeType = intent.getStringExtra(MIME_TYPE_EXTRA + extrasKeySuffix);
if (mimeType == null) {
// Try to use extension for backwards compatibility.
String extension = intent.getStringExtra(EXTENSION_EXTRA + extrasKeySuffix);
mimeType = inferAdaptiveStreamMimeType(uri, extension);
}
MediaItem.Builder builder =
new MediaItem.Builder()
.setSourceUri(uri)
.setStreamKeys(downloadRequest != null ? downloadRequest.streamKeys : null)
.setCustomCacheKey(downloadRequest != null ? downloadRequest.customCacheKey : null)
.setMimeType(inferAdaptiveStreamMimeType(uri, extension))
.setMimeType(mimeType)
.setAdTagUri(intent.getStringExtra(AD_TAG_URI_EXTRA + extrasKeySuffix))
.setSubtitles(createSubtitlesFromIntent(intent, extrasKeySuffix));
return populateDrmPropertiesFromIntent(builder, intent, extrasKeySuffix).build();
......@@ -178,19 +238,57 @@ public class IntentUtil {
return new ArrayList<>(trackTypes);
}
@Nullable
private static String inferAdaptiveStreamMimeType(Uri uri, @Nullable String extension) {
@C.ContentType int contentType = Util.inferContentType(uri, extension);
switch (contentType) {
case C.TYPE_DASH:
return MimeTypes.APPLICATION_MPD;
case C.TYPE_HLS:
return MimeTypes.APPLICATION_M3U8;
case C.TYPE_SS:
return MimeTypes.APPLICATION_SS;
case C.TYPE_OTHER:
default:
return null;
private static void addPlaybackPropertiesToIntent(
MediaItem.PlaybackProperties playbackProperties, Intent intent, String extrasKeySuffix) {
boolean isLive = false;
String sphericalStereoMode = null;
if (playbackProperties.tag instanceof Tag) {
Tag tag = (Tag) playbackProperties.tag;
isLive = tag.isLive;
sphericalStereoMode = tag.sphericalStereoMode;
}
intent
.putExtra(MIME_TYPE_EXTRA + extrasKeySuffix, playbackProperties.mimeType)
.putExtra(
AD_TAG_URI_EXTRA + extrasKeySuffix,
playbackProperties.adTagUri != null ? playbackProperties.adTagUri.toString() : null)
.putExtra(IS_LIVE_EXTRA + extrasKeySuffix, isLive)
.putExtra(SPHERICAL_STEREO_MODE_EXTRA, sphericalStereoMode);
if (playbackProperties.drmConfiguration != null) {
addDrmConfigurationToIntent(playbackProperties.drmConfiguration, intent, extrasKeySuffix);
}
if (!playbackProperties.subtitles.isEmpty()) {
checkState(playbackProperties.subtitles.size() == 1);
MediaItem.Subtitle subtitle = playbackProperties.subtitles.get(0);
intent.putExtra(SUBTITLE_URI_EXTRA + extrasKeySuffix, subtitle.uri.toString());
intent.putExtra(SUBTITLE_MIME_TYPE_EXTRA + extrasKeySuffix, subtitle.mimeType);
intent.putExtra(SUBTITLE_LANGUAGE_EXTRA + extrasKeySuffix, subtitle.language);
}
}
private static void addDrmConfigurationToIntent(
MediaItem.DrmConfiguration drmConfiguration, Intent intent, String extrasKeySuffix) {
intent.putExtra(DRM_SCHEME_EXTRA + extrasKeySuffix, drmConfiguration.uuid.toString());
intent.putExtra(
DRM_LICENSE_URL_EXTRA + extrasKeySuffix,
checkNotNull(drmConfiguration.licenseUri).toString());
intent.putExtra(DRM_MULTI_SESSION_EXTRA + extrasKeySuffix, drmConfiguration.multiSession);
String[] drmKeyRequestProperties = new String[drmConfiguration.requestHeaders.size() * 2];
int index = 0;
for (Map.Entry<String, String> entry : drmConfiguration.requestHeaders.entrySet()) {
drmKeyRequestProperties[index++] = entry.getKey();
drmKeyRequestProperties[index++] = entry.getValue();
}
intent.putExtra(DRM_KEY_REQUEST_PROPERTIES_EXTRA + extrasKeySuffix, drmKeyRequestProperties);
ArrayList<String> typeStrings = new ArrayList<>();
for (int type : drmConfiguration.sessionForClearTypes) {
// Only audio and video are supported.
Assertions.checkState(type == C.TRACK_TYPE_AUDIO || type == C.TRACK_TYPE_VIDEO);
typeStrings.add(type == C.TRACK_TYPE_AUDIO ? "audio" : "video");
}
intent.putExtra(
DRM_SESSION_FOR_CLEAR_TYPES_EXTRA + extrasKeySuffix, typeStrings.toArray(new String[0]));
}
}
/*
* Copyright (C) 2019 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.demo;
import android.content.Intent;
import android.net.Uri;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Util;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.UUID;
/* package */ abstract class Sample {
public static final class UriSample extends Sample {
public final Uri uri;
public final String extension;
public final boolean isLive;
public final DrmInfo drmInfo;
public final Uri adTagUri;
@Nullable public final String sphericalStereoMode;
@Nullable SubtitleInfo subtitleInfo;
public UriSample(
String name,
Uri uri,
String extension,
boolean isLive,
DrmInfo drmInfo,
Uri adTagUri,
@Nullable String sphericalStereoMode,
@Nullable SubtitleInfo subtitleInfo) {
super(name);
this.uri = uri;
this.extension = extension;
this.isLive = isLive;
this.drmInfo = drmInfo;
this.adTagUri = adTagUri;
this.sphericalStereoMode = sphericalStereoMode;
this.subtitleInfo = subtitleInfo;
}
@Override
public void addToIntent(Intent intent) {
intent.setAction(IntentUtil.ACTION_VIEW).setData(uri);
intent.putExtra(IntentUtil.IS_LIVE_EXTRA, isLive);
intent.putExtra(IntentUtil.SPHERICAL_STEREO_MODE_EXTRA, sphericalStereoMode);
addPlayerConfigToIntent(intent, /* extrasKeySuffix= */ "");
}
public void addToPlaylistIntent(Intent intent, String extrasKeySuffix) {
intent.putExtra(IntentUtil.URI_EXTRA + extrasKeySuffix, uri.toString());
intent.putExtra(IntentUtil.IS_LIVE_EXTRA + extrasKeySuffix, isLive);
addPlayerConfigToIntent(intent, extrasKeySuffix);
}
private void addPlayerConfigToIntent(Intent intent, String extrasKeySuffix) {
intent
.putExtra(IntentUtil.EXTENSION_EXTRA + extrasKeySuffix, extension)
.putExtra(
IntentUtil.AD_TAG_URI_EXTRA + extrasKeySuffix,
adTagUri != null ? adTagUri.toString() : null);
if (drmInfo != null) {
drmInfo.addToIntent(intent, extrasKeySuffix);
}
if (subtitleInfo != null) {
subtitleInfo.addToIntent(intent, extrasKeySuffix);
}
}
}
public static final class PlaylistSample extends Sample {
public final UriSample[] children;
public PlaylistSample(String name, UriSample... children) {
super(name);
this.children = children;
}
@Override
public void addToIntent(Intent intent) {
intent.setAction(IntentUtil.ACTION_VIEW_LIST);
for (int i = 0; i < children.length; i++) {
children[i].addToPlaylistIntent(intent, /* extrasKeySuffix= */ "_" + i);
}
}
}
public static final class DrmInfo {
public final UUID drmScheme;
public final String drmLicenseUrl;
public final String[] drmKeyRequestProperties;
public final int[] drmSessionForClearTypes;
public final boolean drmMultiSession;
public DrmInfo(
UUID drmScheme,
String drmLicenseUrl,
String[] drmKeyRequestProperties,
int[] drmSessionForClearTypes,
boolean drmMultiSession) {
this.drmScheme = drmScheme;
this.drmLicenseUrl = drmLicenseUrl;
this.drmKeyRequestProperties = drmKeyRequestProperties;
this.drmSessionForClearTypes = drmSessionForClearTypes;
this.drmMultiSession = drmMultiSession;
}
public void addToIntent(Intent intent, String extrasKeySuffix) {
Assertions.checkNotNull(intent);
intent.putExtra(IntentUtil.DRM_SCHEME_EXTRA + extrasKeySuffix, drmScheme.toString());
intent.putExtra(IntentUtil.DRM_LICENSE_URL_EXTRA + extrasKeySuffix, drmLicenseUrl);
intent.putExtra(
IntentUtil.DRM_KEY_REQUEST_PROPERTIES_EXTRA + extrasKeySuffix, drmKeyRequestProperties);
ArrayList<String> typeStrings = new ArrayList<>();
for (int type : drmSessionForClearTypes) {
// Only audio and video are supported.
typeStrings.add(type == C.TRACK_TYPE_AUDIO ? "audio" : "video");
}
intent.putExtra(
IntentUtil.DRM_SESSION_FOR_CLEAR_TYPES_EXTRA + extrasKeySuffix,
typeStrings.toArray(new String[0]));
intent.putExtra(IntentUtil.DRM_MULTI_SESSION_EXTRA + extrasKeySuffix, drmMultiSession);
}
}
public static final class SubtitleInfo {
public final Uri uri;
public final String mimeType;
@Nullable public final String language;
public SubtitleInfo(Uri uri, String mimeType, @Nullable String language) {
this.uri = Assertions.checkNotNull(uri);
this.mimeType = Assertions.checkNotNull(mimeType);
this.language = language;
}
public void addToIntent(Intent intent, String extrasKeySuffix) {
intent.putExtra(IntentUtil.SUBTITLE_URI_EXTRA + extrasKeySuffix, uri.toString());
intent.putExtra(IntentUtil.SUBTITLE_MIME_TYPE_EXTRA + extrasKeySuffix, mimeType);
intent.putExtra(IntentUtil.SUBTITLE_LANGUAGE_EXTRA + extrasKeySuffix, language);
}
}
public static int[] toTrackTypeArray(@Nullable String[] trackTypeStringsArray) {
if (trackTypeStringsArray == null) {
return new int[0];
}
HashSet<Integer> trackTypes = new HashSet<>();
for (String trackTypeString : trackTypeStringsArray) {
switch (Util.toLowerInvariant(trackTypeString)) {
case "audio":
trackTypes.add(C.TRACK_TYPE_AUDIO);
break;
case "video":
trackTypes.add(C.TRACK_TYPE_VIDEO);
break;
default:
throw new IllegalArgumentException("Invalid track type: " + trackTypeString);
}
}
return Util.toArray(new ArrayList<>(trackTypes));
}
public final String name;
public Sample(String name) {
this.name = name;
}
public abstract void addToIntent(Intent intent);
}
......@@ -1669,6 +1669,29 @@ public final class Util {
}
/**
* Makes a best guess to infer the type from a {@link Uri} and MIME type.
*
* @param uri The {@link Uri}.
* @param mimeType If not null, used to infer the type.
* @return The content type.
*/
public static int inferContentTypeWithMimeType(Uri uri, @Nullable String mimeType) {
if (mimeType == null) {
return Util.inferContentType(uri);
}
switch (mimeType) {
case MimeTypes.APPLICATION_MPD:
return C.TYPE_DASH;
case MimeTypes.APPLICATION_M3U8:
return C.TYPE_HLS;
case MimeTypes.APPLICATION_SS:
return C.TYPE_SS;
default:
return Util.inferContentType(uri);
}
}
/**
* Returns the specified millisecond time formatted as a string.
*
* @param builder The builder that {@code formatter} will write to.
......
......@@ -248,7 +248,7 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
Assertions.checkNotNull(mediaItem.playbackProperties);
@C.ContentType
int type =
inferContentType(
Util.inferContentTypeWithMimeType(
mediaItem.playbackProperties.sourceUri, mediaItem.playbackProperties.mimeType);
@Nullable MediaSourceFactory mediaSourceFactory = mediaSourceFactories.get(type);
Assertions.checkNotNull(
......@@ -396,20 +396,4 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
factories.put(C.TYPE_OTHER, new ProgressiveMediaSource.Factory(dataSourceFactory));
return factories;
}
private static int inferContentType(Uri sourceUri, @Nullable String mimeType) {
if (mimeType == null) {
return Util.inferContentType(sourceUri);
}
switch (mimeType) {
case MimeTypes.APPLICATION_MPD:
return C.TYPE_DASH;
case MimeTypes.APPLICATION_M3U8:
return C.TYPE_HLS;
case MimeTypes.APPLICATION_SS:
return C.TYPE_SS;
default:
return Util.inferContentType(sourceUri);
}
}
}
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