From 9304cb3f8fdeda394ce5a22968841de0e5e78117 Mon Sep 17 00:00:00 2001 From: olly Date: Tue, 19 Jul 2016 03:57:44 -0700 Subject: [PATCH] Plumb key-rotation and drm-playlist support With this change, MediaCodecRenderer acquires a session from its DrmSessionManager whenever the DrmInitData in the format changes. The DrmSessionManager is permitted to return the same session if it can be re-used. This plumbing adds support for: 1. Key-rotation, in the case that a key-rotation-aware DrmSessionManager is used. Such an implementation will return the same DrmSession for every aquisition, but will be making use of multiple MediaDrm instances within that session to enable the rotation. 2. Playlists with mixed clear and protected content. One final piece to this will be to have each MediaPeriod provide its own license URL. We could also allow each MediaPeriod to specify the DRM UUID, but switching from PlayReady to Widevine in a playlist seems like quite a hypothetical thing. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=127816046 --- .../src/main/assets/sample_media.exolist.json | 107 +++++++++++++----- .../exoplayer2/demo/PlayerActivity.java | 17 ++- .../demo/SampleChooserActivity.java | 78 ++++++------- .../exoplayer2/demo/TestMediaDrmCallback.java | 10 +- .../mediacodec/MediaCodecRenderer.java | 55 +++++++-- 5 files changed, 171 insertions(+), 96 deletions(-) diff --git a/demo/src/main/assets/sample_media.exolist.json b/demo/src/main/assets/sample_media.exolist.json index 6ea5069a91..8798cba036 100644 --- a/demo/src/main/assets/sample_media.exolist.json +++ b/demo/src/main/assets/sample_media.exolist.json @@ -30,42 +30,50 @@ { "name": "WV: HDCP not specified", "uri": "https://storage.googleapis.com/wvmedia/cenc/h264/tears/tears.mpd", - "drm": "widevine:d286538032258a1c:widevine_test" + "drm_scheme": "widevine", + "drm_license_url": "https://proxy.uat.widevine.com/proxy?video_id=d286538032258a1c&provider=widevine_test" }, { "name": "WV: HDCP not required", "uri": "https://storage.googleapis.com/wvmedia/cenc/h264/tears/tears.mpd", - "drm": "widevine:48fcc369939ac96c:widevine_test" + "drm_scheme": "widevine", + "drm_license_url": "https://proxy.uat.widevine.com/proxy?video_id=48fcc369939ac96c&provider=widevine_test" }, { "name": "WV: HDCP required", "uri": "https://storage.googleapis.com/wvmedia/cenc/h264/tears/tears.mpd", - "drm": "widevine:e06c39f1151da3df:widevine_test" + "drm_scheme": "widevine", + "drm_license_url": "https://proxy.uat.widevine.com/proxy?video_id=e06c39f1151da3df&provider=widevine_test" }, { "name": "WV: Secure video path required (MP4,H264)", "uri": "https://storage.googleapis.com/wvmedia/cenc/h264/tears/tears.mpd", - "drm": "widevine:0894c7c8719b28a0:widevine_test" + "drm_scheme": "widevine", + "drm_license_url": "https://proxy.uat.widevine.com/proxy?video_id=0894c7c8719b28a0&provider=widevine_test" }, { "name": "WV: Secure video path required (WebM,VP9)", "uri": "https://storage.googleapis.com/wvmedia/cenc/vp9/tears/tears.mpd", - "drm": "widevine:0894c7c8719b28a0:widevine_test" + "drm_scheme": "widevine", + "drm_license_url": "https://proxy.uat.widevine.com/proxy?video_id=0894c7c8719b28a0&provider=widevine_test" }, { "name": "WV: Secure video path required (MP4,H265)", "uri": "https://storage.googleapis.com/wvmedia/cenc/hevc/tears/tears.mpd", - "drm": "widevine:0894c7c8719b28a0:widevine_test" + "drm_scheme": "widevine", + "drm_license_url": "https://proxy.uat.widevine.com/proxy?video_id=0894c7c8719b28a0&provider=widevine_test" }, { "name": "WV: HDCP + secure video path required", "uri": "https://storage.googleapis.com/wvmedia/cenc/h264/tears/tears.mpd", - "drm": "widevine:efd045b1eb61888a:widevine_test" + "drm_scheme": "widevine", + "drm_license_url": "https://proxy.uat.widevine.com/proxy?video_id=efd045b1eb61888a&provider=widevine_test" }, { "name": "WV: 30s license duration (fails at ~30s)", "uri": "https://storage.googleapis.com/wvmedia/cenc/h264/tears/tears.mpd", - "drm": "widevine:f9a34cab7b05881a:widevine_test" + "drm_scheme": "widevine", + "drm_license_url": "https://proxy.uat.widevine.com/proxy?video_id=f9a34cab7b05881a&provider=widevine_test" } ] }, @@ -75,32 +83,38 @@ { "name": "WV: HDCP: None (not required)", "uri": "https://storage.googleapis.com/wvmedia/cenc/h264/tears/tears.mpd", - "drm": "widevine:HDCP_None:widevine_test" + "drm_scheme": "widevine", + "drm_license_url": "https://proxy.uat.widevine.com/proxy?video_id=HDCP_None&provider=widevine_test" }, { "name": "WV: HDCP: 1.0 required", "uri": "https://storage.googleapis.com/wvmedia/cenc/h264/tears/tears.mpd", - "drm": "widevine:HDCP_V1:widevine_test" + "drm_scheme": "widevine", + "drm_license_url": "https://proxy.uat.widevine.com/proxy?video_id=HDCP_V1&provider=widevine_test" }, { "name": "WV: HDCP: 2.0 required", "uri": "https://storage.googleapis.com/wvmedia/cenc/h264/tears/tears.mpd", - "drm": "widevine:HDCP_V2:widevine_test" + "drm_scheme": "widevine", + "drm_license_url": "https://proxy.uat.widevine.com/proxy?video_id=HDCP_V2&provider=widevine_test" }, { "name": "WV: HDCP: 2.1 required", "uri": "https://storage.googleapis.com/wvmedia/cenc/h264/tears/tears.mpd", - "drm": "widevine:HDCP_V2_1:widevine_test" + "drm_scheme": "widevine", + "drm_license_url": "https://proxy.uat.widevine.com/proxy?video_id=HDCP_V2_1&provider=widevine_test" }, { "name": "WV: HDCP: 2.2 required", "uri": "https://storage.googleapis.com/wvmedia/cenc/h264/tears/tears.mpd", - "drm": "widevine:HDCP_V2_2:widevine_test" + "drm_scheme": "widevine", + "drm_license_url": "https://proxy.uat.widevine.com/proxy?video_id=HDCP_V2_2&provider=widevine_test" }, { "name": "WV: HDCP: No digital output", "uri": "https://storage.googleapis.com/wvmedia/cenc/h264/tears/tears.mpd", - "drm": "widevine:HDCP_NO_DIGTAL_OUTPUT:widevine_test" + "drm_scheme": "widevine", + "drm_license_url": "https://proxy.uat.widevine.com/proxy?video_id=HDCP_NO_DIGTAL_OUTPUT&provider=widevine_test" } ] }, @@ -126,22 +140,26 @@ { "name": "WV: Secure SD & HD (MP4,H264)", "uri": "https://storage.googleapis.com/wvmedia/cenc/h264/tears/tears.mpd", - "drm": "widevine::widevine_test" + "drm_scheme": "widevine", + "drm_license_url": "https://proxy.uat.widevine.com/proxy?provider=widevine_test" }, { "name": "WV: Secure SD (MP4,H264)", "uri": "https://storage.googleapis.com/wvmedia/cenc/h264/tears/tears_sd.mpd", - "drm": "widevine::widevine_test" + "drm_scheme": "widevine", + "drm_license_url": "https://proxy.uat.widevine.com/proxy?provider=widevine_test" }, { "name": "WV: Secure HD (MP4,H264)", "uri": "https://storage.googleapis.com/wvmedia/cenc/h264/tears/tears_hd.mpd", - "drm": "widevine::widevine_test" + "drm_scheme": "widevine", + "drm_license_url": "https://proxy.uat.widevine.com/proxy?provider=widevine_test" }, { "name": "WV: Secure UHD (MP4,H264)", "uri": "https://storage.googleapis.com/wvmedia/cenc/h264/tears/tears_uhd.mpd", - "drm": "widevine::widevine_test" + "drm_scheme": "widevine", + "drm_license_url": "https://proxy.uat.widevine.com/proxy?provider=widevine_test" } ] }, @@ -167,22 +185,26 @@ { "name": "WV: Secure SD & HD (WebM,VP9)", "uri": "https://storage.googleapis.com/wvmedia/cenc/vp9/tears/tears.mpd", - "drm": "widevine::widevine_test" + "drm_scheme": "widevine", + "drm_license_url": "https://proxy.uat.widevine.com/proxy?provider=widevine_test" }, { "name": "WV: Secure SD (WebM,VP9)", "uri": "https://storage.googleapis.com/wvmedia/cenc/vp9/tears/tears_sd.mpd", - "drm": "widevine::widevine_test" + "drm_scheme": "widevine", + "drm_license_url": "https://proxy.uat.widevine.com/proxy?provider=widevine_test" }, { "name": "WV: Secure HD (WebM,VP9)", "uri": "https://storage.googleapis.com/wvmedia/cenc/vp9/tears/tears_hd.mpd", - "drm": "widevine::widevine_test" + "drm_scheme": "widevine", + "drm_license_url": "https://proxy.uat.widevine.com/proxy?provider=widevine_test" }, { "name": "WV: Secure UHD (WebM,VP9)", "uri": "https://storage.googleapis.com/wvmedia/cenc/vp9/tears/tears_uhd.mpd", - "drm": "widevine::widevine_test" + "drm_scheme": "widevine", + "drm_license_url": "https://proxy.uat.widevine.com/proxy?provider=widevine_test" } ] }, @@ -208,22 +230,26 @@ { "name": "WV: Secure SD & HD (MP4,H265)", "uri": "https://storage.googleapis.com/wvmedia/cenc/hevc/tears/tears.mpd", - "drm": "widevine::widevine_test" + "drm_scheme": "widevine", + "drm_license_url": "https://proxy.uat.widevine.com/proxy?provider=widevine_test" }, { "name": "WV: Secure SD (MP4,H265)", "uri": "https://storage.googleapis.com/wvmedia/cenc/hevc/tears/tears_sd.mpd", - "drm": "widevine::widevine_test" + "drm_scheme": "widevine", + "drm_license_url": "https://proxy.uat.widevine.com/proxy?provider=widevine_test" }, { "name": "WV: Secure HD (MP4,H265)", "uri": "https://storage.googleapis.com/wvmedia/cenc/hevc/tears/tears_hd.mpd", - "drm": "widevine::widevine_test" + "drm_scheme": "widevine", + "drm_license_url": "https://proxy.uat.widevine.com/proxy?provider=widevine_test" }, { "name": "WV: Secure UHD (MP4,H265)", "uri": "https://storage.googleapis.com/wvmedia/cenc/hevc/tears/tears_uhd.mpd", - "drm": "widevine::widevine_test" + "drm_scheme": "widevine", + "drm_license_url": "https://proxy.uat.widevine.com/proxy?provider=widevine_test" } ] }, @@ -237,7 +263,8 @@ { "name": "Super speed (PlayReady)", "uri": "http://playready.directtaps.net/smoothstreaming/SSWSS720H264PR/SuperSpeedway_720.ism", - "drm": "playready::" + "drm_scheme": "playready", + "drm_license_url": "http://playready.directtaps.net/pr/svc/rightsmanager.asmx" } ] }, @@ -335,7 +362,7 @@ "name": "Playlists", "samples": [ { - "name": "Cats and dogs", + "name": "Cats -> Dogs", "playlist": [ { "uri": "http://html5demos.com/assets/dizzy.mp4" @@ -346,7 +373,7 @@ ] }, { - "name": "Audio then Video", + "name": "Audio -> Video", "playlist": [ { "uri": "https://storage.googleapis.com/exoplayer-test-media-1/gen-3/screens/dash-vod-single-segment/audio-141.mp4" @@ -355,6 +382,28 @@ "uri": "http://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv" } ] + }, + { + "name": "Clear -> Enc -> Clear -> Enc -> Enc", + "drm_scheme": "widevine", + "drm_license_url": "https://proxy.uat.widevine.com/proxy?provider=widevine_test", + "playlist": [ + { + "uri": "http://html5demos.com/assets/dizzy.mp4" + }, + { + "uri": "https://storage.googleapis.com/wvmedia/cenc/h264/tears/tears_sd.mpd" + }, + { + "uri": "http://html5demos.com/assets/dizzy.mp4" + }, + { + "uri": "https://storage.googleapis.com/wvmedia/cenc/h264/tears/tears_sd.mpd" + }, + { + "uri": "https://storage.googleapis.com/wvmedia/cenc/h264/tears/tears_sd.mpd" + } + ] } ] } diff --git a/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java b/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java index 067da8bd5f..36e189de9f 100644 --- a/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java +++ b/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java @@ -99,8 +99,7 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback, SimpleExoPlayer.Id3MetadataListener, MappingTrackSelector.EventListener { 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_PROVIDER_EXTRA = "drm_provider"; + public static final String DRM_LICENSE_URL = "drm_license_url"; public static final String PREFER_EXTENSION_DECODERS = "prefer_extension_decoders"; public static final String ACTION_VIEW = "com.google.android.exoplayer.demo.action.VIEW"; @@ -267,13 +266,13 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback, Intent intent = getIntent(); if (player == null) { boolean preferExtensionDecoders = intent.getBooleanExtra(PREFER_EXTENSION_DECODERS, false); - UUID drmSchemeUuid = (UUID) intent.getSerializableExtra(DRM_SCHEME_UUID_EXTRA); + UUID drmSchemeUuid = intent.hasExtra(DRM_SCHEME_UUID_EXTRA) + ? UUID.fromString(intent.getStringExtra(DRM_SCHEME_UUID_EXTRA)) : null; DrmSessionManager drmSessionManager = null; if (drmSchemeUuid != null) { - String drmContentId = intent.getStringExtra(DRM_CONTENT_ID_EXTRA); - String drmProvider = intent.getStringExtra(DRM_PROVIDER_EXTRA); + String drmLicenseUrl = intent.getStringExtra(DRM_LICENSE_URL); try { - drmSessionManager = buildDrmSessionManager(drmSchemeUuid, drmContentId, drmProvider); + drmSessionManager = buildDrmSessionManager(drmSchemeUuid, drmLicenseUrl); } catch (UnsupportedDrmException e) { onUnsupportedDrmError(e); return; @@ -367,17 +366,17 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback, } } - private DrmSessionManager buildDrmSessionManager(UUID uuid, String id, String provider) + private DrmSessionManager buildDrmSessionManager(UUID uuid, String licenseUrl) throws UnsupportedDrmException { if (Util.SDK_INT < 18) { return null; } if (C.PLAYREADY_UUID.equals(uuid)) { return StreamingDrmSessionManager.newPlayReadyInstance( - TestMediaDrmCallback.newPlayReadyInstance(), null, mainHandler, eventLogger); + TestMediaDrmCallback.newPlayReadyInstance(licenseUrl), null, mainHandler, eventLogger); } else if (C.WIDEVINE_UUID.equals(uuid)) { return StreamingDrmSessionManager.newWidevineInstance( - TestMediaDrmCallback.newWidevineInstance(id, provider), null, mainHandler, eventLogger); + TestMediaDrmCallback.newWidevineInstance(licenseUrl), null, mainHandler, eventLogger); } else { throw new UnsupportedDrmException(UnsupportedDrmException.REASON_UNSUPPORTED_SCHEME); } diff --git a/demo/src/main/java/com/google/android/exoplayer2/demo/SampleChooserActivity.java b/demo/src/main/java/com/google/android/exoplayer2/demo/SampleChooserActivity.java index 0ba9c299ce..3fe4359227 100644 --- a/demo/src/main/java/com/google/android/exoplayer2/demo/SampleChooserActivity.java +++ b/demo/src/main/java/com/google/android/exoplayer2/demo/SampleChooserActivity.java @@ -162,8 +162,7 @@ public class SampleChooserActivity extends Activity { String uri = null; String extension = null; UUID drmUuid = null; - String drmContentId = null; - String drmProvider = null; + String drmLicenseUrl = null; boolean preferExtensionDecoders = false; ArrayList playlistSamples = null; @@ -180,17 +179,22 @@ public class SampleChooserActivity extends Activity { case "extension": extension = reader.nextString(); break; - case "drm": - String[] drmComponents = reader.nextString().split(":", -1); - drmUuid = getDrmUuid(drmComponents[0]); - drmContentId = drmComponents[1]; - drmProvider = drmComponents[2]; + case "drm_scheme": + Assertions.checkState(!insidePlaylist, "Invalid attribute on nested item: drm_scheme"); + drmUuid = getDrmUuid(reader.nextString()); + break; + case "drm_license_url": + Assertions.checkState(!insidePlaylist, + "Invalid attribute on nested item: drm_license_url"); + drmLicenseUrl = reader.nextString(); break; case "prefer_extension_decoders": + Assertions.checkState(!insidePlaylist, + "Invalid attribute on nested item: prefer_extension_decoders"); preferExtensionDecoders = reader.nextBoolean(); break; case "playlist": - Assertions.checkState(!insidePlaylist, "Nested playlists are invalid"); + Assertions.checkState(!insidePlaylist, "Invalid nesting of playlists"); playlistSamples = new ArrayList<>(); reader.beginArray(); while (reader.hasNext()) { @@ -207,11 +211,11 @@ public class SampleChooserActivity extends Activity { if (playlistSamples != null) { UriSample[] playlistSamplesArray = playlistSamples.toArray( new UriSample[playlistSamples.size()]); - return new PlaylistSample(sampleName, drmUuid, drmContentId, drmProvider, - preferExtensionDecoders, playlistSamplesArray); + return new PlaylistSample(sampleName, drmUuid, drmLicenseUrl, preferExtensionDecoders, + playlistSamplesArray); } else { - return new UriSample(sampleName, drmUuid, drmContentId, drmProvider, - preferExtensionDecoders, uri, extension); + return new UriSample(sampleName, drmUuid, drmLicenseUrl, preferExtensionDecoders, uri, + extension); } } @@ -233,7 +237,11 @@ public class SampleChooserActivity extends Activity { case "playready": return C.PLAYREADY_UUID; default: - throw new ParserException("Unsupported drm type: " + typeString); + try { + return UUID.fromString(typeString); + } catch (RuntimeException e) { + throw new ParserException("Unsupported drm type: " + typeString); + } } } @@ -331,24 +339,26 @@ public class SampleChooserActivity extends Activity { public final String name; public final boolean preferExtensionDecoders; - - // 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 String drmContentId; - public final String drmProvider; + public final String drmLicenseUrl; - public Sample(String name, UUID drmSchemeUuid, String drmContentId, String drmProvider, + public Sample(String name, UUID drmSchemeUuid, String drmLicenseUrl, boolean preferExtensionDecoders) { this.name = name; this.drmSchemeUuid = drmSchemeUuid; - this.drmContentId = drmContentId; - this.drmProvider = drmProvider; + this.drmLicenseUrl = drmLicenseUrl; this.preferExtensionDecoders = preferExtensionDecoders; } - public abstract Intent buildIntent(Context context); + public Intent buildIntent(Context context) { + Intent intent = new Intent(context, PlayerActivity.class); + intent.putExtra(PlayerActivity.PREFER_EXTENSION_DECODERS, preferExtensionDecoders); + if (drmSchemeUuid != null) { + intent.putExtra(PlayerActivity.DRM_SCHEME_UUID_EXTRA, drmSchemeUuid.toString()); + intent.putExtra(PlayerActivity.DRM_LICENSE_URL, drmLicenseUrl); + } + return intent; + } } @@ -357,21 +367,16 @@ public class SampleChooserActivity extends Activity { public final String uri; public final String extension; - public UriSample(String name, UUID drmSchemeUuid, String drmContentId, String drmProvider, + public UriSample(String name, UUID drmSchemeUuid, String drmLicenseUrl, boolean preferExtensionDecoders, String uri, String extension) { - super(name, drmSchemeUuid, drmContentId, drmProvider, preferExtensionDecoders); + super(name, drmSchemeUuid, drmLicenseUrl, 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) + return super.buildIntent(context) .setData(Uri.parse(uri)) .putExtra(PlayerActivity.EXTENSION_EXTRA, extension) .setAction(PlayerActivity.ACTION_VIEW); @@ -383,9 +388,9 @@ public class SampleChooserActivity extends Activity { public final UriSample[] children; - public PlaylistSample(String name, UUID drmSchemeUuid, String drmContentId, String drmProvider, + public PlaylistSample(String name, UUID drmSchemeUuid, String drmLicenseUrl, boolean preferExtensionDecoders, UriSample... children) { - super(name, drmSchemeUuid, drmContentId, drmProvider, preferExtensionDecoders); + super(name, drmSchemeUuid, drmLicenseUrl, preferExtensionDecoders); this.children = children; } @@ -397,12 +402,7 @@ public class SampleChooserActivity extends Activity { 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) + return super.buildIntent(context) .putExtra(PlayerActivity.URI_LIST_EXTRA, uris) .putExtra(PlayerActivity.EXTENSION_LIST_EXTRA, extensions) .setAction(PlayerActivity.ACTION_VIEW_LIST); diff --git a/demo/src/main/java/com/google/android/exoplayer2/demo/TestMediaDrmCallback.java b/demo/src/main/java/com/google/android/exoplayer2/demo/TestMediaDrmCallback.java index f009319762..dff33c9958 100644 --- a/demo/src/main/java/com/google/android/exoplayer2/demo/TestMediaDrmCallback.java +++ b/demo/src/main/java/com/google/android/exoplayer2/demo/TestMediaDrmCallback.java @@ -38,9 +38,6 @@ import java.util.UUID; @TargetApi(18) /* package */ final class TestMediaDrmCallback implements MediaDrmCallback { - private static final String WIDEVINE_BASE_URL = "https://proxy.uat.widevine.com/proxy"; - private static final String PLAYREADY_BASE_URL = - "http://playready.directtaps.net/pr/svc/rightsmanager.asmx"; private static final Map PLAYREADY_KEY_REQUEST_PROPERTIES; static { HashMap keyRequestProperties = new HashMap<>(); @@ -53,13 +50,12 @@ import java.util.UUID; private final String defaultUrl; private final Map keyRequestProperties; - public static TestMediaDrmCallback newWidevineInstance(String contentId, String provider) { - String defaultUrl = WIDEVINE_BASE_URL + "?video_id=" + contentId + "&provider=" + provider; + public static TestMediaDrmCallback newWidevineInstance(String defaultUrl) { return new TestMediaDrmCallback(defaultUrl, null); } - public static TestMediaDrmCallback newPlayReadyInstance() { - return new TestMediaDrmCallback(PLAYREADY_BASE_URL, PLAYREADY_KEY_REQUEST_PROPERTIES); + public static TestMediaDrmCallback newPlayReadyInstance(String defaultUrl) { + return new TestMediaDrmCallback(defaultUrl, PLAYREADY_KEY_REQUEST_PROPERTIES); } private TestMediaDrmCallback(String defaultUrl, Map keyRequestProperties) { diff --git a/library/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java b/library/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java index 781b4d7be3..4f91c966e3 100644 --- a/library/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java +++ b/library/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java @@ -177,6 +177,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { private Format format; private MediaCodec codec; private DrmSession drmSession; + private DrmSession pendingDrmSession; private boolean codecIsAdaptive; private boolean codecNeedsDiscardToSpsWorkaround; private boolean codecNeedsFlushWorkaround; @@ -287,17 +288,11 @@ public abstract class MediaCodecRenderer extends BaseRenderer { return; } + drmSession = pendingDrmSession; String mimeType = format.sampleMimeType; MediaCrypto mediaCrypto = null; boolean drmSessionRequiresSecureDecoder = false; - if (format.drmInitData != null) { - if (drmSessionManager == null) { - throw ExoPlaybackException.createForRenderer( - new IllegalStateException("Media requires a DrmSessionManager"), getIndex()); - } - if (drmSession == null) { - drmSession = drmSessionManager.acquireSession(Looper.myLooper(), format.drmInitData); - } + if (drmSession != null) { int drmSessionState = drmSession.getState(); if (drmSessionState == DrmSession.STATE_ERROR) { throw ExoPlaybackException.createForRenderer(drmSession.getError(), getIndex()); @@ -400,9 +395,19 @@ public abstract class MediaCodecRenderer extends BaseRenderer { try { releaseCodec(); } finally { - if (drmSession != null) { - drmSessionManager.releaseSession(drmSession); - drmSession = null; + try { + if (drmSession != null) { + drmSessionManager.releaseSession(drmSession); + } + } finally { + try { + if (pendingDrmSession != null && pendingDrmSession != drmSession) { + drmSessionManager.releaseSession(pendingDrmSession); + } + } finally { + drmSession = null; + pendingDrmSession = null; + } } } } @@ -439,6 +444,13 @@ public abstract class MediaCodecRenderer extends BaseRenderer { codec.release(); } finally { codec = null; + if (drmSession != null && pendingDrmSession != drmSession) { + try { + drmSessionManager.releaseSession(drmSession); + } finally { + drmSession = null; + } + } } } } @@ -700,7 +712,26 @@ public abstract class MediaCodecRenderer extends BaseRenderer { protected void onInputFormatChanged(Format newFormat) throws ExoPlaybackException { Format oldFormat = format; format = newFormat; - if (codec != null && canReconfigureCodec(codec, codecIsAdaptive, oldFormat, format)) { + + boolean drmInitDataChanged = !Util.areEqual(format.drmInitData, oldFormat == null ? null + : oldFormat.drmInitData); + if (drmInitDataChanged) { + if (format.drmInitData != null) { + if (drmSessionManager == null) { + throw ExoPlaybackException.createForRenderer( + new IllegalStateException("Media requires a DrmSessionManager"), getIndex()); + } + pendingDrmSession = drmSessionManager.acquireSession(Looper.myLooper(), format.drmInitData); + if (pendingDrmSession == drmSession) { + drmSessionManager.releaseSession(pendingDrmSession); + } + } else { + pendingDrmSession = null; + } + } + + if (pendingDrmSession == drmSession && codec != null + && canReconfigureCodec(codec, codecIsAdaptive, oldFormat, format)) { codecReconfigured = true; codecReconfigurationState = RECONFIGURATION_STATE_WRITE_PENDING; codecNeedsAdaptationWorkaroundBuffer = codecNeedsAdaptationWorkaround