mirror of
https://github.com/shaka-project/shaka-player.git
synced 2026-06-24 17:35:10 +03:00
0726543a04
The ParsedBox structure used by the Mp4Parser, previously, had its property names changed in compiled mode. This makes ParsedBox into an extern, so that it will be preserved unchanged in compiled mode. Closes #1522 Change-Id: I0964f8a4b9ccea57c61e2c587a776ed76cfbc8da
166 lines
4.9 KiB
JavaScript
166 lines
4.9 KiB
JavaScript
/**
|
|
* @license
|
|
* Copyright 2016 Google Inc.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
goog.provide('shaka.media.Mp4SegmentIndexParser');
|
|
|
|
goog.require('goog.asserts');
|
|
goog.require('shaka.log');
|
|
goog.require('shaka.media.SegmentReference');
|
|
goog.require('shaka.util.Error');
|
|
goog.require('shaka.util.Mp4Parser');
|
|
|
|
|
|
/**
|
|
* Parses SegmentReferences from an ISO BMFF SIDX structure.
|
|
* @param {!ArrayBuffer} sidxData The MP4's container's SIDX.
|
|
* @param {number} sidxOffset The SIDX's offset, in bytes, from the start of
|
|
* the MP4 container.
|
|
* @param {!Array.<string>} uris The possible locations of the MP4 file that
|
|
* contains the segments.
|
|
* @param {number} scaledPresentationTimeOffset
|
|
* @return {!Array.<!shaka.media.SegmentReference>}
|
|
* @throws {shaka.util.Error}
|
|
*/
|
|
shaka.media.Mp4SegmentIndexParser = function(
|
|
sidxData, sidxOffset, uris, scaledPresentationTimeOffset) {
|
|
const Mp4SegmentIndexParser = shaka.media.Mp4SegmentIndexParser;
|
|
|
|
let references;
|
|
|
|
let parser = new shaka.util.Mp4Parser()
|
|
.fullBox('sidx', function(box) {
|
|
references = Mp4SegmentIndexParser.parseSIDX_(
|
|
sidxOffset,
|
|
scaledPresentationTimeOffset,
|
|
uris,
|
|
box);
|
|
});
|
|
|
|
if (sidxData) {
|
|
parser.parse(sidxData);
|
|
}
|
|
|
|
if (references) {
|
|
return references;
|
|
} else {
|
|
shaka.log.error('Invalid box type, expected "sidx".');
|
|
throw new shaka.util.Error(
|
|
shaka.util.Error.Severity.CRITICAL,
|
|
shaka.util.Error.Category.MEDIA,
|
|
shaka.util.Error.Code.MP4_SIDX_WRONG_BOX_TYPE);
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* Parse a SIDX box from the given reader.
|
|
*
|
|
* @param {number} sidxOffset
|
|
* @param {number} scaledPresentationTimeOffset
|
|
* @param {!Array.<string>} uris The possible locations of the MP4 file that
|
|
* contains the segments.
|
|
* @param {!shaka.extern.ParsedBox} box
|
|
* @return {!Array.<!shaka.media.SegmentReference>}
|
|
* @private
|
|
*/
|
|
shaka.media.Mp4SegmentIndexParser.parseSIDX_ = function(
|
|
sidxOffset,
|
|
scaledPresentationTimeOffset,
|
|
uris,
|
|
box) {
|
|
goog.asserts.assert(
|
|
box.version != null,
|
|
'SIDX is a full box and should have a valid version.');
|
|
|
|
let references = [];
|
|
|
|
// Parse the SIDX structure.
|
|
// Skip reference_ID (32 bits).
|
|
box.reader.skip(4);
|
|
|
|
let timescale = box.reader.readUint32();
|
|
|
|
if (timescale == 0) {
|
|
shaka.log.error('Invalid timescale.');
|
|
throw new shaka.util.Error(
|
|
shaka.util.Error.Severity.CRITICAL,
|
|
shaka.util.Error.Category.MEDIA,
|
|
shaka.util.Error.Code.MP4_SIDX_INVALID_TIMESCALE);
|
|
}
|
|
|
|
let earliestPresentationTime;
|
|
let firstOffset;
|
|
|
|
if (box.version == 0) {
|
|
earliestPresentationTime = box.reader.readUint32();
|
|
firstOffset = box.reader.readUint32();
|
|
} else {
|
|
earliestPresentationTime = box.reader.readUint64();
|
|
firstOffset = box.reader.readUint64();
|
|
}
|
|
|
|
// Skip reserved (16 bits).
|
|
box.reader.skip(2);
|
|
|
|
// Add references.
|
|
let referenceCount = box.reader.readUint16();
|
|
|
|
// Substract the presentation time offset
|
|
let unscaledStartTime = earliestPresentationTime;
|
|
let startByte = sidxOffset + box.size + firstOffset;
|
|
|
|
for (let i = 0; i < referenceCount; i++) {
|
|
// |chunk| is 1 bit for |referenceType|, and 31 bits for |referenceSize|.
|
|
let chunk = box.reader.readUint32();
|
|
let referenceType = (chunk & 0x80000000) >>> 31;
|
|
let referenceSize = chunk & 0x7FFFFFFF;
|
|
|
|
let subsegmentDuration = box.reader.readUint32();
|
|
|
|
// Skipping 1 bit for |startsWithSap|, 3 bits for |sapType|, and 28 bits
|
|
// for |sapDelta|.
|
|
box.reader.skip(4);
|
|
|
|
// If |referenceType| is 1 then the reference is to another SIDX.
|
|
// We do not support this.
|
|
if (referenceType == 1) {
|
|
shaka.log.error('Heirarchical SIDXs are not supported.');
|
|
throw new shaka.util.Error(
|
|
shaka.util.Error.Severity.CRITICAL,
|
|
shaka.util.Error.Category.MEDIA,
|
|
shaka.util.Error.Code.MP4_SIDX_TYPE_NOT_SUPPORTED);
|
|
}
|
|
|
|
references.push(
|
|
new shaka.media.SegmentReference(
|
|
references.length,
|
|
(unscaledStartTime / timescale) -
|
|
scaledPresentationTimeOffset,
|
|
((unscaledStartTime + subsegmentDuration) / timescale) -
|
|
scaledPresentationTimeOffset,
|
|
function() { return uris; },
|
|
startByte,
|
|
startByte + referenceSize - 1));
|
|
|
|
unscaledStartTime += subsegmentDuration;
|
|
startByte += referenceSize;
|
|
}
|
|
|
|
box.parser.stop();
|
|
return references;
|
|
};
|