UNPKG

@remotion/media-parser

Version:

A pure JavaScript library for parsing video files

1,873 lines (1,851 loc) 510 kB
// src/aac-codecprivate.ts var getSampleRateFromSampleFrequencyIndex = (samplingFrequencyIndex) => { switch (samplingFrequencyIndex) { case 0: return 96000; case 1: return 88200; case 2: return 64000; case 3: return 48000; case 4: return 44100; case 5: return 32000; case 6: return 24000; case 7: return 22050; case 8: return 16000; case 9: return 12000; case 10: return 11025; case 11: return 8000; case 12: return 7350; default: throw new Error(`Unexpected sampling frequency index ${samplingFrequencyIndex}`); } }; var getConfigForSampleRate = (sampleRate) => { if (sampleRate === 96000) { return 0; } if (sampleRate === 88200) { return 1; } if (sampleRate === 64000) { return 2; } if (sampleRate === 48000) { return 3; } if (sampleRate === 44100) { return 4; } if (sampleRate === 32000) { return 5; } if (sampleRate === 24000) { return 6; } if (sampleRate === 22050) { return 7; } if (sampleRate === 16000) { return 8; } if (sampleRate === 12000) { return 9; } if (sampleRate === 11025) { return 10; } if (sampleRate === 8000) { return 11; } if (sampleRate === 7350) { return 12; } throw new Error(`Unexpected sample rate ${sampleRate}`); }; var createAacCodecPrivate = ({ audioObjectType, sampleRate, channelConfiguration, codecPrivate }) => { if (codecPrivate !== null && codecPrivate.length > 2) { return codecPrivate; } const bits = `${audioObjectType.toString(2).padStart(5, "0")}${getConfigForSampleRate(sampleRate).toString(2).padStart(4, "0")}${channelConfiguration.toString(2).padStart(4, "0")}000`; if (bits.length !== 16) { throw new Error("Invalid AAC codec private " + bits.length); } if (channelConfiguration === 0 || channelConfiguration > 7) { throw new Error("Invalid channel configuration " + channelConfiguration); } const firstByte = parseInt(bits.slice(0, 8), 2); const secondByte = parseInt(bits.slice(8, 16), 2); return new Uint8Array([firstByte, secondByte]); }; var parseAacCodecPrivate = (bytes) => { if (bytes.length < 2) { throw new Error("Invalid AAC codec private length"); } const bits = [...bytes].map((b) => b.toString(2).padStart(8, "0")).join(""); let offset = 0; const audioObjectType = parseInt(bits.slice(offset, offset + 5), 2); offset += 5; const samplingFrequencyIndex = parseInt(bits.slice(offset, offset + 4), 2); offset += 4; if (samplingFrequencyIndex === 15) { offset += 24; } const channelConfiguration = parseInt(bits.slice(offset, offset + 4), 2); offset += 4; if (audioObjectType === 5) { const extensionSamplingFrequencyIndex = parseInt(bits.slice(offset, offset + 4), 2); offset += 4; const newAudioObjectType = parseInt(bits.slice(offset, offset + 5), 2); offset += 5; return { audioObjectType: newAudioObjectType, sampleRate: getSampleRateFromSampleFrequencyIndex(extensionSamplingFrequencyIndex), channelConfiguration }; } const sampleRate = getSampleRateFromSampleFrequencyIndex(samplingFrequencyIndex); return { audioObjectType, sampleRate, channelConfiguration }; }; var mapAudioObjectTypeToCodecString = (audioObjectType) => { switch (audioObjectType) { case 1: return "mp4a.40.2"; case 2: return "mp4a.40.5"; case 3: return "mp4a.40.29"; case 4: return "mp4a.40.1"; case 5: return "mp4a.40.3"; case 6: return "mp4a.40.4"; case 17: return "mp4a.40.17"; case 23: return "mp4a.40.23"; default: throw new Error(`Unexpected audio object type ${audioObjectType}`); } }; // src/containers/iso-base-media/ftyp.ts var parseFtyp = ({ iterator, size, offset }) => { const majorBrand = iterator.getByteString(4, false); const minorVersion = iterator.getFourByteNumber(); const types = (size - iterator.counter.getOffset()) / 4; const compatibleBrands = []; for (let i = 0;i < types; i++) { compatibleBrands.push(iterator.getByteString(4, false).trim()); } const offsetAtEnd = iterator.counter.getOffset(); return { type: "ftyp-box", majorBrand, minorVersion, compatibleBrands, offset, boxSize: offsetAtEnd - offset }; }; // src/containers/webm/segments/all-segments.ts var matroskaElements = { Header: "0x1a45dfa3", EBMLMaxIDLength: "0x42f2", EBMLVersion: "0x4286", EBMLReadVersion: "0x42f7", EBMLMaxSizeLength: "0x42f3", DocType: "0x4282", DocTypeVersion: "0x4287", DocTypeReadVersion: "0x4285", Segment: "0x18538067", SeekHead: "0x114d9b74", Seek: "0x4dbb", SeekID: "0x53ab", SeekPosition: "0x53ac", Info: "0x1549a966", SegmentUUID: "0x73a4", SegmentFilename: "0x7384", PrevUUID: "0x3cb923", PrevFilename: "0x3c83ab", NextUUID: "0x3eb923", NextFilename: "0x3e83bb", SegmentFamily: "0x4444", ChapterTranslate: "0x6924", ChapterTranslateID: "0x69a5", ChapterTranslateCodec: "0x69bf", ChapterTranslateEditionUID: "0x69fc", TimestampScale: "0x2ad7b1", Duration: "0x4489", DateUTC: "0x4461", Title: "0x7ba9", MuxingApp: "0x4d80", WritingApp: "0x5741", Cluster: "0x1f43b675", Timestamp: "0xe7", SilentTracks: "0x5854", SilentTrackNumber: "0x58d7", Position: "0xa7", PrevSize: "0xab", SimpleBlock: "0xa3", BlockGroup: "0xa0", Block: "0xa1", BlockVirtual: "0xa2", BlockAdditions: "0x75a1", BlockMore: "0xa6", BlockAdditional: "0xa5", BlockAddID: "0xee", BlockDuration: "0x9b", ReferencePriority: "0xfa", ReferenceBlock: "0xfb", ReferenceVirtual: "0xfd", CodecState: "0xa4", DiscardPadding: "0x75a2", Slices: "0x8e", TimeSlice: "0xe8", LaceNumber: "0xcc", FrameNumber: "0xcd", BlockAdditionID: "0xcb", Delay: "0xce", SliceDuration: "0xcf", ReferenceFrame: "0xc8", ReferenceOffset: "0xc9", ReferenceTimestamp: "0xca", EncryptedBlock: "0xaf", Tracks: "0x1654ae6b", TrackEntry: "0xae", TrackNumber: "0xd7", TrackUID: "0x73c5", TrackType: "0x83", FlagEnabled: "0xb9", FlagDefault: "0x88", FlagForced: "0x55aa", FlagHearingImpaired: "0x55ab", FlagVisualImpaired: "0x55ac", FlagTextDescriptions: "0x55ad", FlagOriginal: "0x55ae", FlagCommentary: "0x55af", FlagLacing: "0x9c", MinCache: "0x6de7", MaxCache: "0x6df8", DefaultDuration: "0x23e383", DefaultDecodedFieldDuration: "0x234e7a", TrackTimestampScale: "0x23314f", TrackOffset: "0x537f", MaxBlockAdditionID: "0x55ee", BlockAdditionMapping: "0x41e4", BlockAddIDValue: "0x41f0", BlockAddIDName: "0x41a4", BlockAddIDType: "0x41e7", BlockAddIDExtraData: "0x41ed", Name: "0x536e", Language: "0x22b59c", LanguageBCP47: "0x22b59d", CodecID: "0x86", CodecPrivate: "0x63a2", CodecName: "0x258688", AttachmentLink: "0x7446", CodecSettings: "0x3a9697", CodecInfoURL: "0x3b4040", CodecDownloadURL: "0x26b240", CodecDecodeAll: "0xaa", TrackOverlay: "0x6fab", CodecDelay: "0x56aa", SeekPreRoll: "0x56bb", TrackTranslate: "0x6624", TrackTranslateTrackID: "0x66a5", TrackTranslateCodec: "0x66bf", TrackTranslateEditionUID: "0x66fc", Video: "0xe0", FlagInterlaced: "0x9a", FieldOrder: "0x9d", StereoMode: "0x53b8", AlphaMode: "0x53c0", OldStereoMode: "0x53b9", PixelWidth: "0xb0", PixelHeight: "0xba", PixelCropBottom: "0x54aa", PixelCropTop: "0x54bb", PixelCropLeft: "0x54cc", PixelCropRight: "0x54dd", DisplayWidth: "0x54b0", DisplayHeight: "0x54ba", DisplayUnit: "0x54b2", AspectRatioType: "0x54b3", UncompressedFourCC: "0x2eb524", GammaValue: "0x2fb523", FrameRate: "0x2383e3", Colour: "0x55b0", MatrixCoefficients: "0x55b1", BitsPerChannel: "0x55b2", ChromaSubsamplingHorz: "0x55b3", ChromaSubsamplingVert: "0x55b4", CbSubsamplingHorz: "0x55b5", CbSubsamplingVert: "0x55b6", ChromaSitingHorz: "0x55b7", ChromaSitingVert: "0x55b8", Range: "0x55b9", TransferCharacteristics: "0x55ba", Primaries: "0x55bb", MaxCLL: "0x55bc", MaxFALL: "0x55bd", MasteringMetadata: "0x55d0", PrimaryRChromaticityX: "0x55d1", PrimaryRChromaticityY: "0x55d2", PrimaryGChromaticityX: "0x55d3", PrimaryGChromaticityY: "0x55d4", PrimaryBChromaticityX: "0x55d5", PrimaryBChromaticityY: "0x55d6", WhitePointChromaticityX: "0x55d7", WhitePointChromaticityY: "0x55d8", LuminanceMax: "0x55d9", LuminanceMin: "0x55da", Projection: "0x7670", ProjectionType: "0x7671", ProjectionPrivate: "0x7672", ProjectionPoseYaw: "0x7673", ProjectionPosePitch: "0x7674", ProjectionPoseRoll: "0x7675", Audio: "0xe1", SamplingFrequency: "0xb5", OutputSamplingFrequency: "0x78b5", Channels: "0x9f", ChannelPositions: "0x7d7b", BitDepth: "0x6264", Emphasis: "0x52f1", TrackOperation: "0xe2", TrackCombinePlanes: "0xe3", TrackPlane: "0xe4", TrackPlaneUID: "0xe5", TrackPlaneType: "0xe6", TrackJoinBlocks: "0xe9", TrackJoinUID: "0xed", TrickTrackUID: "0xc0", TrickTrackSegmentUID: "0xc1", TrickTrackFlag: "0xc6", TrickMasterTrackUID: "0xc7", TrickMasterTrackSegmentUID: "0xc4", ContentEncodings: "0x6d80", ContentEncoding: "0x6240", ContentEncodingOrder: "0x5031", ContentEncodingScope: "0x5032", ContentEncodingType: "0x5033", ContentCompression: "0x5034", ContentCompAlgo: "0x4254", ContentCompSettings: "0x4255", ContentEncryption: "0x5035", ContentEncAlgo: "0x47e1", ContentEncKeyID: "0x47e2", ContentEncAESSettings: "0x47e7", AESSettingsCipherMode: "0x47e8", ContentSignature: "0x47e3", ContentSigKeyID: "0x47e4", ContentSigAlgo: "0x47e5", ContentSigHashAlgo: "0x47e6", Cues: "0x1c53bb6b", CuePoint: "0xbb", CueTime: "0xb3", CueTrackPositions: "0xb7", CueTrack: "0xf7", CueClusterPosition: "0xf1", CueRelativePosition: "0xf0", CueDuration: "0xb2", CueBlockNumber: "0x5378", CueCodecState: "0xea", CueReference: "0xdb", CueRefTime: "0x96", CueRefCluster: "0x97", CueRefNumber: "0x535f", CueRefCodecState: "0xeb", Attachments: "0x1941a469", AttachedFile: "0x61a7", FileDescription: "0x467e", FileName: "0x466e", FileMediaType: "0x4660", FileData: "0x465c", FileUID: "0x46ae", FileReferral: "0x4675", FileUsedStartTime: "0x4661", FileUsedEndTime: "0x4662", Chapters: "0x1043a770", EditionEntry: "0x45b9", EditionUID: "0x45bc", EditionFlagHidden: "0x45bd", EditionFlagDefault: "0x45db", EditionFlagOrdered: "0x45dd", EditionDisplay: "0x4520", EditionString: "0x4521", EditionLanguageIETF: "0x45e4", ChapterAtom: "0xb6", ChapterUID: "0x73c4", ChapterStringUID: "0x5654", ChapterTimeStart: "0x91", ChapterTimeEnd: "0x92", ChapterFlagHidden: "0x98", ChapterFlagEnabled: "0x4598", ChapterSegmentUUID: "0x6e67", ChapterSkipType: "0x4588", ChapterSegmentEditionUID: "0x6ebc", ChapterPhysicalEquiv: "0x63c3", ChapterTrack: "0x8f", ChapterTrackUID: "0x89", ChapterDisplay: "0x80", ChapString: "0x85", ChapLanguage: "0x437c", ChapLanguageBCP47: "0x437d", ChapCountry: "0x437e", ChapProcess: "0x6944", ChapProcessCodecID: "0x6955", ChapProcessPrivate: "0x450d", ChapProcessCommand: "0x6911", ChapProcessTime: "0x6922", ChapProcessData: "0x6933", Tags: "0x1254c367", Tag: "0x7373", Targets: "0x63c0", TargetTypeValue: "0x68ca", TargetType: "0x63ca", TagTrackUID: "0x63c5", TagEditionUID: "0x63c9", TagChapterUID: "0x63c4", TagAttachmentUID: "0x63c6", SimpleTag: "0x67c8", TagName: "0x45a3", TagLanguage: "0x447a", TagLanguageBCP47: "0x447b", TagDefault: "0x4484", TagDefaultBogus: "0x44b4", TagString: "0x4487", TagBinary: "0x4485", Void: "0xec", Crc32: "0xbf" }; var matroskaIds = Object.values(matroskaElements); var knownIdsWithOneLength = matroskaIds.filter((id) => id.length === 4); var knownIdsWithTwoLength = matroskaIds.filter((id) => id.length === 6); var knownIdsWithThreeLength = matroskaIds.filter((id) => id.length === 8); var ebmlVersion = { name: "EBMLVersion", type: "uint" }; var ebmlReadVersion = { name: "EBMLReadVersion", type: "uint" }; var ebmlMaxIdLength = { name: "EBMLMaxIDLength", type: "uint" }; var ebmlMaxSizeLength = { name: "EBMLMaxSizeLength", type: "uint" }; var docType = { name: "DocType", type: "string" }; var docTypeVersion = { name: "DocTypeVersion", type: "uint" }; var docTypeReadVersion = { name: "DocTypeReadVersion", type: "uint" }; var voidEbml = { name: "Void", type: "uint8array" }; var matroskaHeader = { name: "Header", type: "children" }; var seekId = { name: "SeekID", type: "hex-string" }; var _name = { name: "Name", type: "string" }; var minCache = { name: "MinCache", type: "uint" }; var maxCache = { name: "MaxCache", type: "uint" }; var seekPosition = { name: "SeekPosition", type: "uint" }; var seek = { name: "Seek", type: "children" }; var seekHead = { name: "SeekHead", type: "children" }; var trackType = { name: "TrackType", type: "uint" }; var widthType = { name: "PixelWidth", type: "uint" }; var heightType = { name: "PixelHeight", type: "uint" }; var muxingApp = { name: "MuxingApp", type: "string" }; var duration = { name: "Duration", type: "float" }; var timestampScale = { name: "TimestampScale", type: "uint" }; var infoType = { name: "Info", type: "children" }; var titleType = { name: "Title", type: "string" }; var tagTrackUidType = { name: "TagTrackUID", type: "hex-string" }; var samplingFrequency = { name: "SamplingFrequency", type: "float" }; var channels = { name: "Channels", type: "uint" }; var alphaMode = { name: "AlphaMode", type: "uint" }; var interlaced = { name: "FlagInterlaced", type: "uint" }; var bitDepth = { name: "BitDepth", type: "uint" }; var displayWidth = { name: "DisplayWidth", type: "uint" }; var displayHeight = { name: "DisplayHeight", type: "uint" }; var displayUnit = { name: "DisplayUnit", type: "uint" }; var flagLacing = { name: "FlagLacing", type: "uint" }; var tagSegment = { name: "Tag", type: "children" }; var tags = { name: "Tags", type: "children" }; var trackNumber = { name: "TrackNumber", type: "uint" }; var trackUID = { name: "TrackUID", type: "hex-string" }; var color = { name: "Colour", type: "children" }; var transferCharacteristics = { name: "TransferCharacteristics", type: "uint" }; var matrixCoefficients = { name: "MatrixCoefficients", type: "uint" }; var primaries = { name: "Primaries", type: "uint" }; var range = { name: "Range", type: "uint" }; var ChromaSitingHorz = { name: "ChromaSitingHorz", type: "uint" }; var ChromaSitingVert = { name: "ChromaSitingVert", type: "uint" }; var language = { name: "Language", type: "string" }; var defaultDuration = { name: "DefaultDuration", type: "uint" }; var codecPrivate = { name: "CodecPrivate", type: "uint8array" }; var blockAdditionsSegment = { name: "BlockAdditions", type: "uint8array" }; var maxBlockAdditionIdSegment = { name: "MaxBlockAdditionID", type: "uint" }; var audioSegment = { name: "Audio", type: "children" }; var videoSegment = { name: "Video", type: "children" }; var flagDefault = { name: "FlagDefault", type: "uint" }; var referenceBlock = { name: "ReferenceBlock", type: "uint" }; var blockDurationSegment = { name: "BlockDuration", type: "uint" }; var codecName = { name: "CodecName", type: "string" }; var trackTimestampScale = { name: "TrackTimestampScale", type: "float" }; var trackEntry = { name: "TrackEntry", type: "children" }; var tracks = { name: "Tracks", type: "children" }; var block = { name: "Block", type: "uint8array" }; var simpleBlock = { name: "SimpleBlock", type: "uint8array" }; var blockGroup = { name: "BlockGroup", type: "children" }; var targetsType = { name: "Targets", type: "children" }; var simpleTagType = { name: "SimpleTag", type: "children" }; var tagNameType = { name: "TagName", type: "string" }; var tagStringType = { name: "TagString", type: "string" }; var ebmlMap = { [matroskaElements.Header]: matroskaHeader, [matroskaElements.DocType]: docType, [matroskaElements.Targets]: targetsType, [matroskaElements.SimpleTag]: simpleTagType, [matroskaElements.TagName]: tagNameType, [matroskaElements.TagString]: tagStringType, [matroskaElements.DocTypeVersion]: docTypeVersion, [matroskaElements.DocTypeReadVersion]: docTypeReadVersion, [matroskaElements.EBMLVersion]: ebmlVersion, [matroskaElements.EBMLReadVersion]: ebmlReadVersion, [matroskaElements.EBMLMaxIDLength]: ebmlMaxIdLength, [matroskaElements.EBMLMaxSizeLength]: ebmlMaxSizeLength, [matroskaElements.Void]: voidEbml, [matroskaElements.Cues]: { name: "Cues", type: "children" }, [matroskaElements.CuePoint]: { name: "CuePoint", type: "children" }, [matroskaElements.CueTime]: { name: "CueTime", type: "uint" }, [matroskaElements.CueTrackPositions]: { name: "CueTrackPositions", type: "children" }, [matroskaElements.CueClusterPosition]: { name: "CueClusterPosition", type: "uint" }, [matroskaElements.CueRelativePosition]: { name: "CueRelativePosition", type: "uint" }, [matroskaElements.CueBlockNumber]: { name: "CueBlockNumber", type: "uint" }, [matroskaElements.CueTrack]: { name: "CueTrack", type: "uint" }, [matroskaElements.DateUTC]: { name: "DateUTC", type: "uint8array" }, [matroskaElements.TrackTimestampScale]: trackTimestampScale, [matroskaElements.CodecDelay]: { name: "CodecDelay", type: "uint8array" }, [matroskaElements.SeekPreRoll]: { name: "SeekPreRoll", type: "uint8array" }, [matroskaElements.DiscardPadding]: { name: "DiscardPadding", type: "uint8array" }, [matroskaElements.OutputSamplingFrequency]: { name: "OutputSamplingFrequency", type: "uint8array" }, [matroskaElements.CodecName]: codecName, [matroskaElements.Position]: { name: "Position", type: "uint8array" }, [matroskaElements.SliceDuration]: { name: "SliceDuration", type: "uint8array" }, [matroskaElements.TagTrackUID]: tagTrackUidType, [matroskaElements.SeekHead]: seekHead, [matroskaElements.Seek]: seek, [matroskaElements.SeekID]: seekId, [matroskaElements.Name]: _name, [matroskaElements.MinCache]: minCache, [matroskaElements.MaxCache]: maxCache, [matroskaElements.SeekPosition]: seekPosition, [matroskaElements.Crc32]: { name: "Crc32", type: "uint8array" }, [matroskaElements.MuxingApp]: muxingApp, [matroskaElements.WritingApp]: { name: "WritingApp", type: "string" }, [matroskaElements.SegmentUUID]: { name: "SegmentUUID", type: "string" }, [matroskaElements.Duration]: duration, [matroskaElements.CodecID]: { name: "CodecID", type: "string" }, [matroskaElements.TrackType]: trackType, [matroskaElements.PixelWidth]: widthType, [matroskaElements.PixelHeight]: heightType, [matroskaElements.TimestampScale]: timestampScale, [matroskaElements.Info]: infoType, [matroskaElements.Title]: titleType, [matroskaElements.SamplingFrequency]: samplingFrequency, [matroskaElements.Channels]: channels, [matroskaElements.AlphaMode]: alphaMode, [matroskaElements.FlagInterlaced]: interlaced, [matroskaElements.BitDepth]: bitDepth, [matroskaElements.DisplayHeight]: displayHeight, [matroskaElements.DisplayWidth]: displayWidth, [matroskaElements.DisplayUnit]: displayUnit, [matroskaElements.FlagLacing]: flagLacing, [matroskaElements.Tags]: tags, [matroskaElements.Tag]: tagSegment, [matroskaElements.TrackNumber]: trackNumber, [matroskaElements.TrackUID]: trackUID, [matroskaElements.Colour]: color, [matroskaElements.Language]: language, [matroskaElements.DefaultDuration]: defaultDuration, [matroskaElements.CodecPrivate]: codecPrivate, [matroskaElements.BlockDuration]: blockDurationSegment, [matroskaElements.BlockAdditions]: blockAdditionsSegment, [matroskaElements.MaxBlockAdditionID]: maxBlockAdditionIdSegment, [matroskaElements.Audio]: audioSegment, [matroskaElements.Video]: videoSegment, [matroskaElements.FlagDefault]: flagDefault, [matroskaElements.ReferenceBlock]: referenceBlock, [matroskaElements.TrackEntry]: trackEntry, [matroskaElements.Timestamp]: { name: "Timestamp", type: "uint" }, [matroskaElements.Tracks]: tracks, [matroskaElements.Block]: block, [matroskaElements.SimpleBlock]: simpleBlock, [matroskaElements.BlockGroup]: blockGroup, [matroskaElements.Segment]: { name: "Segment", type: "children" }, [matroskaElements.Cluster]: { name: "Cluster", type: "children" }, [matroskaElements.TransferCharacteristics]: transferCharacteristics, [matroskaElements.MatrixCoefficients]: matrixCoefficients, [matroskaElements.Primaries]: primaries, [matroskaElements.Range]: range, [matroskaElements.ChromaSitingHorz]: ChromaSitingHorz, [matroskaElements.ChromaSitingVert]: ChromaSitingVert }; // src/file-types/detect-file-type.ts var webmPattern = new Uint8Array([26, 69, 223, 163]); var matchesPattern = (pattern) => { return (data) => { return pattern.every((value, index) => data[index] === value); }; }; var isRiffAvi = (data) => { const riffPattern = new Uint8Array([82, 73, 70, 70]); if (!matchesPattern(riffPattern)(data.subarray(0, 4))) { return false; } const fileType = data.subarray(8, 12); const aviPattern = new Uint8Array([65, 86, 73, 32]); return matchesPattern(aviPattern)(fileType); }; var isRiffWave = (data) => { const riffPattern = new Uint8Array([82, 73, 70, 70]); if (!matchesPattern(riffPattern)(data.subarray(0, 4))) { return false; } const fileType = data.subarray(8, 12); const wavePattern = new Uint8Array([87, 65, 86, 69]); return matchesPattern(wavePattern)(fileType); }; var isWebm = (data) => { return matchesPattern(webmPattern)(data.subarray(0, 4)); }; var isIsoBaseMedia = (data) => { const isoBaseMediaMp4Pattern = new TextEncoder().encode("ftyp"); return matchesPattern(isoBaseMediaMp4Pattern)(data.subarray(4, 8)); }; var isTransportStream = (data) => { return data[0] === 71 && data[188] === 71; }; var isMp3 = (data) => { const mpegPattern = new Uint8Array([255, 243]); const mpegPattern2 = new Uint8Array([255, 251]); const id3v4Pattern = new Uint8Array([73, 68, 51, 4]); const id3v3Pattern = new Uint8Array([73, 68, 51, 3]); const id3v2Pattern = new Uint8Array([73, 68, 51, 2]); const subarray = data.subarray(0, 4); return matchesPattern(mpegPattern)(subarray) || matchesPattern(mpegPattern2)(subarray) || matchesPattern(id3v4Pattern)(subarray) || matchesPattern(id3v3Pattern)(subarray) || matchesPattern(id3v2Pattern)(subarray); }; var isAac = (data) => { const aacPattern = new Uint8Array([255, 241]); return matchesPattern(aacPattern)(data.subarray(0, 2)); }; var isFlac = (data) => { const flacPattern = new Uint8Array([102, 76, 97, 67]); return matchesPattern(flacPattern)(data.subarray(0, 4)); }; var isM3u = (data) => { return new TextDecoder("utf-8").decode(data.slice(0, 7)) === "#EXTM3U"; }; // src/file-types/bmp.ts function getBmpDimensions(bmpData) { if (bmpData.length < 26) { return null; } const view = new DataView(bmpData.buffer, bmpData.byteOffset); return { width: view.getUint32(18, true), height: Math.abs(view.getInt32(22, true)) }; } var isBmp = (data) => { const bmpPattern = new Uint8Array([66, 77]); if (matchesPattern(bmpPattern)(data.subarray(0, 2))) { const bmp = getBmpDimensions(data); return { dimensions: bmp, type: "bmp" }; } return null; }; // src/file-types/gif.ts var getGifDimensions = (data) => { const view = new DataView(data.buffer, data.byteOffset); const width = view.getUint16(6, true); const height = view.getUint16(8, true); return { width, height }; }; var isGif = (data) => { const gifPattern = new Uint8Array([71, 73, 70, 56]); if (matchesPattern(gifPattern)(data.subarray(0, 4))) { return { type: "gif", dimensions: getGifDimensions(data) }; } return null; }; // src/file-types/jpeg.ts function getJpegDimensions(data) { let offset = 0; function readUint16BE(o) { return data[o] << 8 | data[o + 1]; } if (readUint16BE(offset) !== 65496) { return null; } offset += 2; while (offset < data.length) { if (data[offset] === 255) { const marker = data[offset + 1]; if (marker === 192 || marker === 194) { const height = readUint16BE(offset + 5); const width = readUint16BE(offset + 7); return { width, height }; } const length = readUint16BE(offset + 2); offset += length + 2; } else { offset++; } } return null; } var isJpeg = (data) => { const jpegPattern = new Uint8Array([255, 216]); const jpeg = matchesPattern(jpegPattern)(data.subarray(0, 2)); if (!jpeg) { return null; } const dim = getJpegDimensions(data); return { dimensions: dim, type: "jpeg" }; }; // src/file-types/pdf.ts var isPdf = (data) => { if (data.length < 4) { return null; } const pdfPattern = new Uint8Array([37, 80, 68, 70]); return matchesPattern(pdfPattern)(data.subarray(0, 4)) ? { type: "pdf" } : null; }; // src/file-types/png.ts function getPngDimensions(pngData) { if (pngData.length < 24) { return null; } const view = new DataView(pngData.buffer, pngData.byteOffset); const pngSignature = [137, 80, 78, 71, 13, 10, 26, 10]; for (let i = 0;i < 8; i++) { if (pngData[i] !== pngSignature[i]) { return null; } } return { width: view.getUint32(16, false), height: view.getUint32(20, false) }; } var isPng = (data) => { const pngPattern = new Uint8Array([137, 80, 78, 71]); if (matchesPattern(pngPattern)(data.subarray(0, 4))) { const png = getPngDimensions(data); return { dimensions: png, type: "png" }; } return null; }; // src/file-types/webp.ts function getWebPDimensions(bytes) { if (bytes.length < 30) { return null; } if (bytes[0] !== 82 || bytes[1] !== 73 || bytes[2] !== 70 || bytes[3] !== 70 || bytes[8] !== 87 || bytes[9] !== 69 || bytes[10] !== 66 || bytes[11] !== 80) { return null; } if (bytes[12] === 86 && bytes[13] === 80 && bytes[14] === 56) { if (bytes[15] === 32) { return { width: bytes[26] | bytes[27] << 8 & 16383, height: bytes[28] | bytes[29] << 8 & 16383 }; } } if (bytes[12] === 86 && bytes[13] === 80 && bytes[14] === 56 && bytes[15] === 76) { return { width: 1 + (bytes[21] | (bytes[22] & 63) << 8), height: 1 + ((bytes[22] & 192) >> 6 | bytes[23] << 2 | (bytes[24] & 15) << 10) }; } if (bytes[12] === 86 && bytes[13] === 80 && bytes[14] === 56 && bytes[15] === 88) { return { width: 1 + (bytes[24] | bytes[25] << 8 | bytes[26] << 16), height: 1 + (bytes[27] | bytes[28] << 8 | bytes[29] << 16) }; } return null; } var isWebp = (data) => { const webpPattern = new Uint8Array([82, 73, 70, 70]); if (matchesPattern(webpPattern)(data.subarray(0, 4))) { return { type: "webp", dimensions: getWebPDimensions(data) }; } return null; }; // src/file-types/index.ts var detectFileType = (data) => { if (isRiffWave(data)) { return { type: "wav" }; } if (isRiffAvi(data)) { return { type: "riff" }; } if (isAac(data)) { return { type: "aac" }; } if (isFlac(data)) { return { type: "flac" }; } if (isM3u(data)) { return { type: "m3u" }; } const webp = isWebp(data); if (webp) { return webp; } if (isWebm(data)) { return { type: "webm" }; } if (isIsoBaseMedia(data)) { return { type: "iso-base-media" }; } if (isTransportStream(data)) { return { type: "transport-stream" }; } if (isMp3(data)) { return { type: "mp3" }; } const gif = isGif(data); if (gif) { return gif; } const png = isPng(data); if (png) { return png; } const pdf = isPdf(data); if (pdf) { return pdf; } const bmp = isBmp(data); if (bmp) { return bmp; } const jpeg = isJpeg(data); if (jpeg) { return jpeg; } return { type: "unknown" }; }; // src/log.ts var logLevels = ["trace", "verbose", "info", "warn", "error"]; var getNumberForLogLevel = (level) => { return logLevels.indexOf(level); }; var isEqualOrBelowLogLevel = (currentLevel, level) => { return getNumberForLogLevel(currentLevel) <= getNumberForLogLevel(level); }; var Log = { trace: (logLevel, ...args) => { if (isEqualOrBelowLogLevel(logLevel, "trace")) { return console.log(...args); } }, verbose: (logLevel, ...args) => { if (isEqualOrBelowLogLevel(logLevel, "verbose")) { return console.log(...args); } }, info: (logLevel, ...args) => { if (isEqualOrBelowLogLevel(logLevel, "info")) { return console.log(...args); } }, warn: (logLevel, ...args) => { if (isEqualOrBelowLogLevel(logLevel, "warn")) { return console.warn(...args); } }, error: (...args) => { return console.error(...args); } }; // src/iterator/buffer-manager.ts var makeBufferWithMaxBytes = (initialData, maxBytes) => { const maxByteLength = Math.min(maxBytes, 2 ** 31); try { const buf = new ArrayBuffer(initialData.byteLength, { maxByteLength }); return buf; } catch (e) { if (e instanceof RangeError && maxBytes > 2 ** 27) { return new ArrayBuffer(initialData.byteLength, { maxByteLength: 2 ** 27 }); } throw e; } }; var bufferManager = ({ initialData, maxBytes, counter }) => { const buf = makeBufferWithMaxBytes(initialData, maxBytes); if (!buf.resize) { throw new Error("`ArrayBuffer.resize` is not supported in this Runtime. On the server: Use at least Node.js 20 or Bun. In the browser: Chrome 111, Edge 111, Safari 16.4, Firefox 128, Opera 111"); } let uintArray = new Uint8Array(buf); uintArray.set(initialData); let view = new DataView(uintArray.buffer); const destroy = () => { uintArray = new Uint8Array(0); buf.resize(0); }; const flushBytesRead = (force, mode) => { const bytesToRemove = counter.getDiscardedOffset(); if (bytesToRemove < 3000000 && !force) { return { bytesRemoved: 0, removedData: null }; } if (view.byteLength < bytesToRemove && !force) { return { bytesRemoved: 0, removedData: null }; } counter.discardBytes(bytesToRemove); const removedData = mode === "download" ? uintArray.slice(0, bytesToRemove) : null; const newData = uintArray.slice(bytesToRemove); uintArray.set(newData); buf.resize(newData.byteLength); view = new DataView(uintArray.buffer); return { bytesRemoved: bytesToRemove, removedData }; }; const skipTo = (offset) => { const becomesSmaller = offset < counter.getOffset(); if (becomesSmaller) { const toDecrement = counter.getOffset() - offset; if (toDecrement > counter.getDiscardedOffset()) { throw new Error("Cannot count backwards, data has already been flushed"); } counter.decrement(toDecrement); } const currentOffset = counter.getOffset(); counter.increment(offset - currentOffset); }; const addData = (newData) => { const oldLength = buf.byteLength; const newLength = oldLength + newData.byteLength; if (newLength < oldLength) { throw new Error("Cannot decrement size"); } if (newLength > (maxBytes ?? Infinity)) { throw new Error(`Exceeded maximum byte length ${maxBytes} with ${newLength}`); } buf.resize(newLength); uintArray = new Uint8Array(buf); uintArray.set(newData, oldLength); view = new DataView(uintArray.buffer); }; const replaceData = (newData, seekTo) => { buf.resize(newData.byteLength); uintArray = new Uint8Array(buf); uintArray.set(newData); view = new DataView(uintArray.buffer); counter.setDiscardedOffset(seekTo); counter.decrement(counter.getOffset()); counter.increment(seekTo); }; return { view, uintArray, destroy, addData, skipTo, removeBytesRead: flushBytesRead, replaceData }; }; // src/iterator/offset-counter.ts var makeOffsetCounter = (initial) => { let offset = initial; let discardedBytes = 0; return { getOffset: () => offset, discardBytes: (bytes) => { discardedBytes += bytes; }, increment: (bytes) => { if (bytes < 0) { throw new Error("Cannot increment by a negative amount: " + bytes); } offset += bytes; }, getDiscardedBytes: () => discardedBytes, setDiscardedOffset: (bytes) => { discardedBytes = bytes; }, getDiscardedOffset: () => offset - discardedBytes, decrement: (bytes) => { if (bytes < 0) { throw new Error("Cannot decrement by a negative amount: " + bytes); } offset -= bytes; } }; }; // src/iterator/buffer-iterator.ts var getArrayBufferIterator = (initialData, maxBytes) => { const counter = makeOffsetCounter(0); const { uintArray, view, addData, destroy, removeBytesRead, skipTo, replaceData } = bufferManager({ initialData, maxBytes, counter }); const startCheckpoint = () => { const checkpoint = counter.getOffset(); return { returnToCheckpoint: () => { counter.decrement(counter.getOffset() - checkpoint); } }; }; const getSlice = (amount) => { const value = uintArray.slice(counter.getDiscardedOffset(), counter.getDiscardedOffset() + amount); counter.increment(value.length); return value; }; const discard = (length) => { counter.increment(length); }; const readUntilNullTerminator = () => { const bytes = []; let byte; while ((byte = getUint8()) !== 0) { bytes.push(byte); } counter.decrement(1); return new TextDecoder().decode(new Uint8Array(bytes)); }; const readUntilLineEnd = () => { const bytes = []; while (true) { if (bytesRemaining() === 0) { return null; } const byte = getUint8(); bytes.push(byte); if (byte === 10) { break; } } const str = new TextDecoder().decode(new Uint8Array(bytes)).trim(); return str; }; const getUint8 = () => { const val = view.getUint8(counter.getDiscardedOffset()); counter.increment(1); return val; }; const getEightByteNumber = (littleEndian = false) => { if (littleEndian) { const one = getUint8(); const two = getUint8(); const three = getUint8(); const four = getUint8(); const five = getUint8(); const six = getUint8(); const seven = getUint8(); const eight = getUint8(); return (eight << 56 | seven << 48 | six << 40 | five << 32 | four << 24 | three << 16 | two << 8 | one) >>> 0; } function byteArrayToBigInt(byteArray) { let result = BigInt(0); for (let i = 0;i < byteArray.length; i++) { result = (result << BigInt(8)) + BigInt(byteArray[i]); } return result; } const bigInt = byteArrayToBigInt([ getUint8(), getUint8(), getUint8(), getUint8(), getUint8(), getUint8(), getUint8(), getUint8() ]); return Number(bigInt); }; const getFourByteNumber = () => { const unsigned = getUint8() << 24 | getUint8() << 16 | getUint8() << 8 | getUint8(); return unsigned >>> 0; }; const getPaddedFourByteNumber = () => { let lastInt = 128; while (lastInt = getUint8(), lastInt === 128) {} return lastInt; }; const getUint32 = () => { const val = view.getUint32(counter.getDiscardedOffset()); counter.increment(4); return val; }; const getSyncSafeInt32 = () => { const val = view.getUint32(counter.getDiscardedOffset()); counter.increment(4); return (val & 2130706432) >> 3 | (val & 8323072) >> 2 | (val & 32512) >> 1 | val & 127; }; const getUint64 = (littleEndian = false) => { const val = view.getBigUint64(counter.getDiscardedOffset(), littleEndian); counter.increment(8); return val; }; const getInt64 = (littleEndian = false) => { const val = view.getBigInt64(counter.getDiscardedOffset(), littleEndian); counter.increment(8); return val; }; const startBox = (size) => { const startOffset = counter.getOffset(); return { discardRest: () => discard(size - (counter.getOffset() - startOffset)), expectNoMoreBytes: () => { const remaining = size - (counter.getOffset() - startOffset); if (remaining !== 0) { throw new Error("expected 0 bytes, got " + remaining); } } }; }; const getUint32Le = () => { const val = view.getUint32(counter.getDiscardedOffset(), true); counter.increment(4); return val; }; const getInt32Le = () => { const val = view.getInt32(counter.getDiscardedOffset(), true); counter.increment(4); return val; }; const getInt32 = () => { const val = view.getInt32(counter.getDiscardedOffset()); counter.increment(4); return val; }; const bytesRemaining = () => { return uintArray.byteLength - counter.getDiscardedOffset(); }; const readExpGolomb = () => { if (!bitReadingMode) { throw new Error("Not in bit reading mode"); } let zerosCount = 0; while (getBits(1) === 0) { zerosCount++; } let suffix = 0; for (let i = 0;i < zerosCount; i++) { suffix = suffix << 1 | getBits(1); } return (1 << zerosCount) - 1 + suffix; }; const peekB = (length) => { Log.info("info", [...getSlice(length)].map((b) => b.toString(16).padStart(2, "0"))); counter.decrement(length); }; const peekD = (length) => { Log.info("info", [...getSlice(length)].map((b) => b.toString(16).padStart(2, "0"))); counter.decrement(length); }; const leb128 = () => { let result = 0; let shift = 0; let byte; do { byte = getBits(8); result |= (byte & 127) << shift; shift += 7; } while (byte >= 128); return result; }; let bitIndex = 0; const stopReadingBits = () => { bitIndex = 0; bitReadingMode = false; }; let byteToShift = 0; let bitReadingMode = false; const startReadingBits = () => { bitReadingMode = true; byteToShift = getUint8(); }; const getFlacCodecNumber = () => { let ones = 0; let bits = 0; while ((++bits || true) && getBits(1) === 1) { ones++; } if (ones === 0) { return getBits(7); } const bitArray = []; const firstByteBits = 8 - ones - 1; for (let i = 0;i < firstByteBits; i++) { bitArray.unshift(getBits(1)); } const extraBytes = ones - 1; for (let i = 0;i < extraBytes; i++) { for (let j = 0;j < 8; j++) { const val = getBits(1); if (j < 2) { continue; } bitArray.unshift(val); } } const encoded = bitArray.reduce((acc, bit, index) => { return acc | bit << index; }, 0); return encoded; }; const getBits = (bits) => { let result = 0; let bitsCollected = 0; while (bitsCollected < bits) { if (bitIndex >= 8) { bitIndex = 0; byteToShift = getUint8(); } const remainingBitsInByte = 8 - bitIndex; const bitsToReadNow = Math.min(bits - bitsCollected, remainingBitsInByte); const mask = (1 << bitsToReadNow) - 1; const shift = remainingBitsInByte - bitsToReadNow; result <<= bitsToReadNow; result |= byteToShift >> shift & mask; bitsCollected += bitsToReadNow; bitIndex += bitsToReadNow; } return result; }; return { startReadingBits, stopReadingBits, skipTo, addData, counter, peekB, peekD, getBits, bytesRemaining, leb128, removeBytesRead, discard, getEightByteNumber, getFourByteNumber, getSlice, getAtom: () => { const atom = getSlice(4); return new TextDecoder().decode(atom); }, detectFileType: () => { return detectFileType(uintArray); }, getPaddedFourByteNumber, getMatroskaSegmentId: () => { if (bytesRemaining() === 0) { return null; } const first = getSlice(1); const firstOneString = `0x${Array.from(new Uint8Array(first)).map((b) => { return b.toString(16).padStart(2, "0"); }).join("")}`; if (knownIdsWithOneLength.includes(firstOneString)) { return firstOneString; } if (bytesRemaining() === 0) { return null; } const firstTwo = getSlice(1); const firstTwoString = `${firstOneString}${Array.from(new Uint8Array(firstTwo)).map((b) => { return b.toString(16).padStart(2, "0"); }).join("")}`; if (knownIdsWithTwoLength.includes(firstTwoString)) { return firstTwoString; } if (bytesRemaining() === 0) { return null; } const firstThree = getSlice(1); const firstThreeString = `${firstTwoString}${Array.from(new Uint8Array(firstThree)).map((b) => { return b.toString(16).padStart(2, "0"); }).join("")}`; if (knownIdsWithThreeLength.includes(firstThreeString)) { return firstThreeString; } if (bytesRemaining() === 0) { return null; } const segmentId = getSlice(1); return `${firstThreeString}${Array.from(new Uint8Array(segmentId)).map((b) => { return b.toString(16).padStart(2, "0"); }).join("")}`; }, getVint: () => { if (bytesRemaining() === 0) { return null; } const firstByte = getUint8(); const totalLength = firstByte; if (totalLength === 0) { return 0; } let actualLength = 0; while ((totalLength >> 7 - actualLength & 1) === 0) { actualLength++; } if (bytesRemaining() < actualLength) { return null; } const slice = getSlice(actualLength); const d = [firstByte, ...Array.from(new Uint8Array(slice))]; actualLength += 1; let value = 0; value = totalLength & 255 >> actualLength; for (let i = 1;i < actualLength; i++) { value = value << 8 | d[i]; } if (value === -1) { return Infinity; } return value; }, getUint8, getEBML: () => { const val = getUint8(); const actualValue = val & 127; return actualValue; }, getInt8: () => { const val = view.getInt8(counter.getDiscardedOffset()); counter.increment(1); return val; }, getUint16: () => { const val = view.getUint16(counter.getDiscardedOffset()); counter.increment(2); return val; }, getUint16Le: () => { const val = view.getUint16(counter.getDiscardedOffset(), true); counter.increment(2); return val; }, getUint24: () => { const val1 = view.getUint8(counter.getDiscardedOffset()); const val2 = view.getUint8(counter.getDiscardedOffset() + 1); const val3 = view.getUint8(counter.getDiscardedOffset() + 2); counter.increment(3); return val1 << 16 | val2 << 8 | val3; }, getInt24: () => { const val1 = view.getInt8(counter.getDiscardedOffset()); const val2 = view.getUint8(counter.getDiscardedOffset() + 1); const val3 = view.getUint8(counter.getDiscardedOffset() + 2); counter.increment(3); return val1 << 16 | val2 << 8 | val3; }, getInt16: () => { const val = view.getInt16(counter.getDiscardedOffset()); counter.increment(2); return val; }, getUint32, getUint64, getInt64, getFixedPointUnsigned1616Number: () => { const val = getUint32(); return val / 2 ** 16; }, getFixedPointSigned1616Number: () => { const val = getInt32(); return val / 2 ** 16; }, getFixedPointSigned230Number: () => { const val = getInt32(); return val / 2 ** 30; }, getPascalString: () => { const val = getSlice(32); return [...Array.from(new Uint8Array(val))]; }, getUint(length) { const bytes = getSlice(length); const numbers = [...Array.from(new Uint8Array(bytes))]; return numbers.reduce((acc, byte, index) => acc + (byte << 8 * (numbers.length - index - 1)), 0); }, getByteString(length, trimTrailingZeroes) { let bytes = getSlice(length); while (trimTrailingZeroes && bytes[bytes.length - 1] === 0) { bytes = bytes.slice(0, -1); } return new TextDecoder().decode(bytes).trim(); }, planBytes: (size) => { const currentOffset = counter.getOffset(); return { discardRest: () => { const toDiscard = size - (counter.getOffset() - currentOffset); if (toDiscard < 0) { throw new Error("read too many bytes"); } return getSlice(toDiscard); } }; }, getFloat64: () => { const val = view.getFloat64(counter.getDiscardedOffset()); counter.increment(8); return val; }, readUntilNullTerminator, getFloat32: () => { const val = view.getFloat32(counter.getDiscardedOffset()); counter.increment(4); return val; }, getUint32Le, getInt32Le, getInt32, destroy, startBox, readExpGolomb, startCheckpoint, getFlacCodecNumber, readUntilLineEnd, getSyncSafeInt32, replaceData }; }; // src/containers/iso-base-media/to-date.ts var toUnixTimestamp = (value) => { if (value === 0) { return null; } const baseDate = new Date("1904-01-01T00:00:00Z"); return Math.floor(value + baseDate.getTime() / 1000) * 1000; }; // src/containers/iso-base-media/moov/mvhd.ts var parseMvhd = ({ iterator, offset, size }) => { const version = iterator.getUint8(); iterator.discard(3); const creationTime = version === 1 ? iterator.getUint64() : iterator.getUint32(); const modificationTime = version === 1 ? iterator.getUint64() : iterator.getUint32(); const timeScale = iterator.getUint32(); const durationInUnits = version === 1 ? iterator.getUint64() : iterator.getUint32(); const durationInSeconds = Number(durationInUnits) / timeScale; const rateArray = iterator.getSlice(4); const rateView = getArrayBufferIterator(rateArray, rateArray.length); const rate = rateView.getInt8() * 10 + rateView.getInt8() + rateView.getInt8() * 0.1 + rateView.getInt8() * 0.01; const volumeArray = iterator.getSlice(2); const volumeView = getArrayBufferIterator(volumeArray, volumeArray.length); const volume = volumeView.getInt8() + volumeView.getInt8() * 0.1; iterator.discard(2); iterator.discard(4); iterator.discard(4); const matrix = [ iterator.getFixedPointSigned1616Number(), iterator.getFixedPointSigned1616Number(), iterator.getFixedPointSigned230Number(), iterator.getFixedPointSigned1616Number(), iterator.getFixedPointSigned1616Number(), iterator.getFixedPointSigned230Number(), iterator.getFixedPointSigned1616Number(), iterator.getFixedPointSigned1616Number(), iterator.getFixedPointSigned230Number() ]; iterator.discard(4 * 6); const nextTrackId = iterator.getUint32(); volumeView.destroy(); const bytesRemaining = size - (iterator.counter.getOffset() - offset); if (bytesRemaining !== 0) { throw new Error("expected 0 bytes " + bytesRemaining); } return { creationTime: toUnixTimestamp(Number(creationTime)), modificationTime: toUnixTimestamp(Number(modificationTime)), timeScale, durationInUnits: Number(durationInUnits), durationInSeconds, rate, volume, matrix, nextTrackId, type: "mvhd-box", boxSize: size, offset }; }; // src/containers/avc/codec-string.ts var getCodecStringFromSpsAndPps = (sps) => { return `avc1.${sps.spsData.profile.toString(16).padStart(2, "0")}${sps.spsData.compatibility.toString(16).padStart(2, "0")}${sps.spsData.level.toString(16).padStart(2, "0")}`; }; // src/combine-uint8-arrays.ts var combineUint8Arrays = (arrays) => { if (arrays.length === 0) { return new Uint8Array([]); } if (arrays.length === 1) { return arrays[0]; } let totalLength = 0; for (const array of arrays) { totalLength += array.length; } const result = new Uint8Array(totalLength); let offset = 0; for (const array of arrays) { result.set(array, offset); offset += array.length; } return result; }; // src/truthy.ts function truthy(value) { return Boolean(value); } // src/containers/avc/create-sps-pps-data.ts function serializeUint16(value) { const buffer = new ArrayBuffer(2); const view = new DataView(buffer); view.setUint16(0, value); return new Uint8Array(buffer); } var createSpsPpsData = (avc1Profile) => { return combineUint8Arrays([ new Uint8Array([ 1, avc1Profile.sps.spsData.profile, avc1Profile.sps.spsData.compatibility, avc1Profile.sps.spsData.level, 255, 225 ]), serializeUint16(avc1Profile.sps.sps.length), avc1Profile.sps.sps, new Uint8Array([1]), serializeUint16(avc1Profile.pps.pps.length), avc1Profile.pps.pps, [66, 77, 88].some((b) => avc1Profile.sps.spsData.profile === b) ? null : new Uint8Array([253, 248, 248, 0]) ].filter(truthy)); }; // src/add-avc-profile-to-track.ts var addAvcProfileToTrack = (track, avc1Profile) => { if (avc1Profile === null) { return track; } return { ...track, codec: getCodecStringFromSpsAndPps(avc1Profile.sps), codecData: { type: "avc-sps-pps", data: createSpsPpsData(avc1Profile) }, description: undefined }; }; // src/register-track.ts var registerVideoTrack = async ({ track, container, logLevel, onVideoTrack, registerVideoSampleCallback, tracks: tracks2 }) => { if (tracks2.getTracks().fi