From f4c6063b82207a28bd975f73fefc644f9734a468 Mon Sep 17 00:00:00 2001 From: Michelle Zhuo Date: Fri, 5 Mar 2021 14:10:33 -0800 Subject: [PATCH] feat(MediaCap): Add polyfill for MediaCapabilities If navigator.mediaCapabilties is not supported by the browser, use MediaSource.isTypeSupported to check if the stream is supported. Issue #1391 Change-Id: Iee0c7e339add2a07028ed14a03df14e4d36a203e --- build/types/polyfill | 1 + lib/polyfill/media_capabilities.js | 77 ++++++++++++++++++++++++++++++ lib/util/stream_utils.js | 75 +++++++++++------------------ 3 files changed, 105 insertions(+), 48 deletions(-) create mode 100644 lib/polyfill/media_capabilities.js diff --git a/build/types/polyfill b/build/types/polyfill index 1476a2cdd0..7cc96ef464 100644 --- a/build/types/polyfill +++ b/build/types/polyfill @@ -7,6 +7,7 @@ +../../lib/polyfill/languages.js +../../lib/polyfill/mathround.js +../../lib/polyfill/mediasource.js ++../../lib/polyfill/media_capabilities.js +../../lib/polyfill/orientation.js +../../lib/polyfill/patchedmediakeys_apple.js +../../lib/polyfill/patchedmediakeys_ms.js diff --git a/lib/polyfill/media_capabilities.js b/lib/polyfill/media_capabilities.js new file mode 100644 index 0000000000..0242e19325 --- /dev/null +++ b/lib/polyfill/media_capabilities.js @@ -0,0 +1,77 @@ +/*! @license + * Shaka Player + * Copyright 2016 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +goog.provide('shaka.polyfill.MediaCapabilities'); + +goog.require('shaka.log'); +goog.require('shaka.polyfill'); + + +/** + * @summary A polyfill to provide navigator.mediaCapabilities on all browsers. + * This is necessary for Tizen 3, Xbox One and possibly others we have yet to + * discover. + */ +shaka.polyfill.MediaCapabilities = class { + /** + * Install the polyfill if needed. + */ + static install() { + shaka.log.debug('MediaCapabilities: install'); + + if (navigator.mediaCapabilities) { + shaka.log.debug( + 'MediaCapabilities: Native mediaCapabilities support found.'); + return; + } + + navigator.mediaCapabilities = /** @type {!MediaCapabilities} */ ({}); + navigator.mediaCapabilities.decodingInfo = + shaka.polyfill.MediaCapabilities.decodingInfo_; + } + + /** + * @param {!MediaDecodingConfiguration} mediaDecodingConfig + * @return {!Promise.} + * @private + */ + static decodingInfo_(mediaDecodingConfig) { + const res = { + supported: false, + powerEfficient: true, + smooth: true, + keySystemAccess: null, + configuration: mediaDecodingConfig, + }; + + if (!mediaDecodingConfig) { + return Promise.resolve(res); + } + + // Use 'MediaSource.isTypeSupported' to check if the stream is supported. + if (mediaDecodingConfig['video']) { + const contentType = mediaDecodingConfig['video'].contentType; + const isSupported = MediaSource.isTypeSupported(contentType); + if (!isSupported) { + return Promise.resolve(res); + } + } + + if (mediaDecodingConfig['audio']) { + const contentType = mediaDecodingConfig['audio'].contentType; + const isSupported = MediaSource.isTypeSupported(contentType); + if (!isSupported) { + return Promise.resolve(res); + } + } + + res.supported = true; + return Promise.resolve(res); + } +}; + + +shaka.polyfill.register(shaka.polyfill.MediaCapabilities.install); diff --git a/lib/util/stream_utils.js b/lib/util/stream_utils.js index 0331432dd8..aba60fb024 100644 --- a/lib/util/stream_utils.js +++ b/lib/util/stream_utils.js @@ -9,7 +9,6 @@ goog.provide('shaka.util.StreamUtils'); goog.require('goog.asserts'); goog.require('shaka.log'); goog.require('shaka.media.DrmEngine'); -goog.require('shaka.media.MediaSourceEngine'); goog.require('shaka.text.TextEngine'); goog.require('shaka.util.Functional'); goog.require('shaka.util.LanguageUtils'); @@ -308,57 +307,37 @@ shaka.util.StreamUtils = class { * @private */ static async filterManifestByMediaCapabilities_(manifest) { - if ('mediaCapabilities' in navigator) { - const MediaCapabilities = navigator.mediaCapabilities; - const getVariantDecodingInfo = (async (variant) => { - /** @type {!MediaDecodingConfiguration} */ - const decodingConfig = - shaka.util.StreamUtils.prepareDecodingConfiguration_(variant); - const result = await MediaCapabilities.decodingInfo(decodingConfig); - variant.decodingInfos.push(result); - }); + goog.asserts.assert(navigator.mediaCapabilities, + 'MediaCapabilities should be valid.'); + + const MediaCapabilities = navigator.mediaCapabilities; + const getVariantDecodingInfo = (async (variant) => { + /** @type {!MediaDecodingConfiguration} */ + const decodingConfig = + shaka.util.StreamUtils.prepareDecodingConfiguration_(variant); + const result = await MediaCapabilities.decodingInfo(decodingConfig); + variant.decodingInfos.push(result); + }); - const operations = []; - for (const variant of manifest.variants) { - if (!variant.decodingInfos.length) { - operations.push(getVariantDecodingInfo(variant)); - } + const operations = []; + for (const variant of manifest.variants) { + if (!variant.decodingInfos.length) { + operations.push(getVariantDecodingInfo(variant)); } - await Promise.all(operations); - - manifest.variants = manifest.variants.filter((variant) => { - const supported = variant.decodingInfos.some((decodingInfo) => { - return decodingInfo.supported; - }); - // Filter out all unsupported variants. - if (!supported) { - shaka.log.debug('Dropping variant - not compatible with platform', - shaka.util.StreamUtils.getVariantSummaryString_(variant)); - } - return supported; - }); - } else { - // TODO: move to MediaCapabilities polyfill. - manifest.variants = manifest.variants.filter((variant) => { - const audio = variant.audio; - const video = variant.video; - - if (audio && !shaka.media.MediaSourceEngine.isStreamSupported(audio)) { - shaka.log.debug( - 'Dropping variant - audio not compatible with platform', - shaka.util.StreamUtils.getStreamSummaryString_(audio)); - return false; - } + } + await Promise.all(operations); - if (video && !shaka.media.MediaSourceEngine.isStreamSupported(video)) { - shaka.log.debug( - 'Dropping variant - video not compatible with platform', - shaka.util.StreamUtils.getStreamSummaryString_(video)); - return false; - } - return true; + manifest.variants = manifest.variants.filter((variant) => { + const supported = variant.decodingInfos.some((decodingInfo) => { + return decodingInfo.supported; }); - } + // Filter out all unsupported variants. + if (!supported) { + shaka.log.debug('Dropping variant - not compatible with platform', + shaka.util.StreamUtils.getVariantSummaryString_(variant)); + } + return supported; + }); }