Commit 75435b42 by Toni

Merge pull request #6286 from sr1990:dev-v2

PiperOrigin-RevId: 267323559
parents 33eb49ca 3198b9ef
...@@ -243,7 +243,7 @@ public class DashManifestParser extends DefaultHandler ...@@ -243,7 +243,7 @@ public class DashManifestParser extends DefaultHandler
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentBase")) { } else if (XmlPullParserUtil.isStartTag(xpp, "SegmentBase")) {
segmentBase = parseSegmentBase(xpp, null); segmentBase = parseSegmentBase(xpp, null);
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentList")) { } else if (XmlPullParserUtil.isStartTag(xpp, "SegmentList")) {
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 { } else {
...@@ -339,8 +339,8 @@ public class DashManifestParser extends DefaultHandler ...@@ -339,8 +339,8 @@ public class DashManifestParser extends DefaultHandler
segmentBase = parseSegmentList(xpp, (SegmentList) segmentBase, periodDurationMs); segmentBase = parseSegmentList(xpp, (SegmentList) segmentBase, periodDurationMs);
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentTemplate")) { } else if (XmlPullParserUtil.isStartTag(xpp, "SegmentTemplate")) {
segmentBase = segmentBase =
parseSegmentTemplate(xpp, (SegmentTemplate) segmentBase, supplementalProperties, parseSegmentTemplate(
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)) { } else if (XmlPullParserUtil.isStartTag(xpp)) {
...@@ -494,7 +494,8 @@ public class DashManifestParser extends DefaultHandler ...@@ -494,7 +494,8 @@ public class DashManifestParser extends DefaultHandler
List<Descriptor> adaptationSetRoleDescriptors, List<Descriptor> adaptationSetRoleDescriptors,
List<Descriptor> adaptationSetAccessibilityDescriptors, List<Descriptor> adaptationSetAccessibilityDescriptors,
List<Descriptor> adaptationSetSupplementalProperties, List<Descriptor> adaptationSetSupplementalProperties,
@Nullable SegmentBase segmentBase, long periodDurationMs) @Nullable SegmentBase segmentBase,
long periodDurationMs)
throws XmlPullParserException, IOException { throws XmlPullParserException, IOException {
String id = xpp.getAttributeValue(null, "id"); String id = xpp.getAttributeValue(null, "id");
int bandwidth = parseInt(xpp, "bandwidth", Format.NO_VALUE); int bandwidth = parseInt(xpp, "bandwidth", Format.NO_VALUE);
...@@ -528,7 +529,9 @@ public class DashManifestParser extends DefaultHandler ...@@ -528,7 +529,9 @@ public class DashManifestParser extends DefaultHandler
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentTemplate")) { } else if (XmlPullParserUtil.isStartTag(xpp, "SegmentTemplate")) {
segmentBase = segmentBase =
parseSegmentTemplate( parseSegmentTemplate(
xpp, (SegmentTemplate) segmentBase, adaptationSetSupplementalProperties, xpp,
(SegmentTemplate) segmentBase,
adaptationSetSupplementalProperties,
periodDurationMs); periodDurationMs);
} else if (XmlPullParserUtil.isStartTag(xpp, "ContentProtection")) { } else if (XmlPullParserUtil.isStartTag(xpp, "ContentProtection")) {
Pair<String, SchemeData> contentProtection = parseContentProtection(xpp); Pair<String, SchemeData> contentProtection = parseContentProtection(xpp);
...@@ -720,8 +723,8 @@ public class DashManifestParser extends DefaultHandler ...@@ -720,8 +723,8 @@ public class DashManifestParser extends DefaultHandler
indexLength); indexLength);
} }
protected SegmentList parseSegmentList(XmlPullParser xpp, @Nullable SegmentList parent, protected SegmentList parseSegmentList(
long periodDurationMs) XmlPullParser xpp, @Nullable SegmentList parent, long periodDurationMs)
throws XmlPullParserException, IOException { throws XmlPullParserException, IOException {
long timescale = parseLong(xpp, "timescale", parent != null ? parent.timescale : 1); long timescale = parseLong(xpp, "timescale", parent != null ? parent.timescale : 1);
...@@ -739,7 +742,7 @@ public class DashManifestParser extends DefaultHandler ...@@ -739,7 +742,7 @@ public class DashManifestParser extends DefaultHandler
if (XmlPullParserUtil.isStartTag(xpp, "Initialization")) { if (XmlPullParserUtil.isStartTag(xpp, "Initialization")) {
initialization = parseInitialization(xpp); initialization = parseInitialization(xpp);
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentTimeline")) { } else if (XmlPullParserUtil.isStartTag(xpp, "SegmentTimeline")) {
timeline = parseSegmentTimeline(xpp,timescale,periodDurationMs); timeline = parseSegmentTimeline(xpp, timescale, periodDurationMs);
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentURL")) { } else if (XmlPullParserUtil.isStartTag(xpp, "SegmentURL")) {
if (segments == null) { if (segments == null) {
segments = new ArrayList<>(); segments = new ArrayList<>();
...@@ -799,7 +802,7 @@ public class DashManifestParser extends DefaultHandler ...@@ -799,7 +802,7 @@ public class DashManifestParser extends DefaultHandler
if (XmlPullParserUtil.isStartTag(xpp, "Initialization")) { if (XmlPullParserUtil.isStartTag(xpp, "Initialization")) {
initialization = parseInitialization(xpp); initialization = parseInitialization(xpp);
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentTimeline")) { } else if (XmlPullParserUtil.isStartTag(xpp, "SegmentTimeline")) {
timeline = parseSegmentTimeline(xpp,timescale,periodDurationMs); timeline = parseSegmentTimeline(xpp, timescale, periodDurationMs);
} else { } else {
maybeSkipTag(xpp); maybeSkipTag(xpp);
} }
...@@ -994,35 +997,79 @@ public class DashManifestParser extends DefaultHandler ...@@ -994,35 +997,79 @@ public class DashManifestParser extends DefaultHandler
return new EventMessage(schemeIdUri, value, durationMs, id, messageData); return new EventMessage(schemeIdUri, value, durationMs, id, messageData);
} }
protected List<SegmentTimelineElement> parseSegmentTimeline(XmlPullParser xpp,long timescale, protected List<SegmentTimelineElement> parseSegmentTimeline(
long periodDurationMs) XmlPullParser xpp, long timescale, long periodDurationMs)
throws XmlPullParserException, IOException { throws XmlPullParserException, IOException {
List<SegmentTimelineElement> segmentTimeline = new ArrayList<>(); List<SegmentTimelineElement> segmentTimeline = new ArrayList<>();
long elapsedTime = 0; long startTime = 0;
long elementDuration = C.TIME_UNSET;
int elementRepeatCount = 0;
boolean havePreviousTimelineElement = false;
do { do {
xpp.next(); xpp.next();
if (XmlPullParserUtil.isStartTag(xpp, "S")) { if (XmlPullParserUtil.isStartTag(xpp, "S")) {
elapsedTime = parseLong(xpp, "t", elapsedTime); long newStartTime = parseLong(xpp, "t", C.TIME_UNSET);
long duration = parseLong(xpp, "d", C.TIME_UNSET); if (havePreviousTimelineElement) {
startTime =
//if repeat is negative : length of each segment = duration / timescale and addSegmentTimelineElementsToList(
// number of segments = periodDuration / length of each segment segmentTimeline,
int repeat = parseInt(xpp,"r",0); startTime,
int count = repeat >= 0? 1 + repeat : (int) (((periodDurationMs / 1000) * timescale) / duration); elementDuration,
elementRepeatCount,
for (int i = 0; i < count; i++) { /* endTime= */ newStartTime);
segmentTimeline.add(buildSegmentTimelineElement(elapsedTime, duration)); }
elapsedTime += duration; if (newStartTime != C.TIME_UNSET) {
} startTime = newStartTime;
}
elementDuration = parseLong(xpp, "d", C.TIME_UNSET);
elementRepeatCount = parseInt(xpp, "r", 0);
havePreviousTimelineElement = true;
} else { } else {
maybeSkipTag(xpp); maybeSkipTag(xpp);
} }
} while (!XmlPullParserUtil.isEndTag(xpp, "SegmentTimeline")); } while (!XmlPullParserUtil.isEndTag(xpp, "SegmentTimeline"));
if (havePreviousTimelineElement) {
long periodDuration = Util.scaleLargeTimestamp(periodDurationMs, timescale, 1000);
addSegmentTimelineElementsToList(
segmentTimeline,
startTime,
elementDuration,
elementRepeatCount,
/* endTime= */ periodDuration);
}
return segmentTimeline; return segmentTimeline;
} }
protected SegmentTimelineElement buildSegmentTimelineElement(long elapsedTime, long duration) { /**
return new SegmentTimelineElement(elapsedTime, duration); * Adds timeline elements for one S tag to the segment timeline.
*
* @param startTime Start time of the first timeline element.
* @param elementDuration Duration of one timeline element.
* @param elementRepeatCount Number of timeline elements minus one. May be negative to indicate
* that the count is determined by the total duration and the element duration.
* @param endTime End time of the last timeline element for this S tag, or {@link C#TIME_UNSET} if
* unknown. Only needed if {@code repeatCount} is negative.
* @return Calculated next start time.
*/
private long addSegmentTimelineElementsToList(
List<SegmentTimelineElement> segmentTimeline,
long startTime,
long elementDuration,
int elementRepeatCount,
long endTime) {
int count =
elementRepeatCount >= 0
? 1 + elementRepeatCount
: (int) Util.ceilDivide(endTime - startTime, elementDuration);
for (int i = 0; i < count; i++) {
segmentTimeline.add(buildSegmentTimelineElement(startTime, elementDuration));
startTime += elementDuration;
}
return startTime;
}
protected SegmentTimelineElement buildSegmentTimelineElement(long startTime, long duration) {
return new SegmentTimelineElement(startTime, duration);
} }
@Nullable @Nullable
......
...@@ -397,6 +397,22 @@ public abstract class SegmentBase { ...@@ -397,6 +397,22 @@ public abstract class SegmentBase {
this.duration = duration; this.duration = duration;
} }
@Override
public boolean equals(@Nullable Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
SegmentTimelineElement that = (SegmentTimelineElement) o;
return startTime == that.startTime && duration == that.duration;
}
@Override
public int hashCode() {
return 31 * (int) startTime + (int) duration;
}
} }
} }
...@@ -23,14 +23,18 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; ...@@ -23,14 +23,18 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.metadata.emsg.EventMessage; import com.google.android.exoplayer2.metadata.emsg.EventMessage;
import com.google.android.exoplayer2.source.dash.manifest.SegmentBase.SegmentTimelineElement;
import com.google.android.exoplayer2.testutil.TestUtil; import com.google.android.exoplayer2.testutil.TestUtil;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import java.io.IOException; import java.io.IOException;
import java.io.StringReader;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserFactory;
/** Unit tests for {@link DashManifestParser}. */ /** Unit tests for {@link DashManifestParser}. */
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
...@@ -255,6 +259,74 @@ public class DashManifestParserTest { ...@@ -255,6 +259,74 @@ public class DashManifestParserTest {
.isEqualTo(Format.NO_VALUE); .isEqualTo(Format.NO_VALUE);
} }
@Test
public void parseSegmentTimeline_withRepeatCount() throws Exception {
DashManifestParser parser = new DashManifestParser();
XmlPullParser xpp = XmlPullParserFactory.newInstance().newPullParser();
xpp.setInput(
new StringReader(
"<SegmentTimeline><S d=\"96000\" r=\"2\"/><S d=\"48000\" r=\"0\"/></SegmentTimeline>"));
xpp.next();
List<SegmentTimelineElement> elements =
parser.parseSegmentTimeline(xpp, /* timescale= */ 48000, /* periodDurationMs= */ 10000);
assertThat(elements)
.containsExactly(
new SegmentTimelineElement(/* startTime= */ 0, /* duration= */ 96000),
new SegmentTimelineElement(/* startTime= */ 96000, /* duration= */ 96000),
new SegmentTimelineElement(/* startTime= */ 192000, /* duration= */ 96000),
new SegmentTimelineElement(/* startTime= */ 288000, /* duration= */ 48000))
.inOrder();
}
@Test
public void parseSegmentTimeline_withSingleUndefinedRepeatCount() throws Exception {
DashManifestParser parser = new DashManifestParser();
XmlPullParser xpp = XmlPullParserFactory.newInstance().newPullParser();
xpp.setInput(new StringReader("<SegmentTimeline><S d=\"96000\" r=\"-1\"/></SegmentTimeline>"));
xpp.next();
List<SegmentTimelineElement> elements =
parser.parseSegmentTimeline(xpp, /* timescale= */ 48000, /* periodDurationMs= */ 10000);
assertThat(elements)
.containsExactly(
new SegmentTimelineElement(/* startTime= */ 0, /* duration= */ 96000),
new SegmentTimelineElement(/* startTime= */ 96000, /* duration= */ 96000),
new SegmentTimelineElement(/* startTime= */ 192000, /* duration= */ 96000),
new SegmentTimelineElement(/* startTime= */ 288000, /* duration= */ 96000),
new SegmentTimelineElement(/* startTime= */ 384000, /* duration= */ 96000))
.inOrder();
}
@Test
public void parseSegmentTimeline_withTimeOffsetsAndUndefinedRepeatCount() throws Exception {
DashManifestParser parser = new DashManifestParser();
XmlPullParser xpp = XmlPullParserFactory.newInstance().newPullParser();
xpp.setInput(
new StringReader(
"<SegmentTimeline><S t=\"0\" "
+ "d=\"96000\" r=\"-1\"/><S t=\"192000\" d=\"48000\" r=\"-1\"/>"
+ "</SegmentTimeline>"));
xpp.next();
List<SegmentTimelineElement> elements =
parser.parseSegmentTimeline(xpp, /* timescale= */ 48000, /* periodDurationMs= */ 10000);
assertThat(elements)
.containsExactly(
new SegmentTimelineElement(/* startTime= */ 0, /* duration= */ 96000),
new SegmentTimelineElement(/* startTime= */ 96000, /* duration= */ 96000),
new SegmentTimelineElement(/* startTime= */ 192000, /* duration= */ 48000),
new SegmentTimelineElement(/* startTime= */ 240000, /* duration= */ 48000),
new SegmentTimelineElement(/* startTime= */ 288000, /* duration= */ 48000),
new SegmentTimelineElement(/* startTime= */ 336000, /* duration= */ 48000),
new SegmentTimelineElement(/* startTime= */ 384000, /* duration= */ 48000),
new SegmentTimelineElement(/* startTime= */ 432000, /* duration= */ 48000))
.inOrder();
}
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));
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment