UNPKG

shaka-player

Version:
166 lines (139 loc) 5.02 kB
/** * @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; };