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
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentBase")) {
segmentBase = parseSegmentBase(xpp, null);
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentList")) {
segmentBase = parseSegmentList(xpp, null,durationMs);
segmentBase = parseSegmentList(xpp, null, durationMs);
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentTemplate")) {
segmentBase = parseSegmentTemplate(xpp, null, Collections.emptyList(), durationMs);
} else {
......@@ -339,8 +339,8 @@ public class DashManifestParser extends DefaultHandler
segmentBase = parseSegmentList(xpp, (SegmentList) segmentBase, periodDurationMs);
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentTemplate")) {
segmentBase =
parseSegmentTemplate(xpp, (SegmentTemplate) segmentBase, supplementalProperties,
periodDurationMs);
parseSegmentTemplate(
xpp, (SegmentTemplate) segmentBase, supplementalProperties, periodDurationMs);
} else if (XmlPullParserUtil.isStartTag(xpp, "InbandEventStream")) {
inbandEventStreams.add(parseDescriptor(xpp, "InbandEventStream"));
} else if (XmlPullParserUtil.isStartTag(xpp)) {
......@@ -494,7 +494,8 @@ public class DashManifestParser extends DefaultHandler
List<Descriptor> adaptationSetRoleDescriptors,
List<Descriptor> adaptationSetAccessibilityDescriptors,
List<Descriptor> adaptationSetSupplementalProperties,
@Nullable SegmentBase segmentBase, long periodDurationMs)
@Nullable SegmentBase segmentBase,
long periodDurationMs)
throws XmlPullParserException, IOException {
String id = xpp.getAttributeValue(null, "id");
int bandwidth = parseInt(xpp, "bandwidth", Format.NO_VALUE);
......@@ -528,7 +529,9 @@ public class DashManifestParser extends DefaultHandler
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentTemplate")) {
segmentBase =
parseSegmentTemplate(
xpp, (SegmentTemplate) segmentBase, adaptationSetSupplementalProperties,
xpp,
(SegmentTemplate) segmentBase,
adaptationSetSupplementalProperties,
periodDurationMs);
} else if (XmlPullParserUtil.isStartTag(xpp, "ContentProtection")) {
Pair<String, SchemeData> contentProtection = parseContentProtection(xpp);
......@@ -720,8 +723,8 @@ public class DashManifestParser extends DefaultHandler
indexLength);
}
protected SegmentList parseSegmentList(XmlPullParser xpp, @Nullable SegmentList parent,
long periodDurationMs)
protected SegmentList parseSegmentList(
XmlPullParser xpp, @Nullable SegmentList parent, long periodDurationMs)
throws XmlPullParserException, IOException {
long timescale = parseLong(xpp, "timescale", parent != null ? parent.timescale : 1);
......@@ -739,7 +742,7 @@ public class DashManifestParser extends DefaultHandler
if (XmlPullParserUtil.isStartTag(xpp, "Initialization")) {
initialization = parseInitialization(xpp);
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentTimeline")) {
timeline = parseSegmentTimeline(xpp,timescale,periodDurationMs);
timeline = parseSegmentTimeline(xpp, timescale, periodDurationMs);
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentURL")) {
if (segments == null) {
segments = new ArrayList<>();
......@@ -799,7 +802,7 @@ public class DashManifestParser extends DefaultHandler
if (XmlPullParserUtil.isStartTag(xpp, "Initialization")) {
initialization = parseInitialization(xpp);
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentTimeline")) {
timeline = parseSegmentTimeline(xpp,timescale,periodDurationMs);
timeline = parseSegmentTimeline(xpp, timescale, periodDurationMs);
} else {
maybeSkipTag(xpp);
}
......@@ -994,35 +997,79 @@ public class DashManifestParser extends DefaultHandler
return new EventMessage(schemeIdUri, value, durationMs, id, messageData);
}
protected List<SegmentTimelineElement> parseSegmentTimeline(XmlPullParser xpp,long timescale,
long periodDurationMs)
protected List<SegmentTimelineElement> parseSegmentTimeline(
XmlPullParser xpp, long timescale, long periodDurationMs)
throws XmlPullParserException, IOException {
List<SegmentTimelineElement> segmentTimeline = new ArrayList<>();
long elapsedTime = 0;
long startTime = 0;
long elementDuration = C.TIME_UNSET;
int elementRepeatCount = 0;
boolean havePreviousTimelineElement = false;
do {
xpp.next();
if (XmlPullParserUtil.isStartTag(xpp, "S")) {
elapsedTime = parseLong(xpp, "t", elapsedTime);
long duration = parseLong(xpp, "d", C.TIME_UNSET);
//if repeat is negative : length of each segment = duration / timescale and
// number of segments = periodDuration / length of each segment
int repeat = parseInt(xpp,"r",0);
int count = repeat >= 0? 1 + repeat : (int) (((periodDurationMs / 1000) * timescale) / duration);
for (int i = 0; i < count; i++) {
segmentTimeline.add(buildSegmentTimelineElement(elapsedTime, duration));
elapsedTime += duration;
long newStartTime = parseLong(xpp, "t", C.TIME_UNSET);
if (havePreviousTimelineElement) {
startTime =
addSegmentTimelineElementsToList(
segmentTimeline,
startTime,
elementDuration,
elementRepeatCount,
/* endTime= */ newStartTime);
}
if (newStartTime != C.TIME_UNSET) {
startTime = newStartTime;
}
elementDuration = parseLong(xpp, "d", C.TIME_UNSET);
elementRepeatCount = parseInt(xpp, "r", 0);
havePreviousTimelineElement = true;
} else {
maybeSkipTag(xpp);
}
} while (!XmlPullParserUtil.isEndTag(xpp, "SegmentTimeline"));
if (havePreviousTimelineElement) {
long periodDuration = Util.scaleLargeTimestamp(periodDurationMs, timescale, 1000);
addSegmentTimelineElementsToList(
segmentTimeline,
startTime,
elementDuration,
elementRepeatCount,
/* endTime= */ periodDuration);
}
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
......
......@@ -397,6 +397,22 @@ public abstract class SegmentBase {
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;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
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.util.Util;
import java.io.IOException;
import java.io.StringReader;
import java.nio.charset.Charset;
import java.util.Collections;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserFactory;
/** Unit tests for {@link DashManifestParser}. */
@RunWith(AndroidJUnit4.class)
......@@ -255,6 +259,74 @@ public class DashManifestParserTest {
.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) {
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