diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index 6775fa6643..7aa5f2710b 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -103,6 +103,8 @@
priority in manifests that do not declare the dvb namespace. This
prevents the exclusion logic to exclude base URL when they actually
should be used as a fallback base URL.
+ * Support relative `MPD.Location` URLs
+ ([#9939](https://github.com/google/ExoPlayer/issues/9939)).
* HLS:
* Use chunkless preparation by default to improve start up time. If your
renditions contain muxed closed-caption tracks that are *not* declared
diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java
index 867018d33c..86fd8239df 100644
--- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java
+++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java
@@ -161,7 +161,7 @@ public class DashManifestParser extends DefaultHandler
} else if (XmlPullParserUtil.isStartTag(xpp, "UTCTiming")) {
utcTiming = parseUtcTiming(xpp);
} else if (XmlPullParserUtil.isStartTag(xpp, "Location")) {
- location = Uri.parse(xpp.nextText());
+ location = UriUtil.resolveToUri(documentBaseUri.toString(), xpp.nextText());
} else if (XmlPullParserUtil.isStartTag(xpp, "ServiceDescription")) {
serviceDescription = parseServiceDescription(xpp);
} else if (XmlPullParserUtil.isStartTag(xpp, "Period") && !seenEarlyAccessPeriod) {
diff --git a/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParserTest.java b/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParserTest.java
index 3a2ce9a309..3038ceedd3 100644
--- a/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParserTest.java
+++ b/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParserTest.java
@@ -46,6 +46,10 @@ import org.xmlpull.v1.XmlPullParserFactory;
public class DashManifestParserTest {
private static final String SAMPLE_MPD_LIVE = "media/mpd/sample_mpd_live";
+ private static final String SAMPLE_MPD_LIVE_LOCATION_REDIRECT_RELATIVE =
+ "media/mpd/sample_mpd_live_location_redirect_relative";
+ private static final String SAMPLE_MPD_LIVE_LOCATION_REDIRECT_ABSOLUTE =
+ "media/mpd/sample_mpd_live_location_redirect_absolute";
private static final String SAMPLE_MPD_UNKNOWN_MIME_TYPE =
"media/mpd/sample_mpd_unknown_mime_type";
private static final String SAMPLE_MPD_SEGMENT_TEMPLATE = "media/mpd/sample_mpd_segment_template";
@@ -201,6 +205,32 @@ public class DashManifestParserTest {
assertThat(manifest.programInformation).isEqualTo(expectedProgramInformation);
}
+ @Test
+ public void parseMediaPresentationDescription_locationRedirectRelative() throws IOException {
+ DashManifestParser parser = new DashManifestParser();
+ DashManifest manifest =
+ parser.parse(
+ Uri.parse("https://example.com/a/b/test.mpd"),
+ TestUtil.getInputStream(
+ ApplicationProvider.getApplicationContext(),
+ SAMPLE_MPD_LIVE_LOCATION_REDIRECT_RELATIVE));
+ Uri expectedLocation = Uri.parse("https://example.com/a/relative/redirect.mpd");
+ assertThat(manifest.location).isEqualTo(expectedLocation);
+ }
+
+ @Test
+ public void parseMediaPresentationDescription_locationRedirectAbsolute() throws IOException {
+ DashManifestParser parser = new DashManifestParser();
+ DashManifest manifest =
+ parser.parse(
+ Uri.parse("https://example.com/a/b/test.mpd"),
+ TestUtil.getInputStream(
+ ApplicationProvider.getApplicationContext(),
+ SAMPLE_MPD_LIVE_LOCATION_REDIRECT_ABSOLUTE));
+ Uri expectedLocation = Uri.parse("https://example2.com/absolute/redirect.mpd");
+ assertThat(manifest.location).isEqualTo(expectedLocation);
+ }
+
@Test
public void parseMediaPresentationDescription_images() throws IOException {
DashManifestParser parser = new DashManifestParser();
diff --git a/testdata/src/test/assets/media/mpd/sample_mpd_live_location_redirect_absolute b/testdata/src/test/assets/media/mpd/sample_mpd_live_location_redirect_absolute
new file mode 100644
index 0000000000..a6b368e163
--- /dev/null
+++ b/testdata/src/test/assets/media/mpd/sample_mpd_live_location_redirect_absolute
@@ -0,0 +1,21 @@
+
+
+ https://example2.com/absolute/redirect.mpd
+
+
+
+
+
+
+
+
+
diff --git a/testdata/src/test/assets/media/mpd/sample_mpd_live_location_redirect_relative b/testdata/src/test/assets/media/mpd/sample_mpd_live_location_redirect_relative
new file mode 100644
index 0000000000..63db7de219
--- /dev/null
+++ b/testdata/src/test/assets/media/mpd/sample_mpd_live_location_redirect_relative
@@ -0,0 +1,21 @@
+
+
+ ../relative/redirect.mpd
+
+
+
+
+
+
+
+
+