diff --git a/lib/net/networking_utils.js b/lib/net/networking_utils.js index 6108c8e5f3..0481b025cd 100644 --- a/lib/net/networking_utils.js +++ b/lib/net/networking_utils.js @@ -6,6 +6,7 @@ goog.provide('shaka.net.NetworkingUtils'); +goog.require('goog.Uri'); goog.require('shaka.net.NetworkingEngine'); @@ -20,6 +21,12 @@ shaka.net.NetworkingUtils = class { * @return {!Promise.} */ static async getMimeType(uri, netEngine, retryParams) { + const extension = shaka.net.NetworkingUtils.getExtension_(uri); + let mimeType = + shaka.net.NetworkingUtils.EXTENSIONS_TO_MIME_TYPES_[extension]; + if (mimeType) { + return mimeType; + } const type = shaka.net.NetworkingEngine.RequestType.MANIFEST; const request = shaka.net.NetworkingEngine.makeRequest([uri], retryParams); @@ -29,7 +36,60 @@ shaka.net.NetworkingUtils = class { // https://bit.ly/2K9s9kf says this header should always be available, // but just to be safe: - const mimeType = response.headers['content-type']; + mimeType = response.headers['content-type']; return mimeType ? mimeType.toLowerCase().split(';').shift() : ''; } + + + /** + * @param {string} uri + * @return {string} + * @private + */ + static getExtension_(uri) { + const uriObj = new goog.Uri(uri); + const uriPieces = uriObj.getPath().split('/'); + const uriFilename = uriPieces.pop(); + const filenamePieces = uriFilename.split('.'); + + // Only one piece means there is no extension. + if (filenamePieces.length == 1) { + return ''; + } + + return filenamePieces.pop().toLowerCase(); + } +}; + +/** + * @const {!Object.} + * @private + */ +shaka.net.NetworkingUtils.EXTENSIONS_TO_MIME_TYPES_ = { + 'mp4': 'video/mp4', + 'm4v': 'video/mp4', + 'm4a': 'audio/mp4', + 'webm': 'video/webm', + 'weba': 'audio/webm', + 'mkv': 'video/webm', // Chromium browsers supports it. + 'ts': 'video/mp2t', + 'ogv': 'video/ogg', + 'ogg': 'audio/ogg', + 'mpg': 'video/mpeg', + 'mpeg': 'video/mpeg', + 'm3u8': 'application/x-mpegurl', + 'mpd': 'application/dash+xml', + 'ism': 'application/vnd.ms-sstr+xml', + 'mp3': 'audio/mpeg', + 'aac': 'audio/aac', + 'flac': 'audio/flac', + 'wav': 'audio/wav', + 'sbv': 'text/x-subviewer', + 'srt': 'text/srt', + 'vtt': 'text/vtt', + 'webvtt': 'text/vtt', + 'ttml': 'application/ttml+xml', + 'lrc': 'application/x-subtitle-lrc', + 'ssa': 'text/x-ssa', + 'ass': 'text/x-ssa', }; diff --git a/lib/player.js b/lib/player.js index 3c308710bd..5c387b01b6 100644 --- a/lib/player.js +++ b/lib/player.js @@ -7,7 +7,6 @@ goog.provide('shaka.Player'); goog.require('goog.asserts'); -goog.require('goog.Uri'); goog.require('shaka.config.AutoShowText'); goog.require('shaka.Deprecate'); goog.require('shaka.log'); @@ -719,9 +718,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget { setupLcevc_(config) { if (config.lcevc.enabled) { const tracks = this.getVariantTracks(); - if (tracks && tracks[0] && - tracks[0].videoMimeType == - shaka.Player.EXTENSIONS_TO_MIME_TYPES_['ts']) { + if (tracks && tracks[0] && tracks[0].videoMimeType == 'video/mp2t') { const edge = shaka.util.Platform.isEdge() || shaka.util.Platform.isLegacyEdge(); if (edge) { @@ -1372,13 +1369,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget { async guessMimeType_() { goog.asserts.assert(this.assetUri_, 'should have a uri by now.'); - // If we don't have a MIME type, try to guess based on the file extension. - // Try using the uri extension. - const extension = this.getExtension_(this.assetUri_); - if (shaka.Player.EXTENSIONS_TO_MIME_TYPES_[extension]) { - return shaka.Player.EXTENSIONS_TO_MIME_TYPES_[extension]; - } - // If no MIME type is provided, and we can't base it on extension, make a // HEAD request to determine it. goog.asserts.assert(this.networkingEngine_, 'Should have a net engine!'); @@ -1391,26 +1381,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget { return mimeType; } - - /** - * @param {string} uri - * @return {string} - * @private - */ - getExtension_(uri) { - const uriObj = new goog.Uri(uri); - const uriPieces = uriObj.getPath().split('/'); - const uriFilename = uriPieces.pop(); - const filenamePieces = uriFilename.split('.'); - - // Only one piece means there is no extension. - if (filenamePieces.length == 1) { - return ''; - } - - return filenamePieces.pop().toLowerCase(); - } - /** * Determines if we should use src equals, based on the the mimeType (if * known), the URI, and platform information. @@ -4852,14 +4822,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget { * @private */ async getTextMimetype_(uri) { - // Try using the uri extension. - const extension = this.getExtension_(uri); - let mimeType = shaka.Player.TEXT_EXTENSIONS_TO_MIME_TYPES_[extension]; - - if (mimeType) { - return mimeType; - } - + let mimeType; try { goog.asserts.assert( this.networkingEngine_, 'Need networking engine.'); @@ -4875,12 +4838,12 @@ shaka.Player = class extends shaka.util.FakeEventTarget { shaka.log.error( 'The mimeType has not been provided and it could not be deduced ' + - 'from its extension.'); + 'from its uri.'); throw new shaka.util.Error( shaka.util.Error.Severity.RECOVERABLE, shaka.util.Error.Category.TEXT, shaka.util.Error.Code.TEXT_COULD_NOT_GUESS_MIME_TYPE, - extension); + uri); } /** @@ -6711,48 +6674,6 @@ shaka.Player.supportPlugins_ = {}; shaka.Player.adManagerFactory_ = null; -/** - * @const {!Object.} - * @private - */ -shaka.Player.EXTENSIONS_TO_MIME_TYPES_ = { - 'mp4': 'video/mp4', - 'm4v': 'video/mp4', - 'm4a': 'audio/mp4', - 'webm': 'video/webm', - 'weba': 'audio/webm', - 'mkv': 'video/webm', // Chromium browsers supports it. - 'ts': 'video/mp2t', - 'ogv': 'video/ogg', - 'ogg': 'audio/ogg', - 'mpg': 'video/mpeg', - 'mpeg': 'video/mpeg', - 'm3u8': 'application/x-mpegurl', - 'mpd': 'application/dash+xml', - 'ism': 'application/vnd.ms-sstr+xml', - 'mp3': 'audio/mpeg', - 'aac': 'audio/aac', - 'flac': 'audio/flac', - 'wav': 'audio/wav', -}; - - -/** - * @const {!Object.} - * @private - */ -shaka.Player.TEXT_EXTENSIONS_TO_MIME_TYPES_ = { - 'sbv': 'text/x-subviewer', - 'srt': 'text/srt', - 'vtt': 'text/vtt', - 'webvtt': 'text/vtt', - 'ttml': 'application/ttml+xml', - 'lrc': 'application/x-subtitle-lrc', - 'ssa': 'text/x-ssa', - 'ass': 'text/x-ssa', -}; - - /** * @const {string} */ diff --git a/lib/util/error.js b/lib/util/error.js index 37bf5d4648..1c4f5d2e5b 100644 --- a/lib/util/error.js +++ b/lib/util/error.js @@ -330,7 +330,7 @@ shaka.util.Error.Code = { /** * Unable to guess mime type of the text. - *
error.data[0] is the text file's extension. + *
error.data[0] is the text file's uri. */ 'TEXT_COULD_NOT_GUESS_MIME_TYPE': 2011, diff --git a/lib/util/player_configuration.js b/lib/util/player_configuration.js index 72c0cab630..7de3912073 100644 --- a/lib/util/player_configuration.js +++ b/lib/util/player_configuration.js @@ -381,7 +381,8 @@ shaka.util.PlayerConfiguration = class { // eslint-disable-next-line require-await offline.trackSelectionCallback = async (tracks) => { return shaka.util.PlayerConfiguration.defaultTrackSelect( - tracks, config.preferredAudioLanguage); + tracks, config.preferredAudioLanguage, + config.preferredVideoHdrLevel); }; return config; @@ -422,14 +423,34 @@ shaka.util.PlayerConfiguration = class { /** * @param {!Array.} tracks * @param {string} preferredAudioLanguage + * @param {string} preferredVideoHdrLevel * @return {!Array.} */ - static defaultTrackSelect(tracks, preferredAudioLanguage) { + static defaultTrackSelect( + tracks, preferredAudioLanguage, preferredVideoHdrLevel) { const ContentType = shaka.util.ManifestParserUtils.ContentType; const LanguageUtils = shaka.util.LanguageUtils; + let hdrLevel = preferredVideoHdrLevel; + if (hdrLevel == 'AUTO') { + // Auto detect the ideal HDR level. + if (window.matchMedia('(color-gamut: p3)').matches) { + hdrLevel = 'PQ'; + } else { + hdrLevel = 'SDR'; + } + } + /** @type {!Array.} */ - const allVariants = tracks.filter((track) => track.type == 'variant'); + const allVariants = tracks.filter((track) => { + if (track.type != 'variant') { + return false; + } + if (track.hdr && track.hdr != hdrLevel) { + return false; + } + return true; + }); /** @type {!Array.} */ let selectedVariants = []; diff --git a/test/offline/storage_integration.js b/test/offline/storage_integration.js index f673b7abd7..ff4836402a 100644 --- a/test/offline/storage_integration.js +++ b/test/offline/storage_integration.js @@ -269,7 +269,7 @@ filterDescribe('Storage', storageSupport, () => { ]; const selected = - PlayerConfiguration.defaultTrackSelect(tracks, englishUS); + PlayerConfiguration.defaultTrackSelect(tracks, englishUS, 'SDR'); expect(selected).toBeTruthy(); expect(selected.length).toBe(1); expect(selected[0]).toBeTruthy(); @@ -285,7 +285,7 @@ filterDescribe('Storage', storageSupport, () => { ]; const selected = - PlayerConfiguration.defaultTrackSelect(tracks, englishUS); + PlayerConfiguration.defaultTrackSelect(tracks, englishUS, 'SDR'); expect(selected).toBeTruthy(); expect(selected.length).toBe(2); for (const track of tracks) { @@ -302,7 +302,7 @@ filterDescribe('Storage', storageSupport, () => { ]; const selected = - PlayerConfiguration.defaultTrackSelect(tracks, 'eng-us'); + PlayerConfiguration.defaultTrackSelect(tracks, 'eng-us', 'SDR'); expect(selected).toBeTruthy(); expect(selected.length).toBe(1); expect(selected[0]).toBeTruthy(); @@ -317,7 +317,8 @@ filterDescribe('Storage', storageSupport, () => { variantTrack(3, 480, 'eng', kbps(1)), ]; - const selected = PlayerConfiguration.defaultTrackSelect(tracks, 'eng'); + const selected = + PlayerConfiguration.defaultTrackSelect(tracks, 'eng', 'SDR'); expect(selected).toBeTruthy(); expect(selected.length).toBe(1); expect(selected[0]).toBeTruthy(); @@ -331,7 +332,8 @@ filterDescribe('Storage', storageSupport, () => { variantTrack(2, 480, 'eng-ca', kbps(1)), ]; - const selected = PlayerConfiguration.defaultTrackSelect(tracks, 'fr'); + const selected = + PlayerConfiguration.defaultTrackSelect(tracks, 'fr', 'SDR'); expect(selected).toBeTruthy(); expect(selected.length).toBe(1); expect(selected[0]).toBeTruthy(); @@ -346,7 +348,7 @@ filterDescribe('Storage', storageSupport, () => { ]; const selected = - PlayerConfiguration.defaultTrackSelect(tracks, 'fr-uk'); + PlayerConfiguration.defaultTrackSelect(tracks, 'fr-uk', 'SDR'); expect(selected).toBeTruthy(); expect(selected.length).toBe(1); expect(selected[0]).toBeTruthy(); @@ -362,7 +364,8 @@ filterDescribe('Storage', storageSupport, () => { tracks[0].primary = true; - const selected = PlayerConfiguration.defaultTrackSelect(tracks, 'de'); + const selected = + PlayerConfiguration.defaultTrackSelect(tracks, 'de', 'SDR'); expect(selected).toBeTruthy(); expect(selected.length).toBe(1); expect(selected[0]).toBeTruthy();