Skip to content

Commit 3b95600

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

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
@@ -6011,15 +6011,19 @@ describe('HlsParser', () => {
60116011
'#EXTM3U\n',
60126012
'#EXT-X-CONTENT-STEERING:SERVER-URI="http://contentsteering",',
60136013
'PATHWAY-ID="a"\n',
6014+
'#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subsA",LANGUAGE="eng",',
6015+
'NAME="English",PATHWAY-ID="a",URI="subs/a/media.m3u8"\n',
6016+
'#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subsB",LANGUAGE="eng",',
6017+
'NAME="English",PATHWAY-ID="b",URI="subs/b/media.m3u8"\n',
60146018
'#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="a",LANGUAGE="eng",',
60156019
'URI="audio/a/media.m3u8"\n',
60166020
'#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="b",LANGUAGE="eng",',
60176021
'URI="audio/b/media.m3u8"\n',
60186022
'#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc,mp4a",',
6019-
'AUDIO="a",PATHWAY-ID="a",CLOSED-CAPTIONS=NONE\n',
6023+
'AUDIO="a",PATHWAY-ID="a",CLOSED-CAPTIONS=NONE,SUBTITLES="subsA"\n',
60206024
'a/media.m3u8\n',
60216025
'#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc,mp4a",',
6022-
'AUDIO="b",PATHWAY-ID="b",CLOSED-CAPTIONS=NONE\n',
6026+
'AUDIO="b",PATHWAY-ID="b",CLOSED-CAPTIONS=NONE,SUBTITLES="subsB"\n',
60236027
'b/media.m3u8',
60246028
].join('');
60256029

@@ -6049,6 +6053,8 @@ describe('HlsParser', () => {
60496053
.setResponseText('http://master/b/media.m3u8', media)
60506054
.setResponseText('http://master/audio/a/media.m3u8', media)
60516055
.setResponseText('http://master/audio/b/media.m3u8', media)
6056+
.setResponseText('http://master/subs/a/media.m3u8', media)
6057+
.setResponseText('http://master/subs/b/media.m3u8', media)
60526058
.setMaxUris(2);
60536059

60546060
/** @type {shaka.extern.Manifest} */
@@ -6074,6 +6080,17 @@ describe('HlsParser', () => {
60746080

60756081
expect(videoUri0).toBe('http://master/b/main.mp4');
60766082
expect(videoUri1).toBe('http://master/a/main.mp4');
6083+
6084+
expect(manifest.textStreams.length).toBe(1);
6085+
const text = manifest.textStreams[0];
6086+
await text.createSegmentIndex();
6087+
goog.asserts.assert(text.segmentIndex, 'Null segmentIndex!');
6088+
const textSegment0 = Array.from(text.segmentIndex)[0];
6089+
const textUri0 = textSegment0.getUris()[0];
6090+
const textUri1 = textSegment0.getUris()[1];
6091+
6092+
expect(textUri0).toBe('http://master/subs/b/main.mp4');
6093+
expect(textUri1).toBe('http://master/subs/a/main.mp4');
60776094
});
60786095

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

0 commit comments

Comments
 (0)