diff --git a/lib/hls/hls_parser.js b/lib/hls/hls_parser.js index c4a24b483d..07eb103299 100644 --- a/lib/hls/hls_parser.js +++ b/lib/hls/hls_parser.js @@ -776,22 +776,22 @@ shaka.hls.HlsParser = class { }); const videoCodecs = this.guessCodecsSafe_(ContentType.VIDEO, allCodecs); - const hasVideoRelatedInfo = resolution || frameRate || videoCodecs; + const audioCodecs = this.guessCodecsSafe_(ContentType.AUDIO, allCodecs); - if (allCodecs.length == 1 && !hasVideoRelatedInfo) { - // There are no associated media tags, and there's only one codec, and no - // video related information, so it should be audio. + if (audioCodecs && !videoCodecs) { + // There are no associated media tags, and there's only audio codec, + // and no video codec, so it should be audio. type = ContentType.AUDIO; shaka.log.debug('Guessing audio-only.'); - } else if (!streamInfos.length && allCodecs.length > 1) { - // There are multiple codecs, so assume multiplexed content. + } else if (!streamInfos.length && audioCodecs && videoCodecs) { + // There are both audio and video codecs, so assume multiplexed content. // Note that the default used when CODECS is missing assumes multiple // (and therefore multiplexed). // Recombine the codec strings into one so that MediaSource isn't // lied to later. (That would trigger an error in Chrome.) shaka.log.debug('Guessing multiplexed audio+video.'); type = ContentType.VIDEO; - allCodecs = [allCodecs.join(',')]; + allCodecs = [[videoCodecs, audioCodecs].join(',')]; } else if (res.audio.length && hasSameUri) { shaka.log.debug('Guessing audio-only.'); type = ContentType.AUDIO; diff --git a/test/hls/hls_parser_unit.js b/test/hls/hls_parser_unit.js index e5aebc95cf..8397df2171 100644 --- a/test/hls/hls_parser_unit.js +++ b/test/hls/hls_parser_unit.js @@ -295,6 +295,37 @@ describe('HlsParser', () => { await testHlsParser(master, media, manifest); }); + it('guesses video-only variant when text codecs are present', async () => { + const master = [ + // NOTE: This manifest is technically invalid. It has text codecs, but + // no text stream. We're tesing text stream parsing elswhere, so this + // only has the stream we're interested in (video) for simplicity. + '#EXTM3U\n', + '#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1,stpp.ttml.im1t"\n', + 'video', + ].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 manifest = shaka.test.ManifestGenerator.generate((manifest) => { + manifest.anyTimeline(); + manifest.addPartialVariant((variant) => { + variant.addPartialStream(ContentType.VIDEO, (stream) => { + stream.mime('video/mp4', 'avc1'); + }); + }); + }); + + await testHlsParser(master, media, manifest); + }); + it('parses audio-only variant', async () => { const master = [ '#EXTM3U\n',