From c25b26a26a7e930af9455bae2f9d82804b921b7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Velad=20Galv=C3=A1n?= Date: Thu, 29 Jun 2023 10:52:13 +0200 Subject: [PATCH] fix(HLS): Ignore segments with zero duration (#5371) --- lib/hls/hls_parser.js | 6 ++- test/hls/hls_parser_unit.js | 76 +++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 1 deletion(-) diff --git a/lib/hls/hls_parser.js b/lib/hls/hls_parser.js index 8fa7756e3d..87d543a302 100644 --- a/lib/hls/hls_parser.js +++ b/lib/hls/hls_parser.js @@ -2981,6 +2981,10 @@ shaka.hls.HlsParser = class { // We're interested in the duration part. const extinfValues = extinfTag.value.split(','); const duration = Number(extinfValues[0]); + // Skip segments without duration + if (duration == 0) { + return null; + } endTime = startTime + duration; } else { endTime = partialSegmentRefs[partialSegmentRefs.length - 1].endTime; @@ -3196,9 +3200,9 @@ shaka.hls.HlsParser = class { mimeType, lastDiscontinuityStartTime, hlsAes128Key); - previousReference = reference; if (reference) { + previousReference = reference; reference.discontinuitySequence = discontinuitySequence; if (this.config_.hls.ignoreManifestProgramDateTime && diff --git a/test/hls/hls_parser_unit.js b/test/hls/hls_parser_unit.js index e5e9d50c24..a417f8c229 100644 --- a/test/hls/hls_parser_unit.js +++ b/test/hls/hls_parser_unit.js @@ -1916,6 +1916,82 @@ describe('HlsParser', () => { } }); + it('ignore segments with #EXTINF:0', async () => { + const master = [ + '#EXTM3U\n', + '#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aud1",LANGUAGE="eng",', + 'CHANNELS="2",URI="audio"\n', + '#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1,mp4a",', + 'RESOLUTION=960x540,FRAME-RATE=60,AUDIO="aud1"\n', + 'video\n', + ].join(''); + + const video = [ + '#EXTM3U\n', + '#EXT-X-PLAYLIST-TYPE:VOD\n', + '#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n', + '#EXTINF:5,\n', + 'main.mp4\n', + '#EXTINF:0,\n', + 'main.mp4\n', + '#EXTINF:5,\n', + 'main.mp4\n', + ].join(''); + + const audio = [ + '#EXTM3U\n', + '#EXT-X-PLAYLIST-TYPE:VOD\n', + '#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n', + '#EXTINF:5,\n', + 'main.mp4\n', + '#EXTINF:0,\n', + 'main.mp4\n', + '#EXTINF:5,\n', + 'main.mp4\n', + ].join(''); + + fakeNetEngine + .setResponseText('test:/master', master) + .setResponseText('test:/audio', audio) + .setResponseText('test:/video', video) + .setResponseValue('test:/init.mp4', initSegmentData) + .setResponseValue('test:/main.mp4', segmentData); + + const actual = await parser.start('test:/master', playerInterface); + await loadAllStreamsFor(actual); + + expect(actual.variants.length).toBe(1); + + const variant = actual.variants[0]; + expect(variant.video).toBeTruthy(); + expect(variant.audio).toBeTruthy(); + + await variant.video.createSegmentIndex(); + goog.asserts.assert(variant.video.segmentIndex != null, + 'Null segmentIndex!'); + + const firstVideoReference = variant.video.segmentIndex.get(0); + const secondVideoReference = variant.video.segmentIndex.get(1); + const thirdVideoReference = variant.video.segmentIndex.get(2); + + expect(firstVideoReference).not.toBe(null); + expect(secondVideoReference).not.toBe(null); + expect(thirdVideoReference).toBe(null); + + + await variant.audio.createSegmentIndex(); + goog.asserts.assert(variant.audio.segmentIndex != null, + 'Null segmentIndex!'); + + const firstAudioReference = variant.audio.segmentIndex.get(0); + const secondAudioReference = variant.audio.segmentIndex.get(1); + const thirdAudioReference = variant.audio.segmentIndex.get(2); + + expect(firstAudioReference).not.toBe(null); + expect(secondAudioReference).not.toBe(null); + expect(thirdAudioReference).toBe(null); + }); + it('Disable audio does not create audio streams', async () => { const master = [ '#EXTM3U\n',