Files
shaka-player/lib/media/manifest_parser.js
T
Joey Parrish f539147d48 fix: Correct license headers in compiled output
This fixes all the license headers in the main library, which corrects
the appearance of the main license in the compiled output.

It seems that the `!` in the header forces the compiler to keep it in
the output.  I believe older compiler releases did this purely based
on `@license`.

Issue #2638

Change-Id: I7f0e918caad10c9af689c9d07672b7fe9be7b2f3
2020-06-09 16:05:09 -07:00

269 lines
7.6 KiB
JavaScript

/*! @license
* Shaka Player
* Copyright 2016 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
goog.provide('shaka.media.ManifestParser');
goog.require('goog.Uri');
goog.require('shaka.log');
goog.require('shaka.net.NetworkingEngine');
goog.require('shaka.util.Error');
goog.require('shaka.util.Platform');
// TODO: revisit this when Closure Compiler supports partially-exported classes.
/**
* @summary An interface to register manifest parsers.
* @export
*/
shaka.media.ManifestParser = class {
/**
* Registers a manifest parser by file extension.
*
* @param {string} extension The file extension of the manifest.
* @param {shaka.extern.ManifestParser.Factory} parserFactory The factory
* used to create parser instances.
* @export
*/
static registerParserByExtension(extension, parserFactory) {
shaka.media.ManifestParser.parsersByExtension[extension] = parserFactory;
}
/**
* Registers a manifest parser by MIME type.
*
* @param {string} mimeType The MIME type of the manifest.
* @param {shaka.extern.ManifestParser.Factory} parserFactory The factory
* used to create parser instances.
* @export
*/
static registerParserByMime(mimeType, parserFactory) {
shaka.media.ManifestParser.parsersByMime[mimeType] = parserFactory;
}
/**
* Unregisters a manifest parser by MIME type.
*
* @param {string} mimeType The MIME type of the manifest.
* @export
*/
static unregisterParserByMime(mimeType) {
delete shaka.media.ManifestParser.parsersByMime[mimeType];
}
/**
* Returns a map of manifest support for well-known types.
*
* @return {!Object.<string, boolean>}
*/
static probeSupport() {
const ManifestParser = shaka.media.ManifestParser;
const support = {};
// Make sure all registered parsers are shown, but only for MSE-enabled
// platforms where our parsers matter.
if (shaka.util.Platform.supportsMediaSource()) {
for (const type in ManifestParser.parsersByMime) {
support[type] = true;
}
for (const type in ManifestParser.parsersByExtension) {
support[type] = true;
}
}
// Make sure all well-known types are tested as well, just to show an
// explicit false for things people might be expecting.
const testMimeTypes = [
// DASH
'application/dash+xml',
// HLS
'application/x-mpegurl',
'application/vnd.apple.mpegurl',
// SmoothStreaming
'application/vnd.ms-sstr+xml',
];
const testExtensions = {
// DASH
'mpd': 'application/dash+xml',
// HLS
'm3u8': 'application/x-mpegurl',
// SmoothStreaming
'ism': 'application/vnd.ms-sstr+xml',
};
for (const type of testMimeTypes) {
// Only query our parsers for MSE-enabled platforms. Otherwise, query a
// temporary media element for native support for these types.
if (shaka.util.Platform.supportsMediaSource()) {
support[type] = !!ManifestParser.parsersByMime[type];
} else {
support[type] = shaka.util.Platform.supportsMediaType(type);
}
}
for (const extension in testExtensions) {
// Only query our parsers for MSE-enabled platforms. Otherwise, query a
// temporary media element for native support for these MIME type for the
// extension.
if (shaka.util.Platform.supportsMediaSource()) {
support[extension] = !!ManifestParser.parsersByExtension[extension];
} else {
const type = testExtensions[extension];
support[extension] = shaka.util.Platform.supportsMediaType(type);
}
}
return support;
}
/**
* Get a factory that can create a manifest parser that should be able to
* parse the manifest at |uri|.
*
* @param {string} uri
* @param {!shaka.net.NetworkingEngine} netEngine
* @param {shaka.extern.RetryParameters} retryParams
* @param {?string} mimeType
* @return {!Promise.<shaka.extern.ManifestParser.Factory>}
*/
static async getFactory(uri, netEngine, retryParams, mimeType) {
const ManifestParser = shaka.media.ManifestParser;
// Try using the MIME type we were given.
if (mimeType) {
const factory = ManifestParser.parsersByMime[mimeType.toLowerCase()];
if (factory) {
return factory;
}
shaka.log.warning(
'Could not determine manifest type using MIME type ', mimeType);
}
const extension = ManifestParser.getExtension(uri);
if (extension) {
const factory = ManifestParser.parsersByExtension[extension];
if (factory) {
return factory;
}
shaka.log.warning(
'Could not determine manifest type for extension ', extension);
} else {
shaka.log.warning('Could not find extension for ', uri);
}
if (!mimeType) {
mimeType = await ManifestParser.getMimeType(uri, netEngine, retryParams);
if (mimeType) {
const factory = shaka.media.ManifestParser.parsersByMime[mimeType];
if (factory) {
return factory;
}
shaka.log.warning('Could not determine manifest type using MIME type',
mimeType);
}
}
throw new shaka.util.Error(
shaka.util.Error.Severity.CRITICAL,
shaka.util.Error.Category.MANIFEST,
shaka.util.Error.Code.UNABLE_TO_GUESS_MANIFEST_TYPE,
uri);
}
/**
* @param {string} uri
* @param {!shaka.net.NetworkingEngine} netEngine
* @param {shaka.extern.RetryParameters} retryParams
* @return {!Promise.<string>}
*/
static async getMimeType(uri, netEngine, retryParams) {
const type = shaka.net.NetworkingEngine.RequestType.MANIFEST;
const request = shaka.net.NetworkingEngine.makeRequest([uri], retryParams);
request.method = 'HEAD';
const response = await netEngine.request(type, request).promise;
// https://bit.ly/2K9s9kf says this header should always be available,
// but just to be safe:
const mimeType = response.headers['content-type'];
return mimeType ? mimeType.toLowerCase().split(';').shift() : '';
}
/**
* @param {string} uri
* @return {string}
*/
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();
}
/**
* Determines whether or not this URI and MIME type are supported by our own
* manifest parsers on this platform. This takes into account whether or not
* MediaSource is available, as well as which parsers are registered to the
* system.
*
* @param {string} uri
* @param {string} mimeType
* @return {boolean}
*/
static isSupported(uri, mimeType) {
// Without MediaSource, our own parsers are useless.
if (!shaka.util.Platform.supportsMediaSource()) {
return false;
}
if (mimeType in shaka.media.ManifestParser.parsersByMime) {
return true;
}
const extension = shaka.media.ManifestParser.getExtension(uri);
if (extension in shaka.media.ManifestParser.parsersByExtension) {
return true;
}
return false;
}
};
/**
* Contains the parser factory functions indexed by MIME type.
*
* @type {!Object.<string, shaka.extern.ManifestParser.Factory>}
*/
shaka.media.ManifestParser.parsersByMime = {};
/**
* Contains the parser factory functions indexed by file extension.
*
* @type {!Object.<string, shaka.extern.ManifestParser.Factory>}
*/
shaka.media.ManifestParser.parsersByExtension = {};