Merge pull request #7057 from Chimerapps:dash_assetidentifier
PiperOrigin-RevId: 300313753
This commit is contained in:
commit
0175dd4441
@ -76,6 +76,7 @@
|
|||||||
MediaSources factories.
|
MediaSources factories.
|
||||||
* Downloads: Merge downloads in `SegmentDownloader` to improve overall
|
* Downloads: Merge downloads in `SegmentDownloader` to improve overall
|
||||||
download speed ([#5978](https://github.com/google/ExoPlayer/issues/5978)).
|
download speed ([#5978](https://github.com/google/ExoPlayer/issues/5978)).
|
||||||
|
* DASH: Parse period `AssetIdentifier` elements.
|
||||||
* MP3: Add `IndexSeeker` for accurate seeks in VBR streams
|
* MP3: Add `IndexSeeker` for accurate seeks in VBR streams
|
||||||
([#6787](https://github.com/google/ExoPlayer/issues/6787)). This seeker is
|
([#6787](https://github.com/google/ExoPlayer/issues/6787)). This seeker is
|
||||||
enabled by passing `FLAG_ENABLE_INDEX_SEEKING` to the `Mp3Extractor`. It may
|
enabled by passing `FLAG_ENABLE_INDEX_SEEKING` to the `Mp3Extractor`. It may
|
||||||
|
@ -222,10 +222,11 @@ public class DashManifestParser extends DefaultHandler
|
|||||||
|
|
||||||
protected Pair<Period, Long> parsePeriod(XmlPullParser xpp, String baseUrl, long defaultStartMs)
|
protected Pair<Period, Long> parsePeriod(XmlPullParser xpp, String baseUrl, long defaultStartMs)
|
||||||
throws XmlPullParserException, IOException {
|
throws XmlPullParserException, IOException {
|
||||||
String id = xpp.getAttributeValue(null, "id");
|
@Nullable String id = xpp.getAttributeValue(null, "id");
|
||||||
long startMs = parseDuration(xpp, "start", defaultStartMs);
|
long startMs = parseDuration(xpp, "start", defaultStartMs);
|
||||||
long durationMs = parseDuration(xpp, "duration", C.TIME_UNSET);
|
long durationMs = parseDuration(xpp, "duration", C.TIME_UNSET);
|
||||||
SegmentBase segmentBase = null;
|
@Nullable SegmentBase segmentBase = null;
|
||||||
|
@Nullable Descriptor assetIdentifier = null;
|
||||||
List<AdaptationSet> adaptationSets = new ArrayList<>();
|
List<AdaptationSet> adaptationSets = new ArrayList<>();
|
||||||
List<EventStream> eventStreams = new ArrayList<>();
|
List<EventStream> eventStreams = new ArrayList<>();
|
||||||
boolean seenFirstBaseUrl = false;
|
boolean seenFirstBaseUrl = false;
|
||||||
@ -246,17 +247,24 @@ public class DashManifestParser extends DefaultHandler
|
|||||||
segmentBase = parseSegmentList(xpp, null, durationMs);
|
segmentBase = parseSegmentList(xpp, null, durationMs);
|
||||||
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentTemplate")) {
|
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentTemplate")) {
|
||||||
segmentBase = parseSegmentTemplate(xpp, null, Collections.emptyList(), durationMs);
|
segmentBase = parseSegmentTemplate(xpp, null, Collections.emptyList(), durationMs);
|
||||||
|
} else if (XmlPullParserUtil.isStartTag(xpp, "AssetIdentifier")) {
|
||||||
|
assetIdentifier = parseDescriptor(xpp, "AssetIdentifier");
|
||||||
} else {
|
} else {
|
||||||
maybeSkipTag(xpp);
|
maybeSkipTag(xpp);
|
||||||
}
|
}
|
||||||
} while (!XmlPullParserUtil.isEndTag(xpp, "Period"));
|
} while (!XmlPullParserUtil.isEndTag(xpp, "Period"));
|
||||||
|
|
||||||
return Pair.create(buildPeriod(id, startMs, adaptationSets, eventStreams), durationMs);
|
return Pair.create(
|
||||||
|
buildPeriod(id, startMs, adaptationSets, eventStreams, assetIdentifier), durationMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Period buildPeriod(String id, long startMs, List<AdaptationSet> adaptationSets,
|
protected Period buildPeriod(
|
||||||
List<EventStream> eventStreams) {
|
@Nullable String id,
|
||||||
return new Period(id, startMs, adaptationSets, eventStreams);
|
long startMs,
|
||||||
|
List<AdaptationSet> adaptationSets,
|
||||||
|
List<EventStream> eventStreams,
|
||||||
|
@Nullable Descriptor assetIdentifier) {
|
||||||
|
return new Period(id, startMs, adaptationSets, eventStreams, assetIdentifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
// AdaptationSet parsing.
|
// AdaptationSet parsing.
|
||||||
|
@ -45,13 +45,16 @@ public class Period {
|
|||||||
*/
|
*/
|
||||||
public final List<EventStream> eventStreams;
|
public final List<EventStream> eventStreams;
|
||||||
|
|
||||||
|
/** The asset identifier for this period, if one exists */
|
||||||
|
@Nullable public final Descriptor assetIdentifier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param id The period identifier. May be null.
|
* @param id The period identifier. May be null.
|
||||||
* @param startMs The start time of the period in milliseconds.
|
* @param startMs The start time of the period in milliseconds.
|
||||||
* @param adaptationSets The adaptation sets belonging to the period.
|
* @param adaptationSets The adaptation sets belonging to the period.
|
||||||
*/
|
*/
|
||||||
public Period(@Nullable String id, long startMs, List<AdaptationSet> adaptationSets) {
|
public Period(@Nullable String id, long startMs, List<AdaptationSet> adaptationSets) {
|
||||||
this(id, startMs, adaptationSets, Collections.emptyList());
|
this(id, startMs, adaptationSets, Collections.emptyList(), /* assetIdentifier= */ null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -62,10 +65,27 @@ public class Period {
|
|||||||
*/
|
*/
|
||||||
public Period(@Nullable String id, long startMs, List<AdaptationSet> adaptationSets,
|
public Period(@Nullable String id, long startMs, List<AdaptationSet> adaptationSets,
|
||||||
List<EventStream> eventStreams) {
|
List<EventStream> eventStreams) {
|
||||||
|
this(id, startMs, adaptationSets, eventStreams, /* assetIdentifier= */ null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param id The period identifier. May be null.
|
||||||
|
* @param startMs The start time of the period in milliseconds.
|
||||||
|
* @param adaptationSets The adaptation sets belonging to the period.
|
||||||
|
* @param eventStreams The {@link EventStream}s belonging to the period.
|
||||||
|
* @param assetIdentifier The asset identifier for this period
|
||||||
|
*/
|
||||||
|
public Period(
|
||||||
|
@Nullable String id,
|
||||||
|
long startMs,
|
||||||
|
List<AdaptationSet> adaptationSets,
|
||||||
|
List<EventStream> eventStreams,
|
||||||
|
@Nullable Descriptor assetIdentifier) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.startMs = startMs;
|
this.startMs = startMs;
|
||||||
this.adaptationSets = Collections.unmodifiableList(adaptationSets);
|
this.adaptationSets = Collections.unmodifiableList(adaptationSets);
|
||||||
this.eventStreams = Collections.unmodifiableList(eventStreams);
|
this.eventStreams = Collections.unmodifiableList(eventStreams);
|
||||||
|
this.assetIdentifier = assetIdentifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -18,6 +18,7 @@ package com.google.android.exoplayer2.source.dash.manifest;
|
|||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
@ -45,6 +46,7 @@ public class DashManifestParserTest {
|
|||||||
private static final String SAMPLE_MPD_SEGMENT_TEMPLATE = "mpd/sample_mpd_segment_template";
|
private static final String SAMPLE_MPD_SEGMENT_TEMPLATE = "mpd/sample_mpd_segment_template";
|
||||||
private static final String SAMPLE_MPD_EVENT_STREAM = "mpd/sample_mpd_event_stream";
|
private static final String SAMPLE_MPD_EVENT_STREAM = "mpd/sample_mpd_event_stream";
|
||||||
private static final String SAMPLE_MPD_LABELS = "mpd/sample_mpd_labels";
|
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 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 + "/>";
|
||||||
@ -377,6 +379,27 @@ public class DashManifestParserTest {
|
|||||||
.isEqualTo(Format.NO_VALUE);
|
.isEqualTo(Format.NO_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void parsePeriodAssetIdentifier() throws IOException {
|
||||||
|
DashManifestParser parser = new DashManifestParser();
|
||||||
|
DashManifest mpd =
|
||||||
|
parser.parse(
|
||||||
|
Uri.parse("https://example.com/test.mpd"),
|
||||||
|
TestUtil.getInputStream(
|
||||||
|
ApplicationProvider.getApplicationContext(), SAMPLE_MPD_ASSET_IDENTIFIER));
|
||||||
|
|
||||||
|
assertThat(mpd.getPeriodCount()).isEqualTo(1);
|
||||||
|
|
||||||
|
Period period = mpd.getPeriod(0);
|
||||||
|
assertThat(period).isNotNull();
|
||||||
|
@Nullable Descriptor assetIdentifier = period.assetIdentifier;
|
||||||
|
assertThat(assetIdentifier).isNotNull();
|
||||||
|
|
||||||
|
assertThat(assetIdentifier.schemeIdUri).isEqualTo("urn:org:dashif:asset-id:2013");
|
||||||
|
assertThat(assetIdentifier.value).isEqualTo("md:cid:EIDR:10.5240%2f0EFB-02CD-126E-8092-1E49-W");
|
||||||
|
assertThat(assetIdentifier.id).isEqualTo("uniqueId");
|
||||||
|
}
|
||||||
|
|
||||||
private static List<Descriptor> buildCea608AccessibilityDescriptors(String value) {
|
private static List<Descriptor> buildCea608AccessibilityDescriptors(String value) {
|
||||||
return Collections.singletonList(new Descriptor("urn:scte:dash:cc:cea-608:2015", value, null));
|
return Collections.singletonList(new Descriptor("urn:scte:dash:cc:cea-608:2015", value, null));
|
||||||
}
|
}
|
||||||
|
24
testdata/src/test/assets/mpd/sample_mpd_asset_identifier
vendored
Normal file
24
testdata/src/test/assets/mpd/sample_mpd_asset_identifier
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<MPD xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:mpeg:DASH:schema:MPD:2011" xmlns:yt="http://youtube.com/yt/2012/10/10" xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011 DASH-MPD.xsd" minBufferTime="PT1.500S" profiles="urn:mpeg:dash:profile:isoff-main:2011" type="dynamic" availabilityStartTime="2016-10-14T17:00:17" timeShiftBufferDepth="PT7200.000S" minimumUpdatePeriod="PT2.000S" yt:earliestMediaSequence="0" yt:mpdRequestTime="2016-10-14T18:29:17.082" yt:mpdResponseTime="2016-10-14T18:29:17.194">
|
||||||
|
<Period start="PT0.000S" yt:segmentIngestTime="2016-10-14T17:00:14.257">
|
||||||
|
<AssetIdentifier schemeIdUri="urn:org:dashif:asset-id:2013" value="md:cid:EIDR:10.5240%2f0EFB-02CD-126E-8092-1E49-W" id="uniqueId"/>
|
||||||
|
<SegmentTemplate startNumber="0" timescale="1000" media="sq/$Number$">
|
||||||
|
<SegmentTimeline>
|
||||||
|
<S d="2002" t="6009" r="2"/>
|
||||||
|
</SegmentTimeline>
|
||||||
|
</SegmentTemplate>
|
||||||
|
<AdaptationSet id="0" mimeType="audio/mp4" subsegmentAlignment="true">
|
||||||
|
<Role schemeIdUri="urn:mpeg:DASH:role:2011" value="main"/>
|
||||||
|
<Representation id="140" codecs="mp4a.40.2" audioSamplingRate="48000" startWithSAP="1" bandwidth="144000">
|
||||||
|
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
|
||||||
|
<BaseURL>http://www.dummy.url/</BaseURL>
|
||||||
|
</Representation>
|
||||||
|
</AdaptationSet>
|
||||||
|
<AdaptationSet id="1" mimeType="video/mp4" subsegmentAlignment="true">
|
||||||
|
<Role schemeIdUri="urn:mpeg:DASH:role:2011" value="main"/>
|
||||||
|
<Representation id="133" codecs="avc1.4d4015" width="426" height="240" startWithSAP="1" maxPlayoutRate="1" bandwidth="258000" frameRate="30">
|
||||||
|
<BaseURL>http://www.dummy.url/</BaseURL>
|
||||||
|
</Representation>
|
||||||
|
</AdaptationSet>
|
||||||
|
</Period>
|
||||||
|
</MPD>
|
Loading…
x
Reference in New Issue
Block a user