From d7280f096ff38e94d1676f968106ac42c3e4c697 Mon Sep 17 00:00:00 2001 From: bachinger Date: Wed, 15 Apr 2020 21:35:08 +0100 Subject: [PATCH] Add custom cache key to media item This is required to migrate the PlayerActivity away from Sample to MediaItem. It hence needs adding buildUpon to MediaItem to mix in the customCacheKey and streamKeys before playback. PiperOrigin-RevId: 306710643 --- .../exoplayer2/demo/PlayerActivity.java | 8 ++- .../google/android/exoplayer2/MediaItem.java | 60 ++++++++++++++++++- .../android/exoplayer2/MediaItemTest.java | 44 ++++++++++++++ .../source/ProgressiveMediaSource.java | 13 ++-- 4 files changed, 113 insertions(+), 12 deletions(-) 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 44d471bb27..f94123426e 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 @@ -42,7 +42,6 @@ import com.google.android.exoplayer2.audio.AudioAttributes; import com.google.android.exoplayer2.demo.Sample.UriSample; import com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.DecoderInitializationException; import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException; -import com.google.android.exoplayer2.offline.DownloadHelper; import com.google.android.exoplayer2.offline.DownloadRequest; import com.google.android.exoplayer2.source.BehindLiveWindowException; import com.google.android.exoplayer2.source.DefaultMediaSourceFactory; @@ -473,7 +472,12 @@ public class PlayerActivity extends AppCompatActivity .getDownloadTracker() .getDownloadRequest(mediaItem.playbackProperties.sourceUri); if (downloadRequest != null) { - return DownloadHelper.createMediaSource(downloadRequest, dataSourceFactory); + mediaItem = + mediaItem + .buildUpon() + .setStreamKeys(downloadRequest.streamKeys) + .setCustomCacheKey(downloadRequest.customCacheKey) + .build(); } return mediaSourceFactory .setDrmHttpDataSourceFactory(drmDataSourceFactory) diff --git a/library/common/src/main/java/com/google/android/exoplayer2/MediaItem.java b/library/common/src/main/java/com/google/android/exoplayer2/MediaItem.java index a78a2d06ee..f484d3f80e 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/MediaItem.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/MediaItem.java @@ -69,17 +69,47 @@ public final class MediaItem { private boolean drmPlayClearContentWithoutKey; private List drmSessionForClearTypes; private List streamKeys; + @Nullable private String customCacheKey; private List subtitles; @Nullable private Object tag; @Nullable private MediaMetadata mediaMetadata; /** Creates a builder. */ public Builder() { - streamKeys = Collections.emptyList(); - subtitles = Collections.emptyList(); + clipEndPositionMs = C.TIME_END_OF_SOURCE; drmSessionForClearTypes = Collections.emptyList(); drmLicenseRequestHeaders = Collections.emptyMap(); - clipEndPositionMs = C.TIME_END_OF_SOURCE; + streamKeys = Collections.emptyList(); + subtitles = Collections.emptyList(); + } + + private Builder(MediaItem mediaItem) { + this(); + clipEndPositionMs = mediaItem.clippingProperties.endPositionMs; + clipRelativeToLiveWindow = mediaItem.clippingProperties.relativeToLiveWindow; + clipRelativeToDefaultPosition = mediaItem.clippingProperties.relativeToDefaultPosition; + clipStartsAtKeyFrame = mediaItem.clippingProperties.startsAtKeyFrame; + clipStartPositionMs = mediaItem.clippingProperties.startPositionMs; + mediaId = mediaItem.mediaId; + mediaMetadata = mediaItem.mediaMetadata; + @Nullable PlaybackProperties playbackProperties = mediaItem.playbackProperties; + if (playbackProperties != null) { + customCacheKey = playbackProperties.customCacheKey; + mimeType = playbackProperties.mimeType; + sourceUri = playbackProperties.sourceUri; + streamKeys = playbackProperties.streamKeys; + subtitles = playbackProperties.subtitles; + tag = playbackProperties.tag; + @Nullable DrmConfiguration drmConfiguration = playbackProperties.drmConfiguration; + if (drmConfiguration != null) { + drmLicenseUri = drmConfiguration.licenseUri; + drmLicenseRequestHeaders = drmConfiguration.requestHeaders; + drmMultiSession = drmConfiguration.multiSession; + drmPlayClearContentWithoutKey = drmConfiguration.playClearContentWithoutKey; + drmSessionForClearTypes = drmConfiguration.sessionForClearTypes; + drmUuid = drmConfiguration.uuid; + } + } } /** @@ -296,6 +326,17 @@ public final class MediaItem { return this; } + /** + * Sets the optional custom cache key (only used for progressive streams). + * + *

If a {@link PlaybackProperties#sourceUri} is set, the custom cache key is used to create a + * {@link PlaybackProperties} object. Otherwise it will be ignored. + */ + public Builder setCustomCacheKey(@Nullable String customCacheKey) { + this.customCacheKey = customCacheKey; + return this; + } + /** * Sets the optional subtitles. * @@ -352,6 +393,7 @@ public final class MediaItem { drmSessionForClearTypes) : null, streamKeys, + customCacheKey, subtitles, tag); mediaId = mediaId != null ? mediaId : sourceUri.toString(); @@ -461,6 +503,9 @@ public final class MediaItem { /** Optional stream keys by which the manifest is filtered. */ public final List streamKeys; + /** Optional custom cache key (only used for progressive streams). */ + @Nullable public final String customCacheKey; + /** Optional subtitles to be sideloaded. */ public final List subtitles; @@ -476,12 +521,14 @@ public final class MediaItem { @Nullable String mimeType, @Nullable DrmConfiguration drmConfiguration, List streamKeys, + @Nullable String customCacheKey, List subtitles, @Nullable Object tag) { this.sourceUri = sourceUri; this.mimeType = mimeType; this.drmConfiguration = drmConfiguration; this.streamKeys = streamKeys; + this.customCacheKey = customCacheKey; this.subtitles = subtitles; this.tag = tag; } @@ -500,6 +547,7 @@ public final class MediaItem { && Util.areEqual(mimeType, other.mimeType) && Util.areEqual(drmConfiguration, other.drmConfiguration) && streamKeys.equals(other.streamKeys) + && Util.areEqual(customCacheKey, other.customCacheKey) && subtitles.equals(other.subtitles) && Util.areEqual(tag, other.tag); } @@ -510,6 +558,7 @@ public final class MediaItem { result = 31 * result + (mimeType == null ? 0 : mimeType.hashCode()); result = 31 * result + (drmConfiguration == null ? 0 : drmConfiguration.hashCode()); result = 31 * result + streamKeys.hashCode(); + result = 31 * result + (customCacheKey == null ? 0 : customCacheKey.hashCode()); result = 31 * result + subtitles.hashCode(); result = 31 * result + (tag == null ? 0 : tag.hashCode()); return result; @@ -674,6 +723,11 @@ public final class MediaItem { this.clippingProperties = clippingProperties; } + /** Returns a {@link Builder} initialized with the values of this instance. */ + public Builder buildUpon() { + return new Builder(this); + } + @Override public boolean equals(@Nullable Object obj) { if (this == obj) { diff --git a/library/common/src/test/java/com/google/android/exoplayer2/MediaItemTest.java b/library/common/src/test/java/com/google/android/exoplayer2/MediaItemTest.java index bb470114d3..adfbc60085 100644 --- a/library/common/src/test/java/com/google/android/exoplayer2/MediaItemTest.java +++ b/library/common/src/test/java/com/google/android/exoplayer2/MediaItemTest.java @@ -141,6 +141,14 @@ public class MediaItemTest { .build()); } + @Test + public void builderSetCustomCacheKey_setsCustomCacheKey() { + MediaItem mediaItem = + new MediaItem.Builder().setSourceUri(URI_STRING).setCustomCacheKey("key").build(); + + assertThat(mediaItem.playbackProperties.customCacheKey).isEqualTo("key"); + } + @Test public void builderSetStreamKeys_setsStreamKeys() { List streamKeys = new ArrayList<>(); @@ -267,4 +275,40 @@ public class MediaItemTest { assertThat(mediaItem.mediaMetadata).isEqualTo(mediaMetadata); } + + @Test + public void buildUpon_equalsToOriginal() { + MediaItem mediaItem = + new MediaItem.Builder() + .setClipEndPositionMs(1000) + .setClipRelativeToDefaultPosition(true) + .setClipRelativeToLiveWindow(true) + .setClipStartPositionMs(100) + .setClipStartsAtKeyFrame(true) + .setCustomCacheKey("key") + .setDrmUuid(C.WIDEVINE_UUID) + .setDrmLicenseUri(URI_STRING + "/license") + .setDrmLicenseRequestHeaders( + Collections.singletonMap("Referer", "http://www.google.com")) + .setDrmMultiSession(true) + .setDrmPlayClearContentWithoutKey(true) + .setDrmSessionForClearTypes(Collections.singletonList(C.TRACK_TYPE_AUDIO)) + .setMediaId("mediaId") + .setMediaMetadata(new MediaMetadata.Builder().setTitle("title").build()) + .setMimeType(MimeTypes.APPLICATION_MP4) + .setSourceUri(URI_STRING) + .setStreamKeys(Collections.singletonList(new StreamKey(1, 0, 0))) + .setSubtitles( + Collections.singletonList( + new MediaItem.Subtitle( + Uri.parse(URI_STRING + "/en"), + MimeTypes.APPLICATION_TTML, + /* language= */ "en"))) + .setTag(new Object()) + .build(); + + MediaItem copy = mediaItem.buildUpon().build(); + + assertThat(copy).isEqualTo(mediaItem); + } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ProgressiveMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ProgressiveMediaSource.java index b2404db56c..ef9a965e76 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ProgressiveMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ProgressiveMediaSource.java @@ -95,13 +95,10 @@ public final class ProgressiveMediaSource extends BaseMediaSource } /** - * Sets the custom key that uniquely identifies the original stream. Used for cache indexing. - * The default value is {@code null}. - * - * @param customCacheKey A custom key that uniquely identifies the original stream. Used for - * cache indexing. - * @return This factory, for convenience. + * @deprecated Use {@link MediaItem.Builder#setCustomCacheKey(String)} and {@link + * #createMediaSource(MediaItem)} instead. */ + @Deprecated public Factory setCustomCacheKey(@Nullable String customCacheKey) { this.customCacheKey = customCacheKey; return this; @@ -188,7 +185,9 @@ public final class ProgressiveMediaSource extends BaseMediaSource extractorsFactory, drmSessionManager, loadErrorHandlingPolicy, - customCacheKey, + mediaItem.playbackProperties.customCacheKey != null + ? mediaItem.playbackProperties.customCacheKey + : customCacheKey, continueLoadingCheckIntervalBytes, mediaItem.playbackProperties.tag != null ? mediaItem.playbackProperties.tag : tag); }