/** * Copyright 2015 CANAL+ Group * * 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. */ import log from "../../log"; import type { ISegment } from "../../manifest"; import { getDurationFromTrun, getTrackFragmentDecodeTime, } from "../../parsers/containers/isobmff"; import type { IChunkTimeInfo } from "../types"; /** * Get precize start and duration of a chunk. * @param {UInt8Array} buffer - An ISOBMFF container (at least a `moof` + a * `mdat` box. * @param {Boolean} isChunked - If true, the whole segment was chunked into * multiple parts and buffer is one of them. If false, buffer is the whole * segment. * @param {Object} segment * @param {number|undefined} initTimescale * @returns {Object} */ export default function getISOBMFFTimingInfos( buffer: Uint8Array, isChunked: boolean, segment: ISegment, initTimescale?: number, ): IChunkTimeInfo | null { const baseDecodeTime = getTrackFragmentDecodeTime(buffer); if (baseDecodeTime === undefined || initTimescale === undefined) { return null; } let startTime = segment.timestampOffset !== undefined ? baseDecodeTime + segment.timestampOffset * initTimescale : baseDecodeTime; let trunDuration = getDurationFromTrun(buffer); if (startTime < 0) { if (trunDuration !== undefined) { trunDuration += startTime; // remove from duration what comes before `0` } startTime = 0; } if (isChunked || !segment.complete) { if (trunDuration === undefined) { log.warn( "dash", "Chunked segments should indicate a duration through their trun boxes", ); } return { time: startTime / initTimescale, duration: trunDuration !== undefined ? trunDuration / initTimescale : undefined, }; } let duration: number | undefined; const segmentDuration = segment.duration * initTimescale; // we could always make a mistake when reading a container. // If the estimate is too far from what the segment seems to imply, take // the segment infos instead. const maxDecodeTimeDelta = Math.min(initTimescale * 0.9, segmentDuration / 4); if ( trunDuration !== undefined && Math.abs(trunDuration - segmentDuration) <= maxDecodeTimeDelta ) { duration = trunDuration; } return { time: startTime / initTimescale, duration: duration !== undefined ? duration / initTimescale : duration, }; }