@editframe/assets 0.59.4 → 0.59.6

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.
@@ -76,6 +76,19 @@ declare const VideoRenderOptions: z.ZodObject<{
76
76
  numberOfChannels: number;
77
77
  }>;
78
78
  }, "strip", z.ZodTypeAny, {
79
+ audio: {
80
+ codec: string;
81
+ bitrate: number;
82
+ sampleRate: number;
83
+ numberOfChannels: number;
84
+ };
85
+ video: {
86
+ width: number;
87
+ height: number;
88
+ framerate: number;
89
+ codec: string;
90
+ bitrate: number;
91
+ };
79
92
  sequenceNumber: number;
80
93
  keyframeIntervalMs: number;
81
94
  fromMs: number;
@@ -85,6 +98,15 @@ declare const VideoRenderOptions: z.ZodObject<{
85
98
  alignedFromUs: number;
86
99
  alignedToUs: number;
87
100
  isInitSegment: boolean;
101
+ noVideo?: boolean | undefined;
102
+ noAudio?: boolean | undefined;
103
+ }, {
104
+ audio: {
105
+ codec: string;
106
+ bitrate: number;
107
+ sampleRate: number;
108
+ numberOfChannels: number;
109
+ };
88
110
  video: {
89
111
  width: number;
90
112
  height: number;
@@ -92,15 +114,6 @@ declare const VideoRenderOptions: z.ZodObject<{
92
114
  codec: string;
93
115
  bitrate: number;
94
116
  };
95
- audio: {
96
- codec: string;
97
- bitrate: number;
98
- sampleRate: number;
99
- numberOfChannels: number;
100
- };
101
- noVideo?: boolean | undefined;
102
- noAudio?: boolean | undefined;
103
- }, {
104
117
  sequenceNumber: number;
105
118
  keyframeIntervalMs: number;
106
119
  fromMs: number;
@@ -110,19 +123,6 @@ declare const VideoRenderOptions: z.ZodObject<{
110
123
  alignedFromUs: number;
111
124
  alignedToUs: number;
112
125
  isInitSegment: boolean;
113
- video: {
114
- width: number;
115
- height: number;
116
- framerate: number;
117
- codec: string;
118
- bitrate: number;
119
- };
120
- audio: {
121
- codec: string;
122
- bitrate: number;
123
- sampleRate: number;
124
- numberOfChannels: number;
125
- };
126
126
  noVideo?: boolean | undefined;
127
127
  noAudio?: boolean | undefined;
128
128
  }>;
@@ -131,6 +131,19 @@ declare const VideoRenderOptions: z.ZodObject<{
131
131
  mode: "canvas" | "screenshot";
132
132
  strategy: "v1" | "v2";
133
133
  encoderOptions: {
134
+ audio: {
135
+ codec: string;
136
+ bitrate: number;
137
+ sampleRate: number;
138
+ numberOfChannels: number;
139
+ };
140
+ video: {
141
+ width: number;
142
+ height: number;
143
+ framerate: number;
144
+ codec: string;
145
+ bitrate: number;
146
+ };
134
147
  sequenceNumber: number;
135
148
  keyframeIntervalMs: number;
136
149
  fromMs: number;
@@ -140,19 +153,6 @@ declare const VideoRenderOptions: z.ZodObject<{
140
153
  alignedFromUs: number;
141
154
  alignedToUs: number;
142
155
  isInitSegment: boolean;
143
- video: {
144
- width: number;
145
- height: number;
146
- framerate: number;
147
- codec: string;
148
- bitrate: number;
149
- };
150
- audio: {
151
- codec: string;
152
- bitrate: number;
153
- sampleRate: number;
154
- numberOfChannels: number;
155
- };
156
156
  noVideo?: boolean | undefined;
157
157
  noAudio?: boolean | undefined;
158
158
  };
@@ -163,6 +163,19 @@ declare const VideoRenderOptions: z.ZodObject<{
163
163
  mode: "canvas" | "screenshot";
164
164
  strategy: "v1" | "v2";
165
165
  encoderOptions: {
166
+ audio: {
167
+ codec: string;
168
+ bitrate: number;
169
+ sampleRate: number;
170
+ numberOfChannels: number;
171
+ };
172
+ video: {
173
+ width: number;
174
+ height: number;
175
+ framerate: number;
176
+ codec: string;
177
+ bitrate: number;
178
+ };
166
179
  sequenceNumber: number;
167
180
  keyframeIntervalMs: number;
168
181
  fromMs: number;
@@ -172,19 +185,6 @@ declare const VideoRenderOptions: z.ZodObject<{
172
185
  alignedFromUs: number;
173
186
  alignedToUs: number;
174
187
  isInitSegment: boolean;
175
- video: {
176
- width: number;
177
- height: number;
178
- framerate: number;
179
- codec: string;
180
- bitrate: number;
181
- };
182
- audio: {
183
- codec: string;
184
- bitrate: number;
185
- sampleRate: number;
186
- numberOfChannels: number;
187
- };
188
188
  noVideo?: boolean | undefined;
189
189
  noAudio?: boolean | undefined;
190
190
  };
package/dist/index.cjs CHANGED
@@ -8,10 +8,13 @@ const require_generateScrubTrack = require("./tasks/generateScrubTrack.cjs");
8
8
  const require_findOrCreateCaptions = require("./tasks/findOrCreateCaptions.cjs");
9
9
  const require_cacheImage = require("./tasks/cacheImage.cjs");
10
10
  const require_VideoRenderOptions = require("./VideoRenderOptions.cjs");
11
+ const require_MediabunnyIngest = require("./mediabunny-ingest/MediabunnyIngest.cjs");
11
12
  exports.PacketProbe = require_Probe.PacketProbe;
12
13
  exports.Probe = require_Probe.Probe;
13
14
  exports.VideoRenderOptions = require_VideoRenderOptions.VideoRenderOptions;
14
15
  exports.cacheImage = require_cacheImage.cacheImage;
16
+ exports.extractAudioTrack = require_MediabunnyIngest.extractAudioTrack;
17
+ exports.extractVideoTrack = require_MediabunnyIngest.extractVideoTrack;
15
18
  exports.findOrCreateCaptions = require_findOrCreateCaptions.findOrCreateCaptions;
16
19
  exports.generateCaptionDataFromPath = require_findOrCreateCaptions.generateCaptionDataFromPath;
17
20
  exports.generateFragmentIndex = require_generateFragmentIndex.generateFragmentIndex;
@@ -25,3 +28,5 @@ exports.md5Buffer = require_md5.md5Buffer;
25
28
  exports.md5Directory = require_md5.md5Directory;
26
29
  exports.md5FilePath = require_md5.md5FilePath;
27
30
  exports.md5ReadStream = require_md5.md5ReadStream;
31
+ exports.openIngestInput = require_MediabunnyIngest.openIngestInput;
32
+ exports.selectIngestTracks = require_MediabunnyIngest.selectIngestTracks;
package/dist/index.d.cts CHANGED
@@ -8,4 +8,5 @@ import { generateScrubTrack, generateScrubTrackFromPath } from "./tasks/generate
8
8
  import { findOrCreateCaptions, generateCaptionDataFromPath } from "./tasks/findOrCreateCaptions.cjs";
9
9
  import { cacheImage } from "./tasks/cacheImage.cjs";
10
10
  import { VideoRenderOptions } from "./VideoRenderOptions.cjs";
11
- export { type AudioStreamSchema, type AudioTrackFragmentIndex, PacketProbe, type PacketProbeSchema, Probe, type ProbeSchema, type StreamSchema, type TaskResult, type TrackFragmentIndex, type TrackSegment, VideoRenderOptions, type VideoStreamSchema, type VideoTrackFragmentIndex, cacheImage, findOrCreateCaptions, generateCaptionDataFromPath, generateFragmentIndex, generateScrubTrack, generateScrubTrackFromPath, generateTrack, generateTrackFragmentIndex, generateTrackFragmentIndexFromPath, generateTrackFromPath, md5Buffer, md5Directory, md5FilePath, md5ReadStream };
11
+ import { IngestSource, SelectedIngestTracks, TrackExtractionResult, extractAudioTrack, extractVideoTrack, openIngestInput, selectIngestTracks } from "./mediabunny-ingest/MediabunnyIngest.cjs";
12
+ export { type AudioStreamSchema, type AudioTrackFragmentIndex, type IngestSource, PacketProbe, type PacketProbeSchema, Probe, type ProbeSchema, type SelectedIngestTracks, type StreamSchema, type TaskResult, type TrackExtractionResult, type TrackFragmentIndex, type TrackSegment, VideoRenderOptions, type VideoStreamSchema, type VideoTrackFragmentIndex, cacheImage, extractAudioTrack, extractVideoTrack, findOrCreateCaptions, generateCaptionDataFromPath, generateFragmentIndex, generateScrubTrack, generateScrubTrackFromPath, generateTrack, generateTrackFragmentIndex, generateTrackFragmentIndexFromPath, generateTrackFromPath, md5Buffer, md5Directory, md5FilePath, md5ReadStream, openIngestInput, selectIngestTracks };
package/dist/index.d.ts CHANGED
@@ -8,4 +8,5 @@ import { generateScrubTrack, generateScrubTrackFromPath } from "./tasks/generate
8
8
  import { findOrCreateCaptions, generateCaptionDataFromPath } from "./tasks/findOrCreateCaptions.js";
9
9
  import { cacheImage } from "./tasks/cacheImage.js";
10
10
  import { VideoRenderOptions } from "./VideoRenderOptions.js";
11
- export { type AudioStreamSchema, type AudioTrackFragmentIndex, PacketProbe, type PacketProbeSchema, Probe, type ProbeSchema, type StreamSchema, type TaskResult, type TrackFragmentIndex, type TrackSegment, VideoRenderOptions, type VideoStreamSchema, type VideoTrackFragmentIndex, cacheImage, findOrCreateCaptions, generateCaptionDataFromPath, generateFragmentIndex, generateScrubTrack, generateScrubTrackFromPath, generateTrack, generateTrackFragmentIndex, generateTrackFragmentIndexFromPath, generateTrackFromPath, md5Buffer, md5Directory, md5FilePath, md5ReadStream };
11
+ import { IngestSource, SelectedIngestTracks, TrackExtractionResult, extractAudioTrack, extractVideoTrack, openIngestInput, selectIngestTracks } from "./mediabunny-ingest/MediabunnyIngest.js";
12
+ export { type AudioStreamSchema, type AudioTrackFragmentIndex, type IngestSource, PacketProbe, type PacketProbeSchema, Probe, type ProbeSchema, type SelectedIngestTracks, type StreamSchema, type TaskResult, type TrackExtractionResult, type TrackFragmentIndex, type TrackSegment, VideoRenderOptions, type VideoStreamSchema, type VideoTrackFragmentIndex, cacheImage, extractAudioTrack, extractVideoTrack, findOrCreateCaptions, generateCaptionDataFromPath, generateFragmentIndex, generateScrubTrack, generateScrubTrackFromPath, generateTrack, generateTrackFragmentIndex, generateTrackFragmentIndexFromPath, generateTrackFromPath, md5Buffer, md5Directory, md5FilePath, md5ReadStream, openIngestInput, selectIngestTracks };
package/dist/index.js CHANGED
@@ -7,4 +7,5 @@ import { generateScrubTrack, generateScrubTrackFromPath } from "./tasks/generate
7
7
  import { findOrCreateCaptions, generateCaptionDataFromPath } from "./tasks/findOrCreateCaptions.js";
8
8
  import { cacheImage } from "./tasks/cacheImage.js";
9
9
  import { VideoRenderOptions } from "./VideoRenderOptions.js";
10
- export { PacketProbe, Probe, VideoRenderOptions, cacheImage, findOrCreateCaptions, generateCaptionDataFromPath, generateFragmentIndex, generateScrubTrack, generateScrubTrackFromPath, generateTrack, generateTrackFragmentIndex, generateTrackFragmentIndexFromPath, generateTrackFromPath, md5Buffer, md5Directory, md5FilePath, md5ReadStream };
10
+ import { extractAudioTrack, extractVideoTrack, openIngestInput, selectIngestTracks } from "./mediabunny-ingest/MediabunnyIngest.js";
11
+ export { PacketProbe, Probe, VideoRenderOptions, cacheImage, extractAudioTrack, extractVideoTrack, findOrCreateCaptions, generateCaptionDataFromPath, generateFragmentIndex, generateScrubTrack, generateScrubTrackFromPath, generateTrack, generateTrackFragmentIndex, generateTrackFragmentIndexFromPath, generateTrackFromPath, md5Buffer, md5Directory, md5FilePath, md5ReadStream, openIngestInput, selectIngestTracks };
@@ -0,0 +1,238 @@
1
+ const require_runtime = require("../_virtual/_rolldown/runtime.cjs");
2
+ const require_bitstream = require("./bitstream.cjs");
3
+ let debug = require("debug");
4
+ debug = require_runtime.__toESM(debug);
5
+ let node_stream = require("node:stream");
6
+ let node_crypto = require("node:crypto");
7
+ node_crypto = require_runtime.__toESM(node_crypto);
8
+ let _mediabunny_server = require("@mediabunny/server");
9
+ let mediabunny = require("mediabunny");
10
+ //#region src/mediabunny-ingest/MediabunnyIngest.ts
11
+ const log = (0, debug.default)("ef:assets:mediabunny-ingest");
12
+ (0, _mediabunny_server.registerMediabunnyServer)();
13
+ /** Opens a mediabunny `Input` over a URL or local file path, auto-detecting the container/HLS format. */
14
+ function openIngestInput(source) {
15
+ return new mediabunny.Input({
16
+ formats: mediabunny.ALL_FORMATS,
17
+ source: source.type === "url" ? new mediabunny.UrlSource(source.url) : new mediabunny.FilePathSource(source.path)
18
+ });
19
+ }
20
+ /**
21
+ * Selects the best video track and its best pairable audio track from an
22
+ * input (matching the "ingest only the best audio and video track" ingest
23
+ * policy). For plain progressive files this is just "the" video/audio track;
24
+ * for HLS master playlists, mediabunny's `getPrimaryVideoTrack`/
25
+ * `getPrimaryAudioTrack` already implement bitrate-based ABR selection.
26
+ *
27
+ * Throws if the source has no usable tracks, or if any selected track is
28
+ * still live (open-ended) — ingestion only supports VOD sources.
29
+ */
30
+ async function selectIngestTracks(input) {
31
+ const video = await input.getPrimaryVideoTrack();
32
+ const audio = video ? await video.getPrimaryPairableAudioTrack() ?? await input.getPrimaryAudioTrack() : await input.getPrimaryAudioTrack();
33
+ if (!video && !audio) throw new Error("No video or audio tracks found in source");
34
+ for (const track of [video, audio]) if (track && await track.isLive()) throw new Error("Live (open-ended) sources are not supported for ingestion — only VOD sources can be processed");
35
+ return {
36
+ video,
37
+ audio
38
+ };
39
+ }
40
+ function bridgeToNodeReadable() {
41
+ const pass = new node_stream.PassThrough();
42
+ return {
43
+ readable: pass,
44
+ target: new mediabunny.AppendOnlyStreamTarget(node_stream.Writable.toWeb(pass))
45
+ };
46
+ }
47
+ /**
48
+ * Zero-bases a track's packet timestamps around its own decode-order first
49
+ * packet, for two reasons:
50
+ *
51
+ * 1. Mediabunny's MP4 muxer rejects packets with negative timestamps outright.
52
+ * Negative first-packet timestamps are common and legitimate — e.g. AAC
53
+ * encoder priming samples, or B-frame reordering — and ffmpeg silently
54
+ * normalizes them by default (`-avoid_negative_ts make_zero`) when remuxing.
55
+ *
56
+ * 2. For *positive* first-packet timestamps (e.g. a source with a non-zero
57
+ * container-level `format.start_time`, such as Mux's 90kHz start-time
58
+ * offset), mediabunny's fragmented-MP4 muxer does NOT zero-base decode
59
+ * timestamps the way its non-fragmented muxer (and the old ffmpeg-CLI
60
+ * ingest's remux) does — that normalization is explicitly gated behind
61
+ * `!isFragmented` in mediabunny's isobmff muxer. Left unshifted, that
62
+ * container-level offset leaks into the produced track's absolute
63
+ * timestamps, which `generateFragmentIndex` reads assuming DTS starts at
64
+ * 0 (see its "After ffmpeg re-mux, DTS is always 0" comment) — corrupting
65
+ * its detected `startTimeOffsetMs` by exactly that leaked amount.
66
+ *
67
+ * Shifting every packet by `-firstTimestamp` handles both cases and is a
68
+ * no-op for the common case where the track already starts at t=0. It does
69
+ * NOT erase a genuine B-frame reordering offset (CTS > DTS for the first
70
+ * decode-order packet): that offset is a *relative* property between a
71
+ * packet's own timestamp and its decode-order position, which a uniform
72
+ * shift preserves.
73
+ */
74
+ async function getTimestampOffset(track) {
75
+ return -await track.getFirstTimestamp();
76
+ }
77
+ function md5Digest(hash) {
78
+ const hex = hash.digest("hex");
79
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`;
80
+ }
81
+ /**
82
+ * Extracts a single video track into a fragmented single-track MP4 stream via
83
+ * packet-copy transmux (no re-encoding — matches the previous ffmpeg `-c:v copy`
84
+ * behavior). SEI NAL units (type 6) are stripped from every packet, mirroring the
85
+ * previous `-bsf:v filter_units=remove_types=6` ffmpeg filter.
86
+ */
87
+ function extractVideoTrack(track) {
88
+ const { readable, target } = bridgeToNodeReadable();
89
+ const hash = node_crypto.default.createHash("md5");
90
+ const digestDeferred = createDeferred();
91
+ (async () => {
92
+ const codec = await track.getCodec();
93
+ if (!codec) throw new Error("Video track has no known codec");
94
+ const decoderConfig = await track.getDecoderConfig();
95
+ const isAnnexB = decoderConfig?.description === void 0;
96
+ const tsOffset = await getTimestampOffset(track);
97
+ const output = new mediabunny.Output({
98
+ format: new mediabunny.Mp4OutputFormat({ fastStart: "fragmented" }),
99
+ target
100
+ });
101
+ const source = new mediabunny.EncodedVideoPacketSource(codec);
102
+ output.addVideoTrack(source);
103
+ await output.start();
104
+ const sink = new mediabunny.EncodedPacketSink(track);
105
+ let isFirst = true;
106
+ for await (const packet of sink.packets()) {
107
+ hash.update(packet.data);
108
+ const strippedData = require_bitstream.stripSeiNalUnits(packet.data, isAnnexB);
109
+ const outPacket = strippedData !== packet.data || tsOffset !== 0 ? packet.clone({
110
+ data: strippedData,
111
+ timestamp: packet.timestamp + tsOffset
112
+ }) : packet;
113
+ await source.add(outPacket, isFirst && decoderConfig ? { decoderConfig } : void 0);
114
+ isFirst = false;
115
+ }
116
+ await output.finalize();
117
+ })().then(() => digestDeferred.resolve(md5Digest(hash))).catch((error) => {
118
+ digestDeferred.reject(error);
119
+ readable.emit("error", error);
120
+ readable.destroy(error instanceof Error ? error : new Error(String(error)));
121
+ });
122
+ return {
123
+ stream: readable,
124
+ digest: digestDeferred.promise
125
+ };
126
+ }
127
+ /**
128
+ * Extracts a single audio track into a fragmented single-track MP4 stream.
129
+ *
130
+ * - AAC-raw sources (description present) are packet-copied directly.
131
+ * - AAC-ADTS sources (typical of MPEG-TS/HLS demuxed AAC) have their ADTS
132
+ * headers stripped and an AudioSpecificConfig synthesized, mirroring the
133
+ * previous `-bsf:a aac_adtstoasc` ffmpeg filter.
134
+ * - Any other codec is decoded and re-encoded to AAC (192kbps), mirroring the
135
+ * previous `-c:a aac -b:a 192k -ar 48000` ffmpeg re-encode fallback.
136
+ */
137
+ function extractAudioTrack(track) {
138
+ const { readable, target } = bridgeToNodeReadable();
139
+ const hash = node_crypto.default.createHash("md5");
140
+ const digestDeferred = createDeferred();
141
+ (async () => {
142
+ const codec = await track.getCodec();
143
+ const decoderConfig = await track.getDecoderConfig();
144
+ const isAdtsAac = codec === "aac" && decoderConfig?.description === void 0;
145
+ const needsReencode = codec !== "aac";
146
+ const tsOffset = await getTimestampOffset(track);
147
+ const output = new mediabunny.Output({
148
+ format: new mediabunny.Mp4OutputFormat({ fastStart: "fragmented" }),
149
+ target
150
+ });
151
+ if (needsReencode) {
152
+ const source = new mediabunny.AudioSampleSource({
153
+ codec: "aac",
154
+ bitrate: 192e3
155
+ });
156
+ output.addAudioTrack(source);
157
+ await output.start();
158
+ const hashPromise = (async () => {
159
+ const packetSink = new mediabunny.EncodedPacketSink(track);
160
+ for await (const packet of packetSink.packets()) hash.update(packet.data);
161
+ })();
162
+ const sampleSink = new mediabunny.AudioSampleSink(track);
163
+ for await (const sample of sampleSink.samples()) try {
164
+ if (tsOffset === 0) {
165
+ await source.add(sample);
166
+ continue;
167
+ }
168
+ const shifted = mediabunny.AudioSample.fromAudioBuffer(sample.toAudioBuffer(), sample.timestamp + tsOffset);
169
+ for (const out of shifted) try {
170
+ await source.add(out);
171
+ } finally {
172
+ out.close();
173
+ }
174
+ } finally {
175
+ sample.close();
176
+ }
177
+ await hashPromise;
178
+ await output.finalize();
179
+ return;
180
+ }
181
+ const source = new mediabunny.EncodedAudioPacketSource("aac");
182
+ output.addAudioTrack(source);
183
+ await output.start();
184
+ const sink = new mediabunny.EncodedPacketSink(track);
185
+ const [sampleRate, numberOfChannels] = await Promise.all([track.getSampleRate(), track.getNumberOfChannels()]);
186
+ let isFirst = true;
187
+ for await (const packet of sink.packets()) {
188
+ hash.update(packet.data);
189
+ if (!isAdtsAac) {
190
+ const outPacket = tsOffset !== 0 ? packet.clone({ timestamp: packet.timestamp + tsOffset }) : packet;
191
+ await source.add(outPacket, isFirst && decoderConfig ? { decoderConfig } : void 0);
192
+ isFirst = false;
193
+ continue;
194
+ }
195
+ const raw = require_bitstream.adtsToRawAac(packet.data);
196
+ const outPacket = packet.clone({
197
+ data: raw.data,
198
+ timestamp: packet.timestamp + tsOffset
199
+ });
200
+ await source.add(outPacket, isFirst ? { decoderConfig: {
201
+ codec: raw.codec,
202
+ sampleRate,
203
+ numberOfChannels,
204
+ description: raw.audioSpecificConfig
205
+ } } : void 0);
206
+ isFirst = false;
207
+ }
208
+ await output.finalize();
209
+ })().then(() => digestDeferred.resolve(md5Digest(hash))).catch((error) => {
210
+ digestDeferred.reject(error);
211
+ readable.emit("error", error);
212
+ readable.destroy(error instanceof Error ? error : new Error(String(error)));
213
+ });
214
+ return {
215
+ stream: readable,
216
+ digest: digestDeferred.promise
217
+ };
218
+ }
219
+ function createDeferred() {
220
+ let resolve;
221
+ let reject;
222
+ return {
223
+ promise: new Promise((res, rej) => {
224
+ resolve = res;
225
+ reject = rej;
226
+ }),
227
+ resolve,
228
+ reject
229
+ };
230
+ }
231
+ log("Mediabunny ingest module loaded");
232
+ //#endregion
233
+ exports.extractAudioTrack = extractAudioTrack;
234
+ exports.extractVideoTrack = extractVideoTrack;
235
+ exports.openIngestInput = openIngestInput;
236
+ exports.selectIngestTracks = selectIngestTracks;
237
+
238
+ //# sourceMappingURL=MediabunnyIngest.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MediabunnyIngest.cjs","names":["Input","ALL_FORMATS","UrlSource","FilePathSource","PassThrough","AppendOnlyStreamTarget","NodeWritable","crypto","Output","Mp4OutputFormat","EncodedVideoPacketSource","EncodedPacketSink","stripSeiNalUnits","AudioSampleSource","AudioSampleSink","AudioSample","EncodedAudioPacketSource","adtsToRawAac"],"sources":["../../src/mediabunny-ingest/MediabunnyIngest.ts"],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ import { Readable } from "node:stream";
2
+ import { Input, InputAudioTrack, InputVideoTrack } from "mediabunny";
3
+
4
+ //#region src/mediabunny-ingest/MediabunnyIngest.d.ts
5
+ type IngestSource = {
6
+ type: "url";
7
+ url: string;
8
+ } | {
9
+ type: "path";
10
+ path: string;
11
+ };
12
+ /** Opens a mediabunny `Input` over a URL or local file path, auto-detecting the container/HLS format. */
13
+ declare function openIngestInput(source: IngestSource): Input;
14
+ interface SelectedIngestTracks {
15
+ video: InputVideoTrack | null;
16
+ audio: InputAudioTrack | null;
17
+ }
18
+ /**
19
+ * Selects the best video track and its best pairable audio track from an
20
+ * input (matching the "ingest only the best audio and video track" ingest
21
+ * policy). For plain progressive files this is just "the" video/audio track;
22
+ * for HLS master playlists, mediabunny's `getPrimaryVideoTrack`/
23
+ * `getPrimaryAudioTrack` already implement bitrate-based ABR selection.
24
+ *
25
+ * Throws if the source has no usable tracks, or if any selected track is
26
+ * still live (open-ended) — ingestion only supports VOD sources.
27
+ */
28
+ declare function selectIngestTracks(input: Input): Promise<SelectedIngestTracks>;
29
+ interface TrackExtractionResult {
30
+ /** A single-track fragmented MP4 stream, ready to be written to storage / fed to generateFragmentIndex. */
31
+ stream: Readable;
32
+ /**
33
+ * Resolves to an md5 digest (formatted as a dashed UUID, matching the rest of the
34
+ * codebase's md5 convention) of this track's raw source packet bytes, once fully read.
35
+ * For URL-sourced ingests there is no bulk-downloaded file to hash, so this is used as
36
+ * the file's content fingerprint instead of a whole-file md5.
37
+ */
38
+ digest: Promise<string>;
39
+ }
40
+ /**
41
+ * Extracts a single video track into a fragmented single-track MP4 stream via
42
+ * packet-copy transmux (no re-encoding — matches the previous ffmpeg `-c:v copy`
43
+ * behavior). SEI NAL units (type 6) are stripped from every packet, mirroring the
44
+ * previous `-bsf:v filter_units=remove_types=6` ffmpeg filter.
45
+ */
46
+ declare function extractVideoTrack(track: InputVideoTrack): TrackExtractionResult;
47
+ /**
48
+ * Extracts a single audio track into a fragmented single-track MP4 stream.
49
+ *
50
+ * - AAC-raw sources (description present) are packet-copied directly.
51
+ * - AAC-ADTS sources (typical of MPEG-TS/HLS demuxed AAC) have their ADTS
52
+ * headers stripped and an AudioSpecificConfig synthesized, mirroring the
53
+ * previous `-bsf:a aac_adtstoasc` ffmpeg filter.
54
+ * - Any other codec is decoded and re-encoded to AAC (192kbps), mirroring the
55
+ * previous `-c:a aac -b:a 192k -ar 48000` ffmpeg re-encode fallback.
56
+ */
57
+ declare function extractAudioTrack(track: InputAudioTrack): TrackExtractionResult;
58
+ //#endregion
59
+ export { IngestSource, SelectedIngestTracks, TrackExtractionResult, extractAudioTrack, extractVideoTrack, openIngestInput, selectIngestTracks };
60
+ //# sourceMappingURL=MediabunnyIngest.d.cts.map
@@ -0,0 +1,60 @@
1
+ import { Readable } from "node:stream";
2
+ import { Input, InputAudioTrack, InputVideoTrack } from "mediabunny";
3
+
4
+ //#region src/mediabunny-ingest/MediabunnyIngest.d.ts
5
+ type IngestSource = {
6
+ type: "url";
7
+ url: string;
8
+ } | {
9
+ type: "path";
10
+ path: string;
11
+ };
12
+ /** Opens a mediabunny `Input` over a URL or local file path, auto-detecting the container/HLS format. */
13
+ declare function openIngestInput(source: IngestSource): Input;
14
+ interface SelectedIngestTracks {
15
+ video: InputVideoTrack | null;
16
+ audio: InputAudioTrack | null;
17
+ }
18
+ /**
19
+ * Selects the best video track and its best pairable audio track from an
20
+ * input (matching the "ingest only the best audio and video track" ingest
21
+ * policy). For plain progressive files this is just "the" video/audio track;
22
+ * for HLS master playlists, mediabunny's `getPrimaryVideoTrack`/
23
+ * `getPrimaryAudioTrack` already implement bitrate-based ABR selection.
24
+ *
25
+ * Throws if the source has no usable tracks, or if any selected track is
26
+ * still live (open-ended) — ingestion only supports VOD sources.
27
+ */
28
+ declare function selectIngestTracks(input: Input): Promise<SelectedIngestTracks>;
29
+ interface TrackExtractionResult {
30
+ /** A single-track fragmented MP4 stream, ready to be written to storage / fed to generateFragmentIndex. */
31
+ stream: Readable;
32
+ /**
33
+ * Resolves to an md5 digest (formatted as a dashed UUID, matching the rest of the
34
+ * codebase's md5 convention) of this track's raw source packet bytes, once fully read.
35
+ * For URL-sourced ingests there is no bulk-downloaded file to hash, so this is used as
36
+ * the file's content fingerprint instead of a whole-file md5.
37
+ */
38
+ digest: Promise<string>;
39
+ }
40
+ /**
41
+ * Extracts a single video track into a fragmented single-track MP4 stream via
42
+ * packet-copy transmux (no re-encoding — matches the previous ffmpeg `-c:v copy`
43
+ * behavior). SEI NAL units (type 6) are stripped from every packet, mirroring the
44
+ * previous `-bsf:v filter_units=remove_types=6` ffmpeg filter.
45
+ */
46
+ declare function extractVideoTrack(track: InputVideoTrack): TrackExtractionResult;
47
+ /**
48
+ * Extracts a single audio track into a fragmented single-track MP4 stream.
49
+ *
50
+ * - AAC-raw sources (description present) are packet-copied directly.
51
+ * - AAC-ADTS sources (typical of MPEG-TS/HLS demuxed AAC) have their ADTS
52
+ * headers stripped and an AudioSpecificConfig synthesized, mirroring the
53
+ * previous `-bsf:a aac_adtstoasc` ffmpeg filter.
54
+ * - Any other codec is decoded and re-encoded to AAC (192kbps), mirroring the
55
+ * previous `-c:a aac -b:a 192k -ar 48000` ffmpeg re-encode fallback.
56
+ */
57
+ declare function extractAudioTrack(track: InputAudioTrack): TrackExtractionResult;
58
+ //#endregion
59
+ export { IngestSource, SelectedIngestTracks, TrackExtractionResult, extractAudioTrack, extractVideoTrack, openIngestInput, selectIngestTracks };
60
+ //# sourceMappingURL=MediabunnyIngest.d.ts.map