From ea6c02aece1510598a898c235e66335d20eabedb Mon Sep 17 00:00:00 2001 From: wjywbs Date: Fri, 11 Feb 2022 15:58:47 -0500 Subject: [PATCH] fix(HLS): skip whitespace in attributes (#3884) Example: `#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=1000000, RESOLUTION=1920x1080` Co-authored-by: Joey Parrish --- lib/hls/manifest_text_parser.js | 1 + test/hls/hls_parser_unit.js | 75 +++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/lib/hls/manifest_text_parser.js b/lib/hls/manifest_text_parser.js index df81569cd2..1e3f57c7fe 100644 --- a/lib/hls/manifest_text_parser.js +++ b/lib/hls/manifest_text_parser.js @@ -277,6 +277,7 @@ shaka.hls.ManifestTextParser = class { const attrValue = blockAttrs[2] || blockAttrs[3]; const attribute = new shaka.hls.Attribute(attrName, attrValue); attributes.push(attribute); + parser.skipWhitespace(); } } diff --git a/test/hls/hls_parser_unit.js b/test/hls/hls_parser_unit.js index 150e58fdcb..25b65b6fe0 100644 --- a/test/hls/hls_parser_unit.js +++ b/test/hls/hls_parser_unit.js @@ -209,6 +209,81 @@ describe('HlsParser', () => { expect(actual).toEqual(manifest); }); + it('parses manifest attributes with space', async () => { + const master = [ + '#EXTM3U\n', + '#EXT-X-MEDIA:TYPE=AUDIO, GROUP-ID="aud1", LANGUAGE="eng", ', + 'CHANNELS="16/JOC", URI="audio"\n', + '#EXT-X-MEDIA:TYPE=SUBTITLES, GROUP-ID="sub1", LANGUAGE="eng", ', + 'URI="text"\n', + '#EXT-X-MEDIA:TYPE=SUBTITLES, GROUP-ID="sub2", LANGUAGE="es", ', + 'URI="text2"\n', + '#EXT-X-STREAM-INF:BANDWIDTH=200, CODECS="avc1,mp4a", ', + 'RESOLUTION=960x540, FRAME-RATE=60, AUDIO="aud1"\n', + 'video\n', + ].join(''); + + const media = [ + '#EXTM3U\n', + '#EXT-X-PLAYLIST-TYPE:VOD\n', + '#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n', + '#EXTINF:5,\n', + '#EXT-X-BYTERANGE:121090@616\n', + 'main.mp4', + ].join(''); + + const textMedia = [ + '#EXTM3U\n', + '#EXT-X-PLAYLIST-TYPE:VOD\n', + '#EXTINF:5,\n', + '#EXT-X-BYTERANGE:121090@616\n', + 'main.vtt', + ].join(''); + + const manifest = shaka.test.ManifestGenerator.generate((manifest) => { + manifest.sequenceMode = true; + manifest.anyTimeline(); + manifest.addPartialVariant((variant) => { + variant.language = 'en'; + variant.bandwidth = 200; + variant.addPartialStream(ContentType.VIDEO, (stream) => { + stream.frameRate = 60; + stream.mime('video/mp4', 'avc1'); + stream.size(960, 540); + }); + variant.addPartialStream(ContentType.AUDIO, (stream) => { + stream.language = 'en'; + stream.channelsCount = 16; + stream.spatialAudio = true; + stream.mime('audio/mp4', 'mp4a'); + }); + }); + manifest.addPartialTextStream((stream) => { + stream.language = 'en'; + stream.kind = TextStreamKind.SUBTITLE; + stream.mime('text/vtt', ''); + }); + manifest.addPartialTextStream((stream) => { + stream.language = 'es'; + stream.kind = TextStreamKind.SUBTITLE; + stream.mime('text/vtt', ''); + }); + }); + + fakeNetEngine + .setResponseText('test:/master', master) + .setResponseText('test:/audio', media) + .setResponseText('test:/video', media) + .setResponseText('test:/text', textMedia) + .setResponseText('test:/text2', textMedia) + .setResponseText('test:/main.vtt', vttText) + .setResponseValue('test:/init.mp4', initSegmentData) + .setResponseValue('test:/main.mp4', segmentData); + + const actual = await parser.start('test:/master', playerInterface); + expect(actual).toEqual(manifest); + }); + it('prioritize AVERAGE-BANDWIDTH to BANDWIDTH', async () => { const master = [ '#EXTM3U\n',