Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(HLS): Add HLS config to ignore manifest timestamps when in segments mode #5103

Merged
merged 3 commits into from
Mar 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions demo/common/message_ids.js
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ shakaDemo.MessageIds = {
IGNORE_HLS_IMAGE_FAILURES: 'DEMO_IGNORE_HLS_IMAGE_FAILURES',
IGNORE_HLS_TEXT_FAILURES: 'DEMO_IGNORE_HLS_TEXT_FAILURES',
IGNORE_MANIFEST_PROGRAM_DATE_TIME: 'DEMO_IGNORE_MANIFEST_PROGRAM_DATE_TIME',
IGNORE_MANIFEST_TIMESTAMPS_IN_SEGMENTS_MODE: 'DEMO_IGNORE_MANIFEST_TIMESTAMPS_IN_SEGMENTS_MODE',
IGNORE_MIN_BUFFER_TIME: 'DEMO_IGNORE_MIN_BUFFER_TIME',
IGNORE_TEXT_FAILURES: 'DEMO_IGNORE_TEXT_FAILURES',
INACCURATE_MANIFEST_TOLERANCE: 'DEMO_INACCURATE_MANIFEST_TOLERANCE',
Expand Down
2 changes: 2 additions & 0 deletions demo/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,8 @@ shakaDemo.Config = class {
'manifest.hls.liveSegmentsDelay')
.addBoolInput_(MessageIds.HLS_SEQUENCE_MODE,
'manifest.hls.sequenceMode')
.addBoolInput_(MessageIds.IGNORE_MANIFEST_TIMESTAMPS_IN_SEGMENTS_MODE,
'manifest.hls.ignoreManifestTimestampsInSegmentsMode')
.addNumberInput_(MessageIds.AVAILABILITY_WINDOW_OVERRIDE,
'manifest.availabilityWindowOverride',
/* canBeDecimal= */ true,
Expand Down
1 change: 1 addition & 0 deletions demo/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
"DEMO_IMA_MANIFEST_TYPE": "Manifest type (for DAI Content)",
"DEMO_IMA_VIDEO_ID": "Video ID (for VOD DAI Content)",
"DEMO_IGNORE_MANIFEST_PROGRAM_DATE_TIME": "Ignore Program Date Time from manifest",
"DEMO_IGNORE_MANIFEST_TIMESTAMPS_IN_SEGMENTS_MODE": "Ignore Manifest Timestamps in Segments Mode",
"DEMO_IGNORE_MIN_BUFFER_TIME": "Ignore Min Buffer Time",
"DEMO_IGNORE_TEXT_FAILURES": "Ignore Text Stream Failures",
"DEMO_INACCURATE_MANIFEST_TOLERANCE": "Inaccurate Manifest Tolerance",
Expand Down
4 changes: 4 additions & 0 deletions demo/locales/source.json
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,10 @@
"description": "The name of a configuration value.",
"message": "Ignore Program Date Time from manifest"
},
"DEMO_IGNORE_MANIFEST_TIMESTAMPS_IN_SEGMENTS_MODE": {
"description": "The name of a configuration value.",
"message": "Ignore Manifest Timestamps in Segments Mode"
},
"DEMO_IGNORE_MIN_BUFFER_TIME": {
"description": "The name of a configuration value.",
"message": "Ignore Min Buffer Time"
Expand Down
9 changes: 9 additions & 0 deletions externs/shaka/manifest.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
* offlineSessionIds: !Array.<string>,
* minBufferTime: number,
* sequenceMode: boolean,
* ignoreManifestTimestampsInSegmentsMode: boolean,
* type: string
* }}
*
Expand Down Expand Up @@ -77,6 +78,14 @@
* @property {boolean} sequenceMode
* If true, we will append the media segments using sequence mode; that is to
* say, ignoring any timestamps inside the media files.
* @property {boolean} ignoreManifestTimestampsInSegmentsMode
* If true, don't adjust the timestamp offset to account for manifest
* segment durations being out of sync with segment durations. In other
* words, assume that there are no gaps in the segments when appending
* to the SourceBuffer, even if the manifest and segment times disagree.
* Only applies when sequenceMode is <code>false</code>, and only for HLS
* streams.
* <i>Defaults to <code>false</code>.</i>
* @property {string} type
* Indicates the type of the manifest. It can be <code>'HLS'</code> or
* <code>'DASH'</code>.
Expand Down
10 changes: 9 additions & 1 deletion externs/shaka/player.js
Original file line number Diff line number Diff line change
Expand Up @@ -841,7 +841,8 @@ shaka.extern.DashManifestConfiguration;
* mediaPlaylistFullMimeType: string,
* useSafariBehaviorForLive: boolean,
* liveSegmentsDelay: number,
* sequenceMode: boolean
* sequenceMode: boolean,
* ignoreManifestTimestampsInSegmentsMode: boolean
* }}
*
* @property {boolean} ignoreTextStreamFailures
Expand Down Expand Up @@ -887,6 +888,13 @@ shaka.extern.DashManifestConfiguration;
* "sequence mode" (ignoring their internal timestamps).
* Defaults to <code>true</code> except on WebOS 3, Tizen 2,
* Tizen 3 and PlayStation 4 whose default value is <code>false</code>.
* @property {boolean} ignoreManifestTimestampsInSegmentsMode
* If true, don't adjust the timestamp offset to account for manifest
* segment durations being out of sync with segment durations. In other
* words, assume that there are no gaps in the segments when appending
* to the SourceBuffer, even if the manifest and segment times disagree.
* Only applies when sequenceMode is <code>false</code>.
* <i>Defaults to <code>false</code>.</i>
* @exportDoc
*/
shaka.extern.HlsManifestConfiguration;
Expand Down
1 change: 1 addition & 0 deletions lib/dash/dash_parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,7 @@ shaka.dash.DashParser = class {
offlineSessionIds: [],
minBufferTime: minBufferTime || 0,
sequenceMode: this.config_.dash.sequenceMode,
ignoreManifestTimestampsInSegmentsMode: false,
type: shaka.media.ManifestParser.DASH,
};

