UNPKG

mediabunny

Version:

Pure TypeScript media toolkit for reading, writing, and converting media files, directly in the browser.

233 lines 8.03 kB
/*! * Copyright (c) 2026-present, Vanilagy and contributors * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import { AacCodecInfo, AudioCodec, VideoCodec } from '../codec.js'; import { Av1CodecInfo, AvcDecoderConfigurationRecord, HevcDecoderConfigurationRecord, Vp9CodecInfo } from '../codec-data.js'; import { Demuxer } from '../demuxer.js'; import { Input } from '../input.js'; import { InputTrackBacking } from '../input-track.js'; import { Rotation } from '../misc.js'; import { PsshBox } from './isobmff-misc.js'; import { FileSlice, Reader } from '../reader.js'; import { MetadataTags, TrackDisposition } from '../metadata.js'; type InternalTrack = { id: number; demuxer: IsobmffDemuxer; trackBacking: InputTrackBacking | null; disposition: TrackDisposition; timescale: number; durationInMovieTimescale: number; durationInMediaTimescale: number; rotation: Rotation; internalCodecId: string | null; name: string | null; languageCode: string; sampleTableByteOffset: number | null; sampleTable: SampleTable | null; fragmentLookupTable: FragmentLookupTableEntry[]; currentFragmentState: FragmentTrackState | null; /** * List of all encountered fragment offsets alongside their timestamps. This list never gets truncated, but memory * consumption should be negligible. */ fragmentPositionCache: { moofOffset: number; startTimestamp: number; endTimestamp: number; }[]; /** The segment durations of all edit list entries leading up to the main one (from which the offset is taken.) */ editListPreviousSegmentDurations: number; /** The media time offset of the main edit list entry (with media time !== -1) */ editListOffset: number; /** Set when the track's samples are encrypted using a supported scheme (cenc/cens/cbcs), parsed from sinf/tenc. */ encryptionInfo: TrackEncryptionInfo | null; /** For non-fragmented encrypted tracks: parsed saiz+saio from stbl; aux info is fetched lazily on first use. */ encryptionAuxInfo: SampleEncryptionAuxInfo | null; frmaCodecString: string | null; } & ({ info: null; } | { info: { type: 'video'; width: number; height: number; squarePixelWidth: number; squarePixelHeight: number; codec: VideoCodec | null; codecDescription: Uint8Array | null; colorSpace: VideoColorSpaceInit | null; avcType: 1 | 3 | null; avcCodecInfo: AvcDecoderConfigurationRecord | null; hevcCodecInfo: HevcDecoderConfigurationRecord | null; vp9CodecInfo: Vp9CodecInfo | null; av1CodecInfo: Av1CodecInfo | null; }; } | { info: { type: 'audio'; numberOfChannels: number; sampleRate: number; codec: AudioCodec | null; codecDescription: Uint8Array | null; aacCodecInfo: AacCodecInfo | null; pcmLittleEndian: boolean; pcmSampleSize: number | null; }; }); type SampleTable = { sampleTimingEntries: SampleTimingEntry[]; sampleCompositionTimeOffsets: SampleCompositionTimeOffsetEntry[]; sampleSizes: number[]; keySampleIndices: number[] | null; chunkOffsets: number[]; sampleToChunk: SampleToChunkEntry[]; presentationTimestamps: { presentationTimestamp: number; sampleIndex: number; }[] | null; /** * Provides a fast map from sample index to index in the sorted presentation timestamps array - so, a fast map from * decode order to presentation order. */ presentationTimestampIndexMap: number[] | null; }; type SampleTimingEntry = { startIndex: number; startDecodeTimestamp: number; count: number; delta: number; }; type SampleCompositionTimeOffsetEntry = { startIndex: number; count: number; offset: number; }; type SampleToChunkEntry = { startSampleIndex: number; startChunkIndex: number; samplesPerChunk: number; sampleDescriptionIndex: number; }; type FragmentTrackDefaults = { trackId: number; defaultSampleDescriptionIndex: number; defaultSampleDuration: number; defaultSampleSize: number; defaultSampleFlags: number; }; type FragmentLookupTableEntry = { timestamp: number; moofOffset: number; }; type FragmentTrackState = { baseDataOffset: number; sampleDescriptionIndex: number | null; defaultSampleDuration: number | null; defaultSampleSize: number | null; defaultSampleFlags: number | null; startTimestamp: number | null; encryptionAuxInfo: SampleEncryptionAuxInfo | null; }; type FragmentTrackData = { track: InternalTrack; currentTimestamp: number; currentOffset: number; startTimestamp: number; endTimestamp: number; firstKeyFrameTimestamp: number | null; samples: FragmentTrackSample[]; presentationTimestamps: { presentationTimestamp: number; sampleIndex: number; }[]; startTimestampIsFinal: boolean; encryptionAuxInfo: SampleEncryptionAuxInfo | null; }; type FragmentTrackSample = { presentationTimestamp: number; duration: number; byteOffset: number; byteSize: number; isKeyFrame: boolean; encryption: SampleEncryptionInfo | null; }; type Fragment = { moofOffset: number; moofSize: number; implicitBaseDataOffset: number; trackData: Map<InternalTrack['id'], FragmentTrackData>; psshBoxes: PsshBox[]; }; type TrackEncryptionInfo = { scheme: 'cenc' | 'cens' | 'cbcs'; defaultKid: string | null; defaultIsProtected: boolean | null; defaultPerSampleIvSize: number | null; defaultConstantIv: Uint8Array | null; defaultCryptByteBlock: number | null; defaultSkipByteBlock: number | null; }; type SampleEncryptionInfo = { iv: Uint8Array; subsamples: { clearLen: number; protectedLen: number; }[] | null; }; /** * Holds parsed saiz+saio state. The encryption info itself lives at a file offset and is fetched lazily. * For fragmented files this state is per-traf; for non-fragmented files it's per-track (on stbl). */ type SampleEncryptionAuxInfo = { defaultSampleInfoSize: number; sampleSizes: Uint8Array | null; sampleCount: number; offset: number | null; resolved: SampleEncryptionInfo[] | null; }; export declare class IsobmffDemuxer extends Demuxer { reader: Reader; moovSlice: FileSlice | null; currentTrack: InternalTrack | null; tracks: InternalTrack[]; metadataPromise: Promise<void> | null; movieTimescale: number; movieDurationInTimescale: number; isQuickTime: boolean; metadataTags: MetadataTags; currentMetadataKeys: Map<number, string> | null; isFragmented: boolean; fragmentTrackDefaults: FragmentTrackDefaults[]; psshBoxes: PsshBox[]; currentFragment: Fragment | null; /** * Caches the last fragment that was read. Based on the assumption that there will be multiple reads to the * same fragment in quick succession. */ lastReadFragment: Fragment | null; decryptionKeyCache: Map<string, Promise<Uint8Array<ArrayBufferLike>>>; constructor(input: Input); getTrackBackings(): Promise<InputTrackBacking[]>; getMimeType(): Promise<string>; getMetadataTags(): Promise<MetadataTags>; readMetadata(): Promise<void>; getSampleTableForTrack(internalTrack: InternalTrack): SampleTable; readFragment(startPos: number): Promise<Fragment>; readContiguousBoxes(slice: FileSlice): void; iterateContiguousBoxes(slice: FileSlice): Generator<{ boxInfo: { name: string; totalSize: number; headerSize: number; contentSize: number; }; slice: FileSlice; }, void, unknown>; traverseBox(slice: FileSlice): boolean; } export {}; //# sourceMappingURL=isobmff-demuxer.d.ts.map