Skip to content

Commit 534ae6d

Browse files
aveladjoeyparrish
authored andcommitted
fix(HLS): Fix subtitle timing (#7625)
Simplifies subtitle management for sequence mode and segments mode Runs subtitle tests in segments mode as well (Tizen 3.0) Fixes: #7447
1 parent 74a87a1 commit 534ae6d

14 files changed

+84
-27
lines changed

karma.conf.js

+2
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,8 @@ module.exports = (config) => {
272272
{pattern: 'test/test/assets/hls-raw-ec3/*', included: false},
273273
{pattern: 'test/test/assets/hls-raw-mp3/*', included: false},
274274
{pattern: 'test/test/assets/hls-sample-aes/*', included: false},
275+
// eslint-disable-next-line max-len
276+
{pattern: 'test/test/assets/hls-text-no-discontinuity/*', included: false},
275277
{pattern: 'test/test/assets/hls-text-offset/*', included: false},
276278
{pattern: 'test/test/assets/hls-ts-aac/*', included: false},
277279
{pattern: 'test/test/assets/hls-ts-ac3/*', included: false},

lib/hls/hls_parser.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -4127,7 +4127,7 @@ shaka.hls.HlsParser = class {
41274127
let aesKey = undefined;
41284128

41294129
let discontinuitySequence = shaka.hls.Utils.getFirstTagWithNameAsNumber(
4130-
playlist.tags, 'EXT-X-DISCONTINUITY-SEQUENCE', 0);
4130+
playlist.tags, 'EXT-X-DISCONTINUITY-SEQUENCE', -1);
41314131
const mediaSequenceNumber = shaka.hls.Utils.getFirstTagWithNameAsNumber(
41324132
playlist.tags, 'EXT-X-MEDIA-SEQUENCE', 0);
41334133
const skipTag = shaka.hls.Utils.getFirstTagWithName(

lib/media/media_source_engine.js

+7-2
Original file line numberDiff line numberDiff line change
@@ -1139,7 +1139,8 @@ shaka.media.MediaSourceEngine = class {
11391139
const ContentType = shaka.util.ManifestParserUtils.ContentType;
11401140

11411141
if (contentType == ContentType.TEXT) {
1142-
if (this.sequenceMode_) {
1142+
if (this.manifestType_ == shaka.media.ManifestParser.HLS &&
1143+
reference.discontinuitySequence >= 0) {
11431144
// This won't be known until the first video segment is appended.
11441145
const offset = await this.textSequenceModeOffset_;
11451146
this.textEngine_.setTimestampOffset(offset);
@@ -1233,7 +1234,7 @@ shaka.media.MediaSourceEngine = class {
12331234
const isBestSourceBufferForTimestamps =
12341235
contentType == ContentType.VIDEO ||
12351236
!(ContentType.VIDEO in this.sourceBuffers_);
1236-
if (this.sequenceMode_ && isBestSourceBufferForTimestamps) {
1237+
if (isBestSourceBufferForTimestamps) {
12371238
this.textSequenceModeOffset_.resolve(timestampOffset);
12381239
}
12391240
}
@@ -1562,6 +1563,10 @@ shaka.media.MediaSourceEngine = class {
15621563
this.textSequenceModeOffset_ = new shaka.util.PublicPromise();
15631564
}
15641565

1566+
if (!this.sequenceMode_) {
1567+
return;
1568+
}
1569+
15651570
// Queue an abort() to help MSE splice together overlapping segments.
15661571
// We set appendWindowEnd when we change periods in DASH content, and the
15671572
// period transition may result in overlap.

lib/media/segment_reference.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ shaka.media.SegmentReference = class {
295295
this.thumbnailSprite = null;
296296

297297
/** @type {number} */
298-
this.discontinuitySequence = 0;
298+
this.discontinuitySequence = -1;
299299

300300
/** @type {boolean} */
301301
this.allPartialSegments = allPartialSegments;

lib/media/streaming_engine.js

+9-11
Original file line numberDiff line numberDiff line change
@@ -2156,17 +2156,15 @@ shaka.media.StreamingEngine = class {
21562156
}
21572157
}
21582158

2159-
if (this.manifest_.sequenceMode) {
2160-
const lastDiscontinuitySequence =
2161-
mediaState.lastSegmentReference ?
2162-
mediaState.lastSegmentReference.discontinuitySequence : null;
2163-
// Across discontinuity bounds, we should resync timestamps for
2164-
// sequence mode playbacks. The next segment appended should
2165-
// land at its theoretical timestamp from the segment index.
2166-
if (reference.discontinuitySequence != lastDiscontinuitySequence) {
2167-
operations.push(this.playerInterface_.mediaSourceEngine.resync(
2168-
mediaState.type, reference.startTime));
2169-
}
2159+
const lastDiscontinuitySequence =
2160+
mediaState.lastSegmentReference ?
2161+
mediaState.lastSegmentReference.discontinuitySequence : null;
2162+
// Across discontinuity bounds, we should resync timestamps. The next
2163+
// segment appended should land at its theoretical timestamp from the
2164+
// segment index.
2165+
if (reference.discontinuitySequence != lastDiscontinuitySequence) {
2166+
operations.push(this.playerInterface_.mediaSourceEngine.resync(
2167+
mediaState.type, reference.startTime));
21702168
}
21712169

21722170
await Promise.all(operations);

lib/text/vtt_text_parser.js

+2-8
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,7 @@ shaka.text.VttTextParser = class {
8686
// Only use 'X-TIMESTAMP-MAP' with HLS. This overrides offset above.
8787
if (blocks[0].includes('X-TIMESTAMP-MAP') &&
8888
this.manifestType_ == shaka.media.ManifestParser.HLS) {
89-
if (this.sequenceMode_) {
90-
// Compute a different, rollover-based offset for sequence mode.
91-
offset = this.computeHlsSequenceModeOffset_(blocks[0], time);
92-
} else {
93-
// Calculate the offset from the segment startTime.
94-
offset = time.segmentStart;
95-
}
89+
offset = this.computeHlsOffset_(blocks[0], time);
9690
}
9791

9892
// Parse VTT regions.
@@ -129,7 +123,7 @@ shaka.text.VttTextParser = class {
129123
* @return {number}
130124
* @private
131125
*/
132-
computeHlsSequenceModeOffset_(headerBlock, time) {
126+
computeHlsOffset_(headerBlock, time) {
133127
// https://bit.ly/2K92l7y
134128
// The 'X-TIMESTAMP-MAP' header is used in HLS to align text with
135129
// the rest of the media.

test/hls/hls_parser_integration.js

+21-4
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,6 @@ describe('HlsParser', () => {
111111
});
112112

113113
it('supports text discontinuity', async () => {
114-
if (!shaka.util.Platform.supportsSequenceMode()) {
115-
pending('Sequence mode is not supported by the platform.');
116-
}
117-
118114
player.setTextTrackVisibility(true);
119115

120116
await player.load('/base/test/test/assets/hls-text-offset/index.m3u8');
@@ -134,4 +130,25 @@ describe('HlsParser', () => {
134130

135131
await player.unload();
136132
});
133+
134+
it('supports text without discontinuity', async () => {
135+
player.setTextTrackVisibility(true);
136+
137+
// eslint-disable-next-line max-len
138+
await player.load('/base/test/test/assets/hls-text-no-discontinuity/index.m3u8');
139+
await video.play();
140+
141+
await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 1, 30);
142+
143+
const cues = video.textTracks[0].cues;
144+
expect(cues.length).toBe(3);
145+
expect(cues[0].startTime).toBeCloseTo(0.6, 0);
146+
expect(cues[0].endTime).toBeCloseTo(2.88, 0);
147+
expect(cues[1].startTime).toBeCloseTo(2.88, 0);
148+
expect(cues[1].endTime).toBeCloseTo(6.36, 0);
149+
expect(cues[2].startTime).toBeCloseTo(6.36, 0);
150+
expect(cues[2].endTime).toBeCloseTo(10.68, 0);
151+
152+
await player.unload();
153+
});
137154
});

test/hls/hls_parser_unit.js

+1
Original file line numberDiff line numberDiff line change
@@ -1153,6 +1153,7 @@ describe('HlsParser', () => {
11531153
'#EXT-X-VERSION:3\n',
11541154
'#EXT-X-TARGETDURATION:5\n',
11551155
'#EXT-X-MEDIA-SEQUENCE:0\n',
1156+
'#EXT-X-DISCONTINUITY-SEQUENCE:0\n',
11561157
'#EXTINF:3,\n',
11571158
'clip0-video-0.ts\n',
11581159
'#EXTINF:1,\n',
Binary file not shown.
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#EXTM3U
2+
#EXT-X-VERSION:6
3+
#EXT-X-TARGETDURATION:7
4+
#EXT-X-MEDIA-SEQUENCE:0
5+
#EXT-X-PLAYLIST-TYPE:VOD
6+
#EXT-X-INDEPENDENT-SEGMENTS
7+
#EXTINF:6.000000,
8+
0.ts
9+
#EXTINF:6.000000,
10+
1.ts
11+
#EXT-X-ENDLIST
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#EXTM3U
2+
#EXT-X-VERSION:6
3+
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs",NAME="de",DEFAULT=NO,AUTOSELECT=NO,LANGUAGE="de",FORCED="NO",URI="text.m3u8"
4+
5+
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1240800,CODECS="avc1.640014,mp4a.40.2",RESOLUTION=256x144,SUBTITLES="subs"
6+
av.m3u8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
WEBVTT
2+
3+
1
4+
00:00:00.600 --> 00:00:02.880
5+
Heute haben wir einen wesentlichen Meilenstein
6+
7+
2
8+
00:00:02.880 --> 00:00:06.360
9+
auf dem Weg zur Science
10+
City Hamburg Bahrenfeld erreicht.
11+
12+
3
13+
00:00:06.360 --> 00:00:10.680
14+
Die Science City ist ein 125 Hektar
15+
großes Areal in Bahrenfeld,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#EXTM3U
2+
#EXT-X-VERSION:3
3+
#EXT-X-PLAYLIST-TYPE:VOD
4+
#EXT-X-MEDIA-SEQUENCE:0
5+
#EXT-X-TARGETDURATION:12
6+
#EXTINF:12.000,
7+
subtitle.vtt
8+
#EXT-X-ENDLIST

0 commit comments

Comments
 (0)