Expand Down
2 changes: 2 additions & 0 deletions lib/hls/hls_parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -762,6 +762,8 @@ shaka.hls.HlsParser = class {
offlineSessionIds: [],
minBufferTime: 0,
sequenceMode: this.config_.hls.sequenceMode,
ignoreManifestTimestampsInSegmentsMode:
this.config_.hls.ignoreManifestTimestampsInSegmentsMode,
type: shaka.media.ManifestParser.HLS,
};
this.playerInterface_.makeTextStreamsForClosedCaptions(this.manifest_);
Expand Down
16 changes: 14 additions & 2 deletions lib/media/media_source_engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,9 @@ shaka.media.MediaSourceEngine = class {
/** @private {string} */
this.manifestType_ = shaka.media.ManifestParser.UNKNOWN;

/** @private {boolean} */
this.ignoreManifestTimestampsInSegmentsMode_ = false;

/** @private {!shaka.util.PublicPromise.<number>} */
this.textSequenceModeOffset_ = new shaka.util.PublicPromise();
}
Expand Down Expand Up @@ -351,17 +354,25 @@ shaka.media.MediaSourceEngine = class {
* sequence.
* @param {string=} manifestType
* Indicates the type of the manifest.
* @param {boolean=} ignoreManifestTimestampsInSegmentsMode
* If true, don't adjust the timestamp offset to account for manifest
* segment durations being out of sync with segment durations. In other
* words, assume that there are no gaps in the segments when appending
* to the SourceBuffer, even if the manifest and segment times disagree.
*
* @return {!Promise}
*/
async init(streamsByType, sequenceMode=false,
manifestType=shaka.media.ManifestParser.UNKNOWN) {
manifestType=shaka.media.ManifestParser.UNKNOWN,
ignoreManifestTimestampsInSegmentsMode=false) {
const ContentType = shaka.util.ManifestParserUtils.ContentType;

await this.mediaSourceOpen_;

this.sequenceMode_ = sequenceMode;
this.manifestType_ = manifestType;
this.ignoreManifestTimestampsInSegmentsMode_ =
ignoreManifestTimestampsInSegmentsMode;

for (const contentType of streamsByType.keys()) {
const stream = streamsByType.get(contentType);
Expand Down Expand Up @@ -599,7 +610,8 @@ shaka.media.MediaSourceEngine = class {
}

const attemptTimestampOffsetCalculation = !this.sequenceMode_ &&
this.manifestType_ == shaka.media.ManifestParser.HLS;
this.manifestType_ == shaka.media.ManifestParser.HLS &&
!this.ignoreManifestTimestampsInSegmentsMode_;

let timestampOffset = this.sourceBuffers_[contentType].timestampOffset;

Expand Down
4 changes: 3 additions & 1 deletion lib/media/streaming_engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -812,7 +812,9 @@ shaka.media.StreamingEngine = class {

await mediaSourceEngine.init(streamsByType,
this.manifest_.sequenceMode,
this.manifest_.type);
this.manifest_.type,
this.manifest_.ignoreManifestTimestampsInSegmentsMode,
);
this.destroyer_.ensureNotDestroyed();

this.updateDuration();
Expand Down
1 change: 1 addition & 0 deletions lib/offline/manifest_converter.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ shaka.offline.ManifestConverter = class {
textStreams: textStreams,
imageStreams: imageStreams,
sequenceMode: manifestDB.sequenceMode || false,
ignoreManifestTimestampsInSegmentsMode: false,
type: manifestDB.type || shaka.media.ManifestParser.UNKNOWN,
};
}
Expand Down
1 change: 1 addition & 0 deletions lib/util/player_configuration.js
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ shaka.util.PlayerConfiguration = class {
useSafariBehaviorForLive: true,
liveSegmentsDelay: 3,
sequenceMode: supportsSequenceMode,
ignoreManifestTimestampsInSegmentsMode: false,
},
};

Expand Down
1 change: 1 addition & 0 deletions test/media/playhead_unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ describe('Playhead', () => {
minBufferTime: 10,
offlineSessionIds: [],
sequenceMode: false,
ignoreManifestTimestampsInSegmentsMode: false,
type: 'UNKNOWN',
};

Expand Down
1 change: 1 addition & 0 deletions test/media/streaming_engine_integration.js
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,7 @@ describe('StreamingEngine', () => {
textStreams: [],
imageStreams: [],
sequenceMode: false,
ignoreManifestTimestampsInSegmentsMode: false,
type: 'UNKNOWN',
variants: [{
id: 1,
Expand Down
3 changes: 2 additions & 1 deletion test/media/streaming_engine_unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,8 @@ describe('StreamingEngine', () => {
expectedMseInit.set(ContentType.TEXT, textStream);

expect(mediaSourceEngine.init).toHaveBeenCalledWith(expectedMseInit,
/** sequenceMode= */ false, /** manifestType= */ 'UNKNOWN');
/** sequenceMode= */ false, /** manifestType= */ 'UNKNOWN',
/** ignoreManifestTimestampsInSegmentsMode= */ false);
expect(mediaSourceEngine.init).toHaveBeenCalledTimes(1);

expect(mediaSourceEngine.setDuration).toHaveBeenCalledTimes(1);
Expand Down
2 changes: 2 additions & 0 deletions test/test/util/manifest_generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ shaka.test.ManifestGenerator.Manifest = class {
this.minBufferTime = 0;
/** @type {boolean} */
this.sequenceMode = false;
/** @type {boolean} */
this.ignoreManifestTimestampsInSegmentsMode = false;
/** @type {string} */
this.type = 'UNKNOWN';

Expand Down
1 change: 1 addition & 0 deletions test/test/util/streaming_engine_util.js
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ shaka.test.StreamingEngineUtil = class {
textStreams: [],
imageStreams: [],
sequenceMode: false,
ignoreManifestTimestampsInSegmentsMode: false,
type: 'UNKNOWN',
};

Expand Down