Skip to content

Commit e4ffa1a

Browse files
committed
fix(HLS): Support PATHWAY-ID (Content Steering) for subtitles (#9442)
1 parent 5252464 commit e4ffa1a

File tree

2 files changed

+45
-13
lines changed

2 files changed

+45
-13
lines changed

lib/hls/hls_parser.js

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1473,20 +1473,31 @@ shaka.hls.HlsParser = class {
14731473
// Create text stream for each Subtitle media tag.
14741474
const subtitleTags =
14751475
shaka.hls.Utils.filterTagsByType(mediaTags, 'SUBTITLES');
1476-
const textStreams = subtitleTags.map((tag) => {
1477-
const disableText = this.config_.disableText;
1478-
if (disableText) {
1479-
return null;
1476+
1477+
const groupedTags = {};
1478+
for (const tag of subtitleTags) {
1479+
const key = tag.getTagKey(!this.contentSteeringManager_);
1480+
if (!groupedTags[key]) {
1481+
groupedTags[key] = [tag];
1482+
} else {
1483+
groupedTags[key].push(tag);
14801484
}
1481-
try {
1482-
return this.createStreamInfoFromMediaTags_([tag], new Map()).stream;
1483-
} catch (e) {
1484-
if (this.config_.hls.ignoreTextStreamFailures) {
1485-
return null;
1485+
}
1486+
1487+
const textStreams = [];
1488+
if (!this.config_.disableText) {
1489+
for (const key in groupedTags) {
1490+
try {
1491+
textStreams.push(this.createStreamInfoFromMediaTags_(
1492+
groupedTags[key], new Map()).stream);
1493+
} catch (e) {
1494+
if (this.config_.hls.ignoreTextStreamFailures) {
1495+
continue;
1496+
}
1497+
throw e;
14861498
}
1487-
throw e;
14881499
}
1489-
});
1500+
}
14901501

14911502
const type = shaka.util.ManifestParserUtils.ContentType.TEXT;
14921503

@@ -2255,6 +2266,10 @@ shaka.hls.HlsParser = class {
22552266
verbatimMediaPlaylistUris.push(uri);
22562267
globalGroupIds.push(groupId);
22572268
groupIdUriMapping.set(groupId, uri);
2269+
const pathwayId = tag.getAttributeValue('PATHWAY-ID');
2270+
if (pathwayId) {
2271+
groupIdPathwayIdMapping.set(groupId, pathwayId);
2272+
}
22582273
}
22592274

22602275
const globalGroupId = globalGroupIds.sort().join(',');

test/hls/hls_parser_unit.js

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5988,15 +5988,19 @@ describe('HlsParser', () => {
59885988
'#EXTM3U\n',
59895989
'#EXT-X-CONTENT-STEERING:SERVER-URI="http://contentsteering",',
59905990
'PATHWAY-ID="a"\n',
5991+
'#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subsA",LANGUAGE="eng",',
5992+
'NAME="English",PATHWAY-ID="a",URI="subs/a/media.m3u8"\n',
5993+
'#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subsB",LANGUAGE="eng",',
5994+
'NAME="English",PATHWAY-ID="b",URI="subs/b/media.m3u8"\n',
59915995
'#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="a",LANGUAGE="eng",',
59925996
'URI="audio/a/media.m3u8"\n',
59935997
'#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="b",LANGUAGE="eng",',
59945998
'URI="audio/b/media.m3u8"\n',
59955999
'#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc,mp4a",',
5996-
'AUDIO="a",PATHWAY-ID="a",CLOSED-CAPTIONS=NONE\n',
6000+
'AUDIO="a",PATHWAY-ID="a",CLOSED-CAPTIONS=NONE,SUBTITLES="subsA"\n',
59976001
'a/media.m3u8\n',
59986002
'#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc,mp4a",',
5999-
'AUDIO="b",PATHWAY-ID="b",CLOSED-CAPTIONS=NONE\n',
6003+
'AUDIO="b",PATHWAY-ID="b",CLOSED-CAPTIONS=NONE,SUBTITLES="subsB"\n',
60006004
'b/media.m3u8',
60016005
].join('');
60026006

@@ -6026,6 +6030,8 @@ describe('HlsParser', () => {
60266030
.setResponseText('http://master/b/media.m3u8', media)
60276031
.setResponseText('http://master/audio/a/media.m3u8', media)
60286032
.setResponseText('http://master/audio/b/media.m3u8', media)
6033+
.setResponseText('http://master/subs/a/media.m3u8', media)
6034+
.setResponseText('http://master/subs/b/media.m3u8', media)
60296035
.setMaxUris(2);
60306036

60316037
/** @type {shaka.extern.Manifest} */
@@ -6051,6 +6057,17 @@ describe('HlsParser', () => {
60516057

60526058
expect(videoUri0).toBe('http://master/b/main.mp4');
60536059
expect(videoUri1).toBe('http://master/a/main.mp4');
6060+
6061+
expect(manifest.textStreams.length).toBe(1);
6062+
const text = manifest.textStreams[0];
6063+
await text.createSegmentIndex();
6064+
goog.asserts.assert(text.segmentIndex, 'Null segmentIndex!');
6065+
const textSegment0 = Array.from(text.segmentIndex)[0];
6066+
const textUri0 = textSegment0.getUris()[0];
6067+
const textUri1 = textSegment0.getUris()[1];
6068+
6069+
expect(textUri0).toBe('http://master/subs/b/main.mp4');
6070+
expect(textUri1).toBe('http://master/subs/a/main.mp4');
60546071
});
60556072

60566073
describe('EXT-X-DATERANGE', () => {

0 commit comments

Comments
 (0)