diff --git a/RELEASENOTES.md b/RELEASENOTES.md index f5509a07ec..883862e386 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -181,6 +181,8 @@ * Fix bug where re-preparing a multi-period live stream can throw an `IndexOutOfBoundsException` ([#1329](https://github.com/androidx/media/issues/1329)). + * Add support for `dashif:Laurl` license urls + ([#1345](https://github.com/androidx/media/issues/1345)). * Smooth Streaming Extension: * RTSP Extension: * Decoder Extensions (FFmpeg, VP9, AV1, MIDI, etc.): diff --git a/libraries/exoplayer_dash/src/main/java/androidx/media3/exoplayer/dash/manifest/DashManifestParser.java b/libraries/exoplayer_dash/src/main/java/androidx/media3/exoplayer/dash/manifest/DashManifestParser.java index 9318cab3d3..99a7d79f27 100644 --- a/libraries/exoplayer_dash/src/main/java/androidx/media3/exoplayer/dash/manifest/DashManifestParser.java +++ b/libraries/exoplayer_dash/src/main/java/androidx/media3/exoplayer/dash/manifest/DashManifestParser.java @@ -619,9 +619,9 @@ public class DashManifestParser extends DefaultHandler do { xpp.next(); - if (XmlPullParserUtil.isStartTag(xpp, "clearkey:Laurl") && xpp.next() == XmlPullParser.TEXT) { - licenseServerUrl = xpp.getText(); - } else if (XmlPullParserUtil.isStartTag(xpp, "dashif:Laurl") && xpp.next() == XmlPullParser.TEXT) { + if ((XmlPullParserUtil.isStartTag(xpp, "clearkey:Laurl") + || XmlPullParserUtil.isStartTag(xpp, "dashif:Laurl")) + && xpp.next() == XmlPullParser.TEXT) { licenseServerUrl = xpp.getText(); } else if (XmlPullParserUtil.isStartTag(xpp, "ms:laurl")) { licenseServerUrl = xpp.getAttributeValue(null, "licenseUrl"); diff --git a/libraries/exoplayer_dash/src/test/java/androidx/media3/exoplayer/dash/manifest/DashManifestParserTest.java b/libraries/exoplayer_dash/src/test/java/androidx/media3/exoplayer/dash/manifest/DashManifestParserTest.java index 2e6fa372b2..c39e827439 100644 --- a/libraries/exoplayer_dash/src/test/java/androidx/media3/exoplayer/dash/manifest/DashManifestParserTest.java +++ b/libraries/exoplayer_dash/src/test/java/androidx/media3/exoplayer/dash/manifest/DashManifestParserTest.java @@ -83,6 +83,8 @@ public class DashManifestParserTest { "media/mpd/sample_mpd_service_description_low_latency_only_target_latency"; private static final String SAMPLE_MPD_CLEAR_KEY_LICENSE_URL = "media/mpd/sample_mpd_clear_key_license_url"; + private static final String SAMPLE_MPD_DASHIF_LICENSE_URL = + "media/mpd/sample_mpd_dashif_license_url"; private static final String NEXT_TAG_NAME = "Next"; private static final String NEXT_TAG = "<" + NEXT_TAG_NAME + "/>"; @@ -951,6 +953,37 @@ public class DashManifestParserTest { assertThat(schemeData1.licenseServerUrl).isEqualTo("https://testserver2.test/AcquireLicense"); } + @Test + public void contentProtection_withDashIfLicenseUrl() throws IOException { + DashManifestParser parser = new DashManifestParser(); + + DashManifest manifest = + parser.parse( + Uri.parse("https://example.com/test.mpd"), + TestUtil.getInputStream( + ApplicationProvider.getApplicationContext(), SAMPLE_MPD_DASHIF_LICENSE_URL)); + + assertThat(manifest.getPeriodCount()).isEqualTo(1); + Period period = manifest.getPeriod(0); + assertThat(period.adaptationSets).hasSize(2); + AdaptationSet adaptationSet0 = period.adaptationSets.get(0); + AdaptationSet adaptationSet1 = period.adaptationSets.get(1); + assertThat(adaptationSet0.representations).hasSize(1); + assertThat(adaptationSet1.representations).hasSize(1); + Representation representation0 = adaptationSet0.representations.get(0); + Representation representation1 = adaptationSet1.representations.get(0); + assertThat(representation0.format.drmInitData.schemeType).isEqualTo("cenc"); + assertThat(representation1.format.drmInitData.schemeType).isEqualTo("cenc"); + assertThat(representation0.format.drmInitData.schemeDataCount).isEqualTo(2); + assertThat(representation1.format.drmInitData.schemeDataCount).isEqualTo(2); + DrmInitData.SchemeData schemeData0 = representation0.format.drmInitData.get(0); + DrmInitData.SchemeData schemeData1 = representation1.format.drmInitData.get(0); + assertThat(schemeData0.uuid).isEqualTo(C.WIDEVINE_UUID); + assertThat(schemeData1.uuid).isEqualTo(C.WIDEVINE_UUID); + assertThat(schemeData0.licenseServerUrl).isEqualTo("https://testserver1.test/AcquireLicense"); + assertThat(schemeData1.licenseServerUrl).isEqualTo("https://testserver2.test/AcquireLicense"); + } + private static List buildCea608AccessibilityDescriptors(String value) { return Collections.singletonList(new Descriptor("urn:scte:dash:cc:cea-608:2015", value, null)); } diff --git a/libraries/test_data/src/test/assets/media/mpd/sample_mpd_dashif_license_url b/libraries/test_data/src/test/assets/media/mpd/sample_mpd_dashif_license_url new file mode 100644 index 0000000000..128741590d --- /dev/null +++ b/libraries/test_data/src/test/assets/media/mpd/sample_mpd_dashif_license_url @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + AAAANHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABQIARIQnrQFDeRLSAKTLifXUIPiZg== + https://testserver1.test/AcquireLicense + + + + + + https://testserver2.test/AcquireLicense + AAAANHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABQIARIQnrQFDeRLSAKTLifXUIPiZg== + + + + + +