mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Check language/role flags before merging adaptation sets
The spec technically allows to mark adaptation sets with the switching property if they allow seamless switching with non-overlapping segments. This is typically only used for compatible content (e.g. different codecs), but the spec allows it to be used for other content as well (e.g. different languages, roles). ExoPlayer's concept of a TrackGroup only allows formats with the same language and role flags to be merged, so we should check that before merging. Issue: androidx/media#2222 #cherrypick PiperOrigin-RevId: 736564055
This commit is contained in:
parent
412ba2e201
commit
d37f05238a
@ -51,6 +51,9 @@
|
|||||||
* RTMP extension:
|
* RTMP extension:
|
||||||
* HLS extension:
|
* HLS extension:
|
||||||
* DASH extension:
|
* DASH extension:
|
||||||
|
* Fix issue where adaptation sets marked with `adaptation-set-switching`
|
||||||
|
but different languages or role flags are merged together
|
||||||
|
([#2222](https://github.com/androidx/media/issues/2222)).
|
||||||
* Smooth Streaming extension:
|
* Smooth Streaming extension:
|
||||||
* RTSP extension:
|
* RTSP extension:
|
||||||
* Decoder extensions (FFmpeg, VP9, AV1, etc.):
|
* Decoder extensions (FFmpeg, VP9, AV1, etc.):
|
||||||
|
@ -72,6 +72,7 @@ import java.util.Arrays;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.IdentityHashMap;
|
import java.util.IdentityHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
@ -624,7 +625,9 @@ import java.util.regex.Pattern;
|
|||||||
@Nullable
|
@Nullable
|
||||||
Integer otherAdaptationSetIndex =
|
Integer otherAdaptationSetIndex =
|
||||||
adaptationSetIdToIndex.get(Long.parseLong(adaptationSetId));
|
adaptationSetIdToIndex.get(Long.parseLong(adaptationSetId));
|
||||||
if (otherAdaptationSetIndex != null) {
|
if (otherAdaptationSetIndex != null
|
||||||
|
&& canMergeAdaptationSets(
|
||||||
|
adaptationSet, adaptationSets.get(otherAdaptationSetIndex))) {
|
||||||
mergedGroupIndex = min(mergedGroupIndex, otherAdaptationSetIndex);
|
mergedGroupIndex = min(mergedGroupIndex, otherAdaptationSetIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -650,6 +653,20 @@ import java.util.regex.Pattern;
|
|||||||
return groupedAdaptationSetIndices;
|
return groupedAdaptationSetIndices;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean canMergeAdaptationSets(
|
||||||
|
AdaptationSet adaptationSet1, AdaptationSet adaptationSet2) {
|
||||||
|
if (adaptationSet1.type != adaptationSet2.type) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (adaptationSet1.representations.isEmpty() || adaptationSet2.representations.isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Format format1 = adaptationSet1.representations.get(0).format;
|
||||||
|
Format format2 = adaptationSet2.representations.get(0).format;
|
||||||
|
return Objects.equals(format1.language, format2.language)
|
||||||
|
&& format1.roleFlags == format2.roleFlags;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Iterates through list of primary track groups and identifies embedded tracks.
|
* Iterates through list of primary track groups and identifies embedded tracks.
|
||||||
*
|
*
|
||||||
|
@ -94,6 +94,31 @@ public final class DashMediaPeriodTest {
|
|||||||
MediaPeriodAsserts.assertTrackGroups(dashMediaPeriod, expectedTrackGroups);
|
MediaPeriodAsserts.assertTrackGroups(dashMediaPeriod, expectedTrackGroups);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void
|
||||||
|
adaptationSetSwitchingProperty_withIncompatibleFormats_mergesOnlyCompatibleTrackGroups()
|
||||||
|
throws IOException {
|
||||||
|
DashManifest manifest = parseManifest("media/mpd/sample_mpd_switching_property_incompatible");
|
||||||
|
DashMediaPeriod dashMediaPeriod = createDashMediaPeriod(manifest, /* periodIndex= */ 0);
|
||||||
|
List<AdaptationSet> adaptationSets = manifest.getPeriod(0).adaptationSets;
|
||||||
|
|
||||||
|
// Only the two matching pairs of adaptation sets should be merged.
|
||||||
|
TrackGroupArray expectedTrackGroups =
|
||||||
|
new TrackGroupArray(
|
||||||
|
new TrackGroup(/* id= */ "0", adaptationSets.get(0).representations.get(0).format),
|
||||||
|
new TrackGroup(
|
||||||
|
/* id= */ "1",
|
||||||
|
adaptationSets.get(1).representations.get(0).format,
|
||||||
|
adaptationSets.get(3).representations.get(0).format),
|
||||||
|
new TrackGroup(
|
||||||
|
/* id= */ "2",
|
||||||
|
adaptationSets.get(2).representations.get(0).format,
|
||||||
|
adaptationSets.get(4).representations.get(0).format),
|
||||||
|
new TrackGroup(/* id= */ "5", adaptationSets.get(5).representations.get(0).format));
|
||||||
|
|
||||||
|
MediaPeriodAsserts.assertTrackGroups(dashMediaPeriod, expectedTrackGroups);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void trickPlayProperty_mergesTrackGroups() throws IOException {
|
public void trickPlayProperty_mergesTrackGroups() throws IOException {
|
||||||
DashManifest manifest = parseManifest("media/mpd/sample_mpd_trick_play_property");
|
DashManifest manifest = parseManifest("media/mpd/sample_mpd_trick_play_property");
|
||||||
|
@ -0,0 +1,42 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<MPD availabilityStartTime="2014-06-19T23:07:42" type="dynamic">
|
||||||
|
<Period start="PT7462826.784S" id="0">
|
||||||
|
<AdaptationSet id="0" lang="fr" contentType="video">
|
||||||
|
<Role schemeIdUri="urn:mpeg:DASH:role:2011" value="commentary"/>
|
||||||
|
<SupplementalProperty
|
||||||
|
schemeIdUri="urn:mpeg:dash:adaptation-set-switching:2016"
|
||||||
|
value="1,2,3,4,5"/>
|
||||||
|
<Representation id="0"/>
|
||||||
|
</AdaptationSet>
|
||||||
|
<AdaptationSet id="1" lang="fr" contentType="video">
|
||||||
|
<SupplementalProperty
|
||||||
|
schemeIdUri="urn:mpeg:dash:adaptation-set-switching:2016"
|
||||||
|
value="0,2,3,4,5"/>
|
||||||
|
<Representation id="1"/>
|
||||||
|
</AdaptationSet>
|
||||||
|
<AdaptationSet id="2" lang="en" contentType="video">
|
||||||
|
<SupplementalProperty
|
||||||
|
schemeIdUri="urn:mpeg:dash:adaptation-set-switching:2016"
|
||||||
|
value="0,1,3,4,5"/>
|
||||||
|
<Representation id="2"/>
|
||||||
|
</AdaptationSet>
|
||||||
|
<AdaptationSet id="3" lang="fr" contentType="video">
|
||||||
|
<SupplementalProperty
|
||||||
|
schemeIdUri="urn:mpeg:dash:adaptation-set-switching:2016"
|
||||||
|
value="0,1,2,4,5"/>
|
||||||
|
<Representation id="3"/>
|
||||||
|
</AdaptationSet>
|
||||||
|
<AdaptationSet id="4" lang="en" contentType="video">
|
||||||
|
<SupplementalProperty
|
||||||
|
schemeIdUri="urn:mpeg:dash:adaptation-set-switching:2016"
|
||||||
|
value="0,1,2,3,5"/>
|
||||||
|
<Representation id="4"/>
|
||||||
|
</AdaptationSet>
|
||||||
|
<AdaptationSet id="5" lang="en" contentType="audio">
|
||||||
|
<SupplementalProperty
|
||||||
|
schemeIdUri="urn:mpeg:dash:adaptation-set-switching:2016"
|
||||||
|
value="0,1,2,3,4"/>
|
||||||
|
<Representation id="4"/>
|
||||||
|
</AdaptationSet>
|
||||||
|
</Period>
|
||||||
|
</MPD>
|
Loading…
x
Reference in New Issue
Block a user