Parse Label elements for adaptation sets

Issue: #6297
PiperOrigin-RevId: 273297284
This commit is contained in:
olly 2019-10-07 16:30:04 +01:00 committed by Oliver Woodman
parent 48bfb37e93
commit b052ea9bed
5 changed files with 151 additions and 14 deletions

View file

@ -24,8 +24,11 @@
* Remove the `DataSpec.FLAG_ALLOW_ICY_METADATA` flag. Instead, set the header
`IcyHeaders.REQUEST_HEADER_ENABLE_METADATA_NAME` in the `DataSpec`
`httpRequestHeaders`.
* DASH: Support negative @r values in segment timelines
([#1787](https://github.com/google/ExoPlayer/issues/1787)).
* DASH:
* Support negative @r values in segment timelines
([#1787](https://github.com/google/ExoPlayer/issues/1787)).
* Support `Label` elements
([#6297](https://github.com/google/ExoPlayer/issues/6297)).
* Add `allowedCapturePolicy` field to `AudioAttributes` wrapper to allow to
opt-out of audio recording.
* Add `DataSpec.httpRequestHeaders` to set HTTP request headers when connecting

View file

@ -1099,6 +1099,39 @@ public final class Format implements Parcelable {
exoMediaCryptoType);
}
public Format copyWithLabel(@Nullable String label) {
return new Format(
id,
label,
selectionFlags,
roleFlags,
bitrate,
codecs,
metadata,
containerMimeType,
sampleMimeType,
maxInputSize,
initializationData,
drmInitData,
subsampleOffsetUs,
width,
height,
frameRate,
rotationDegrees,
pixelWidthHeightRatio,
projectionData,
stereoMode,
colorInfo,
channelCount,
sampleRate,
pcmEncoding,
encoderDelay,
encoderPadding,
language,
accessibilityChannel,
exoMediaCryptoType);
}
public Format copyWithContainerInfo(
@Nullable String id,
@Nullable String label,

View file

@ -316,7 +316,6 @@ public class DashManifestParser extends DefaultHandler
parseRepresentation(
xpp,
baseUrl,
label,
mimeType,
codecs,
width,
@ -343,6 +342,8 @@ public class DashManifestParser extends DefaultHandler
xpp, (SegmentTemplate) segmentBase, supplementalProperties, periodDurationMs);
} else if (XmlPullParserUtil.isStartTag(xpp, "InbandEventStream")) {
inbandEventStreams.add(parseDescriptor(xpp, "InbandEventStream"));
} else if (XmlPullParserUtil.isStartTag(xpp, "Label")) {
label = parseLabel(xpp);
} else if (XmlPullParserUtil.isStartTag(xpp)) {
parseAdaptationSetChild(xpp);
}
@ -353,7 +354,11 @@ public class DashManifestParser extends DefaultHandler
for (int i = 0; i < representationInfos.size(); i++) {
representations.add(
buildRepresentation(
representationInfos.get(i), drmSchemeType, drmSchemeDatas, inbandEventStreams));
representationInfos.get(i),
label,
drmSchemeType,
drmSchemeDatas,
inbandEventStreams));
}
return buildAdaptationSet(id, contentType, representations, accessibilityDescriptors,
@ -482,7 +487,6 @@ public class DashManifestParser extends DefaultHandler
protected RepresentationInfo parseRepresentation(
XmlPullParser xpp,
String baseUrl,
@Nullable String label,
@Nullable String adaptationSetMimeType,
@Nullable String adaptationSetCodecs,
int adaptationSetWidth,
@ -553,7 +557,6 @@ public class DashManifestParser extends DefaultHandler
Format format =
buildFormat(
id,
label,
mimeType,
width,
height,
@ -574,7 +577,6 @@ public class DashManifestParser extends DefaultHandler
protected Format buildFormat(
@Nullable String id,
@Nullable String label,
@Nullable String containerMimeType,
int width,
int height,
@ -598,7 +600,7 @@ public class DashManifestParser extends DefaultHandler
if (MimeTypes.isVideo(sampleMimeType)) {
return Format.createVideoContainerFormat(
id,
label,
/* label= */ null,
containerMimeType,
sampleMimeType,
codecs,
@ -613,7 +615,7 @@ public class DashManifestParser extends DefaultHandler
} else if (MimeTypes.isAudio(sampleMimeType)) {
return Format.createAudioContainerFormat(
id,
label,
/* label= */ null,
containerMimeType,
sampleMimeType,
codecs,
@ -636,7 +638,7 @@ public class DashManifestParser extends DefaultHandler
}
return Format.createTextContainerFormat(
id,
label,
/* label= */ null,
containerMimeType,
sampleMimeType,
codecs,
@ -649,7 +651,7 @@ public class DashManifestParser extends DefaultHandler
}
return Format.createContainerFormat(
id,
label,
/* label= */ null,
containerMimeType,
sampleMimeType,
codecs,
@ -661,10 +663,14 @@ public class DashManifestParser extends DefaultHandler
protected Representation buildRepresentation(
RepresentationInfo representationInfo,
@Nullable String label,
@Nullable String extraDrmSchemeType,
ArrayList<SchemeData> extraDrmSchemeDatas,
ArrayList<Descriptor> extraInbandEventStreams) {
Format format = representationInfo.format;
if (label != null) {
format = format.copyWithLabel(label);
}
String drmSchemeType = representationInfo.drmSchemeType != null
? representationInfo.drmSchemeType : extraDrmSchemeType;
ArrayList<SchemeData> drmSchemeDatas = representationInfo.drmSchemeDatas;
@ -1132,6 +1138,32 @@ public class DashManifestParser extends DefaultHandler
return new ProgramInformation(title, source, copyright, moreInformationURL, lang);
}
/**
* Parses a Label element.
*
* @param xpp The parser from which to read.
* @throws XmlPullParserException If an error occurs parsing the element.
* @throws IOException If an error occurs reading the element.
* @return The parsed label.
*/
protected String parseLabel(XmlPullParser xpp) throws XmlPullParserException, IOException {
return parseText(xpp, "Label");
}
/**
* Parses a BaseURL element.
*
* @param xpp The parser from which to read.
* @param parentBaseUrl A base URL for resolving the parsed URL.
* @throws XmlPullParserException If an error occurs parsing the element.
* @throws IOException If an error occurs reading the element.
* @return The parsed and resolved URL.
*/
protected String parseBaseUrl(XmlPullParser xpp, String parentBaseUrl)
throws XmlPullParserException, IOException {
return UriUtil.resolve(parentBaseUrl, parseText(xpp, "BaseURL"));
}
// AudioChannelConfiguration parsing.
protected int parseAudioChannelConfiguration(XmlPullParser xpp)
@ -1487,10 +1519,18 @@ public class DashManifestParser extends DefaultHandler
}
}
protected static String parseBaseUrl(XmlPullParser xpp, String parentBaseUrl)
protected static String parseText(XmlPullParser xpp, String label)
throws XmlPullParserException, IOException {
xpp.next();
return UriUtil.resolve(parentBaseUrl, xpp.getText());
String text = "";
do {
xpp.next();
if (xpp.getEventType() == XmlPullParser.TEXT) {
text = xpp.getText();
} else {
maybeSkipTag(xpp);
}
} while (!XmlPullParserUtil.isEndTag(xpp, label));
return text;
}
protected static int parseInt(XmlPullParser xpp, String name, int defaultValue) {

View file

@ -0,0 +1,21 @@
<?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="audio/mp4" subsegmentAlignment="true" label="audio label">
<Representation id="0" codecs="mp4a.40.2" audioSamplingRate="48000" bandwidth="144000">
<BaseURL>https://test.com/0</BaseURL>
</Representation>
</AdaptationSet>
<AdaptationSet id="1" mimeType="video/mp4" subsegmentAlignment="true" label="ignored label">
<Representation id="1" codecs="avc1.4d4015" width="426" height="240" bandwidth="258000">
<BaseURL>https://test.com/1</BaseURL>
</Representation>
<Label>video label</Label>
</AdaptationSet>
</Period>
</MPD>

View file

@ -44,6 +44,7 @@ public class DashManifestParserTest {
private static final String SAMPLE_MPD_UNKNOWN_MIME_TYPE = "sample_mpd_unknown_mime_type";
private static final String SAMPLE_MPD_SEGMENT_TEMPLATE = "sample_mpd_segment_template";
private static final String SAMPLE_MPD_EVENT_STREAM = "sample_mpd_event_stream";
private static final String SAMPLE_MPD_LABELS = "sample_mpd_labels";
private static final String NEXT_TAG_NAME = "Next";
private static final String NEXT_TAG = "<" + NEXT_TAG_NAME + "/>";
@ -176,6 +177,21 @@ public class DashManifestParserTest {
assertThat(mpd.programInformation).isEqualTo(expectedProgramInformation);
}
@Test
public void parseMediaPresentationDescription_labels() throws IOException {
DashManifestParser parser = new DashManifestParser();
DashManifest manifest =
parser.parse(
Uri.parse("https://example.com/test.mpd"),
TestUtil.getInputStream(
ApplicationProvider.getApplicationContext(), SAMPLE_MPD_LABELS));
List<AdaptationSet> adaptationSets = manifest.getPeriod(0).adaptationSets;
assertThat(adaptationSets.get(0).representations.get(0).format.label).isEqualTo("audio label");
assertThat(adaptationSets.get(1).representations.get(0).format.label).isEqualTo("video label");
}
@Test
public void parseSegmentTimeline_repeatCount() throws Exception {
DashManifestParser parser = new DashManifestParser();
@ -251,6 +267,30 @@ public class DashManifestParserTest {
assertNextTag(xpp);
}
@Test
public void parseLabel() throws Exception {
DashManifestParser parser = new DashManifestParser();
XmlPullParser xpp = XmlPullParserFactory.newInstance().newPullParser();
xpp.setInput(new StringReader("<Label>test label</Label>" + NEXT_TAG));
xpp.next();
String label = parser.parseLabel(xpp);
assertThat(label).isEqualTo("test label");
assertNextTag(xpp);
}
@Test
public void parseLabel_noText() throws Exception {
DashManifestParser parser = new DashManifestParser();
XmlPullParser xpp = XmlPullParserFactory.newInstance().newPullParser();
xpp.setInput(new StringReader("<Label/>" + NEXT_TAG));
xpp.next();
String label = parser.parseLabel(xpp);
assertThat(label).isEqualTo("");
assertNextTag(xpp);
}
@Test
public void parseCea608AccessibilityChannel() {
assertThat(