diff --git a/lib/dash/dash_parser.js b/lib/dash/dash_parser.js index 5731631878..6f93969d8d 100644 --- a/lib/dash/dash_parser.js +++ b/lib/dash/dash_parser.js @@ -102,10 +102,10 @@ shaka.dash.DashParser = class { this.largestPeriodStartTime_ = null; /** - * Period IDs that have seen before. + * Period start times seen in previous manifest. * @private {!Array.} */ - this.seenPeriodIds_ = []; + this.seenPeriodStartTime_ = []; /** * The minimum of the availabilityTimeOffset values among the adaptation @@ -542,6 +542,7 @@ shaka.dash.DashParser = class { mpd, 'mediaPresentationDuration', XmlUtils.parseDuration); const periods = []; + const periodStartTime = []; let prevEnd = 0; const periodNodes = XmlUtils.findChildren(mpd, 'Period'); // This uses a for-loop rather than a for-of loop because this needs to look @@ -583,21 +584,34 @@ shaka.dash.DashParser = class { periodDuration = givenDuration; } - // Skip all periods with start time < maximum period start time, excepts - // the last period in manifest - if (this.largestPeriodStartTime_ !== null && start !== null && - start < this.largestPeriodStartTime_ && - !this.seenPeriodIds_.includes(start) && + /** + * This is to improve the robustness of the player + * when it received bad content/manifest, while still supporting + * modification of previous periods. + * + * Skip periods that match all of the following criteria: + * - Start time is earlier than latest period start time ever seen + * - Start time is never seen in the previous manifest + * - Not the last period in the manifest + * + * Periods that meet the aforementioned criteria are considered invalid + * and should be safe to discard. + */ + if (this.largestPeriodStartTime_ !== null && start !== null) { + if (start < this.largestPeriodStartTime_ && + !this.seenPeriodStartTime_.includes(start) && i + 1 != periodNodes.length) { - shaka.log.debug( - `Skipping Period ${i+1} as its start time is smaller than ` + - 'the largest period start time that has been seen, and start ' + - 'time is unseen before'); - continue; - } else if (!this.seenPeriodIds_.includes(start)) { - this.seenPeriodIds_.push(start); + shaka.log.debug( + `Skipping Period ${i+1} as its start time is smaller than ` + + 'the largest period start time that has been seen, and start ' + + 'time is unseen before'); + continue; + } else { + periodStartTime.push(start); + } } + // Save maximum period start time if it is the last period if (start !== null && (this.largestPeriodStartTime_ === null || @@ -636,6 +650,9 @@ shaka.dash.DashParser = class { prevEnd = start + periodDuration; } // end of period parsing loop + // Replace previous seen start time with the current one. + this.seenPeriodStartTime_ = periodStartTime; + if (presentationDuration != null) { if (prevEnd != presentationDuration) { shaka.log.warning(