mirror of
https://github.com/shaka-project/shaka-player.git
synced 2026-06-18 16:36:56 +03:00
f539147d48
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
291 lines
8.2 KiB
JavaScript
291 lines
8.2 KiB
JavaScript
/*! @license
|
|
* Shaka Player
|
|
* Copyright 2016 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
goog.provide('shaka.offline.ManifestConverter');
|
|
|
|
goog.require('goog.asserts');
|
|
goog.require('shaka.media.InitSegmentReference');
|
|
goog.require('shaka.media.PresentationTimeline');
|
|
goog.require('shaka.media.SegmentIndex');
|
|
goog.require('shaka.media.SegmentReference');
|
|
goog.require('shaka.offline.OfflineUri');
|
|
goog.require('shaka.util.ManifestParserUtils');
|
|
|
|
|
|
/**
|
|
* Utility class for converting database manifest objects back to normal
|
|
* player-ready objects. Used by the offline system to convert on-disk
|
|
* objects back to the in-memory objects.
|
|
*/
|
|
shaka.offline.ManifestConverter = class {
|
|
/**
|
|
* Create a new manifest converter. Need to know the mechanism and cell that
|
|
* the manifest is from so that all segments paths can be created.
|
|
*
|
|
* @param {string} mechanism
|
|
* @param {string} cell
|
|
*/
|
|
constructor(mechanism, cell) {
|
|
/** @private {string} */
|
|
this.mechanism_ = mechanism;
|
|
|
|
/** @private {string} */
|
|
this.cell_ = cell;
|
|
}
|
|
|
|
/**
|
|
* Convert a |shaka.extern.ManifestDB| object to a |shaka.extern.Manifest|
|
|
* object.
|
|
*
|
|
* @param {shaka.extern.ManifestDB} manifestDB
|
|
* @return {shaka.extern.Manifest}
|
|
*/
|
|
fromManifestDB(manifestDB) {
|
|
const timeline = new shaka.media.PresentationTimeline(null, 0);
|
|
timeline.setDuration(manifestDB.duration);
|
|
|
|
/** @type {!Array.<shaka.extern.StreamDB>} */
|
|
const audioStreams =
|
|
manifestDB.streams.filter((streamDB) => this.isAudio_(streamDB));
|
|
|
|
/** @type {!Array.<shaka.extern.StreamDB>} */
|
|
const videoStreams =
|
|
manifestDB.streams.filter((streamDB) => this.isVideo_(streamDB));
|
|
|
|
/** @type {!Map.<number, shaka.extern.Variant>} */
|
|
const variants = this.createVariants(audioStreams, videoStreams, timeline);
|
|
|
|
/** @type {!Array.<shaka.extern.Stream>} */
|
|
const textStreams =
|
|
manifestDB.streams.filter((streamDB) => this.isText_(streamDB))
|
|
.map((streamDB) => this.fromStreamDB_(streamDB, timeline));
|
|
|
|
const drmInfos = manifestDB.drmInfo ? [manifestDB.drmInfo] : [];
|
|
if (manifestDB.drmInfo) {
|
|
for (const variant of variants.values()) {
|
|
if (variant.audio && variant.audio.encrypted) {
|
|
variant.audio.drmInfos = drmInfos;
|
|
}
|
|
if (variant.video && variant.video.encrypted) {
|
|
variant.video.drmInfos = drmInfos;
|
|
}
|
|
}
|
|
}
|
|
|
|
return {
|
|
presentationTimeline: timeline,
|
|
minBufferTime: 2,
|
|
offlineSessionIds: manifestDB.sessionIds,
|
|
variants: Array.from(variants.values()),
|
|
textStreams: textStreams,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Recreates Variants from audio and video StreamDB collections.
|
|
*
|
|
* @param {!Array.<!shaka.extern.StreamDB>} audios
|
|
* @param {!Array.<!shaka.extern.StreamDB>} videos
|
|
* @param {shaka.media.PresentationTimeline} timeline
|
|
* @return {!Map.<number, !shaka.extern.Variant>}
|
|
*/
|
|
createVariants(audios, videos, timeline) {
|
|
// Get all the variant ids from all audio and video streams.
|
|
/** @type {!Set.<number>} */
|
|
const variantIds = new Set();
|
|
for (const streamDB of audios) {
|
|
for (const id of streamDB.variantIds) {
|
|
variantIds.add(id);
|
|
}
|
|
}
|
|
for (const streamDB of videos) {
|
|
for (const id of streamDB.variantIds) {
|
|
variantIds.add(id);
|
|
}
|
|
}
|
|
|
|
/** @type {!Map.<number, shaka.extern.Variant>} */
|
|
const variantMap = new Map();
|
|
for (const id of variantIds) {
|
|
variantMap.set(id, this.createEmptyVariant_(id));
|
|
}
|
|
|
|
// Assign each audio stream to its variants.
|
|
for (const audio of audios) {
|
|
/** @type {shaka.extern.Stream} */
|
|
const stream = this.fromStreamDB_(audio, timeline);
|
|
|
|
for (const variantId of audio.variantIds) {
|
|
const variant = variantMap.get(variantId);
|
|
|
|
goog.asserts.assert(
|
|
!variant.audio, 'A variant should only have one audio stream');
|
|
|
|
variant.language = stream.language;
|
|
variant.primary = variant.primary || stream.primary;
|
|
variant.audio = stream;
|
|
}
|
|
}
|
|
|
|
// Assign each video stream to its variants.
|
|
for (const video of videos) {
|
|
/** @type {shaka.extern.Stream} */
|
|
const stream = this.fromStreamDB_(video, timeline);
|
|
|
|
for (const variantId of video.variantIds) {
|
|
const variant = variantMap.get(variantId);
|
|
|
|
goog.asserts.assert(
|
|
!variant.video, 'A variant should only have one video stream');
|
|
|
|
variant.primary = variant.primary || stream.primary;
|
|
variant.video = stream;
|
|
}
|
|
}
|
|
|
|
return variantMap;
|
|
}
|
|
|
|
/**
|
|
* @param {shaka.extern.StreamDB} streamDB
|
|
* @param {shaka.media.PresentationTimeline} timeline
|
|
* @return {shaka.extern.Stream}
|
|
* @private
|
|
*/
|
|
fromStreamDB_(streamDB, timeline) {
|
|
/** @type {!Array.<!shaka.media.SegmentReference>} */
|
|
const segments = streamDB.segments.map(
|
|
(segment, index) => this.fromSegmentDB_(index, segment));
|
|
|
|
timeline.notifySegments(segments);
|
|
|
|
/** @type {!shaka.media.SegmentIndex} */
|
|
const segmentIndex = new shaka.media.SegmentIndex(segments);
|
|
|
|
/** @type {shaka.extern.Stream} */
|
|
const stream = {
|
|
id: streamDB.id,
|
|
originalId: streamDB.originalId,
|
|
createSegmentIndex: () => Promise.resolve(),
|
|
segmentIndex,
|
|
mimeType: streamDB.mimeType,
|
|
codecs: streamDB.codecs,
|
|
width: streamDB.width || undefined,
|
|
height: streamDB.height || undefined,
|
|
frameRate: streamDB.frameRate,
|
|
pixelAspectRatio: streamDB.pixelAspectRatio,
|
|
kind: streamDB.kind,
|
|
encrypted: streamDB.encrypted,
|
|
drmInfos: [],
|
|
keyIds: streamDB.keyIds,
|
|
language: streamDB.language,
|
|
label: streamDB.label,
|
|
type: streamDB.type,
|
|
primary: streamDB.primary,
|
|
trickModeVideo: null,
|
|
emsgSchemeIdUris: null,
|
|
roles: streamDB.roles,
|
|
channelsCount: streamDB.channelsCount,
|
|
audioSamplingRate: streamDB.audioSamplingRate,
|
|
closedCaptions: streamDB.closedCaptions,
|
|
};
|
|
|
|
return stream;
|
|
}
|
|
|
|
/**
|
|
* @param {number} index
|
|
* @param {shaka.extern.SegmentDB} segmentDB
|
|
* @return {!shaka.media.SegmentReference}
|
|
* @private
|
|
*/
|
|
fromSegmentDB_(index, segmentDB) {
|
|
/** @type {!shaka.offline.OfflineUri} */
|
|
const uri = shaka.offline.OfflineUri.segment(
|
|
this.mechanism_, this.cell_, segmentDB.dataKey);
|
|
|
|
const initSegmentReference = segmentDB.initSegmentKey != null ?
|
|
this.fromInitSegmentDB_(segmentDB.initSegmentKey) : null;
|
|
|
|
return new shaka.media.SegmentReference(
|
|
segmentDB.startTime,
|
|
segmentDB.endTime,
|
|
() => [uri.toString()],
|
|
/* startByte= */ 0,
|
|
/* endByte= */ null,
|
|
initSegmentReference,
|
|
segmentDB.timestampOffset,
|
|
segmentDB.appendWindowStart,
|
|
segmentDB.appendWindowEnd);
|
|
}
|
|
|
|
/**
|
|
* @param {number} key
|
|
* @return {!shaka.media.InitSegmentReference}
|
|
* @private
|
|
*/
|
|
fromInitSegmentDB_(key) {
|
|
/** @type {!shaka.offline.OfflineUri} */
|
|
const uri = shaka.offline.OfflineUri.segment(
|
|
this.mechanism_, this.cell_, key);
|
|
|
|
return new shaka.media.InitSegmentReference(
|
|
() => [uri.toString()],
|
|
/* startBytes= */ 0,
|
|
/* endBytes= */ null );
|
|
}
|
|
|
|
/**
|
|
* @param {shaka.extern.StreamDB} streamDB
|
|
* @return {boolean}
|
|
* @private
|
|
*/
|
|
isAudio_(streamDB) {
|
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
return streamDB.type == ContentType.AUDIO;
|
|
}
|
|
|
|
/**
|
|
* @param {shaka.extern.StreamDB} streamDB
|
|
* @return {boolean}
|
|
* @private
|
|
*/
|
|
isVideo_(streamDB) {
|
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
return streamDB.type == ContentType.VIDEO;
|
|
}
|
|
|
|
/**
|
|
* @param {shaka.extern.StreamDB} streamDB
|
|
* @return {boolean}
|
|
* @private
|
|
*/
|
|
isText_(streamDB) {
|
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
return streamDB.type == ContentType.TEXT;
|
|
}
|
|
|
|
/**
|
|
* Creates an empty Variant.
|
|
*
|
|
* @param {number} id
|
|
* @return {!shaka.extern.Variant}
|
|
* @private
|
|
*/
|
|
createEmptyVariant_(id) {
|
|
return {
|
|
id: id,
|
|
language: '',
|
|
primary: false,
|
|
audio: null,
|
|
video: null,
|
|
bandwidth: 0,
|
|
allowedByApplication: true,
|
|
allowedByKeySystem: true,
|
|
};
|
|
}
|
|
};
|