@editframe/assets 0.47.1 → 0.48.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/LICENSE-FULL.md +148 -0
  2. package/LICENSE.md +58 -0
  3. package/dist/Probe.cjs +63 -9
  4. package/dist/Probe.cjs.map +1 -1
  5. package/dist/Probe.d.cts +49 -0
  6. package/dist/Probe.d.ts +49 -0
  7. package/dist/Probe.js +59 -3
  8. package/dist/Probe.js.map +1 -1
  9. package/dist/VideoRenderOptions.cjs +2 -4
  10. package/dist/VideoRenderOptions.cjs.map +1 -1
  11. package/dist/VideoRenderOptions.js +1 -2
  12. package/dist/VideoRenderOptions.js.map +1 -1
  13. package/dist/_virtual/{rolldown_runtime.cjs → _rolldown/runtime.cjs} +2 -4
  14. package/dist/generateFragmentIndex.cjs +4 -12
  15. package/dist/generateFragmentIndex.cjs.map +1 -1
  16. package/dist/generateFragmentIndex.d.cts +1 -2
  17. package/dist/generateFragmentIndex.d.ts +1 -2
  18. package/dist/generateFragmentIndex.js +1 -2
  19. package/dist/generateFragmentIndex.js.map +1 -1
  20. package/dist/generateSingleTrack.cjs +7 -10
  21. package/dist/generateSingleTrack.cjs.map +1 -1
  22. package/dist/generateSingleTrack.js +2 -3
  23. package/dist/generateSingleTrack.js.map +1 -1
  24. package/dist/generateWebmSegmentIndex.cjs +346 -0
  25. package/dist/generateWebmSegmentIndex.cjs.map +1 -0
  26. package/dist/generateWebmSegmentIndex.js +343 -0
  27. package/dist/generateWebmSegmentIndex.js.map +1 -0
  28. package/dist/idempotentTask.cjs +5 -10
  29. package/dist/idempotentTask.cjs.map +1 -1
  30. package/dist/idempotentTask.d.cts +0 -1
  31. package/dist/idempotentTask.d.ts +0 -1
  32. package/dist/idempotentTask.js +1 -2
  33. package/dist/idempotentTask.js.map +1 -1
  34. package/dist/index.cjs +11 -11
  35. package/dist/index.js +1 -2
  36. package/dist/md5.cjs +3 -7
  37. package/dist/md5.cjs.map +1 -1
  38. package/dist/md5.js +1 -2
  39. package/dist/md5.js.map +1 -1
  40. package/dist/tasks/cacheImage.cjs +4 -6
  41. package/dist/tasks/cacheImage.cjs.map +1 -1
  42. package/dist/tasks/cacheImage.js +1 -2
  43. package/dist/tasks/cacheImage.js.map +1 -1
  44. package/dist/tasks/findOrCreateCaptions.cjs +5 -10
  45. package/dist/tasks/findOrCreateCaptions.cjs.map +1 -1
  46. package/dist/tasks/findOrCreateCaptions.js +1 -2
  47. package/dist/tasks/findOrCreateCaptions.js.map +1 -1
  48. package/dist/tasks/generateScrubTrack.cjs +6 -9
  49. package/dist/tasks/generateScrubTrack.cjs.map +1 -1
  50. package/dist/tasks/generateScrubTrack.js +1 -2
  51. package/dist/tasks/generateScrubTrack.js.map +1 -1
  52. package/dist/tasks/generateTrack.cjs +21 -9
  53. package/dist/tasks/generateTrack.cjs.map +1 -1
  54. package/dist/tasks/generateTrack.js +17 -4
  55. package/dist/tasks/generateTrack.js.map +1 -1
  56. package/dist/tasks/generateTrackFragmentIndex.cjs +26 -11
  57. package/dist/tasks/generateTrackFragmentIndex.cjs.map +1 -1
  58. package/dist/tasks/generateTrackFragmentIndex.js +21 -5
  59. package/dist/tasks/generateTrackFragmentIndex.js.map +1 -1
  60. package/dist/truncateDecimal.cjs +1 -2
  61. package/dist/truncateDecimal.cjs.map +1 -1
  62. package/dist/truncateDecimal.js +1 -1
  63. package/dist/truncateDecimal.js.map +1 -1
  64. package/package.json +1 -1
@@ -7,7 +7,6 @@ import { unlink } from "node:fs/promises";
7
7
  import { tmpdir } from "node:os";
8
8
  import { join } from "node:path";
9
9
  import { randomBytes } from "node:crypto";
10
-
11
10
  //#region src/generateFragmentIndex.ts
12
11
  const log = debug("ef:generateFragmentIndex");
13
12
  const MIN_SEGMENT_DURATION_MS = 2e3;
@@ -418,7 +417,7 @@ const generateFragmentIndex = async (inputStream, startTimeOffsetMs, trackIdMapp
418
417
  }
419
418
  return trackIndexes;
420
419
  };
421
-
422
420
  //#endregion
423
421
  export { generateFragmentIndex };
