mirror of
https://github.com/shaka-project/shaka-player.git
synced 2026-06-26 17:46:26 +03:00
2ca7d0b060
Related to https://github.com/shaka-project/shaka-player/pull/5261 This PR delays the creation of the final urls of the segments so that they are not calculated in each media playlist parsing.
269 lines
6.2 KiB
JavaScript
269 lines
6.2 KiB
JavaScript
/*! @license
|
|
* Shaka Player
|
|
* Copyright 2016 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
goog.provide('shaka.hls.Attribute');
|
|
goog.provide('shaka.hls.Playlist');
|
|
goog.provide('shaka.hls.PlaylistType');
|
|
goog.provide('shaka.hls.Segment');
|
|
goog.provide('shaka.hls.Tag');
|
|
|
|
goog.require('goog.asserts');
|
|
goog.require('shaka.hls.Utils');
|
|
goog.require('shaka.util.Error');
|
|
|
|
|
|
/**
|
|
* HLS playlist class.
|
|
*/
|
|
shaka.hls.Playlist = class {
|
|
/**
|
|
* @param {string} absoluteUri An absolute, final URI after redirects.
|
|
* @param {!shaka.hls.PlaylistType} type
|
|
* @param {!Array.<shaka.hls.Tag>} tags
|
|
* @param {!Array.<shaka.hls.Segment>=} segments
|
|
*/
|
|
constructor(absoluteUri, type, tags, segments) {
|
|
/**
|
|
* An absolute, final URI after redirects.
|
|
*
|
|
* @const {string}
|
|
*/
|
|
this.absoluteUri = absoluteUri;
|
|
|
|
/** @const {shaka.hls.PlaylistType} */
|
|
this.type = type;
|
|
|
|
/** @const {!Array.<!shaka.hls.Tag>} */
|
|
this.tags = tags;
|
|
|
|
/** @const {Array.<!shaka.hls.Segment>} */
|
|
this.segments = segments || null;
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* @enum {number}
|
|
*/
|
|
shaka.hls.PlaylistType = {
|
|
MASTER: 0,
|
|
MEDIA: 1,
|
|
};
|
|
|
|
|
|
/**
|
|
* HLS tag class.
|
|
*/
|
|
shaka.hls.Tag = class {
|
|
/**
|
|
* @param {number} id
|
|
* @param {string} name
|
|
* @param {!Array.<shaka.hls.Attribute>} attributes
|
|
* @param {?string=} value
|
|
*/
|
|
constructor(id, name, attributes, value = null) {
|
|
/** @const {number} */
|
|
this.id = id;
|
|
|
|
/** @type {string} */
|
|
this.name = name;
|
|
|
|
/** @const {!Array.<shaka.hls.Attribute>} */
|
|
this.attributes = attributes;
|
|
|
|
/** @const {?string} */
|
|
this.value = value;
|
|
}
|
|
|
|
/**
|
|
* Create the string representation of the tag.
|
|
*
|
|
* For the DRM system - the full tag needs to be passed down to the CDM.
|
|
* There are two ways of doing this (1) save the original tag or (2) recreate
|
|
* the tag.
|
|
* As in some cases (like in tests) the tag never existed in string form, it
|
|
* is far easier to recreate the tag from the parsed form.
|
|
*
|
|
* @return {string}
|
|
* @override
|
|
*/
|
|
toString() {
|
|
/**
|
|
* @param {shaka.hls.Attribute} attr
|
|
* @return {string}
|
|
*/
|
|
const attrToStr = (attr) => {
|
|
const isNumericAttr = !isNaN(Number(attr.value));
|
|
const value = (isNumericAttr ? attr.value : '"' + attr.value + '"');
|
|
return attr.name + '=' + value;
|
|
};
|
|
// A valid tag can only follow 1 of 4 patterns.
|
|
// 1) <NAME>:<VALUE>
|
|
// 2) <NAME>:<ATTRIBUTE LIST>
|
|
// 3) <NAME>
|
|
// 4) <NAME>:<VALUE>,<ATTRIBUTE_LIST>
|
|
|
|
let tagStr = '#' + this.name;
|
|
const appendages = this.attributes ? this.attributes.map(attrToStr) : [];
|
|
|
|
if (this.value) {
|
|
appendages.unshift(this.value);
|
|
}
|
|
|
|
if (appendages.length > 0) {
|
|
tagStr += ':' + appendages.join(',');
|
|
}
|
|
|
|
return tagStr;
|
|
}
|
|
|
|
/**
|
|
* Adds an attribute to an HLS Tag.
|
|
*
|
|
* @param {!shaka.hls.Attribute} attribute
|
|
*/
|
|
addAttribute(attribute) {
|
|
this.attributes.push(attribute);
|
|
}
|
|
|
|
|
|
/**
|
|
* Gets the first attribute of the tag with a specified name.
|
|
*
|
|
* @param {string} name
|
|
* @return {?shaka.hls.Attribute} attribute
|
|
*/
|
|
getAttribute(name) {
|
|
const attributes = this.attributes.filter((attr) => {
|
|
return attr.name == name;
|
|
});
|
|
|
|
goog.asserts.assert(attributes.length < 2,
|
|
'A tag should not have multiple attributes ' +
|
|
'with the same name!');
|
|
|
|
if (attributes.length) {
|
|
return attributes[0];
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets the value of the first attribute of the tag with a specified name.
|
|
* If not found, returns an optional default value.
|
|
*
|
|
* @param {string} name
|
|
* @param {string=} defaultValue
|
|
* @return {?string}
|
|
*/
|
|
getAttributeValue(name, defaultValue) {
|
|
const attribute = this.getAttribute(name);
|
|
return attribute ? attribute.value : (defaultValue || null);
|
|
}
|
|
|
|
|
|
/**
|
|
* Finds the attribute and returns its value.
|
|
* Throws an error if attribute was not found.
|
|
*
|
|
* @param {string} name
|
|
* @return {string}
|
|
*/
|
|
getRequiredAttrValue(name) {
|
|
const attribute = this.getAttribute(name);
|
|
if (!attribute) {
|
|
throw new shaka.util.Error(
|
|
shaka.util.Error.Severity.CRITICAL,
|
|
shaka.util.Error.Category.MANIFEST,
|
|
shaka.util.Error.Code.HLS_REQUIRED_ATTRIBUTE_MISSING,
|
|
name);
|
|
}
|
|
|
|
return attribute.value;
|
|
}
|
|
|
|
/**
|
|
* Set the name of the tag. Used only for Preload hinted MAP tag.
|
|
* @param {string} name
|
|
*/
|
|
setName(name) {
|
|
this.name = name;
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* HLS segment class.
|
|
*/
|
|
shaka.hls.Segment = class {
|
|
/**
|
|
* Creates an HLS segment object.
|
|
*
|
|
* @param {string} absoluteMediaPlaylistUri An absolute Media Playlist URI.
|
|
* @param {string} verbatimSegmentUri verbatim segment URI.
|
|
* @param {!Array.<shaka.hls.Tag>} tags
|
|
* @param {!Array.<shaka.hls.Tag>=} partialSegments
|
|
*/
|
|
constructor(absoluteMediaPlaylistUri, verbatimSegmentUri, tags,
|
|
partialSegments=[]) {
|
|
/** @const {!Array.<shaka.hls.Tag>} */
|
|
this.tags = tags;
|
|
|
|
/** @type {?string} */
|
|
this.absoluteUri_ = null;
|
|
|
|
/** @type {?string} */
|
|
this.absoluteMediaPlaylistUri_ = absoluteMediaPlaylistUri;
|
|
|
|
/** @type {?string} */
|
|
this.verbatimSegmentUri_ = verbatimSegmentUri;
|
|
|
|
/** @type {!Array.<shaka.hls.Tag>} */
|
|
this.partialSegments = partialSegments;
|
|
}
|
|
|
|
/**
|
|
* Returns an absolute URI.
|
|
*
|
|
* @return {string}
|
|
*/
|
|
get absoluteUri() {
|
|
if (!this.absoluteUri_ &&
|
|
this.absoluteMediaPlaylistUri_ && this.verbatimSegmentUri_) {
|
|
goog.asserts.assert(this.absoluteMediaPlaylistUri_,
|
|
'An absolute Media Playlist URI should be defined!');
|
|
goog.asserts.assert(this.verbatimSegmentUri_,
|
|
'An verbatim segment URI should be defined!');
|
|
this.absoluteUri_ = shaka.hls.Utils.constructAbsoluteUri(
|
|
this.absoluteMediaPlaylistUri_, this.verbatimSegmentUri_);
|
|
this.absoluteMediaPlaylistUri_ = null;
|
|
this.verbatimSegmentUri_ = null;
|
|
}
|
|
return this.absoluteUri_ || '';
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* HLS Attribute class.
|
|
*/
|
|
shaka.hls.Attribute = class {
|
|
/**
|
|
* Creates an HLS attribute object.
|
|
*
|
|
* @param {string} name
|
|
* @param {string} value
|
|
*/
|
|
constructor(name, value) {
|
|
/** @const {string} */
|
|
this.name = name;
|
|
|
|
/** @const {string} */
|
|
this.value = value;
|
|
}
|
|
};
|