mirror of
https://github.com/androidx/media.git
synced 2025-05-16 20:19:57 +08:00
Parse trick-play role flags from DASH manifests
Issue: #6054 PiperOrigin-RevId: 306641689
This commit is contained in:
parent
50926658b6
commit
ba0028ca2c
@ -50,9 +50,10 @@ public class AdaptationSet {
|
||||
*/
|
||||
public final List<Descriptor> accessibilityDescriptors;
|
||||
|
||||
/**
|
||||
* Supplemental properties in the adaptation set.
|
||||
*/
|
||||
/** Essential properties in the adaptation set. */
|
||||
public final List<Descriptor> essentialProperties;
|
||||
|
||||
/** Supplemental properties in the adaptation set. */
|
||||
public final List<Descriptor> supplementalProperties;
|
||||
|
||||
/**
|
||||
@ -62,21 +63,21 @@ public class AdaptationSet {
|
||||
* {@code TRACK_TYPE_*} constants.
|
||||
* @param representations {@link Representation}s in the adaptation set.
|
||||
* @param accessibilityDescriptors Accessibility descriptors in the adaptation set.
|
||||
* @param essentialProperties Essential properties in the adaptation set.
|
||||
* @param supplementalProperties Supplemental properties in the adaptation set.
|
||||
*/
|
||||
public AdaptationSet(int id, int type, List<Representation> representations,
|
||||
List<Descriptor> accessibilityDescriptors, List<Descriptor> supplementalProperties) {
|
||||
public AdaptationSet(
|
||||
int id,
|
||||
int type,
|
||||
List<Representation> representations,
|
||||
List<Descriptor> accessibilityDescriptors,
|
||||
List<Descriptor> essentialProperties,
|
||||
List<Descriptor> supplementalProperties) {
|
||||
this.id = id;
|
||||
this.type = type;
|
||||
this.representations = Collections.unmodifiableList(representations);
|
||||
this.accessibilityDescriptors =
|
||||
accessibilityDescriptors == null
|
||||
? Collections.emptyList()
|
||||
: Collections.unmodifiableList(accessibilityDescriptors);
|
||||
this.supplementalProperties =
|
||||
supplementalProperties == null
|
||||
? Collections.emptyList()
|
||||
: Collections.unmodifiableList(supplementalProperties);
|
||||
this.accessibilityDescriptors = Collections.unmodifiableList(accessibilityDescriptors);
|
||||
this.essentialProperties = Collections.unmodifiableList(essentialProperties);
|
||||
this.supplementalProperties = Collections.unmodifiableList(supplementalProperties);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -224,9 +224,14 @@ public class DashManifest implements FilterableManifest<DashManifest> {
|
||||
key = keys.poll();
|
||||
} while (key.periodIndex == periodIndex && key.groupIndex == adaptationSetIndex);
|
||||
|
||||
copyAdaptationSets.add(new AdaptationSet(adaptationSet.id, adaptationSet.type,
|
||||
copyRepresentations, adaptationSet.accessibilityDescriptors,
|
||||
adaptationSet.supplementalProperties));
|
||||
copyAdaptationSets.add(
|
||||
new AdaptationSet(
|
||||
adaptationSet.id,
|
||||
adaptationSet.type,
|
||||
copyRepresentations,
|
||||
adaptationSet.accessibilityDescriptors,
|
||||
adaptationSet.essentialProperties,
|
||||
adaptationSet.supplementalProperties));
|
||||
} while(key.periodIndex == periodIndex);
|
||||
// Add back the last key which doesn't belong to the period being processed
|
||||
keys.addFirst(key);
|
||||
|
@ -289,6 +289,7 @@ public class DashManifestParser extends DefaultHandler
|
||||
ArrayList<Descriptor> inbandEventStreams = new ArrayList<>();
|
||||
ArrayList<Descriptor> accessibilityDescriptors = new ArrayList<>();
|
||||
ArrayList<Descriptor> roleDescriptors = new ArrayList<>();
|
||||
ArrayList<Descriptor> essentialProperties = new ArrayList<>();
|
||||
ArrayList<Descriptor> supplementalProperties = new ArrayList<>();
|
||||
List<RepresentationInfo> representationInfos = new ArrayList<>();
|
||||
|
||||
@ -317,6 +318,8 @@ public class DashManifestParser extends DefaultHandler
|
||||
audioChannels = parseAudioChannelConfiguration(xpp);
|
||||
} else if (XmlPullParserUtil.isStartTag(xpp, "Accessibility")) {
|
||||
accessibilityDescriptors.add(parseDescriptor(xpp, "Accessibility"));
|
||||
} else if (XmlPullParserUtil.isStartTag(xpp, "EssentialProperty")) {
|
||||
essentialProperties.add(parseDescriptor(xpp, "EssentialProperty"));
|
||||
} else if (XmlPullParserUtil.isStartTag(xpp, "SupplementalProperty")) {
|
||||
supplementalProperties.add(parseDescriptor(xpp, "SupplementalProperty"));
|
||||
} else if (XmlPullParserUtil.isStartTag(xpp, "Representation")) {
|
||||
@ -334,6 +337,7 @@ public class DashManifestParser extends DefaultHandler
|
||||
language,
|
||||
roleDescriptors,
|
||||
accessibilityDescriptors,
|
||||
essentialProperties,
|
||||
supplementalProperties,
|
||||
segmentBase,
|
||||
periodDurationMs);
|
||||
@ -370,14 +374,28 @@ public class DashManifestParser extends DefaultHandler
|
||||
inbandEventStreams));
|
||||
}
|
||||
|
||||
return buildAdaptationSet(id, contentType, representations, accessibilityDescriptors,
|
||||
return buildAdaptationSet(
|
||||
id,
|
||||
contentType,
|
||||
representations,
|
||||
accessibilityDescriptors,
|
||||
essentialProperties,
|
||||
supplementalProperties);
|
||||
}
|
||||
|
||||
protected AdaptationSet buildAdaptationSet(int id, int contentType,
|
||||
List<Representation> representations, List<Descriptor> accessibilityDescriptors,
|
||||
protected AdaptationSet buildAdaptationSet(
|
||||
int id,
|
||||
int contentType,
|
||||
List<Representation> representations,
|
||||
List<Descriptor> accessibilityDescriptors,
|
||||
List<Descriptor> essentialProperties,
|
||||
List<Descriptor> supplementalProperties) {
|
||||
return new AdaptationSet(id, contentType, representations, accessibilityDescriptors,
|
||||
return new AdaptationSet(
|
||||
id,
|
||||
contentType,
|
||||
representations,
|
||||
accessibilityDescriptors,
|
||||
essentialProperties,
|
||||
supplementalProperties);
|
||||
}
|
||||
|
||||
@ -492,6 +510,7 @@ public class DashManifestParser extends DefaultHandler
|
||||
@Nullable String adaptationSetLanguage,
|
||||
List<Descriptor> adaptationSetRoleDescriptors,
|
||||
List<Descriptor> adaptationSetAccessibilityDescriptors,
|
||||
List<Descriptor> adaptationSetEssentialProperties,
|
||||
List<Descriptor> adaptationSetSupplementalProperties,
|
||||
@Nullable SegmentBase segmentBase,
|
||||
long periodDurationMs)
|
||||
@ -509,7 +528,9 @@ public class DashManifestParser extends DefaultHandler
|
||||
String drmSchemeType = null;
|
||||
ArrayList<SchemeData> drmSchemeDatas = new ArrayList<>();
|
||||
ArrayList<Descriptor> inbandEventStreams = new ArrayList<>();
|
||||
ArrayList<Descriptor> supplementalProperties = new ArrayList<>();
|
||||
ArrayList<Descriptor> essentialProperties = new ArrayList<>(adaptationSetEssentialProperties);
|
||||
ArrayList<Descriptor> supplementalProperties =
|
||||
new ArrayList<>(adaptationSetSupplementalProperties);
|
||||
|
||||
boolean seenFirstBaseUrl = false;
|
||||
do {
|
||||
@ -542,6 +563,8 @@ public class DashManifestParser extends DefaultHandler
|
||||
}
|
||||
} else if (XmlPullParserUtil.isStartTag(xpp, "InbandEventStream")) {
|
||||
inbandEventStreams.add(parseDescriptor(xpp, "InbandEventStream"));
|
||||
} else if (XmlPullParserUtil.isStartTag(xpp, "EssentialProperty")) {
|
||||
essentialProperties.add(parseDescriptor(xpp, "EssentialProperty"));
|
||||
} else if (XmlPullParserUtil.isStartTag(xpp, "SupplementalProperty")) {
|
||||
supplementalProperties.add(parseDescriptor(xpp, "SupplementalProperty"));
|
||||
} else {
|
||||
@ -563,6 +586,7 @@ public class DashManifestParser extends DefaultHandler
|
||||
adaptationSetRoleDescriptors,
|
||||
adaptationSetAccessibilityDescriptors,
|
||||
codecs,
|
||||
essentialProperties,
|
||||
supplementalProperties);
|
||||
segmentBase = segmentBase != null ? segmentBase : new SingleSegmentBase();
|
||||
|
||||
@ -583,6 +607,7 @@ public class DashManifestParser extends DefaultHandler
|
||||
List<Descriptor> roleDescriptors,
|
||||
List<Descriptor> accessibilityDescriptors,
|
||||
@Nullable String codecs,
|
||||
List<Descriptor> essentialProperties,
|
||||
List<Descriptor> supplementalProperties) {
|
||||
@Nullable String sampleMimeType = getSampleMimeType(containerMimeType, codecs);
|
||||
if (MimeTypes.AUDIO_E_AC3.equals(sampleMimeType)) {
|
||||
@ -591,6 +616,8 @@ public class DashManifestParser extends DefaultHandler
|
||||
@C.SelectionFlags int selectionFlags = parseSelectionFlagsFromRoleDescriptors(roleDescriptors);
|
||||
@C.RoleFlags int roleFlags = parseRoleFlagsFromRoleDescriptors(roleDescriptors);
|
||||
roleFlags |= parseRoleFlagsFromAccessibilityDescriptors(accessibilityDescriptors);
|
||||
roleFlags |= parseRoleFlagsFromProperties(essentialProperties);
|
||||
roleFlags |= parseRoleFlagsFromProperties(supplementalProperties);
|
||||
|
||||
Format.Builder formatBuilder =
|
||||
new Format.Builder()
|
||||
@ -1185,6 +1212,18 @@ public class DashManifestParser extends DefaultHandler
|
||||
return result;
|
||||
}
|
||||
|
||||
@C.RoleFlags
|
||||
protected int parseRoleFlagsFromProperties(List<Descriptor> accessibilityDescriptors) {
|
||||
@C.RoleFlags int result = 0;
|
||||
for (int i = 0; i < accessibilityDescriptors.size(); i++) {
|
||||
Descriptor descriptor = accessibilityDescriptors.get(i);
|
||||
if ("http://dashif.org/guidelines/trickmode".equalsIgnoreCase(descriptor.schemeIdUri)) {
|
||||
result |= C.ROLE_FLAG_TRICK_PLAY;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@C.RoleFlags
|
||||
protected int parseDashRoleSchemeValue(@Nullable String value) {
|
||||
if (value == null) {
|
||||
|
@ -165,6 +165,7 @@ public final class DashMediaPeriodTest {
|
||||
trackType,
|
||||
Arrays.asList(representations),
|
||||
/* accessibilityDescriptors= */ Collections.emptyList(),
|
||||
/* essentialProperties= */ Collections.emptyList(),
|
||||
descriptor == null ? Collections.emptyList() : Collections.singletonList(descriptor));
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,7 @@ import com.google.android.exoplayer2.source.dash.manifest.SegmentBase.SingleSegm
|
||||
import com.google.android.exoplayer2.upstream.DummyDataSource;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@ -69,7 +70,13 @@ public final class DashUtilTest {
|
||||
}
|
||||
|
||||
private static AdaptationSet newAdaptationSet(Representation... representations) {
|
||||
return new AdaptationSet(0, C.TRACK_TYPE_VIDEO, Arrays.asList(representations), null, null);
|
||||
return new AdaptationSet(
|
||||
/* id= */ 0,
|
||||
C.TRACK_TYPE_VIDEO,
|
||||
Arrays.asList(representations),
|
||||
/* accessibilityDescriptors= */ Collections.emptyList(),
|
||||
/* essentialProperties= */ Collections.emptyList(),
|
||||
/* supplementalProperties= */ Collections.emptyList());
|
||||
}
|
||||
|
||||
private static Representation newRepresentation(DrmInitData drmInitData) {
|
||||
|
@ -49,6 +49,7 @@ public class DashManifestParserTest {
|
||||
private static final String SAMPLE_MPD_LABELS = "mpd/sample_mpd_labels";
|
||||
private static final String SAMPLE_MPD_ASSET_IDENTIFIER = "mpd/sample_mpd_asset_identifier";
|
||||
private static final String SAMPLE_MPD_TEXT = "mpd/sample_mpd_text";
|
||||
private static final String SAMPLE_MPD_TRICK_PLAY = "mpd/sample_mpd_trick_play";
|
||||
|
||||
private static final String NEXT_TAG_NAME = "Next";
|
||||
private static final String NEXT_TAG = "<" + NEXT_TAG_NAME + "/>";
|
||||
@ -173,7 +174,7 @@ public class DashManifestParserTest {
|
||||
DashManifestParser parser = new DashManifestParser();
|
||||
DashManifest manifest =
|
||||
parser.parse(
|
||||
Uri.parse("Https://example.com/test.mpd"),
|
||||
Uri.parse("https://example.com/test.mpd"),
|
||||
TestUtil.getInputStream(ApplicationProvider.getApplicationContext(), SAMPLE_MPD));
|
||||
ProgramInformation expectedProgramInformation =
|
||||
new ProgramInformation(
|
||||
@ -201,7 +202,7 @@ public class DashManifestParserTest {
|
||||
DashManifestParser parser = new DashManifestParser();
|
||||
DashManifest manifest =
|
||||
parser.parse(
|
||||
Uri.parse("Https://example.com/test.mpd"),
|
||||
Uri.parse("https://example.com/test.mpd"),
|
||||
TestUtil.getInputStream(ApplicationProvider.getApplicationContext(), SAMPLE_MPD_TEXT));
|
||||
|
||||
List<AdaptationSet> adaptationSets = manifest.getPeriod(0).adaptationSets;
|
||||
@ -225,6 +226,46 @@ public class DashManifestParserTest {
|
||||
assertThat(adaptationSets.get(2).type).isEqualTo(C.TRACK_TYPE_TEXT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseMediaPresentationDescription_trickPlay() throws IOException {
|
||||
DashManifestParser parser = new DashManifestParser();
|
||||
DashManifest manifest =
|
||||
parser.parse(
|
||||
Uri.parse("https://example.com/test.mpd"),
|
||||
TestUtil.getInputStream(
|
||||
ApplicationProvider.getApplicationContext(), SAMPLE_MPD_TRICK_PLAY));
|
||||
|
||||
List<AdaptationSet> adaptationSets = manifest.getPeriod(0).adaptationSets;
|
||||
|
||||
AdaptationSet adaptationSet = adaptationSets.get(0);
|
||||
assertThat(adaptationSet.essentialProperties).isEmpty();
|
||||
assertThat(adaptationSet.supplementalProperties).isEmpty();
|
||||
assertThat(adaptationSet.representations.get(0).format.roleFlags).isEqualTo(0);
|
||||
|
||||
adaptationSet = adaptationSets.get(1);
|
||||
assertThat(adaptationSet.essentialProperties).isEmpty();
|
||||
assertThat(adaptationSet.supplementalProperties).isEmpty();
|
||||
assertThat(adaptationSet.representations.get(0).format.roleFlags).isEqualTo(0);
|
||||
|
||||
adaptationSet = adaptationSets.get(2);
|
||||
assertThat(adaptationSet.essentialProperties).hasSize(1);
|
||||
assertThat(adaptationSet.essentialProperties.get(0).schemeIdUri)
|
||||
.isEqualTo("http://dashif.org/guidelines/trickmode");
|
||||
assertThat(adaptationSet.essentialProperties.get(0).value).isEqualTo("0");
|
||||
assertThat(adaptationSet.supplementalProperties).isEmpty();
|
||||
assertThat(adaptationSet.representations.get(0).format.roleFlags)
|
||||
.isEqualTo(C.ROLE_FLAG_TRICK_PLAY);
|
||||
|
||||
adaptationSet = adaptationSets.get(3);
|
||||
assertThat(adaptationSet.essentialProperties).isEmpty();
|
||||
assertThat(adaptationSet.supplementalProperties).hasSize(1);
|
||||
assertThat(adaptationSet.supplementalProperties.get(0).schemeIdUri)
|
||||
.isEqualTo("http://dashif.org/guidelines/trickmode");
|
||||
assertThat(adaptationSet.supplementalProperties.get(0).value).isEqualTo("1");
|
||||
assertThat(adaptationSet.representations.get(0).format.roleFlags)
|
||||
.isEqualTo(C.ROLE_FLAG_TRICK_PLAY);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseSegmentTimeline_repeatCount() throws Exception {
|
||||
DashManifestParser parser = new DashManifestParser();
|
||||
|
@ -239,6 +239,12 @@ public class DashManifestTest {
|
||||
}
|
||||
|
||||
private static AdaptationSet newAdaptationSet(int seed, Representation... representations) {
|
||||
return new AdaptationSet(++seed, ++seed, Arrays.asList(representations), null, null);
|
||||
return new AdaptationSet(
|
||||
++seed,
|
||||
++seed,
|
||||
Arrays.asList(representations),
|
||||
/* accessibilityDescriptors= */ Collections.emptyList(),
|
||||
/* essentialProperties= */ Collections.emptyList(),
|
||||
/* supplementalProperties= */ Collections.emptyList());
|
||||
}
|
||||
}
|
||||
|
32
testdata/src/test/assets/mpd/sample_mpd_trick_play
vendored
Normal file
32
testdata/src/test/assets/mpd/sample_mpd_trick_play
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<MPD type="static" duration="1s" mediaPresentationDuration="PT1S">
|
||||
<Period>
|
||||
<SegmentTemplate startNumber="0" timescale="1000" media="sq/$Number$">
|
||||
<SegmentTimeline>
|
||||
<S d="1000"/>
|
||||
</SegmentTimeline>
|
||||
</SegmentTemplate>
|
||||
<AdaptationSet id="0" mimeType="video/mp4" subsegmentAlignment="true">
|
||||
<Representation id="0" codecs="avc1.42c01f" bandwidth="128000">
|
||||
<BaseURL>https://test.com/0</BaseURL>
|
||||
</Representation>
|
||||
</AdaptationSet>
|
||||
<AdaptationSet id="1" mimeType="video/mp4" subsegmentAlignment="true">
|
||||
<Representation id="0" codecs="avc1.42c01f" bandwidth="128000">
|
||||
<BaseURL>https://test.com/0</BaseURL>
|
||||
</Representation>
|
||||
</AdaptationSet>
|
||||
<AdaptationSet id="2" mimeType="video/mp4" subsegmentAlignment="true">
|
||||
<EssentialProperty schemeIdUri="http://dashif.org/guidelines/trickmode" value="0"/>
|
||||
<Representation id="0" codecs="avc1.42c01f" bandwidth="128000">
|
||||
<BaseURL>https://test.com/0</BaseURL>
|
||||
</Representation>
|
||||
</AdaptationSet>
|
||||
<AdaptationSet id="3" mimeType="video/mp4" subsegmentAlignment="true">
|
||||
<SupplementalProperty schemeIdUri="http://dashif.org/guidelines/trickmode" value="1"/>
|
||||
<Representation id="0" codecs="avc1.42c01f" bandwidth="128000">
|
||||
<BaseURL>https://test.com/0</BaseURL>
|
||||
</Representation>
|
||||
</AdaptationSet>
|
||||
</Period>
|
||||
</MPD>
|
Loading…
x
Reference in New Issue
Block a user