422
+
424
423
  //# sourceMappingURL=generateFragmentIndex.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"generateFragmentIndex.js","names":["box: MP4BoxHeader","probe: PacketProbe","trackIndexes: Record<number, TrackFragmentIndex>","fragmentTimingData: FragmentTimingData[]","segments: TrackSegment[]","trackStartTimeOffsetMs: number | undefined"],"sources":["../src/generateFragmentIndex.ts"],"sourcesContent":["import { Readable, Transform, Writable } from \"node:stream\";\nimport { pipeline } from \"node:stream/promises\";\nimport { createWriteStream } from \"node:fs\";\nimport { unlink } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { randomBytes } from \"node:crypto\";\nimport debug from \"debug\";\nimport type { TrackFragmentIndex, TrackSegment } from \"./Probe.js\";\nimport { PacketProbe } from \"./Probe.js\";\n\nconst log = debug(\"ef:generateFragmentIndex\");\n\n// Minimum segment duration in milliseconds\nconst MIN_SEGMENT_DURATION_MS = 2000; // 2 seconds\nconst MS_PER_SECOND = 1000;\n\n// ============================================================================\n// Core Domain Types (Type Safety as Invariant Enforcement)\n// ============================================================================\n\n/** Raw packet from ffprobe - the fundamental unit of media data */\ninterface ProbePacket {\n stream_index: number;\n pts: number;\n dts: number;\n pts_time: number;\n dts_time: number;\n duration?: number;\n pos?: number;\n flags?: string;\n}\n\n/** Video packet with keyframe status - invariant: isKeyframe is always defined */\ninterface VideoPacket {\n pts: number;\n dts: number;\n duration?: number;\n isKeyframe: boolean;\n}\n\n/** Audio packet - simpler than video, no keyframe concept */\ninterface AudioPacket {\n pts: number;\n dts: number;\n duration?: number;\n}\n\n/** Fragment timing data - packets organized by fragment */\ninterface FragmentTimingData {\n fragmentIndex: number;\n videoPackets: VideoPacket[];\n audioPackets: AudioPacket[];\n}\n\n/** Timebase for timestamp conversion */\ninterface Timebase {\n num: number;\n den: number;\n}\n\n// Helper function to construct H.264 codec string from profile and level\nfunction constructH264CodecString(\n codecTagString: string,\n profile?: string,\n level?: number,\n): string {\n if (codecTagString !== \"avc1\" || !profile || level === undefined) {\n return codecTagString;\n }\n\n // Map H.264 profile names to profile_idc values\n const profileMap: Record<string, number> = {\n Baseline: 0x42,\n Main: 0x4d,\n High: 0x64,\n \"High 10\": 0x6e,\n \"High 422\": 0x7a,\n \"High 444\": 0xf4,\n };\n\n const profileIdc = profileMap[profile];\n if (!profileIdc) {\n return codecTagString;\n }\n\n // Format: avc1.PPCCLL where PP=profile_idc, CC=constraint_flags, LL=level_idc\n const profileHex = profileIdc.toString(16).padStart(2, \"0\");\n const constraintFlags = \"00\"; // Most common case\n const levelHex = level.toString(16).padStart(2, \"0\");\n\n return `${codecTagString}.${profileHex}${constraintFlags}${levelHex}`;\n}\n\ninterface MP4BoxHeader {\n type: string;\n offset: number;\n size: number;\n headerSize: number;\n}\n\ninterface Fragment {\n type: \"init\" | \"media\";\n offset: number;\n size: number;\n moofOffset?: number;\n mdatOffset?: number;\n}\n\n/**\n * Streaming MP4 box parser that detects box boundaries without loading entire file into memory\n */\nclass StreamingBoxParser extends Transform {\n private buffer = Buffer.alloc(0);\n private globalOffset = 0;\n private fragments: Fragment[] = [];\n private currentMoof: MP4BoxHeader | null = null;\n private initSegmentEnd = 0;\n private foundBoxes: MP4BoxHeader[] = [];\n\n constructor() {\n super({ objectMode: false });\n }\n\n _transform(chunk: Buffer, _encoding: BufferEncoding, callback: () => void) {\n // Append new data to our sliding buffer\n this.buffer = Buffer.concat([this.buffer, chunk]);\n\n // Parse all complete boxes in the current buffer\n this.parseBoxes();\n\n // Pass through the original chunk unchanged\n this.push(chunk);\n callback();\n }\n\n private parseBoxes() {\n let bufferOffset = 0;\n\n while (this.buffer.length - bufferOffset >= 8) {\n const size = this.buffer.readUInt32BE(bufferOffset);\n const type = this.buffer.subarray(bufferOffset + 4, bufferOffset + 8).toString(\"ascii\");\n\n // Invalid or incomplete box\n if (size === 0 || size < 8 || this.buffer.length < bufferOffset + size) {\n break;\n }\n\n const box: MP4BoxHeader = {\n type,\n offset: this.globalOffset + bufferOffset,\n size,\n headerSize: 8,\n };\n\n log(`Found box: ${box.type} at offset ${box.offset}, size ${box.size}`);\n this.foundBoxes.push(box);\n this.handleBox(box);\n\n bufferOffset += size;\n }\n\n // Update global offset and trim processed data from buffer\n this.globalOffset += bufferOffset;\n this.buffer = this.buffer.subarray(bufferOffset);\n }\n\n private handleBox(box: MP4BoxHeader) {\n switch (box.type) {\n case \"ftyp\":\n case \"moov\":\n // Part of init segment\n this.initSegmentEnd = Math.max(this.initSegmentEnd, box.offset + box.size);\n break;\n\n case \"moof\":\n this.currentMoof = box;\n break;\n\n case \"mdat\":\n if (this.currentMoof) {\n // Found a complete fragment (moof + mdat pair) - fragmented MP4\n this.fragments.push({\n type: \"media\",\n offset: this.currentMoof.offset,\n size: box.offset + box.size - this.currentMoof.offset,\n moofOffset: this.currentMoof.offset,\n mdatOffset: box.offset,\n });\n this.currentMoof = null;\n } else {\n // mdat without moof - this is non-fragmented content, not a fragment\n // Common in mixed MP4 files where initial content is non-fragmented\n // followed by fragmented content. Ignore for fragment indexing.\n log(`Found non-fragmented mdat at offset ${box.offset}, skipping for fragment index`);\n }\n break;\n }\n }\n\n _flush(callback: () => void) {\n this.parseBoxes(); // Process any remaining buffered data\n\n // Probe always outputs fragmented MP4\n // Init segment is ftyp + moov boxes before the first moof\n if (this.initSegmentEnd > 0) {\n this.fragments.unshift({\n type: \"init\",\n offset: 0,\n size: this.initSegmentEnd,\n });\n }\n\n callback();\n }\n\n getFragments(): Fragment[] {\n return this.fragments;\n }\n}\n\n// Helper to convert timestamp from ffprobe timebase to track timescale\nfunction convertTimestamp(pts: number, timebase: Timebase, timescale: number): number {\n return Math.round((pts * timescale) / timebase.den);\n}\n\n// Helper to calculate duration in milliseconds from timescale units\nfunction durationMsFromTimescale(durationTimescale: number, timescale: number): number {\n return (durationTimescale / timescale) * MS_PER_SECOND;\n}\n\n// Helper to calculate segment byte range from accumulated fragments\nfunction calculateSegmentByteRange(accumulatedFragments: Array<{ fragment: Fragment }>): {\n offset: number;\n size: number;\n} {\n const firstFrag = accumulatedFragments[0]!;\n const lastFrag = accumulatedFragments[accumulatedFragments.length - 1]!;\n return {\n offset: firstFrag.fragment.offset,\n size: lastFrag.fragment.offset + lastFrag.fragment.size - firstFrag.fragment.offset,\n };\n}\n\n// Explicit enumeration of segment accumulation state (Enumerate the Core Concept)\ntype SegmentAccumulationState =\n | { type: \"idle\" }\n | {\n type: \"accumulating\";\n startPts: number;\n startDts: number;\n fragments: Array<{\n fragment: Fragment;\n fragmentData: FragmentTimingData;\n }>;\n };\n\n// Invariant: Segment must start on keyframe (for video) and have minimum duration\ninterface SegmentEvaluation {\n cts: number;\n dts: number;\n duration: number;\n offset: number;\n size: number;\n}\n\n// Track processing context - single source of truth for track processing\ninterface TrackProcessingContext {\n timebase: Timebase;\n timescale: number;\n fragmentTimingData: FragmentTimingData[];\n mediaFragments: Fragment[];\n // Cached filtered packets for this stream (Performance Through Caching)\n streamPackets: ProbePacket[];\n streamType: \"video\" | \"audio\";\n streamIndex: number;\n}\n\n// Segment accumulator that encapsulates accumulation logic\nclass SegmentAccumulator {\n private state: SegmentAccumulationState = { type: \"idle\" };\n private readonly context: TrackProcessingContext;\n private readonly minDurationMs: number;\n\n constructor(context: TrackProcessingContext, minDurationMs: number) {\n this.context = context;\n this.minDurationMs = minDurationMs;\n }\n\n // Evaluation: Determine if we should finalize (semantics)\n shouldFinalize(nextKeyframe: { pts: number; dts: number } | null): boolean {\n if (this.state.type !== \"accumulating\") {\n return false;\n }\n\n const durationMs = this.calculateAccumulatedDurationMs();\n const hasMinimumDuration = durationMs >= this.minDurationMs;\n\n // For video: finalize on keyframe + minimum duration\n // For audio: finalize on minimum duration (no keyframe requirement)\n if (this.context.streamType === \"video\") {\n return hasMinimumDuration && nextKeyframe !== null;\n } else {\n return hasMinimumDuration;\n }\n }\n\n // Evaluation: Calculate what the segment would be (semantics)\n evaluateSegment(nextBoundary: { pts: number } | null): SegmentEvaluation | null {\n if (this.state.type !== \"accumulating\") {\n return null;\n }\n\n const segmentCts = convertTimestamp(\n this.state.startPts,\n this.context.timebase,\n this.context.timescale,\n );\n const segmentDts = convertTimestamp(\n this.state.startDts,\n this.context.timebase,\n this.context.timescale,\n );\n const segmentDuration = this.calculateSegmentDuration(segmentCts, nextBoundary);\n const { offset, size } = calculateSegmentByteRange(this.state.fragments);\n\n return {\n cts: segmentCts,\n dts: segmentDts,\n duration: segmentDuration,\n offset,\n size,\n };\n }\n\n // Application: Add fragment to accumulation (mechanism)\n addFragment(fragment: Fragment, fragmentData: FragmentTimingData): void {\n if (this.state.type === \"idle\") {\n // Start accumulation - invariant: video segments must start on keyframe\n const startPts = this.getStartPts(fragmentData);\n const startDts = this.getStartDts(fragmentData);\n this.state = {\n type: \"accumulating\",\n startPts,\n startDts,\n fragments: [{ fragment, fragmentData }],\n };\n } else {\n // Continue accumulation\n this.state.fragments.push({ fragment, fragmentData });\n }\n }\n\n // Application: Reset accumulation (mechanism)\n reset(): void {\n this.state = { type: \"idle\" };\n }\n\n // Application: Start new segment with keyframe (mechanism)\n startNewSegment(keyframe: { pts: number; dts: number }): void {\n this.state = {\n type: \"accumulating\",\n startPts: keyframe.pts,\n startDts: keyframe.dts,\n fragments: [],\n };\n }\n\n // Query: Get current state\n getState(): SegmentAccumulationState {\n return this.state;\n }\n\n // Query: Check if accumulating\n isAccumulating(): boolean {\n return this.state.type === \"accumulating\";\n }\n\n // Private helpers\n private calculateAccumulatedDurationMs(): number {\n if (this.state.type !== \"accumulating\") {\n return 0;\n }\n\n const lastFrag = this.state.fragments[this.state.fragments.length - 1]!;\n const lastPacket = this.getLastPacket(lastFrag.fragmentData);\n const endCts = convertTimestamp(\n lastPacket.pts + (lastPacket.duration || 0),\n this.context.timebase,\n this.context.timescale,\n );\n const startCts = convertTimestamp(\n this.state.startPts,\n this.context.timebase,\n this.context.timescale,\n );\n return durationMsFromTimescale(endCts - startCts, this.context.timescale);\n }\n\n private calculateSegmentDuration(\n segmentCts: number,\n nextBoundary: { pts: number } | null,\n ): number {\n if (nextBoundary) {\n const nextSegmentCts = convertTimestamp(\n nextBoundary.pts,\n this.context.timebase,\n this.context.timescale,\n );\n return nextSegmentCts - segmentCts;\n }\n\n // Last segment: duration to end of all packets\n // Use pre-cached streamPackets (Performance Through Caching)\n const sortedPackets = [...this.context.streamPackets].sort((a, b) => a.pts - b.pts);\n const lastPacket = sortedPackets[sortedPackets.length - 1]!;\n const streamEnd = convertTimestamp(\n lastPacket.pts + (lastPacket.duration || 0),\n this.context.timebase,\n this.context.timescale,\n );\n return streamEnd - segmentCts;\n }\n\n private getStartPts(fragmentData: FragmentTimingData): number {\n if (this.context.streamType === \"video\") {\n const keyframe = fragmentData.videoPackets.find((p) => p.isKeyframe);\n return keyframe?.pts ?? fragmentData.videoPackets[0]?.pts ?? 0;\n } else {\n return fragmentData.audioPackets[0]?.pts ?? 0;\n }\n }\n\n private getStartDts(fragmentData: FragmentTimingData): number {\n if (this.context.streamType === \"video\") {\n const keyframe = fragmentData.videoPackets.find((p) => p.isKeyframe);\n return keyframe?.dts ?? fragmentData.videoPackets[0]?.dts ?? 0;\n } else {\n return fragmentData.audioPackets[0]?.dts ?? 0;\n }\n }\n\n private getLastPacket(fragmentData: FragmentTimingData): {\n pts: number;\n duration?: number;\n } {\n if (this.context.streamType === \"video\") {\n const packets = fragmentData.videoPackets;\n return packets[packets.length - 1]!;\n } else {\n const packets = fragmentData.audioPackets;\n return packets[packets.length - 1]!;\n }\n }\n}\n\n// Helper function to extract fragment data (init + media fragment)\n\nexport const generateFragmentIndex = async (\n inputStream: Readable,\n startTimeOffsetMs?: number,\n trackIdMapping?: Record<number, number>, // Map from source track ID to desired track ID\n options?: { tmpDir?: string },\n): Promise<Record<number, TrackFragmentIndex>> => {\n // Step 1: Create a streaming parser that detects fragment boundaries\n const parser = new StreamingBoxParser();\n\n // Step 2: Write stream to a temp file to avoid buffering the entire MP4 in memory\n const tempDir = options?.tmpDir ?? tmpdir();\n const tempFile = join(tempDir, `ef-probe-${randomBytes(8).toString(\"hex\")}.mp4`);\n let totalSize = 0;\n\n const dest = new Writable({\n write(chunk, _encoding, callback) {\n totalSize += chunk.length;\n callback();\n },\n });\n\n const tempWriteStream = createWriteStream(tempFile);\n\n // Split input through both parser (for fragment detection) and temp file (for probing)\n // We must tee the stream: pipe inputStream → parser → dest, and also write to tempFile\n const teeTransform = new Transform({\n transform(chunk, _encoding, callback) {\n tempWriteStream.write(chunk);\n this.push(chunk);\n callback();\n },\n flush(callback) {\n tempWriteStream.end(() => callback());\n },\n });\n\n // Process the stream through both parser and collection\n await pipeline(inputStream, teeTransform, parser, dest);\n const fragments = parser.getFragments();\n\n // If no data was collected, clean up and return empty result\n if (totalSize === 0) {\n await unlink(tempFile).catch(() => {});\n return {};\n }\n\n // Step 3: Use ffprobe to analyze the temp file for track metadata (avoids in-memory buffering)\n let probe: PacketProbe;\n try {\n probe = await PacketProbe.probePath(tempFile);\n } catch (error) {\n console.warn(\"Failed to probe stream with ffprobe:\", error);\n await unlink(tempFile).catch(() => {});\n return {};\n } finally {\n await unlink(tempFile).catch(() => {});\n }\n\n const videoStreams = probe.videoStreams;\n const audioStreams = probe.audioStreams;\n\n const trackIndexes: Record<number, TrackFragmentIndex> = {};\n const initFragment = fragments.find((f) => f.type === \"init\");\n const mediaFragments = fragments.filter((f) => f.type === \"media\");\n\n // Map packets to fragments using byte position for moof+mdat boundaries\n // But create contiguous segments based on keyframes\n const fragmentTimingData: FragmentTimingData[] = [];\n\n for (let fragmentIndex = 0; fragmentIndex < mediaFragments.length; fragmentIndex++) {\n const fragment = mediaFragments[fragmentIndex]!;\n\n // Find packets that belong to this fragment based on byte position (moof+mdat boundaries)\n const fragmentStart = fragment.offset;\n const fragmentEnd = fragment.offset + fragment.size;\n\n const videoPackets = probe.packets\n .filter((packet) => {\n const stream = videoStreams.find((s) => s.index === packet.stream_index);\n return (\n stream?.codec_type === \"video\" &&\n packet.pos !== undefined &&\n packet.pos >= fragmentStart &&\n packet.pos < fragmentEnd\n );\n })\n .map((packet) => ({\n pts: packet.pts,\n dts: packet.dts,\n duration: packet.duration,\n isKeyframe: packet.flags?.includes(\"K\") ?? false,\n }));\n\n const audioPackets = probe.packets\n .filter((packet) => {\n const stream = audioStreams.find((s) => s.index === packet.stream_index);\n return (\n stream?.codec_type === \"audio\" &&\n packet.pos !== undefined &&\n packet.pos >= fragmentStart &&\n packet.pos < fragmentEnd\n );\n })\n .map((packet) => ({\n pts: packet.pts,\n dts: packet.dts,\n duration: packet.duration,\n }));\n\n fragmentTimingData.push({\n fragmentIndex,\n videoPackets,\n audioPackets,\n });\n }\n\n // Unified track processing function (One Direction of Truth)\n const processTrack = (\n streamIndex: number,\n streamType: \"video\" | \"audio\",\n timebase: Timebase,\n allPackets: ProbePacket[],\n ): TrackSegment[] => {\n const segments: TrackSegment[] = [];\n const timescale = Math.round(timebase.den / timebase.num);\n\n // Cache filtered packets once (Performance Through Caching)\n const streamPackets = allPackets.filter((p) => p.stream_index === streamIndex);\n\n const context: TrackProcessingContext = {\n timebase,\n timescale,\n fragmentTimingData,\n mediaFragments,\n streamPackets,\n streamType,\n streamIndex,\n };\n\n const accumulator = new SegmentAccumulator(context, MIN_SEGMENT_DURATION_MS);\n\n for (let i = 0; i < fragmentTimingData.length; i++) {\n const fragmentData = fragmentTimingData[i]!;\n const fragment = mediaFragments[fragmentData.fragmentIndex]!;\n const packets =\n streamType === \"video\" ? fragmentData.videoPackets : fragmentData.audioPackets;\n\n log(`Fragment ${fragmentData.fragmentIndex}: ${packets.length} ${streamType} packets`);\n\n if (packets.length === 0) {\n log(`Skipping fragment ${fragmentData.fragmentIndex} - no ${streamType} packets`);\n continue;\n }\n\n if (streamType === \"video\") {\n // Video: segments must start on keyframes\n const keyframe = fragmentData.videoPackets.find((p) => p.isKeyframe);\n const hasKeyframe = keyframe !== undefined;\n\n // Start new segment on keyframe if none exists\n if (!accumulator.isAccumulating() && hasKeyframe) {\n accumulator.startNewSegment({\n pts: keyframe.pts,\n dts: keyframe.dts,\n });\n accumulator.addFragment(fragment, fragmentData);\n continue;\n }\n\n // Skip fragments without keyframes if no segment started\n if (!accumulator.isAccumulating()) {\n continue;\n }\n\n // Check if we should finalize when encountering a new keyframe\n if (hasKeyframe) {\n if (accumulator.shouldFinalize({ pts: keyframe.pts, dts: keyframe.dts })) {\n // Duration should be to the start of this keyframe (start of next segment)\n const nextBoundary = { pts: keyframe.pts };\n const evaluation = accumulator.evaluateSegment(nextBoundary);\n if (evaluation) {\n segments.push(evaluation);\n }\n accumulator.reset();\n accumulator.startNewSegment({\n pts: keyframe.pts,\n dts: keyframe.dts,\n });\n }\n }\n } else {\n // Audio: no keyframe requirement, just duration-based\n if (!accumulator.isAccumulating()) {\n accumulator.addFragment(fragment, fragmentData);\n continue;\n }\n\n // Check if we should finalize based on accumulated duration\n if (accumulator.shouldFinalize(null)) {\n // Duration should be to the start of this fragment (start of next segment)\n const nextBoundary = { pts: fragmentData.audioPackets[0]!.pts };\n const evaluation = accumulator.evaluateSegment(nextBoundary);\n if (evaluation) {\n segments.push(evaluation);\n }\n accumulator.reset();\n }\n }\n\n // Add fragment to current segment\n accumulator.addFragment(fragment, fragmentData);\n }\n\n // Finalize any remaining accumulated fragments\n if (accumulator.isAccumulating()) {\n const evaluation = accumulator.evaluateSegment(null);\n if (evaluation) {\n segments.push(evaluation);\n }\n }\n\n return segments;\n };\n\n // Step 4: Process video tracks using ffprobe data\n for (const videoStream of videoStreams) {\n // Get timebase for this stream to convert timestamps\n const timebase = probe.videoTimebase;\n if (!timebase) {\n console.warn(\"No timebase found for video stream\");\n continue;\n }\n\n const timescale = Math.round(timebase.den / timebase.num);\n\n // Cache filtered packets once (Performance Through Caching)\n const streamPackets = (probe.packets as ProbePacket[]).filter(\n (p) => p.stream_index === videoStream.index,\n );\n const keyframeCount = streamPackets.filter((p) => p.flags?.includes(\"K\")).length;\n const totalSampleCount = streamPackets.length;\n\n log(\n `Complete stream has ${streamPackets.length} video packets, ${keyframeCount} keyframes for stream ${videoStream.index}`,\n );\n\n // Calculate per-track timing offset from first packet for timeline mapping\n let trackStartTimeOffsetMs: number | undefined;\n if (streamPackets.length > 0) {\n log(\n `First video packet dts_time: ${streamPackets[0]!.dts_time}, pts_time: ${streamPackets[0]!.pts_time}`,\n );\n const presentationTime = streamPackets[0]!.pts_time;\n if (Math.abs(presentationTime) > 0.01) {\n trackStartTimeOffsetMs = presentationTime * MS_PER_SECOND;\n }\n }\n if (startTimeOffsetMs !== undefined) {\n trackStartTimeOffsetMs = startTimeOffsetMs;\n }\n\n // Process fragments to create segments with minimum duration\n const segments = processTrack(\n videoStream.index,\n \"video\",\n timebase,\n probe.packets as ProbePacket[],\n );\n\n // Calculate total duration from cached stream packets (inclusive of last frame duration)\n let totalDuration = 0;\n if (streamPackets.length > 0) {\n const firstPacket = streamPackets[0]!;\n const lastPacket = streamPackets[streamPackets.length - 1]!;\n const firstPts = convertTimestamp(firstPacket.pts, timebase, timescale);\n const lastPts = convertTimestamp(lastPacket.pts, timebase, timescale);\n const lastDuration = convertTimestamp(lastPacket.duration ?? 0, timebase, timescale);\n totalDuration = lastPts - firstPts + lastDuration;\n }\n\n const finalTrackId = trackIdMapping?.[videoStream.index] ?? videoStream.index + 1;\n trackIndexes[finalTrackId] = {\n track: finalTrackId,\n type: \"video\",\n width: videoStream.coded_width || videoStream.width,\n height: videoStream.coded_height || videoStream.height,\n timescale: timescale,\n sample_count: totalSampleCount,\n codec: constructH264CodecString(\n videoStream.codec_tag_string,\n videoStream.profile,\n videoStream.level,\n ),\n duration: totalDuration,\n startTimeOffsetMs: trackStartTimeOffsetMs,\n initSegment: {\n offset: 0,\n size: initFragment?.size || 0,\n },\n segments,\n };\n }\n\n // Step 5: Process audio tracks using ffprobe data\n for (const audioStream of audioStreams) {\n // Get timebase for this stream to convert timestamps\n const timebase = probe.audioTimebase;\n if (!timebase) {\n console.warn(\"No timebase found for audio stream\");\n continue;\n }\n\n const timescale = Math.round(timebase.den / timebase.num);\n\n // Cache filtered packets once (Performance Through Caching)\n const streamPackets = (probe.packets as ProbePacket[]).filter(\n (p) => p.stream_index === audioStream.index,\n );\n const totalSampleCount = streamPackets.length;\n\n // Calculate per-track timing offset from first packet for timeline mapping\n let trackStartTimeOffsetMs: number | undefined;\n if (streamPackets.length > 0) {\n const presentationTime = streamPackets[0]!.pts_time;\n if (Math.abs(presentationTime) > 0.01) {\n trackStartTimeOffsetMs = presentationTime * MS_PER_SECOND;\n }\n }\n if (startTimeOffsetMs !== undefined) {\n trackStartTimeOffsetMs = startTimeOffsetMs;\n }\n\n // Process fragments to create segments with minimum duration\n const segments = processTrack(\n audioStream.index,\n \"audio\",\n timebase,\n probe.packets as ProbePacket[],\n );\n\n // Calculate total duration\n const totalDuration = segments.reduce((sum, seg) => sum + seg.duration, 0);\n\n const finalTrackId = trackIdMapping?.[audioStream.index] ?? audioStream.index + 1;\n trackIndexes[finalTrackId] = {\n track: finalTrackId,\n type: \"audio\",\n channel_count: audioStream.channels,\n sample_rate: Number(audioStream.sample_rate),\n sample_size: audioStream.bits_per_sample,\n sample_count: totalSampleCount,\n timescale: timescale,\n codec: audioStream.codec_tag_string || audioStream.codec_name || \"\",\n duration: totalDuration,\n startTimeOffsetMs: trackStartTimeOffsetMs,\n initSegment: {\n offset: 0,\n size: initFragment?.size || 0,\n },\n segments,\n };\n }\n\n return trackIndexes;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"generateFragmentIndex.js","names":[],"sources":["../src/generateFragmentIndex.ts"],"mappings":"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"}
