Skip to content

Commit 2100fd1

Browse files
authored
fix(HLS): Support PATHWAY-ID (Content Steering) for subtitles (#9442)
1 parent 98895ce commit 2100fd1

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
@@ -1478,20 +1478,31 @@ shaka.hls.HlsParser = class {
14781478
// Create text stream for each Subtitle media tag.
14791479
const subtitleTags =
14801480
shaka.hls.Utils.filterTagsByType(mediaTags, 'SUBTITLES');
1481-
const textStreams = subtitleTags.map((tag) => {
1482-
const disableText = this.config_.disableText;
1483-
if (disableText) {
1484-
return null;
1481+
1482+
const groupedTags = {};
1483+
for (const tag of subtitleTags) {
1484+
const key = tag.getTagKey(!this.contentSteeringManager_);
1485+
if (!groupedTags[key]) {
1486+
groupedTags[key] = [tag];
1487+
} else {
1488+
groupedTags[key].push(tag);
14851489
}
1486-
try {
1487-
return this.createStreamInfoFromMediaTags_([tag], new Map()).stream;
1488-
} catch (e) {
1489-
if (this.config_.hls.ignoreTextStreamFailures) {
1490-
return null;
1490+
}
1491+
1492+
const textStreams = [];
1493+
if (!this.config_.disableText) {
1494+
for (const key in groupedTags) {
1495+
try {
1496+
textStreams.push(this.createStreamInfoFromMediaTags_(
1497+
groupedTags[key], new Map()).stream);
1498+
} catch (e) {
1499+
if (this.config_.hls.ignoreTextStreamFailures) {
1500+
continue;
1501+
}
1502+
throw e;
14911503
}
1492-
throw e;
14931504
}
1494-
});
1505+
}
14951506

14961507
const type = shaka.util.ManifestParserUtils.ContentType.TEXT;
14971508

@@ -2384,6 +2395,10 @@ shaka.hls.HlsParser = class {
23842395
verbatimMediaPlaylistUris.push(uri);
23852396
globalGroupIds.push(groupId);
23862397
groupIdUriMapping.set(groupId, uri);
2398+
const pathwayId = tag.getAttributeValue('PATHWAY-ID');
2399+
if (pathwayId) {
2400+
groupIdPathwayIdMapping.set(groupId, pathwayId);
2401+
}
23872402
}
23882403

23892404
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
@@ -6210,15 +6210,19 @@ describe('HlsParser', () => {
62106210
'#EXTM3U\n',
62116211
'#EXT-X-CONTENT-STEERING:SERVER-URI="http://contentsteering",',
62126212
'PATHWAY-ID="a"\n',
6213+
'#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subsA",LANGUAGE="eng",',
6214+
'NAME="English",PATHWAY-ID="a",URI="subs/a/media.m3u8"\n',
6215+
'#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subsB",LANGUAGE="eng",',
6216+
'NAME="English",PATHWAY-ID="b",URI="subs/b/media.m3u8"\n',
62136217
'#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="a",LANGUAGE="eng",',
62146218
'URI="audio/a/media.m3u8"\n',
62156219
'#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="b",LANGUAGE="eng",',
62166220
'URI="audio/b/media.m3u8"\n',
62176221
'#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc,mp4a",',
6218-
'AUDIO="a",PATHWAY-ID="a",CLOSED-CAPTIONS=NONE\n',
6222+
'AUDIO="a",PATHWAY-ID="a",CLOSED-CAPTIONS=NONE,SUBTITLES="subsA"\n',
62196223
'a/media.m3u8\n',
62206224
'#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc,mp4a",',
6221-
'AUDIO="b",PATHWAY-ID="b",CLOSED-CAPTIONS=NONE\n',
6225+
'AUDIO="b",PATHWAY-ID="b",CLOSED-CAPTIONS=NONE,SUBTITLES="subsB"\n',
62226226
'b/media.m3u8',
62236227
].join('');
62246228

@@ -6248,6 +6252,8 @@ describe('HlsParser', () => {
62486252
.setResponseText('http://master/b/media.m3u8', media)
62496253
.setResponseText('http://master/audio/a/media.m3u8', media)
62506254
.setResponseText('http://master/audio/b/media.m3u8', media)
6255+
.setResponseText('http://master/subs/a/media.m3u8', media)
6256+
.setResponseText('http://master/subs/b/media.m3u8', media)
62516257
.setMaxUris(2);
62526258

62536259
/** @type {shaka.extern.Manifest} */
@@ -6273,6 +6279,17 @@ describe('HlsParser', () => {
62736279

62746280
expect(videoUri0).toBe('http://master/b/main.mp4');
62756281
expect(videoUri1).toBe('http://master/a/main.mp4');
6282+
6283+
expect(manifest.textStreams.length).toBe(1);
6284+
const text = manifest.textStreams[0];
6285+
await text.createSegmentIndex();
6286+
goog.asserts.assert(text.segmentIndex, 'Null segmentIndex!');
6287+
const textSegment0 = Array.from(text.segmentIndex)[0];
6288+
const textUri0 = textSegment0.getUris()[0];
6289+
const textUri1 = textSegment0.getUris()[1];
6290+
6291+
expect(textUri0).toBe('http://master/subs/b/main.mp4');
6292+
expect(textUri1).toBe('http://master/subs/a/main.mp4');
62766293
});
62776294

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

0 commit comments

Comments
 (0)