From 64951d23260db5e027a6731cb2ee985714be5820 Mon Sep 17 00:00:00 2001 From: albertdaurell Date: Wed, 16 Jul 2025 11:09:48 +0200 Subject: [PATCH 1/2] Always sort AdaptationSets by mimeType --- .../dash/manifest/DashManifestParser.java | 1 + .../dash/manifest/DashManifestParserTest.java | 28 ++++++++++++++ .../mpd/sample_mpd_segment_template_order | 37 +++++++++++++++++++ 3 files changed, 66 insertions(+) create mode 100644 libraries/test_data/src/test/assets/media/mpd/sample_mpd_segment_template_order 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 09d9282aa95..7660dc1ef51 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 @@ -393,6 +393,7 @@ protected Period buildPeriod( List adaptationSets, List eventStreams, @Nullable Descriptor assetIdentifier) { + java.util.Collections.sort(adaptationSets, (a, b) -> Integer.compare(a.type, b.type)); return new Period(id, startMs, adaptationSets, eventStreams, assetIdentifier); } 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 c4b6499a043..7b3e9716795 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 @@ -55,6 +55,8 @@ public class DashManifestParserTest { 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"; + private static final String SAMPLE_MPD_SEGMENT_TEMPLATE_ORDER = + "media/mpd/sample_mpd_segment_template_order"; private static final String SAMPLE_MPD_EVENT_STREAM = "media/mpd/sample_mpd_event_stream"; private static final String SAMPLE_MPD_IMAGES = "media/mpd/sample_mpd_images"; private static final String SAMPLE_MPD_LABELS = "media/mpd/sample_mpd_labels"; @@ -116,6 +118,11 @@ public void parseMediaPresentationDescription_segmentTemplate() throws IOExcepti Period period = manifest.getPeriod(0); assertThat(period).isNotNull(); assertThat(period.adaptationSets).hasSize(2); + // AdaptationSets should be always sorted from DashManifestParser::buildPeriod by type + assertThat(period.adaptationSets.get(0).type).isEqualTo(C.TRACK_TYPE_AUDIO); + assertThat(period.adaptationSets.get(0).representations).hasSize(1); + assertThat(period.adaptationSets.get(1).type).isEqualTo(C.TRACK_TYPE_VIDEO); + assertThat(period.adaptationSets.get(1).representations).hasSize(5); for (AdaptationSet adaptationSet : period.adaptationSets) { assertThat(adaptationSet).isNotNull(); @@ -132,6 +139,27 @@ public void parseMediaPresentationDescription_segmentTemplate() throws IOExcepti } } + @Test + public void parseMediaPresentationDescription_buildPeriod() throws IOException { + DashManifestParser parser = new DashManifestParser(); + DashManifest manifest = + parser.parse( + Uri.parse("https://example.com/test.mpd"), + TestUtil.getInputStream( + ApplicationProvider.getApplicationContext(), SAMPLE_MPD_SEGMENT_TEMPLATE_ORDER)); + + assertThat(manifest.getPeriodCount()).isEqualTo(1); + + Period period = manifest.getPeriod(0); + assertThat(period).isNotNull(); + assertThat(period.adaptationSets).hasSize(2); + // AdaptationSets should be always sorted from DashManifestParser::buildPeriod by type + assertThat(period.adaptationSets.get(0).type).isEqualTo(C.TRACK_TYPE_AUDIO); + assertThat(period.adaptationSets.get(0).representations).hasSize(1); + assertThat(period.adaptationSets.get(1).type).isEqualTo(C.TRACK_TYPE_VIDEO); + assertThat(period.adaptationSets.get(1).representations).hasSize(5); + } + @Test public void parseMediaPresentationDescription_eventStream() throws IOException { DashManifestParser parser = new DashManifestParser(); diff --git a/libraries/test_data/src/test/assets/media/mpd/sample_mpd_segment_template_order b/libraries/test_data/src/test/assets/media/mpd/sample_mpd_segment_template_order new file mode 100644 index 00000000000..3289e897c83 --- /dev/null +++ b/libraries/test_data/src/test/assets/media/mpd/sample_mpd_segment_template_order @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + http://redirector.googlevideo.com/videoplayback/id/BktsoMO3OMs.0/itag/133/source/yt_live_broadcast/ratebypass/yes/cmbypass/yes/mime/video%2Fmp4/live/1/gir/yes/noclen/1/signature/90154AE9C5C9D9D519CBF2E43AB0A1778375992D.40E2E855ADFB38FA7E95E168FEEEA6796B080BD7/key/dg_test0/mpd_version/5/ip/0.0.0.0/ipbits/0/expire/1476490914/sparams/ip,ipbits,expire,id,itag,source,ratebypass,cmbypass,mime,live,gir,noclen/ + + + http://redirector.googlevideo.com/videoplayback/id/BktsoMO3OMs.0/itag/134/source/yt_live_broadcast/ratebypass/yes/cmbypass/yes/mime/video%2Fmp4/live/1/gir/yes/noclen/1/signature/5C094AEFDCEB1A4D2F3C05F8BD095C336EF0E1C3.7AE6B9951B0237AAE6F031927AACAC4974BAFFAA/key/dg_test0/mpd_version/5/ip/0.0.0.0/ipbits/0/expire/1476490914/sparams/ip,ipbits,expire,id,itag,source,ratebypass,cmbypass,mime,live,gir,noclen/ + + + http://redirector.googlevideo.com/videoplayback/id/BktsoMO3OMs.0/itag/135/source/yt_live_broadcast/ratebypass/yes/cmbypass/yes/mime/video%2Fmp4/live/1/gir/yes/noclen/1/signature/1F7660CA4E5B4AE4D60E18795680E34CDD2EF3C9.800B0A1D5F490DE142CCF4C88C64FD21D42129/key/dg_test0/mpd_version/5/ip/0.0.0.0/ipbits/0/expire/1476490914/sparams/ip,ipbits,expire,id,itag,source,ratebypass,cmbypass,mime,live,gir,noclen/ + + + http://redirector.googlevideo.com/videoplayback/id/BktsoMO3OMs.0/itag/160/source/yt_live_broadcast/ratebypass/yes/cmbypass/yes/mime/video%2Fmp4/live/1/gir/yes/noclen/1/signature/94EB61673784DF0C4237A1A866F2E171C8A64ADB.AEC00AA06C2278FEA8702FB62693B70D8977F46C/key/dg_test0/mpd_version/5/ip/0.0.0.0/ipbits/0/expire/1476490914/sparams/ip,ipbits,expire,id,itag,source,ratebypass,cmbypass,mime,live,gir,noclen/ + + + http://redirector.googlevideo.com/videoplayback/id/BktsoMO3OMs.0/itag/136/source/yt_live_broadcast/ratebypass/yes/cmbypass/yes/mime/video%2Fmp4/live/1/gir/yes/noclen/1/signature/6D8C34FC30A1F1A4F700B61180D1C4CCF6274844.29EBCB4A837DE626C52C66CF650519E61C2FF0BF/key/dg_test0/mpd_version/5/ip/0.0.0.0/ipbits/0/expire/1476490914/sparams/ip,ipbits,expire,id,itag,source,ratebypass,cmbypass,mime,live,gir,noclen/ + + + + + + + http://redirector.googlevideo.com/videoplayback/id/BktsoMO3OMs.0/itag/140/source/yt_live_broadcast/ratebypass/yes/cmbypass/yes/mime/audio%2Fmp4/live/1/gir/yes/noclen/1/signature/B5137EA0CC278C07DD056D204E863CC81EDEB39E.1AD5D242EBC94922EDA7165353A89A5E08A4103A/key/dg_test0/mpd_version/5/ip/0.0.0.0/ipbits/0/expire/1476490914/sparams/ip,ipbits,expire,id,itag,source,ratebypass,cmbypass,mime,live,gir,noclen/ + + + + From 59239b986626b0ae1e6cf368a7fb51504489fdde Mon Sep 17 00:00:00 2001 From: Marc Baechinger Date: Fri, 18 Jul 2025 11:35:17 +0200 Subject: [PATCH 2/2] Add release notes --- RELEASENOTES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 5edb7f8c122..561f61dfcbc 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -88,6 +88,8 @@ when there are no chunks available in the buffer [#2598](https://github.com/androidx/media/issues/2598). * DASH extension: + * Sort adaption sets by type to avoid `IndexOutOfBoundsException` + ([#2612](https://github.com/androidx/media/pull/2612)). * Smooth Streaming extension: * RTSP extension: * Decoder extensions (FFmpeg, VP9, AV1, etc.):