@@ -1,14 +1,11 @@
1
- const require_rolldown_runtime = require('./_virtual/rolldown_runtime.cjs');
2
- const require_Probe = require('./Probe.cjs');
3
- const require_generateFragmentIndex = require('./generateFragmentIndex.cjs');
4
- const require_idempotentTask = require('./idempotentTask.cjs');
1
+ const require_runtime = require("./_virtual/_rolldown/runtime.cjs");
2
+ const require_Probe = require("./Probe.cjs");
3
+ const require_generateFragmentIndex = require("./generateFragmentIndex.cjs");
4
+ const require_idempotentTask = require("./idempotentTask.cjs");
5
5
  let debug = require("debug");
6
- debug = require_rolldown_runtime.__toESM(debug);
6
+ debug = require_runtime.__toESM(debug);
7
7
  let node_stream = require("node:stream");
8
- node_stream = require_rolldown_runtime.__toESM(node_stream);
9
8
  let node_path = require("node:path");
10
- node_path = require_rolldown_runtime.__toESM(node_path);
11
-
12
9
  //#region src/generateSingleTrack.ts
13
10
  const log = (0, debug.default)("ef:generateSingleTrack");
14
11
  const generateSingleTrackFromPath = async (absolutePath, trackId) => {
@@ -43,7 +40,7 @@ const generateSingleTrackFromPath = async (absolutePath, trackId) => {
43
40
  fragmentIndex: fragmentIndexPromise
44
41
  };
45
42
  };
