mirror of
https://github.com/shaka-project/shaka-player.git
synced 2026-06-14 15:56:38 +03:00
245 lines
5.4 KiB
JavaScript
245 lines
5.4 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('shaka.util.Error');
|
|
|
|
|
|
/**
|
|
* HLS playlist class.
|
|
*/
|
|
shaka.hls.Playlist = class {
|
|
/**
|
|
* @param {!shaka.hls.PlaylistType} type
|
|
* @param {!Array<shaka.hls.Tag>} tags
|
|
* @param {!Array<shaka.hls.Segment>=} segments
|
|
*/
|
|
constructor(type, tags, segments) {
|
|
/** @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.
|
|
*
|
|
* @param {?Set<string>=} attributesToSkip
|
|
* @return {string}
|
|
* @override
|
|
*/
|
|
toString(attributesToSkip) {
|
|
/**
|
|
* @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.filter((attr) => {
|
|
if (!attributesToSkip) {
|
|
return true;
|
|
}
|
|
return !attributesToSkip.has(attr.name);
|
|
}).map(attrToStr) : [];
|
|
|
|
if (this.value) {
|
|
appendages.unshift(this.value);
|
|
}
|
|
|
|
if (appendages.length > 0) {
|
|
tagStr += ':' + appendages.join(',');
|
|
}
|
|
|
|
return tagStr;
|
|
}
|
|
|
|
/**
|
|
* Create the string key of the tag.
|
|
*
|
|
* @param {boolean} keepAllAttributes
|
|
* @return {string}
|
|
*/
|
|
getTagKey(keepAllAttributes) {
|
|
if (keepAllAttributes) {
|
|
return this.toString();
|
|
}
|
|
const attributesToSkip = new Set()
|
|
.add('AUDIO')
|
|
.add('VIDEO')
|
|
.add('SUBTITLES')
|
|
.add('PATHWAY-ID')
|
|
.add('GROUP-ID')
|
|
.add('URI');
|
|
return this.toString(attributesToSkip);
|
|
}
|
|
|
|
/**
|
|
* 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) {
|
|
return this.attributes.find((attr) => attr.name === name) || 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} verbatimSegmentUri verbatim segment URI.
|
|
* @param {!Array<shaka.hls.Tag>} tags
|
|
* @param {!Array<shaka.hls.Tag>=} partialSegments
|
|
*/
|
|
constructor(verbatimSegmentUri, tags, partialSegments=[]) {
|
|
/** @const {!Array<shaka.hls.Tag>} */
|
|
this.tags = tags;
|
|
|
|
/** @const {?string} */
|
|
this.verbatimSegmentUri = verbatimSegmentUri;
|
|
|
|
/** @type {!Array<shaka.hls.Tag>} */
|
|
this.partialSegments = partialSegments;
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* 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;
|
|
}
|
|
};
|