mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Parse Label elements for adaptation sets
Issue: #6297 PiperOrigin-RevId: 273297284
This commit is contained in:
parent
48bfb37e93
commit
b052ea9bed
5 changed files with 151 additions and 14 deletions
|
|
@ -24,8 +24,11 @@
|
||||||
* Remove the `DataSpec.FLAG_ALLOW_ICY_METADATA` flag. Instead, set the header
|
* Remove the `DataSpec.FLAG_ALLOW_ICY_METADATA` flag. Instead, set the header
|
||||||
`IcyHeaders.REQUEST_HEADER_ENABLE_METADATA_NAME` in the `DataSpec`
|
`IcyHeaders.REQUEST_HEADER_ENABLE_METADATA_NAME` in the `DataSpec`
|
||||||
`httpRequestHeaders`.
|
`httpRequestHeaders`.
|
||||||
* DASH: Support negative @r values in segment timelines
|
* DASH:
|
||||||
([#1787](https://github.com/google/ExoPlayer/issues/1787)).
|
* 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
|
* Add `allowedCapturePolicy` field to `AudioAttributes` wrapper to allow to
|
||||||
opt-out of audio recording.
|
opt-out of audio recording.
|
||||||
* Add `DataSpec.httpRequestHeaders` to set HTTP request headers when connecting
|
* Add `DataSpec.httpRequestHeaders` to set HTTP request headers when connecting
|
||||||
|
|
|
||||||
|
|
@ -1099,6 +1099,39 @@ public final class Format implements Parcelable {
|
||||||
exoMediaCryptoType);
|
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(
|
public Format copyWithContainerInfo(
|
||||||
@Nullable String id,
|
@Nullable String id,
|
||||||
@Nullable String label,
|
@Nullable String label,
|
||||||
|
|
|
||||||
|
|
@ -316,7 +316,6 @@ public class DashManifestParser extends DefaultHandler
|
||||||
parseRepresentation(
|
parseRepresentation(
|
||||||
xpp,
|
xpp,
|
||||||
baseUrl,
|
baseUrl,
|
||||||
label,
|
|
||||||
mimeType,
|
mimeType,
|
||||||
codecs,
|
codecs,
|
||||||
width,
|
width,
|
||||||
|
|
@ -343,6 +342,8 @@ public class DashManifestParser extends DefaultHandler
|
||||||
xpp, (SegmentTemplate) segmentBase, supplementalProperties, periodDurationMs);
|
xpp, (SegmentTemplate) segmentBase, supplementalProperties, periodDurationMs);
|
||||||
} else if (XmlPullParserUtil.isStartTag(xpp, "InbandEventStream")) {
|
} else if (XmlPullParserUtil.isStartTag(xpp, "InbandEventStream")) {
|
||||||
inbandEventStreams.add(parseDescriptor(xpp, "InbandEventStream"));
|
inbandEventStreams.add(parseDescriptor(xpp, "InbandEventStream"));
|
||||||
|
} else if (XmlPullParserUtil.isStartTag(xpp, "Label")) {
|
||||||
|
label = parseLabel(xpp);
|
||||||
} else if (XmlPullParserUtil.isStartTag(xpp)) {
|
} else if (XmlPullParserUtil.isStartTag(xpp)) {
|
||||||
parseAdaptationSetChild(xpp);
|
parseAdaptationSetChild(xpp);
|
||||||
}
|
}
|
||||||
|
|
@ -353,7 +354,11 @@ public class DashManifestParser extends DefaultHandler
|
||||||
for (int i = 0; i < representationInfos.size(); i++) {
|
for (int i = 0; i < representationInfos.size(); i++) {
|
||||||
representations.add(
|
representations.add(
|
||||||
buildRepresentation(
|
buildRepresentation(
|
||||||
representationInfos.get(i), drmSchemeType, drmSchemeDatas, inbandEventStreams));
|
representationInfos.get(i),
|
||||||
|
label,
|
||||||
|
drmSchemeType,
|
||||||
|
drmSchemeDatas,
|
||||||
|
inbandEventStreams));
|
||||||
}
|
}
|
||||||
|
|
||||||
return buildAdaptationSet(id, contentType, representations, accessibilityDescriptors,
|
return buildAdaptationSet(id, contentType, representations, accessibilityDescriptors,
|
||||||
|
|
@ -482,7 +487,6 @@ public class DashManifestParser extends DefaultHandler
|
||||||
protected RepresentationInfo parseRepresentation(
|
protected RepresentationInfo parseRepresentation(
|
||||||
XmlPullParser xpp,
|
XmlPullParser xpp,
|
||||||
String baseUrl,
|
String baseUrl,
|
||||||
@Nullable String label,
|
|
||||||
@Nullable String adaptationSetMimeType,
|
@Nullable String adaptationSetMimeType,
|
||||||
@Nullable String adaptationSetCodecs,
|
@Nullable String adaptationSetCodecs,
|
||||||
int adaptationSetWidth,
|
int adaptationSetWidth,
|
||||||
|
|
@ -553,7 +557,6 @@ public class DashManifestParser extends DefaultHandler
|
||||||
Format format =
|
Format format =
|
||||||
buildFormat(
|
buildFormat(
|
||||||
id,
|
id,
|
||||||
label,
|
|
||||||
mimeType,
|
mimeType,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
|
|
@ -574,7 +577,6 @@ public class DashManifestParser extends DefaultHandler
|
||||||
|
|
||||||
protected Format buildFormat(
|
protected Format buildFormat(
|
||||||
@Nullable String id,
|
@Nullable String id,
|
||||||
@Nullable String label,
|
|
||||||
@Nullable String containerMimeType,
|
@Nullable String containerMimeType,
|
||||||
int width,
|
int width,
|
||||||
int height,
|
int height,
|
||||||
|
|
@ -598,7 +600,7 @@ public class DashManifestParser extends DefaultHandler
|
||||||
if (MimeTypes.isVideo(sampleMimeType)) {
|
if (MimeTypes.isVideo(sampleMimeType)) {
|
||||||
return Format.createVideoContainerFormat(
|
return Format.createVideoContainerFormat(
|
||||||
id,
|
id,
|
||||||
label,
|
/* label= */ null,
|
||||||
containerMimeType,
|
containerMimeType,
|
||||||
sampleMimeType,
|
sampleMimeType,
|
||||||
codecs,
|
codecs,
|
||||||
|
|
@ -613,7 +615,7 @@ public class DashManifestParser extends DefaultHandler
|
||||||
} else if (MimeTypes.isAudio(sampleMimeType)) {
|
} else if (MimeTypes.isAudio(sampleMimeType)) {
|
||||||
return Format.createAudioContainerFormat(
|
return Format.createAudioContainerFormat(
|
||||||
id,
|
id,
|
||||||
label,
|
/* label= */ null,
|
||||||
containerMimeType,
|
containerMimeType,
|
||||||
sampleMimeType,
|
sampleMimeType,
|
||||||
codecs,
|
codecs,
|
||||||
|
|
@ -636,7 +638,7 @@ public class DashManifestParser extends DefaultHandler
|
||||||
}
|
}
|
||||||
return Format.createTextContainerFormat(
|
return Format.createTextContainerFormat(
|
||||||
id,
|
id,
|
||||||
label,
|
/* label= */ null,
|
||||||
containerMimeType,
|
containerMimeType,
|
||||||
sampleMimeType,
|
sampleMimeType,
|
||||||
codecs,
|
codecs,
|
||||||
|
|
@ -649,7 +651,7 @@ public class DashManifestParser extends DefaultHandler
|
||||||
}
|
}
|
||||||
return Format.createContainerFormat(
|
return Format.createContainerFormat(
|
||||||
id,
|
id,
|
||||||
label,
|
/* label= */ null,
|
||||||
containerMimeType,
|
containerMimeType,
|
||||||
sampleMimeType,
|
sampleMimeType,
|
||||||
codecs,
|
codecs,
|
||||||
|
|
@ -661,10 +663,14 @@ public class DashManifestParser extends DefaultHandler
|
||||||
|
|
||||||
protected Representation buildRepresentation(
|
protected Representation buildRepresentation(
|
||||||
RepresentationInfo representationInfo,
|
RepresentationInfo representationInfo,
|
||||||
|
@Nullable String label,
|
||||||
@Nullable String extraDrmSchemeType,
|
@Nullable String extraDrmSchemeType,
|
||||||
ArrayList<SchemeData> extraDrmSchemeDatas,
|
ArrayList<SchemeData> extraDrmSchemeDatas,
|
||||||
ArrayList<Descriptor> extraInbandEventStreams) {
|
ArrayList<Descriptor> extraInbandEventStreams) {
|
||||||
Format format = representationInfo.format;
|
Format format = representationInfo.format;
|
||||||
|
if (label != null) {
|
||||||
|
format = format.copyWithLabel(label);
|
||||||
|
}
|
||||||
String drmSchemeType = representationInfo.drmSchemeType != null
|
String drmSchemeType = representationInfo.drmSchemeType != null
|
||||||
? representationInfo.drmSchemeType : extraDrmSchemeType;
|
? representationInfo.drmSchemeType : extraDrmSchemeType;
|
||||||
ArrayList<SchemeData> drmSchemeDatas = representationInfo.drmSchemeDatas;
|
ArrayList<SchemeData> drmSchemeDatas = representationInfo.drmSchemeDatas;
|
||||||
|
|
@ -1132,6 +1138,32 @@ public class DashManifestParser extends DefaultHandler
|
||||||
return new ProgramInformation(title, source, copyright, moreInformationURL, lang);
|
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.
|
// AudioChannelConfiguration parsing.
|
||||||
|
|
||||||
protected int parseAudioChannelConfiguration(XmlPullParser xpp)
|
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 {
|
throws XmlPullParserException, IOException {
|
||||||
xpp.next();
|
String text = "";
|
||||||
return UriUtil.resolve(parentBaseUrl, xpp.getText());
|
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) {
|
protected static int parseInt(XmlPullParser xpp, String name, int defaultValue) {
|
||||||
|
|
|
||||||
21
library/dash/src/test/assets/sample_mpd_labels
Normal file
21
library/dash/src/test/assets/sample_mpd_labels
Normal 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>
|
||||||
|
|
@ -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_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_SEGMENT_TEMPLATE = "sample_mpd_segment_template";
|
||||||
private static final String SAMPLE_MPD_EVENT_STREAM = "sample_mpd_event_stream";
|
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_NAME = "Next";
|
||||||
private static final String NEXT_TAG = "<" + NEXT_TAG_NAME + "/>";
|
private static final String NEXT_TAG = "<" + NEXT_TAG_NAME + "/>";
|
||||||
|
|
@ -176,6 +177,21 @@ public class DashManifestParserTest {
|
||||||
assertThat(mpd.programInformation).isEqualTo(expectedProgramInformation);
|
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
|
@Test
|
||||||
public void parseSegmentTimeline_repeatCount() throws Exception {
|
public void parseSegmentTimeline_repeatCount() throws Exception {
|
||||||
DashManifestParser parser = new DashManifestParser();
|
DashManifestParser parser = new DashManifestParser();
|
||||||
|
|
@ -251,6 +267,30 @@ public class DashManifestParserTest {
|
||||||
assertNextTag(xpp);
|
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
|
@Test
|
||||||
public void parseCea608AccessibilityChannel() {
|
public void parseCea608AccessibilityChannel() {
|
||||||
assertThat(
|
assertThat(
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue