UNPKG

shaka-player

Version:
242 lines (220 loc) • 7.25 kB
/*! @license * Shaka Player * Copyright 2016 Google LLC * SPDX-License-Identifier: Apache-2.0 */ goog.provide('shaka.transmuxer.TransmuxerEngine'); goog.require('shaka.log'); goog.require('shaka.util.IDestroyable'); // TODO: revisit this when Closure Compiler supports partially-exported classes. /** * @summary Manages transmuxer plugins. * @implements {shaka.util.IDestroyable} * @export */ shaka.transmuxer.TransmuxerEngine = class { // TODO: revisit this when the compiler supports partially-exported classes. /** * @override * @export */ destroy() {} /** * @param {string} mimeType * @param {!shaka.extern.TransmuxerPlugin} plugin * @param {number} priority * @export */ static registerTransmuxer(mimeType, plugin, priority) { const TransmuxerEngine = shaka.transmuxer.TransmuxerEngine; const normalizedMimetype = TransmuxerEngine.normalizeMimeType_(mimeType); const key = normalizedMimetype + '-' + priority; TransmuxerEngine.transmuxerMap_.set(key, { priority: priority, plugin: plugin, }); } /** * @param {string} mimeType * @param {number} priority * @export */ static unregisterTransmuxer(mimeType, priority) { const TransmuxerEngine = shaka.transmuxer.TransmuxerEngine; const normalizedMimetype = TransmuxerEngine.normalizeMimeType_(mimeType); const key = normalizedMimetype + '-' + priority; TransmuxerEngine.transmuxerMap_.delete(key); } /** * @param {string} mimeType * @param {string=} contentType * @return {?shaka.extern.TransmuxerPlugin} * @export */ static findTransmuxer(mimeType, contentType) { const TransmuxerEngine = shaka.transmuxer.TransmuxerEngine; for (const priority of TransmuxerEngine.PLUGIN_PRIORITY_ORDER) { const plugin = TransmuxerEngine.findTransmuxerPlugin(mimeType, priority); if (!plugin) { continue; } let transmuxer; try { transmuxer = plugin(); } catch (error) { // A support probe must fail closed for this plugin only: one plugin // whose constructor throws (e.g. an optional runtime that has not // loaded) must not break codec probing for every other content type. shaka.log.warning( 'Skipping transmuxer plugin that failed to construct for', mimeType, error); continue; } let isSupported = false; try { isSupported = transmuxer.isSupported(mimeType, contentType); } catch (error) { shaka.log.warning( 'Skipping transmuxer plugin whose support probe threw for', mimeType, error); } finally { transmuxer.destroy(); } if (isSupported) { return plugin; } } return null; } /** * Finds a plugin registered for |mimeType| without instantiating it or * calling isSupported(). Used by the worker where MediaSource may not be * available to validate support. * * When |priority| is null (default), returns the highest-priority plugin. * When |priority| is specified, returns the plugin at that exact priority or * null if none is registered at that level. * * @param {string} mimeType * @param {?number=} priority * @return {?shaka.extern.TransmuxerPlugin} */ static findTransmuxerPlugin(mimeType, priority = null) { const TransmuxerEngine = shaka.transmuxer.TransmuxerEngine; const normalizedMimetype = TransmuxerEngine.normalizeMimeType_(mimeType); const priorities = priority !== null ? [priority] : TransmuxerEngine.PLUGIN_PRIORITY_ORDER; for (const p of priorities) { const key = normalizedMimetype + '-' + p; const object = TransmuxerEngine.transmuxerMap_.get(key); if (object) { return object.plugin; } } return null; } /** * Returns the priority at which |plugin| is registered for |mimeType|, or * null if it is not registered for that type. A worker cannot share plugin * identity with the main thread, but it shares the registrations, so the * priority is what tells the worker which plugin the main thread chose. * If the same plugin is registered at several priorities, the highest is * returned, which is the one findTransmuxer probes first. * * @param {string} mimeType * @param {shaka.extern.TransmuxerPlugin} plugin * @return {?number} */ static findTransmuxerPluginPriority(mimeType, plugin) { const TransmuxerEngine = shaka.transmuxer.TransmuxerEngine; const normalizedMimetype = TransmuxerEngine.normalizeMimeType_(mimeType); for (const p of TransmuxerEngine.PLUGIN_PRIORITY_ORDER) { const object = TransmuxerEngine.transmuxerMap_.get(normalizedMimetype + '-' + p); if (object && object.plugin === plugin) { return p; } } return null; } /** * @param {string} mimeType * @return {string} * @private */ static normalizeMimeType_(mimeType) { return mimeType.toLowerCase().split(';')[0]; } /** * Check if the mime type and the content type is supported. * @param {string} mimeType * @param {string=} contentType * @return {boolean} */ static isSupported(mimeType, contentType) { const TransmuxerEngine = shaka.transmuxer.TransmuxerEngine; const transmuxerPlugin = TransmuxerEngine.findTransmuxer(mimeType); if (!transmuxerPlugin) { return false; } return true; } /** * For any stream, convert its codecs to MP4 codecs. * @param {string} contentType * @param {string} mimeType * @return {string} */ static convertCodecs(contentType, mimeType) { const TransmuxerEngine = shaka.transmuxer.TransmuxerEngine; const transmuxerPlugin = TransmuxerEngine.findTransmuxer(mimeType); if (!transmuxerPlugin) { return mimeType; } const transmuxer = transmuxerPlugin(); const codecs = transmuxer.convertCodecs(contentType, mimeType); transmuxer.destroy(); return codecs; } }; /** * @typedef {{ * plugin: shaka.extern.TransmuxerPlugin, * priority: number, * }} * @property {shaka.extern.TransmuxerPlugin} plugin * The associated plugin. * @property {number} priority * The plugin's priority. */ shaka.transmuxer.TransmuxerEngine.PluginObject; /** * @private {!Map<string, !shaka.transmuxer.TransmuxerEngine.PluginObject>} */ shaka.transmuxer.TransmuxerEngine.transmuxerMap_ = new Map(); /** * Priority level for transmuxer plugins. * If multiple plugins are provided for the same mime type, only the * highest-priority one is used. * * @enum {number} * @export */ shaka.transmuxer.TransmuxerEngine.PluginPriority = { 'FALLBACK': 1, 'PREFERRED_SECONDARY': 2, 'PREFERRED': 3, 'APPLICATION': 4, }; /** * Priorities in descending order (highest first), used when searching for * a matching transmuxer plugin. * * @const {!Array<number>} */ shaka.transmuxer.TransmuxerEngine.PLUGIN_PRIORITY_ORDER = [ shaka.transmuxer.TransmuxerEngine.PluginPriority.APPLICATION, shaka.transmuxer.TransmuxerEngine.PluginPriority.PREFERRED, shaka.transmuxer.TransmuxerEngine.PluginPriority.PREFERRED_SECONDARY, shaka.transmuxer.TransmuxerEngine.PluginPriority.FALLBACK, ];