diff --git a/lib/text/ttml_text_parser.js b/lib/text/ttml_text_parser.js
index dbb42678f2..76502f4298 100644
--- a/lib/text/ttml_text_parser.js
+++ b/lib/text/ttml_text_parser.js
@@ -128,7 +128,7 @@ shaka.text.TtmlTextParser = class {
}
const cue = TtmlTextParser.parseCue_(
- body, time.periodStart, rateInfo, metadataElements, styles,
+ body, time, rateInfo, metadataElements, styles,
regionElements, cueRegions, whitespaceTrim,
cellResolutionInfo, /* parentCueElement= */ null,
/* isContent= */ false);
@@ -149,7 +149,7 @@ shaka.text.TtmlTextParser = class {
* Parses a TTML node into a Cue.
*
* @param {!Node} cueNode
- * @param {number} offset
+ * @param {shaka.extern.TextParser.TimeContext} timeContext
* @param {!shaka.text.TtmlTextParser.RateInfo_} rateInfo
* @param {!Array.} metadataElements
* @param {!Array.} styles
@@ -163,7 +163,7 @@ shaka.text.TtmlTextParser = class {
* @private
*/
static parseCue_(
- cueNode, offset, rateInfo, metadataElements, styles, regionElements,
+ cueNode, timeContext, rateInfo, metadataElements, styles, regionElements,
cueRegions, whitespaceTrim, cellResolution, parentCueElement, isContent) {
/** @type {Element} */
let cueElement;
@@ -228,7 +228,7 @@ shaka.text.TtmlTextParser = class {
for (const childNode of cueElement.childNodes) {
const nestedCue = shaka.text.TtmlTextParser.parseCue_(
childNode,
- offset,
+ timeContext,
rateInfo,
metadataElements,
styles,
@@ -285,15 +285,20 @@ shaka.text.TtmlTextParser = class {
if (start == null) {
start = 0;
}
- start += offset;
+ start += timeContext.periodStart;
// If end is null, that means the duration is effectively infinite.
if (end == null) {
end = Infinity;
} else {
- end += offset;
+ end += timeContext.periodStart;
}
+ // Clip times to segment boundaries.
+ // https://github.com/shaka-project/shaka-player/issues/4631
+ start = Math.max(start, timeContext.segmentStart);
+ end = Math.min(end, timeContext.segmentEnd);
+
if (!hasTimeAttributes && nestedCues.length > 0) {
// If no time is defined for this cue, base the timing information on
// the time of the nested cues. In the case of multiple nested cues with
diff --git a/test/text/mp4_ttml_parser_unit.js b/test/text/mp4_ttml_parser_unit.js
index 94893382dc..b7a8d11e48 100644
--- a/test/text/mp4_ttml_parser_unit.js
+++ b/test/text/mp4_ttml_parser_unit.js
@@ -41,7 +41,7 @@ describe('Mp4TtmlParser', () => {
it('handles media segments with multiple mdats', () => {
const parser = new shaka.text.Mp4TtmlParser();
parser.parseInit(ttmlInitSegment);
- const time = {periodStart: 0, segmentStart: 0, segmentEnd: 0};
+ const time = {periodStart: 0, segmentStart: 60, segmentEnd: 0};
const ret = parser.parseMedia(ttmlSegmentMultipleMDAT, time);
// Bodies.
expect(ret.length).toBe(2);
@@ -54,8 +54,8 @@ describe('Mp4TtmlParser', () => {
});
it('accounts for offset', () => {
- const time1 = {periodStart: 0, segmentStart: 0, segmentEnd: 0};
- const time2 = {periodStart: 7, segmentStart: 0, segmentEnd: 0};
+ const time1 = {periodStart: 0, segmentStart: 0, segmentEnd: 70};
+ const time2 = {periodStart: 7, segmentStart: 0, segmentEnd: 70};
const parser = new shaka.text.Mp4TtmlParser();
parser.parseInit(ttmlInitSegment);
@@ -159,7 +159,7 @@ describe('Mp4TtmlParser', () => {
];
const parser = new shaka.text.Mp4TtmlParser();
parser.parseInit(ttmlInitSegment);
- const time = {periodStart: 0, segmentStart: 0, segmentEnd: 0};
+ const time = {periodStart: 0, segmentStart: 0, segmentEnd: 60};
const result = parser.parseMedia(ttmlSegment, time);
shaka.test.TtmlUtils.verifyHelper(
cues, result, {startTime: 23, endTime: 53.5});
diff --git a/test/text/ttml_text_parser_unit.js b/test/text/ttml_text_parser_unit.js
index a4d498a7bb..9048093185 100644
--- a/test/text/ttml_text_parser_unit.js
+++ b/test/text/ttml_text_parser_unit.js
@@ -13,14 +13,14 @@ describe('TtmlTextParser', () => {
it('supports no cues', () => {
verifyHelper([],
'',
- {periodStart: 0, segmentStart: 0, segmentEnd: 0},
+ {periodStart: 0, segmentStart: 0, segmentEnd: 10},
{});
});
it('supports empty text string', () => {
verifyHelper([],
'',
- {periodStart: 0, segmentStart: 0, segmentEnd: 0},
+ {periodStart: 0, segmentStart: 0, segmentEnd: 10},
{});
});
@@ -28,7 +28,7 @@ describe('TtmlTextParser', () => {
verifyHelper(
[],
'
Second cue' +
'
Test
' + 'Test
' + 'Test
' + 'Test
' + 'Test
' + 'Test
' + 'Test
' + 'Test
' + 'Test
' + 'Test
' + 'Test
' + 'Test
' + 'Test
' + 'Test
' + 'Test
' + 'Test
' + 'Test
' + 'Test
' + 'Test
' + 'Test
' + 'Test
' + 'Test
' + 'Test
' + 'Test
' + 'Test
' + 'Test
' + 'Test
' + 'Test
' + 'Test
' + 'Test
' + 'Test
' + 'Test
' + 'Test
' + 'Test
' + 'Test
' + 'Test
' + 'Test
' + 'Test
' + '' + 'Hello!' + '