46
- const generateSingleTrackTask = require_idempotentTask.idempotentTask({
43
+ require_idempotentTask.idempotentTask({
47
44
  label: "track-single",
48
45
  filename: (absolutePath, trackId) => `${(0, node_path.basename)(absolutePath)}.track-${trackId}.mp4`,
49
46
  runner: async (absolutePath, trackId) => {
@@ -76,7 +73,7 @@ const generateSingleTrackTask = require_idempotentTask.idempotentTask({
76
73
  return finalStream;
77
74
  }
78
75
  });
79
-
80
76
  //#endregion
81
77
  exports.generateSingleTrackFromPath = generateSingleTrackFromPath;
78
+
82
79
  //# sourceMappingURL=generateSingleTrack.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"generateSingleTrack.cjs","names":["Probe","PassThrough","generateFragmentIndex","idempotentTask","progressTimeout: NodeJS.Timeout | null"],"sources":["../src/generateSingleTrack.ts"],"sourcesContent":["import { idempotentTask } from \"./idempotentTask.js\";\nimport debug from \"debug\";\nimport { PassThrough } from \"node:stream\";\nimport { basename } from \"node:path\";\nimport { Probe } from \"./Probe.js\";\nimport { generateFragmentIndex } from \"./generateFragmentIndex.js\";\n\nconst log = debug(\"ef:generateSingleTrack\");\n\nexport const generateSingleTrackFromPath = async (absolutePath: string, trackId: number) => {\n log(`Generating track ${trackId} for ${absolutePath}`);\n\n const probe = await Probe.probePath(absolutePath);\n\n // Map track ID (1-based) to stream index (0-based) - tracks use 1-based IDs, streams use 0-based indices\n const streamIndex = trackId - 1;\n\n if (streamIndex < 0 || streamIndex >= probe.streams.length) {\n throw new Error(`Track ${trackId} not found (valid tracks: 1-${probe.streams.length})`);\n }\n\n // Get the track stream from FFmpeg (single track, fragmented MP4)\n const trackStream = probe.createTrackReadstream(streamIndex);\n\n // Create a PassThrough to tee the stream\n const outputStream = new PassThrough();\n const indexStream = new PassThrough();\n\n // Pipe data but DON'T end outputStream automatically - we'll control this\n trackStream.pipe(outputStream, { end: false });\n trackStream.pipe(indexStream);\n\n // Track when the source stream ends (but don't end output yet)\n let sourceStreamEnded = false;\n trackStream.on(\"end\", () => {\n sourceStreamEnded = true;\n });\n\n trackStream.on(\"error\", (error) => {\n outputStream.destroy(error);\n indexStream.destroy(error);\n });\n\n // Generate fragment index from the single-track stream\n // This will be a single-track index since we're processing isolated track\n // Map the single-track file's track ID 1 to the original multi-track ID\n const trackIdMapping = { 1: trackId }; // Single track 1 -> original trackId\n const fragmentIndexPromise = generateFragmentIndex(indexStream, undefined, trackIdMapping);\n\n // End outputStream only after BOTH source ends AND fragment index completes\n fragmentIndexPromise\n .then(() => {\n if (sourceStreamEnded) {\n outputStream.end();\n } else {\n // If fragment index completes first, wait for stream to end\n trackStream.once(\"end\", () => {\n outputStream.end();\n });\n }\n })\n .catch((error) => {\n outputStream.destroy(error);\n });\n\n // Return both the stream and the index\n return {\n stream: outputStream,\n fragmentIndex: fragmentIndexPromise,\n };\n};\n\nexport const generateSingleTrackTask = idempotentTask({\n label: \"track-single\",\n filename: (absolutePath: string, trackId: number) =>\n `${basename(absolutePath)}.track-${trackId}.mp4`,\n runner: async (absolutePath: string, trackId: number) => {\n const result = await generateSingleTrackFromPath(absolutePath, trackId);\n\n // Create a PassThrough stream that processes fragment index in parallel\n const finalStream = new PassThrough();\n\n // Start fragment index processing immediately (don't wait for stream to end)\n const fragmentIndexPromise = result.fragmentIndex.catch((error) => {\n console.warn(`Fragment index generation failed for track ${trackId}:`, error);\n // Don't fail the stream if fragment index fails\n });\n\n // Monitor progress and extend timeout based on actual work\n let progressTimeout: NodeJS.Timeout | null = null;\n\n const resetProgressTimeout = () => {\n if (progressTimeout) {\n clearTimeout(progressTimeout);\n }\n\n progressTimeout = setTimeout(() => {\n if (!finalStream.destroyed) {\n console.warn(\n `Progress timeout triggered for track ${trackId} - no activity for 10 seconds`,\n );\n finalStream.end();\n }\n }, 10000); // 10 second sliding timeout\n };\n\n // Start the initial timeout\n resetProgressTimeout();\n\n // Monitor data flow to detect active work\n result.stream.on(\"data\", () => {\n resetProgressTimeout(); // Reset timeout when we see data\n });\n\n result.stream.on(\"end\", () => {\n resetProgressTimeout(); // Reset timeout when stream ends\n });\n\n // Pipe data through but don't end until fragment index is ready\n result.stream.pipe(finalStream, { end: false });\n\n // Wait for fragment index to complete, then end the stream\n await fragmentIndexPromise;\n finalStream.end();\n\n // Clean up timeout\n if (progressTimeout) {\n clearTimeout(progressTimeout);\n }\n\n return finalStream;\n },\n});\n\nexport const generateSingleTrack = async (cacheRoot: string, absolutePath: string, url: string) => {\n try {\n const trackId = new URL(`http://localhost${url}`).searchParams.get(\"trackId\");\n if (trackId === null) {\n throw new Error(\"No trackId provided. It must be specified in the query string: ?trackId=0\");\n }\n return await generateSingleTrackTask(cacheRoot, absolutePath, Number(trackId));\n } catch (error) {\n console.error(error);\n console.trace(\"Error generating track\", error);\n throw error;\n }\n};\n"],"mappings":";;;;;;;;;;;;AAOA,MAAM,yBAAY,yBAAyB;AAE3C,MAAa,8BAA8B,OAAO,cAAsB,YAAoB;AAC1F,KAAI,oBAAoB,QAAQ,OAAO,eAAe;CAEtD,MAAM,QAAQ,MAAMA,oBAAM,UAAU,aAAa;CAGjD,MAAM,cAAc,UAAU;AAE9B,KAAI,cAAc,KAAK,eAAe,MAAM,QAAQ,OAClD,OAAM,IAAI,MAAM,SAAS,QAAQ,8BAA8B,MAAM,QAAQ,OAAO,GAAG;CAIzF,MAAM,cAAc,MAAM,sBAAsB,YAAY;CAG5D,MAAM,eAAe,IAAIC,yBAAa;CACtC,MAAM,cAAc,IAAIA,yBAAa;AAGrC,aAAY,KAAK,cAAc,EAAE,KAAK,OAAO,CAAC;AAC9C,aAAY,KAAK,YAAY;CAG7B,IAAI,oBAAoB;AACxB,aAAY,GAAG,aAAa;AAC1B,sBAAoB;GACpB;AAEF,aAAY,GAAG,UAAU,UAAU;AACjC,eAAa,QAAQ,MAAM;AAC3B,cAAY,QAAQ,MAAM;GAC1B;CAMF,MAAM,uBAAuBC,oDAAsB,aAAa,QADzC,EAAE,GAAG,SAAS,CACqD;AAG1F,sBACG,WAAW;AACV,MAAI,kBACF,cAAa,KAAK;MAGlB,aAAY,KAAK,aAAa;AAC5B,gBAAa,KAAK;IAClB;GAEJ,CACD,OAAO,UAAU;AAChB,eAAa,QAAQ,MAAM;GAC3B;AAGJ,QAAO;EACL,QAAQ;EACR,eAAe;EAChB;;AAGH,MAAa,0BAA0BC,sCAAe;CACpD,OAAO;CACP,WAAW,cAAsB,YAC/B,2BAAY,aAAa,CAAC,SAAS,QAAQ;CAC7C,QAAQ,OAAO,cAAsB,YAAoB;EACvD,MAAM,SAAS,MAAM,4BAA4B,cAAc,QAAQ;EAGvE,MAAM,cAAc,IAAIF,yBAAa;EAGrC,MAAM,uBAAuB,OAAO,cAAc,OAAO,UAAU;AACjE,WAAQ,KAAK,8CAA8C,QAAQ,IAAI,MAAM;IAE7E;EAGF,IAAIG,kBAAyC;EAE7C,MAAM,6BAA6B;AACjC,OAAI,gBACF,cAAa,gBAAgB;AAG/B,qBAAkB,iBAAiB;AACjC,QAAI,CAAC,YAAY,WAAW;AAC1B,aAAQ,KACN,wCAAwC,QAAQ,+BACjD;AACD,iBAAY,KAAK;;MAElB,IAAM;;AAIX,wBAAsB;AAGtB,SAAO,OAAO,GAAG,cAAc;AAC7B,yBAAsB;IACtB;AAEF,SAAO,OAAO,GAAG,aAAa;AAC5B,yBAAsB;IACtB;AAGF,SAAO,OAAO,KAAK,aAAa,EAAE,KAAK,OAAO,CAAC;AAG/C,QAAM;AACN,cAAY,KAAK;AAGjB,MAAI,gBACF,cAAa,gBAAgB;AAG/B,SAAO;;CAEV,CAAC"}
1
+ {"version":3,"file":"generateSingleTrack.cjs","names":["Probe","PassThrough","generateFragmentIndex","idempotentTask"],"sources":["../src/generateSingleTrack.ts"],"mappings":";;;;;;;;;AAOA,MAAM,OAAA,GAAA,MAAA,SAAY,yBAAyB;AAE3C,MAAa,8BAA8B,OAAO,cAAsB,YAAoB;AAC1F,KAAI,oBAAoB,QAAQ,OAAO,eAAe;CAEtD,MAAM,QAAQ,MAAMA,cAAAA,MAAM,UAAU,aAAa;CAGjD,MAAM,cAAc,UAAU;AAE9B,KAAI,cAAc,KAAK,eAAe,MAAM,QAAQ,OAClD,OAAM,IAAI,MAAM,SAAS,QAAQ,8BAA8B,MAAM,QAAQ,OAAO,GAAG;CAIzF,MAAM,cAAc,MAAM,sBAAsB,YAAY;CAG5D,MAAM,eAAe,IAAIC,YAAAA,aAAa;CACtC,MAAM,cAAc,IAAIA,YAAAA,aAAa;AAGrC,aAAY,KAAK,cAAc,EAAE,KAAK,OAAO,CAAC;AAC9C,aAAY,KAAK,YAAY;CAG7B,IAAI,oBAAoB;AACxB,aAAY,GAAG,aAAa;AAC1B,sBAAoB;GACpB;AAEF,aAAY,GAAG,UAAU,UAAU;AACjC,eAAa,QAAQ,MAAM;AAC3B,cAAY,QAAQ,MAAM;GAC1B;CAMF,MAAM,uBAAuBC,8BAAAA,sBAAsB,aAAa,KAAA,GADzC,EAAE,GAAG,SAAS,CACqD;AAG1F,sBACG,WAAW;AACV,MAAI,kBACF,cAAa,KAAK;MAGlB,aAAY,KAAK,aAAa;AAC5B,gBAAa,KAAK;IAClB;GAEJ,CACD,OAAO,UAAU;AAChB,eAAa,QAAQ,MAAM;GAC3B;AAGJ,QAAO;EACL,QAAQ;EACR,eAAe;EAChB;;AAGoCC,uBAAAA,eAAe;CACpD,OAAO;CACP,WAAW,cAAsB,YAC/B,IAAA,GAAA,UAAA,UAAY,aAAa,CAAC,SAAS,QAAQ;CAC7C,QAAQ,OAAO,cAAsB,YAAoB;EACvD,MAAM,SAAS,MAAM,4BAA4B,cAAc,QAAQ;EAGvE,MAAM,cAAc,IAAIF,YAAAA,aAAa;EAGrC,MAAM,uBAAuB,OAAO,cAAc,OAAO,UAAU;AACjE,WAAQ,KAAK,8CAA8C,QAAQ,IAAI,MAAM;IAE7E;EAGF,IAAI,kBAAyC;EAE7C,MAAM,6BAA6B;AACjC,OAAI,gBACF,cAAa,gBAAgB;AAG/B,qBAAkB,iBAAiB;AACjC,QAAI,CAAC,YAAY,WAAW;AAC1B,aAAQ,KACN,wCAAwC,QAAQ,+BACjD;AACD,iBAAY,KAAK;;MAElB,IAAM;;AAIX,wBAAsB;AAGtB,SAAO,OAAO,GAAG,cAAc;AAC7B,yBAAsB;IACtB;AAEF,SAAO,OAAO,GAAG,aAAa;AAC5B,yBAAsB;IACtB;AAGF,SAAO,OAAO,KAAK,aAAa,EAAE,KAAK,OAAO,CAAC;AAG/C,QAAM;AACN,cAAY,KAAK;AAGjB,MAAI,gBACF,cAAa,gBAAgB;AAG/B,SAAO;;CAEV,CAAC"}
@@ -4,7 +4,6 @@ import { idempotentTask } from "./idempotentTask.js";
4
4
  import debug from "debug";
5
5
  import { PassThrough } from "node:stream";
6
6
  import { basename } from "node:path";
7
-
8
7
  //#region src/generateSingleTrack.ts
9
8
  const log = debug("ef:generateSingleTrack");
10
9
  const generateSingleTrackFromPath = async (absolutePath, trackId) => {
@@ -39,7 +38,7 @@ const generateSingleTrackFromPath = async (absolutePath, trackId) => {
39
38
  fragmentIndex: fragmentIndexPromise
40
39
  };
41
40
  };
42
- const generateSingleTrackTask = idempotentTask({
41
+ idempotentTask({
43
42
  label: "track-single",
44
43
  filename: (absolutePath, trackId) => `${basename(absolutePath)}.track-${trackId}.mp4`,
45
44
  runner: async (absolutePath, trackId) => {
@@ -72,7 +71,7 @@ const generateSingleTrackTask = idempotentTask({
72
71
  return finalStream;
73
72
  }
74
73
  });
75
-
76
74
  //#endregion
77
75
  export { generateSingleTrackFromPath };
76
+
78
77
  //# sourceMappingURL=generateSingleTrack.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"generateSingleTrack.js","names":["progressTimeout: NodeJS.Timeout | null"],"sources":["../src/generateSingleTrack.ts"],"sourcesContent":["import { idempotentTask } from \"./idempotentTask.js\";\nimport debug from \"debug\";\nimport { PassThrough } from \"node:stream\";\nimport { basename } from \"node:path\";\nimport { Probe } from \"./Probe.js\";\nimport { generateFragmentIndex } from \"./generateFragmentIndex.js\";\n\nconst log = debug(\"ef:generateSingleTrack\");\n\nexport const generateSingleTrackFromPath = async (absolutePath: string, trackId: number) => {\n log(`Generating track ${trackId} for ${absolutePath}`);\n\n const probe = await Probe.probePath(absolutePath);\n\n // Map track ID (1-based) to stream index (0-based) - tracks use 1-based IDs, streams use 0-based indices\n const streamIndex = trackId - 1;\n\n if (streamIndex < 0 || streamIndex >= probe.streams.length) {\n throw new Error(`Track ${trackId} not found (valid tracks: 1-${probe.streams.length})`);\n }\n\n // Get the track stream from FFmpeg (single track, fragmented MP4)\n const trackStream = probe.createTrackReadstream(streamIndex);\n\n // Create a PassThrough to tee the stream\n const outputStream = new PassThrough();\n const indexStream = new PassThrough();\n\n // Pipe data but DON'T end outputStream automatically - we'll control this\n trackStream.pipe(outputStream, { end: false });\n trackStream.pipe(indexStream);\n\n // Track when the source stream ends (but don't end output yet)\n let sourceStreamEnded = false;\n trackStream.on(\"end\", () => {\n sourceStreamEnded = true;\n });\n\n trackStream.on(\"error\", (error) => {\n outputStream.destroy(error);\n indexStream.destroy(error);\n });\n\n // Generate fragment index from the single-track stream\n // This will be a single-track index since we're processing isolated track\n // Map the single-track file's track ID 1 to the original multi-track ID\n const trackIdMapping = { 1: trackId }; // Single track 1 -> original trackId\n const fragmentIndexPromise = generateFragmentIndex(indexStream, undefined, trackIdMapping);\n\n // End outputStream only after BOTH source ends AND fragment index completes\n fragmentIndexPromise\n .then(() => {\n if (sourceStreamEnded) {\n outputStream.end();\n } else {\n // If fragment index completes first, wait for stream to end\n trackStream.once(\"end\", () => {\n outputStream.end();\n });\n }\n })\n .catch((error) => {\n outputStream.destroy(error);\n });\n\n // Return both the stream and the index\n return {\n stream: outputStream,\n fragmentIndex: fragmentIndexPromise,\n };\n};\n\nexport const generateSingleTrackTask = idempotentTask({\n label: \"track-single\",\n filename: (absolutePath: string, trackId: number) =>\n `${basename(absolutePath)}.track-${trackId}.mp4`,\n runner: async (absolutePath: string, trackId: number) => {\n const result = await generateSingleTrackFromPath(absolutePath, trackId);\n\n // Create a PassThrough stream that processes fragment index in parallel\n const finalStream = new PassThrough();\n\n // Start fragment index processing immediately (don't wait for stream to end)\n const fragmentIndexPromise = result.fragmentIndex.catch((error) => {\n console.warn(`Fragment index generation failed for track ${trackId}:`, error);\n // Don't fail the stream if fragment index fails\n });\n\n // Monitor progress and extend timeout based on actual work\n let progressTimeout: NodeJS.Timeout | null = null;\n\n const resetProgressTimeout = () => {\n if (progressTimeout) {\n clearTimeout(progressTimeout);\n }\n\n progressTimeout = setTimeout(() => {\n if (!finalStream.destroyed) {\n console.warn(\n `Progress timeout triggered for track ${trackId} - no activity for 10 seconds`,\n );\n finalStream.end();\n }\n }, 10000); // 10 second sliding timeout\n };\n\n // Start the initial timeout\n resetProgressTimeout();\n\n // Monitor data flow to detect active work\n result.stream.on(\"data\", () => {\n resetProgressTimeout(); // Reset timeout when we see data\n });\n\n result.stream.on(\"end\", () => {\n resetProgressTimeout(); // Reset timeout when stream ends\n });\n\n // Pipe data through but don't end until fragment index is ready\n result.stream.pipe(finalStream, { end: false });\n\n // Wait for fragment index to complete, then end the stream\n await fragmentIndexPromise;\n finalStream.end();\n\n // Clean up timeout\n if (progressTimeout) {\n clearTimeout(progressTimeout);\n }\n\n return finalStream;\n },\n});\n\nexport const generateSingleTrack = async (cacheRoot: string, absolutePath: string, url: string) => {\n try {\n const trackId = new URL(`http://localhost${url}`).searchParams.get(\"trackId\");\n if (trackId === null) {\n throw new Error(\"No trackId provided. It must be specified in the query string: ?trackId=0\");\n }\n return await generateSingleTrackTask(cacheRoot, absolutePath, Number(trackId));\n } catch (error) {\n console.error(error);\n console.trace(\"Error generating track\", error);\n throw error;\n }\n};\n"],"mappings":";;;;;;;;AAOA,MAAM,MAAM,MAAM,yBAAyB;AAE3C,MAAa,8BAA8B,OAAO,cAAsB,YAAoB;AAC1F,KAAI,oBAAoB,QAAQ,OAAO,eAAe;CAEtD,MAAM,QAAQ,MAAM,MAAM,UAAU,aAAa;CAGjD,MAAM,cAAc,UAAU;AAE9B,KAAI,cAAc,KAAK,eAAe,MAAM,QAAQ,OAClD,OAAM,IAAI,MAAM,SAAS,QAAQ,8BAA8B,MAAM,QAAQ,OAAO,GAAG;CAIzF,MAAM,cAAc,MAAM,sBAAsB,YAAY;CAG5D,MAAM,eAAe,IAAI,aAAa;CACtC,MAAM,cAAc,IAAI,aAAa;AAGrC,aAAY,KAAK,cAAc,EAAE,KAAK,OAAO,CAAC;AAC9C,aAAY,KAAK,YAAY;CAG7B,IAAI,oBAAoB;AACxB,aAAY,GAAG,aAAa;AAC1B,sBAAoB;GACpB;AAEF,aAAY,GAAG,UAAU,UAAU;AACjC,eAAa,QAAQ,MAAM;AAC3B,cAAY,QAAQ,MAAM;GAC1B;CAMF,MAAM,uBAAuB,sBAAsB,aAAa,QADzC,EAAE,GAAG,SAAS,CACqD;AAG1F,sBACG,WAAW;AACV,MAAI,kBACF,cAAa,KAAK;MAGlB,aAAY,KAAK,aAAa;AAC5B,gBAAa,KAAK;IAClB;GAEJ,CACD,OAAO,UAAU;AAChB,eAAa,QAAQ,MAAM;GAC3B;AAGJ,QAAO;EACL,QAAQ;EACR,eAAe;EAChB;;AAGH,MAAa,0BAA0B,eAAe;CACpD,OAAO;CACP,WAAW,cAAsB,YAC/B,GAAG,SAAS,aAAa,CAAC,SAAS,QAAQ;CAC7C,QAAQ,OAAO,cAAsB,YAAoB;EACvD,MAAM,SAAS,MAAM,4BAA4B,cAAc,QAAQ;EAGvE,MAAM,cAAc,IAAI,aAAa;EAGrC,MAAM,uBAAuB,OAAO,cAAc,OAAO,UAAU;AACjE,WAAQ,KAAK,8CAA8C,QAAQ,IAAI,MAAM;IAE7E;EAGF,IAAIA,kBAAyC;EAE7C,MAAM,6BAA6B;AACjC,OAAI,gBACF,cAAa,gBAAgB;AAG/B,qBAAkB,iBAAiB;AACjC,QAAI,CAAC,YAAY,WAAW;AAC1B,aAAQ,KACN,wCAAwC,QAAQ,+BACjD;AACD,iBAAY,KAAK;;MAElB,IAAM;;AAIX,wBAAsB;AAGtB,SAAO,OAAO,GAAG,cAAc;AAC7B,yBAAsB;IACtB;AAEF,SAAO,OAAO,GAAG,aAAa;AAC5B,yBAAsB;IACtB;AAGF,SAAO,OAAO,KAAK,aAAa,EAAE,KAAK,OAAO,CAAC;AAG/C,QAAM;AACN,cAAY,KAAK;AAGjB,MAAI,gBACF,cAAa,gBAAgB;AAG/B,SAAO;;CAEV,CAAC"}
1
+ {"version":3,"file":"generateSingleTrack.js","names":[],"sources":["../src/generateSingleTrack.ts"],"mappings":";;;;;;;AAOA,MAAM,MAAM,MAAM,yBAAyB;AAE3C,MAAa,8BAA8B,OAAO,cAAsB,YAAoB;AAC1F,KAAI,oBAAoB,QAAQ,OAAO,eAAe;CAEtD,MAAM,QAAQ,MAAM,MAAM,UAAU,aAAa;CAGjD,MAAM,cAAc,UAAU;AAE9B,KAAI,cAAc,KAAK,eAAe,MAAM,QAAQ,OAClD,OAAM,IAAI,MAAM,SAAS,QAAQ,8BAA8B,MAAM,QAAQ,OAAO,GAAG;CAIzF,MAAM,cAAc,MAAM,sBAAsB,YAAY;CAG5D,MAAM,eAAe,IAAI,aAAa;CACtC,MAAM,cAAc,IAAI,aAAa;AAGrC,aAAY,KAAK,cAAc,EAAE,KAAK,OAAO,CAAC;AAC9C,aAAY,KAAK,YAAY;CAG7B,IAAI,oBAAoB;AACxB,aAAY,GAAG,aAAa;AAC1B,sBAAoB;GACpB;AAEF,aAAY,GAAG,UAAU,UAAU;AACjC,eAAa,QAAQ,MAAM;AAC3B,cAAY,QAAQ,MAAM;GAC1B;CAMF,MAAM,uBAAuB,sBAAsB,aAAa,KAAA,GADzC,EAAE,GAAG,SAAS,CACqD;AAG1F,sBACG,WAAW;AACV,MAAI,kBACF,cAAa,KAAK;MAGlB,aAAY,KAAK,aAAa;AAC5B,gBAAa,KAAK;IAClB;GAEJ,CACD,OAAO,UAAU;AAChB,eAAa,QAAQ,MAAM;GAC3B;AAGJ,QAAO;EACL,QAAQ;EACR,eAAe;EAChB;;AAGoC,eAAe;CACpD,OAAO;CACP,WAAW,cAAsB,YAC/B,GAAG,SAAS,aAAa,CAAC,SAAS,QAAQ;CAC7C,QAAQ,OAAO,cAAsB,YAAoB;EACvD,MAAM,SAAS,MAAM,4BAA4B,cAAc,QAAQ;EAGvE,MAAM,cAAc,IAAI,aAAa;EAGrC,MAAM,uBAAuB,OAAO,cAAc,OAAO,UAAU;AACjE,WAAQ,KAAK,8CAA8C,QAAQ,IAAI,MAAM;IAE7E;EAGF,IAAI,kBAAyC;EAE7C,MAAM,6BAA6B;AACjC,OAAI,gBACF,cAAa,gBAAgB;AAG/B,qBAAkB,iBAAiB;AACjC,QAAI,CAAC,YAAY,WAAW;AAC1B,aAAQ,KACN,wCAAwC,QAAQ,+BACjD;AACD,iBAAY,KAAK;;MAElB,IAAM;;AAIX,wBAAsB;AAGtB,SAAO,OAAO,GAAG,cAAc;AAC7B,yBAAsB;IACtB;AAEF,SAAO,OAAO,GAAG,aAAa;AAC5B,yBAAsB;IACtB;AAGF,SAAO,OAAO,KAAK,aAAa,EAAE,KAAK,OAAO,CAAC;AAG/C,QAAM;AACN,cAAY,KAAK;AAGjB,MAAI,gBACF,cAAa,gBAAgB;AAG/B,SAAO;;CAEV,CAAC"}
@@ -0,0 +1,346 @@
1
+ const require_runtime = require("./_virtual/_rolldown/runtime.cjs");
2
+ const require_Probe = require("./Probe.cjs");
3
+ let debug = require("debug");
4
+ debug = require_runtime.__toESM(debug);
5
+ let node_fs_promises = require("node:fs/promises");
6
+ //#region src/generateWebmSegmentIndex.ts
7
+ /**
8
+ * WebM / Matroska segment index generator.
9
+ *
10
+ * Instead of transcoding VP9-alpha WebM → fragmented MP4 (which strips the
11
+ * alpha BlockAdditions), this module parses the source WebM's EBML structure
12
+ * to produce byte-range segment maps directly into the original file.
13
+ *
14
+ * The pipeline:
15
+ * 1. EBML parse: locate init region (EBML + Segment header + Info + Tracks)
16
+ * and enumerate every Cluster with its timestamp.
17
+ * 2. Keyframe detection: cross-reference cluster byte ranges with ffprobe
18
+ * packet positions+flags to mark which clusters are keyframe-aligned.
19
+ * 3. Segment grouping: accumulate clusters into ≥2-second segments that
20
+ * start on keyframe clusters (mirrors generateFragmentIndex.ts logic).
21
+ * 4. Output: same TrackFragmentIndex shape used by the MP4 path so the
22
+ * rest of the pipeline (middleware, SegmentIndex.ts, EFVideo) is unchanged.
23
+ *
24
+ * Segment size patching
25
+ * ---------------------
26
+ * ffmpeg writes a known Segment-element size in the WebM header. When we
27
+ * serve a subset of clusters, the size field must be replaced with the EBML
28
+ * "unknown" value (0x01FFFFFFFFFFFFFF) so mediabunny does not expect more
29
+ * bytes than we provide. This patch is applied once to the cached copy of
30
+ * the source file (see generateTrack.ts).
31
+ */
32
+ const log = (0, debug.default)("ef:generateWebmSegmentIndex");
33
+ const MIN_SEGMENT_DURATION_MS = 2e3;
34
+ const ID_EBML = 440786851;
35
+ const ID_SEGMENT = 408125543;
36
+ const ID_INFO = 357149030;
37
+ const ID_CLUSTER = 524531317;
38
+ const ID_TIMESTAMP = 231;
39
+ const ID_SIMPLE_BLOCK = 163;
40
+ const ID_BLOCK_GROUP = 160;
41
+ const ID_REFERENCE_BLOCK = 251;
42
+ const ID_TIMESTAMP_SCALE = 2807729;
43
+ /**
44
+ * Decode an EBML variable-length integer used for **element sizes**.
45
+ * The leading 1-bit encodes the byte-width; that bit is then stripped from
46
+ * the value. Returns `null` for the "unknown / streaming" sentinel value
47
+ * (all data-bits = 1).
48
+ */
49
+ function readVintSize(buf, offset) {
50
+ const b = buf[offset];
51
+ let width = 1;
52
+ let mask = 128;
53
+ while (width <= 8 && !(b & mask)) {
54
+ mask >>= 1;
55
+ width++;
56
+ }
57
+ let value = b & mask - 1;
58
+ for (let i = 1; i < width; i++) value = value << 8 | (buf[offset + i] ?? 0);
59
+ const unknownSentinel = (1 << 7 * width) - 1;
60
+ return {
61
+ value: value === unknownSentinel ? null : value,
62
+ width
63
+ };
64
+ }
65
+ /**
66
+ * Decode an EBML **element ID**. Unlike sizes, the leading marker bit is
67
+ * *kept* in the returned value (IDs are opaque bit patterns).
68
+ */
69
+ function readElementId(buf, offset) {
70
+ const b = buf[offset];
71
+ let width = 1;
72
+ let mask = 128;
73
+ while (width <= 4 && !(b & mask)) {
74
+ mask >>= 1;
75
+ width++;
76
+ }
77
+ let id = b;
78
+ for (let i = 1; i < width; i++) id = id << 8 | (buf[offset + i] ?? 0);
79
+ return {
80
+ id,
81
+ width
82
+ };
83
+ }
84
+ /** Read a big-endian unsigned integer of `size` bytes. */
85
+ function readUintBE(buf, offset, size) {
86
+ let val = 0;
87
+ for (let i = 0; i < size; i++) val = val * 256 + (buf[offset + i] ?? 0) >>> 0;
88
+ return val;
89
+ }
90
+ /**
91
+ * Parse the top-level EBML and Segment structure of a WebM file.
92
+ * Only reads as deep as needed: EBML header → Segment → Info/Tracks/Clusters.
93
+ */
94
+ function parseWebmStructure(buf) {
95
+ let pos = 0;
96
+ const { id: ebmlId, width: ebmlIdWidth } = readElementId(buf, pos);
97
+ if (ebmlId !== ID_EBML) throw new Error(`Expected EBML element (0x1A45DFA3), got 0x${ebmlId.toString(16)}`);
98
+ const { value: ebmlSize, width: ebmlSizeWidth } = readVintSize(buf, pos + ebmlIdWidth);
99
+ if (ebmlSize === null) throw new Error("EBML element has unknown size");
100
+ pos += ebmlIdWidth + ebmlSizeWidth + ebmlSize;
101
+ const { id: segId, width: segIdWidth } = readElementId(buf, pos);
102
+ if (segId !== ID_SEGMENT) throw new Error(`Expected Segment element (0x18538067), got 0x${segId.toString(16)}`);
103
+ const segmentSizeVintOffset = pos + segIdWidth;
104
+ const { width: segSizeWidth } = readVintSize(buf, segmentSizeVintOffset);
105
+ let spos = segmentSizeVintOffset + segSizeWidth;
106
+ let initSize = 0;
107
+ let timestampScaleNs = 1e6;
108
+ const clusters = [];
109
+ while (spos < buf.length) {
110
+ if (buf.length - spos < 2) break;
111
+ const { id: childId, width: childIdWidth } = readElementId(buf, spos);
112
+ const { value: childSize, width: childSizeWidth } = readVintSize(buf, spos + childIdWidth);
113
+ const headerSize = childIdWidth + childSizeWidth;
114
+ if (childSize === null) {
115
+ log(`Unknown-size element 0x${childId.toString(16)} at ${spos}, stopping`);
116
+ break;
117
+ }
118
+ const elementEnd = spos + headerSize + childSize;
119
+ if (childId === ID_INFO) {
120
+ let ipos = spos + headerSize;
121
+ while (ipos < elementEnd && ipos < buf.length) {
122
+ const { id: infoChildId, width: infoIdW } = readElementId(buf, ipos);
123
+ const { value: infoChildSize, width: infoSizeW } = readVintSize(buf, ipos + infoIdW);
124
+ if (infoChildSize === null) break;
125
+ if (infoChildId === ID_TIMESTAMP_SCALE) timestampScaleNs = readUintBE(buf, ipos + infoIdW + infoSizeW, infoChildSize);
126
+ ipos += infoIdW + infoSizeW + infoChildSize;
127
+ }
128
+ } else if (childId === ID_CLUSTER) {
129
+ if (initSize === 0) initSize = spos;
130
+ let clusterTimestampUnits = 0;
131
+ let hasKeyframe = false;
132
+ let cpos = spos + headerSize;
133
+ while (cpos < elementEnd && cpos < buf.length) {
134
+ if (buf.length - cpos < 2) break;
135
+ const { id: cid, width: cidW } = readElementId(buf, cpos);
136
+ const { value: csize, width: csizeW } = readVintSize(buf, cpos + cidW);
137
+ if (csize === null) break;
138
+ const cHeaderSize = cidW + csizeW;
139
+ if (cid === ID_TIMESTAMP) clusterTimestampUnits = readUintBE(buf, cpos + cHeaderSize, csize);
140
+ else if (cid === ID_SIMPLE_BLOCK) {
141
+ const sbOffset = cpos + cHeaderSize;
142
+ const { width: trackNumWidth } = readVintSize(buf, sbOffset);
143
+ if ((buf[sbOffset + trackNumWidth + 2] ?? 0) & 128) hasKeyframe = true;
144
+ } else if (cid === ID_BLOCK_GROUP) {
145
+ let bgpos = cpos + cHeaderSize;
146
+ const bgEnd = cpos + cHeaderSize + csize;
147
+ let hasReferenceBlock = false;
148
+ while (bgpos < bgEnd && bgpos < buf.length) {
149
+ const { id: bgid, width: bgidW } = readElementId(buf, bgpos);
150
+ const { value: bgsize, width: bgsizeW } = readVintSize(buf, bgpos + bgidW);
151
+ if (bgsize === null) break;
152
+ if (bgid === ID_REFERENCE_BLOCK) {
153
+ hasReferenceBlock = true;
154
+ break;
155
+ }
156
+ bgpos += bgidW + bgsizeW + bgsize;
157
+ }
158
+ if (!hasReferenceBlock) hasKeyframe = true;
159
+ }
160
+ cpos += cHeaderSize + csize;
161
+ }
162
+ const timestampMs = Math.round(clusterTimestampUnits * timestampScaleNs / 1e6);
163
+ clusters.push({
164
+ offset: spos,
165
+ size: headerSize + childSize,
166
+ timestampMs,
167
+ hasKeyframe
168
+ });
169
+ }
170
+ spos = elementEnd;
171
+ }
172
+ if (initSize === 0) throw new Error("No Cluster elements found in WebM file");
173
+ return {
174
+ segmentSizeVintOffset,
175
+ segmentSizeVintWidth: segSizeWidth,
176
+ initSize,
177
+ clusters,
178
+ timestampScaleNs
179
+ };
180
+ }
181
+ /**
182
+ * Use ffprobe packet data to mark clusters that contain keyframe packets.
183
+ * More reliable than parsing SimpleBlock flags in-process for large files.
184
+ */
185
+ async function annotateKeyframes(clusters, absolutePath) {
186
+ const keyframePositions = (await require_Probe.PacketProbe.probePath(absolutePath)).packets.filter((p) => p.flags?.includes("K") && p.pos !== void 0).map((p) => p.pos);
187
+ for (const cluster of clusters) {
188
+ const clusterEnd = cluster.offset + cluster.size;
189
+ cluster.hasKeyframe = keyframePositions.some((pos) => pos >= cluster.offset && pos < clusterEnd);
190
+ }
191
+ }
192
+ function buildSegments(clusters, timescale, totalDurationMs) {
193
+ const segments = [];
194
+ let segmentClusters = [];
195
+ let segmentStartMs = 0;
196
+ const flushSegment = (nextStartMs) => {
197
+ if (segmentClusters.length === 0) return;
198
+ const first = segmentClusters[0];
199
+ const last = segmentClusters[segmentClusters.length - 1];
200
+ const offset = first.offset;
201
+ const size = last.offset + last.size - first.offset;
202
+ const cts = Math.round(segmentStartMs * timescale / 1e3);
203
+ const dts = cts;
204
+ const duration = Math.round((nextStartMs - segmentStartMs) * timescale / 1e3);
205
+ segments.push({
206
+ cts,
207
+ dts,
208
+ offset,
209
+ size,
210
+ duration
211
+ });
212
+ segmentClusters = [];
213
+ };
214
+ for (let i = 0; i < clusters.length; i++) {
215
+ const cluster = clusters[i];
216
+ const durationSoFarMs = segmentClusters.length > 0 ? cluster.timestampMs - segmentStartMs : 0;
217
+ if (segmentClusters.length > 0 && durationSoFarMs >= MIN_SEGMENT_DURATION_MS && cluster.hasKeyframe) {
218
+ flushSegment(cluster.timestampMs);
219
+ segmentStartMs = cluster.timestampMs;
220
+ }
221
+ if (segmentClusters.length === 0) {
222
+ if (!cluster.hasKeyframe) continue;
223
+ segmentStartMs = cluster.timestampMs;
224
+ }
225
+ segmentClusters.push(cluster);
226
+ }
227
+ flushSegment(totalDurationMs);
228
+ return segments;
229
+ }
230
+ /**
231
+ * Build a TrackFragmentIndex for a VP9-alpha WebM source without any
232
+ * transcoding. The returned index contains byte offsets that point directly
233
+ * into the cached copy of the source file (which has its Segment-size VINT
234
+ * patched to "unknown" by generateTrack.ts).
235
+ */
236
+ async function generateWebmSegmentIndex(absolutePath, startTimeOffsetMs) {
237
+ log(`Generating WebM segment index for ${absolutePath}`);
238
+ const { initSize, clusters, timestampScaleNs } = parseWebmStructure(await (0, node_fs_promises.readFile)(absolutePath));
239
+ const timescale = 1e3;
240
+ log(`Parsed ${clusters.length} clusters, init=${initSize} bytes, timestampScale=${timestampScaleNs}ns`);
241
+ await annotateKeyframes(clusters, absolutePath);
242
+ log(`Keyframe clusters: ${clusters.filter((c) => c.hasKeyframe).map((c) => `${c.timestampMs}ms@${c.offset}`).join(", ")}`);
243
+ const lastCluster = clusters[clusters.length - 1];
244
+ let finalDurationMs = lastCluster.timestampMs + lastCluster.size / 4096;
245
+ try {
246
+ const videoStream = (await require_Probe.PacketProbe.probePath(absolutePath)).data?.streams?.find((s) => s.codec_type === "video");
247
+ if (videoStream?.duration) finalDurationMs = Math.round(parseFloat(videoStream.duration) * 1e3);
248
+ } catch {}
249
+ log(`Total duration: ${finalDurationMs}ms`);
250
+ const segments = buildSegments(clusters, timescale, finalDurationMs);
251
+ log(`Built ${segments.length} segments: ${segments.map((s) => `[${s.cts / timescale * 1e3 | 0}ms offset=${s.offset} size=${s.size}]`).join(", ")}`);
252
+ const probe2 = await require_Probe.PacketProbe.probePath(absolutePath);
253
+ const videoStream = probe2.data?.streams?.find((s) => s.codec_type === "video");
254
+ const width = videoStream?.width ?? 1920;
255
+ const height = videoStream?.height ?? 1080;
256
+ const codec = videoStream?.codec_tag_string ?? videoStream?.codec_name ?? "vp09";
257
+ const sampleCount = probe2.packets?.filter((p) => p.codec_type !== "audio").length ?? 0;
258
+ let trackStartTimeOffsetMs;
259
+ if (startTimeOffsetMs !== void 0) trackStartTimeOffsetMs = startTimeOffsetMs;
260
+ else if (clusters[0] && clusters[0].timestampMs > 1) trackStartTimeOffsetMs = clusters[0].timestampMs;
261
+ const trackIndex = {
262
+ track: 1,
263
+ type: "video",
264
+ width,
265
+ height,
266
+ timescale,
267
+ codec,
268
+ duration: Math.round(finalDurationMs * timescale / 1e3),
269
+ sample_count: sampleCount,
270
+ startTimeOffsetMs: trackStartTimeOffsetMs,
271
+ initSegment: {
272
+ offset: 0,
273
+ size: initSize
274
+ },
275
+ segments
276
+ };
277
+ return { 1: trackIndex };
278
+ }
279
+ const ID_SEEKHEAD = 290298740;
280
+ const EBML_VOID_ID = 236;
281
+ /**
282
+ * Patch a WebM buffer in-place to make it safe for partial (segment-sliced) serving:
283
+ *
284
+ * 1. Segment-element size VINT → EBML unknown-size (0x01FFFFFFFFFFFFFF).
285
+ * Without this, mediabunny expects the full 44 MB when receiving a 5 MB chunk.
286
+ *
287
+ * 2. SeekHead element → EBML Void of the same byte length.
288
+ * The SeekHead contains Cues/cluster offsets relative to the original file.
289
+ * When mediabunny uses those offsets on a sliced buffer it reads garbage or
290
+ * falls off the end of the buffer, causing seek errors and de-sync. Replacing
291
+ * it with a Void element forces linear parsing: EBML → Info → Tracks → Clusters.
292
+ *
293
+ * Both patches are applied to a Buffer copy; the source file on disk is not modified.
294
+ */
295
+ function patchWebmForSegmentedServing(buf) {
296
+ try {
297
+ const { id: ebmlId, width: ebmlIdWidth } = readElementId(buf, 0);
298
+ if (ebmlId !== ID_EBML) return;
299
+ const { value: ebmlSize, width: ebmlSizeWidth } = readVintSize(buf, ebmlIdWidth);
300
+ if (ebmlSize === null) return;
301
+ const segPos = ebmlIdWidth + ebmlSizeWidth + ebmlSize;
302
+ const { id: segId, width: segIdWidth } = readElementId(buf, segPos);
303
+ if (segId !== ID_SEGMENT) return;
304
+ const segSizeOffset = segPos + segIdWidth;
305
+ const { width: segSizeWidth } = readVintSize(buf, segSizeOffset);
306
+ if (segSizeWidth === 8) Buffer.from([
307
+ 1,
308
+ 255,
309
+ 255,
310
+ 255,
311
+ 255,
312
+ 255,
313
+ 255,
314
+ 255
315
+ ]).copy(buf, segSizeOffset);
316
+ let pos = segPos + segIdWidth + segSizeWidth;
317
+ const scanLimit = Math.min(pos + 4096, buf.length);
318
+ while (pos < scanLimit) {
319
+ const { id: childId, width: childIdWidth } = readElementId(buf, pos);
320
+ const { value: childSize, width: childSizeWidth } = readVintSize(buf, pos + childIdWidth);
321
+ if (childSize === null) break;
322
+ const totalElementSize = childIdWidth + childSizeWidth + childSize;
323
+ if (childId === ID_SEEKHEAD) {
324
+ const voidContentSize = totalElementSize - 1;
325
+ let vintBytes;
326
+ if (voidContentSize <= 126) vintBytes = [128 | voidContentSize];
327
+ else if (voidContentSize <= 16382) vintBytes = [64 | voidContentSize >> 8, voidContentSize & 255];
328
+ else vintBytes = [
329
+ 32 | voidContentSize >> 16,
330
+ voidContentSize >> 8 & 255,
331
+ voidContentSize & 255
332
+ ];
333
+ buf[pos] = EBML_VOID_ID;
334
+ for (let i = 0; i < vintBytes.length; i++) buf[pos + 1 + i] = vintBytes[i];
335
+ buf.fill(0, pos + 1 + vintBytes.length, pos + totalElementSize);
336
+ break;
337
+ }
338
+ pos += totalElementSize;
339
+ }
340
+ } catch {}
341
+ }
342
+ //#endregion
343
+ exports.generateWebmSegmentIndex = generateWebmSegmentIndex;
344
+ exports.patchWebmForSegmentedServing = patchWebmForSegmentedServing;
345
+
346
+ //# sourceMappingURL=generateWebmSegmentIndex.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generateWebmSegmentIndex.cjs","names":["PacketProbe"],"sources":["../src/generateWebmSegmentIndex.ts"],"mappings":"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"}