avbridge 2.3.0 → 2.6.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 (111) hide show
  1. package/CHANGELOG.md +114 -0
  2. package/dist/{chunk-6UUT4BEA.cjs → chunk-2IJ66NTD.cjs} +13 -20
  3. package/dist/chunk-2IJ66NTD.cjs.map +1 -0
  4. package/dist/{chunk-XKPSTC34.cjs → chunk-2XW2O3YI.cjs} +5 -20
  5. package/dist/chunk-2XW2O3YI.cjs.map +1 -0
  6. package/dist/chunk-5KVLE6YI.js +167 -0
  7. package/dist/chunk-5KVLE6YI.js.map +1 -0
  8. package/dist/{chunk-7RGG6ME7.cjs → chunk-6SOFJV44.cjs} +422 -688
  9. package/dist/chunk-6SOFJV44.cjs.map +1 -0
  10. package/dist/{chunk-2PGRFCWB.js → chunk-CPJLFFCC.js} +8 -18
  11. package/dist/chunk-CPJLFFCC.js.map +1 -0
  12. package/dist/chunk-CPZ7PXAM.cjs +240 -0
  13. package/dist/chunk-CPZ7PXAM.cjs.map +1 -0
  14. package/dist/{chunk-QQXBPW72.js → chunk-E76AMWI4.js} +4 -18
  15. package/dist/chunk-E76AMWI4.js.map +1 -0
  16. package/dist/chunk-LUFA47FP.js +19 -0
  17. package/dist/chunk-LUFA47FP.js.map +1 -0
  18. package/dist/{chunk-NV7ILLWH.js → chunk-OGYHFY6K.js} +404 -665
  19. package/dist/chunk-OGYHFY6K.js.map +1 -0
  20. package/dist/chunk-Q2VUO52Z.cjs +374 -0
  21. package/dist/chunk-Q2VUO52Z.cjs.map +1 -0
  22. package/dist/chunk-QDJLQR53.cjs +22 -0
  23. package/dist/chunk-QDJLQR53.cjs.map +1 -0
  24. package/dist/chunk-S4WAZC2T.cjs +173 -0
  25. package/dist/chunk-S4WAZC2T.cjs.map +1 -0
  26. package/dist/chunk-SMH6IOP2.js +368 -0
  27. package/dist/chunk-SMH6IOP2.js.map +1 -0
  28. package/dist/chunk-SR3MPV4D.js +237 -0
  29. package/dist/chunk-SR3MPV4D.js.map +1 -0
  30. package/dist/chunk-X2K3GIWE.js +235 -0
  31. package/dist/chunk-X2K3GIWE.js.map +1 -0
  32. package/dist/chunk-ZCUXHW55.cjs +242 -0
  33. package/dist/chunk-ZCUXHW55.cjs.map +1 -0
  34. package/dist/element-browser.js +883 -492
  35. package/dist/element-browser.js.map +1 -1
  36. package/dist/element.cjs +88 -6
  37. package/dist/element.cjs.map +1 -1
  38. package/dist/element.d.cts +51 -1
  39. package/dist/element.d.ts +51 -1
  40. package/dist/element.js +87 -5
  41. package/dist/element.js.map +1 -1
  42. package/dist/index.cjs +523 -393
  43. package/dist/index.cjs.map +1 -1
  44. package/dist/index.d.cts +2 -2
  45. package/dist/index.d.ts +2 -2
  46. package/dist/index.js +494 -366
  47. package/dist/index.js.map +1 -1
  48. package/dist/libav-demux-H2GS46GH.cjs +27 -0
  49. package/dist/libav-demux-H2GS46GH.cjs.map +1 -0
  50. package/dist/libav-demux-OWZ4T2YW.js +6 -0
  51. package/dist/libav-demux-OWZ4T2YW.js.map +1 -0
  52. package/dist/{libav-import-GST2AMPL.cjs → libav-import-2ZVKV2E7.cjs} +2 -2
  53. package/dist/{libav-import-GST2AMPL.cjs.map → libav-import-2ZVKV2E7.cjs.map} +1 -1
  54. package/dist/{libav-import-2JURFHEW.js → libav-import-6MGLCXVQ.js} +2 -2
  55. package/dist/{libav-import-2JURFHEW.js.map → libav-import-6MGLCXVQ.js.map} +1 -1
  56. package/dist/{player-B6WB74RD.d.ts → player-DGXeCNfD.d.cts} +41 -1
  57. package/dist/{player-B6WB74RD.d.cts → player-DGXeCNfD.d.ts} +41 -1
  58. package/dist/player.cjs +731 -472
  59. package/dist/player.cjs.map +1 -1
  60. package/dist/player.d.cts +229 -120
  61. package/dist/player.d.ts +229 -120
  62. package/dist/player.js +710 -451
  63. package/dist/player.js.map +1 -1
  64. package/dist/remux-OBSMIENG.cjs +35 -0
  65. package/dist/remux-OBSMIENG.cjs.map +1 -0
  66. package/dist/remux-WBYIZBBX.js +10 -0
  67. package/dist/remux-WBYIZBBX.js.map +1 -0
  68. package/dist/source-4TZ6KMNV.js +4 -0
  69. package/dist/{source-F656KYYV.js.map → source-4TZ6KMNV.js.map} +1 -1
  70. package/dist/source-7YLO6E7X.cjs +29 -0
  71. package/dist/{source-73CAH6HW.cjs.map → source-7YLO6E7X.cjs.map} +1 -1
  72. package/dist/source-MTX5ELUZ.js +4 -0
  73. package/dist/{source-QJR3OHTW.js.map → source-MTX5ELUZ.js.map} +1 -1
  74. package/dist/source-VFLXLOCN.cjs +29 -0
  75. package/dist/{source-VB74JQ7Z.cjs.map → source-VFLXLOCN.cjs.map} +1 -1
  76. package/dist/subtitles-4T74JRGT.js +4 -0
  77. package/dist/subtitles-4T74JRGT.js.map +1 -0
  78. package/dist/subtitles-QUH4LPI4.cjs +29 -0
  79. package/dist/subtitles-QUH4LPI4.cjs.map +1 -0
  80. package/package.json +1 -1
  81. package/src/convert/remux.ts +1 -35
  82. package/src/convert/transcode-libav.ts +691 -0
  83. package/src/convert/transcode.ts +12 -4
  84. package/src/element/avbridge-player.ts +100 -0
  85. package/src/element/avbridge-video.ts +140 -3
  86. package/src/element/player-styles.ts +12 -0
  87. package/src/errors.ts +6 -0
  88. package/src/player.ts +15 -16
  89. package/src/strategies/fallback/decoder.ts +96 -173
  90. package/src/strategies/fallback/index.ts +46 -2
  91. package/src/strategies/fallback/libav-import.ts +9 -1
  92. package/src/strategies/fallback/video-renderer.ts +107 -0
  93. package/src/strategies/hybrid/decoder.ts +88 -180
  94. package/src/strategies/hybrid/index.ts +35 -2
  95. package/src/strategies/native.ts +6 -3
  96. package/src/strategies/remux/index.ts +14 -2
  97. package/src/strategies/remux/pipeline.ts +72 -12
  98. package/src/subtitles/render.ts +8 -0
  99. package/src/types.ts +32 -0
  100. package/src/util/libav-demux.ts +405 -0
  101. package/src/util/time-ranges.ts +40 -0
  102. package/dist/chunk-2PGRFCWB.js.map +0 -1
  103. package/dist/chunk-6UUT4BEA.cjs.map +0 -1
  104. package/dist/chunk-7RGG6ME7.cjs.map +0 -1
  105. package/dist/chunk-NV7ILLWH.js.map +0 -1
  106. package/dist/chunk-QQXBPW72.js.map +0 -1
  107. package/dist/chunk-XKPSTC34.cjs.map +0 -1
  108. package/dist/source-73CAH6HW.cjs +0 -28
  109. package/dist/source-F656KYYV.js +0 -3
  110. package/dist/source-QJR3OHTW.js +0 -3
  111. package/dist/source-VB74JQ7Z.cjs +0 -28
package/dist/index.cjs CHANGED
@@ -1,401 +1,523 @@
1
1
  'use strict';
2
2
 
3
- var chunk7RGG6ME7_cjs = require('./chunk-7RGG6ME7.cjs');
4
- var chunk6UUT4BEA_cjs = require('./chunk-6UUT4BEA.cjs');
5
- var chunkZ33SBWL5_cjs = require('./chunk-Z33SBWL5.cjs');
3
+ var chunkQ2VUO52Z_cjs = require('./chunk-Q2VUO52Z.cjs');
4
+ var chunk6SOFJV44_cjs = require('./chunk-6SOFJV44.cjs');
5
+ var chunkS4WAZC2T_cjs = require('./chunk-S4WAZC2T.cjs');
6
+ var chunkZCUXHW55_cjs = require('./chunk-ZCUXHW55.cjs');
7
+ var chunk2IJ66NTD_cjs = require('./chunk-2IJ66NTD.cjs');
8
+ require('./chunk-QDJLQR53.cjs');
9
+ require('./chunk-CPZ7PXAM.cjs');
10
+ require('./chunk-Z33SBWL5.cjs');
6
11
  require('./chunk-G4APZMCP.cjs');
7
12
  require('./chunk-F3LQJKXK.cjs');
8
13
 
9
- function isAnnexB(bytes) {
10
- if (bytes.length < 3) return false;
11
- if (bytes[0] === 0 && bytes[1] === 0 && bytes[2] === 1) return true;
12
- if (bytes.length >= 4 && bytes[0] === 0 && bytes[1] === 0 && bytes[2] === 0 && bytes[3] === 1) return true;
13
- return false;
14
+ // src/convert/transcode-libav.ts
15
+ function isLibavTranscodeContainer(container) {
16
+ return container === "avi" || container === "asf" || container === "flv" || container === "rm";
14
17
  }
15
- function* iterateAnnexBNalus(bytes) {
16
- const length = bytes.length;
17
- let i = 0;
18
- let nalStart = -1;
19
- while (i < length) {
20
- let scLen = 0;
21
- if (i + 3 < length && bytes[i] === 0 && bytes[i + 1] === 0 && bytes[i + 2] === 0 && bytes[i + 3] === 1) {
22
- scLen = 4;
23
- } else if (i + 2 < length && bytes[i] === 0 && bytes[i + 1] === 0 && bytes[i + 2] === 1) {
24
- scLen = 3;
25
- }
26
- if (scLen > 0) {
27
- if (nalStart >= 0) {
28
- yield bytes.subarray(nalStart, i);
29
- }
30
- nalStart = i + scLen;
31
- i += scLen;
32
- } else {
33
- i += 1;
34
- }
35
- }
36
- if (nalStart >= 0 && nalStart < length) {
37
- yield bytes.subarray(nalStart, length);
38
- }
39
- }
40
- function annexBToAvcc(annexB) {
41
- const nalus = [];
42
- let total = 0;
43
- for (const nal of iterateAnnexBNalus(annexB)) {
44
- nalus.push(nal);
45
- total += 4 + nal.length;
46
- }
47
- const out = new Uint8Array(total);
48
- let off = 0;
49
- for (const nal of nalus) {
50
- const len = nal.length;
51
- out[off++] = len >>> 24 & 255;
52
- out[off++] = len >>> 16 & 255;
53
- out[off++] = len >>> 8 & 255;
54
- out[off++] = len & 255;
55
- out.set(nal, off);
56
- off += len;
57
- }
58
- return out;
59
- }
60
-
61
- // src/convert/remux.ts
62
- var MEDIABUNNY_CONTAINERS = /* @__PURE__ */ new Set([
63
- "mp4",
64
- "mov",
65
- "mkv",
66
- "webm",
67
- "ogg",
68
- "wav",
69
- "mp3",
70
- "flac",
71
- "adts"
72
- ]);
73
- async function remux(source, options = {}) {
18
+ async function transcodeViaLibav(ctx, options) {
74
19
  const outputFormat = options.outputFormat ?? "mp4";
75
- options.signal?.throwIfAborted();
76
- const ctx = await chunk7RGG6ME7_cjs.probe(source);
77
- options.signal?.throwIfAborted();
78
- validateRemuxEligibility(ctx, options.strict ?? false);
79
- if (MEDIABUNNY_CONTAINERS.has(ctx.container)) {
80
- return remuxViaMediAbunny(ctx, outputFormat, options);
81
- }
82
- return remuxViaLibav(ctx, outputFormat, options);
83
- }
84
- function validateRemuxEligibility(ctx, strict) {
85
- const video = ctx.videoTracks[0];
86
- const audio = ctx.audioTracks[0];
87
- if (video) {
88
- const mbCodec = chunk7RGG6ME7_cjs.avbridgeVideoToMediabunny(video.codec);
89
- if (!mbCodec) {
90
- throw new Error(
91
- `Cannot remux: video codec "${video.codec}" is not supported for remuxing. Use transcode() to re-encode to a modern codec.`
92
- );
93
- }
94
- }
95
- if (audio) {
96
- const mbCodec = chunk7RGG6ME7_cjs.avbridgeAudioToMediabunny(audio.codec);
97
- if (!mbCodec) {
98
- throw new Error(
99
- `Cannot remux: audio codec "${audio.codec}" is not supported for remuxing. Use transcode() to re-encode to a modern codec.`
100
- );
101
- }
102
- }
103
- if (strict && video?.codec === "h264" && audio?.codec === "mp3") {
104
- throw new Error(
105
- `Cannot remux in strict mode: H.264 + MP3 is a best-effort combination that may produce playback issues in some browsers. Set strict: false to allow, or use transcode() to re-encode audio to AAC.`
20
+ if (outputFormat !== "mp4" && outputFormat !== "webm" && outputFormat !== "mkv") {
21
+ throw new chunk2IJ66NTD_cjs.AvbridgeError(
22
+ chunk2IJ66NTD_cjs.ERR_TRANSCODE_UNSUPPORTED_COMBO,
23
+ `legacy-container transcode supports MP4, WebM, and MKV output (got "${outputFormat}").`,
24
+ `Use outputFormat: "mp4", "webm", or "mkv".`
106
25
  );
107
26
  }
108
- if (!video && !audio) {
109
- throw new Error("Cannot remux: source has no video or audio tracks.");
110
- }
111
- }
112
- async function remuxViaMediAbunny(ctx, outputFormat, options) {
113
- const mb = await import('mediabunny');
114
- const input = new mb.Input({
115
- source: await chunk7RGG6ME7_cjs.buildMediabunnySourceFromInput(mb, ctx.source),
116
- formats: mb.ALL_FORMATS
117
- });
118
- const target = new mb.BufferTarget();
119
- const output = new mb.Output({
120
- format: createOutputFormat(mb, outputFormat),
121
- target
122
- });
123
- const conversion = await mb.Conversion.init({
124
- input,
125
- output,
126
- showWarnings: false
27
+ const videoCodec = options.videoCodec ?? (outputFormat === "webm" ? "vp9" : "h264");
28
+ const audioCodec = options.audioCodec ?? (outputFormat === "webm" ? "opus" : "aac");
29
+ const quality = options.quality ?? "medium";
30
+ options.signal?.throwIfAborted();
31
+ const [
32
+ mb,
33
+ { openLibavDemux, sanitizePacketTimestamp, sanitizeFrameTimestamp, libavFrameToInterleavedFloat32 },
34
+ { normalizeSource },
35
+ { createOutputFormat: createOutputFormat2, mimeForFormat: mimeForFormat2, generateFilename: generateFilename2 }
36
+ ] = await Promise.all([
37
+ import('mediabunny'),
38
+ import('./libav-demux-H2GS46GH.cjs'),
39
+ import('./source-VFLXLOCN.cjs'),
40
+ import('./remux-OBSMIENG.cjs')
41
+ ]);
42
+ const normalized = await normalizeSource(ctx.source);
43
+ const demux = await openLibavDemux({
44
+ source: normalized,
45
+ filename: ctx.name ?? "input.bin",
46
+ context: ctx
47
+ // transport config is not yet threaded through ConvertOptions; add
48
+ // later if URL-source transcode with signed URLs becomes a need.
127
49
  });
128
- if (!conversion.isValid) {
129
- const reasons = conversion.discardedTracks.map((d) => `${d.track.type} track discarded: ${d.reason}`).join("; ");
130
- throw new Error(`Cannot remux: mediabunny rejected the conversion. ${reasons}`);
131
- }
132
- if (options.onProgress) {
133
- const onProgress = options.onProgress;
134
- conversion.onProgress = (p) => {
135
- onProgress({ percent: p * 100, bytesWritten: 0 });
136
- };
137
- }
138
- let abortHandler;
139
- if (options.signal) {
140
- options.signal.throwIfAborted();
141
- abortHandler = () => void conversion.cancel();
142
- options.signal.addEventListener("abort", abortHandler, { once: true });
143
- }
144
50
  try {
145
- await conversion.execute();
146
- } finally {
147
- if (abortHandler && options.signal) {
148
- options.signal.removeEventListener("abort", abortHandler);
51
+ let throwIfAborted2 = function() {
52
+ if (ac?.aborted) {
53
+ throw new chunk2IJ66NTD_cjs.AvbridgeError(
54
+ chunk2IJ66NTD_cjs.ERR_TRANSCODE_ABORTED,
55
+ "transcode: aborted by caller.",
56
+ void 0
57
+ );
58
+ }
59
+ }, throwIfDrainError2 = function() {
60
+ if (drainError) {
61
+ const msg = drainError.message;
62
+ throw new chunk2IJ66NTD_cjs.AvbridgeError(
63
+ chunk2IJ66NTD_cjs.ERR_TRANSCODE_DECODE,
64
+ `transcode: video decoder error: ${msg}`,
65
+ "This usually indicates the WebCodecs decoder rejected a malformed packet."
66
+ );
67
+ }
68
+ };
69
+ var throwIfAborted = throwIfAborted2, throwIfDrainError = throwIfDrainError2;
70
+ options.signal?.throwIfAborted();
71
+ if (!demux.videoStream && !demux.audioStream) {
72
+ throw new Error("transcode: source has no decodable tracks");
149
73
  }
150
- }
151
- if (!target.buffer) {
152
- throw new Error("Remux failed: mediabunny produced no output buffer.");
153
- }
154
- const mimeType = mimeForFormat(outputFormat);
155
- const blob = new Blob([target.buffer], { type: mimeType });
156
- const filename = generateFilename(ctx.name, outputFormat);
157
- options.onProgress?.({ percent: 100, bytesWritten: blob.size });
158
- return {
159
- blob,
160
- mimeType,
161
- container: outputFormat,
162
- videoCodec: ctx.videoTracks[0]?.codec,
163
- audioCodec: ctx.audioTracks[0]?.codec,
164
- duration: ctx.duration,
165
- filename
166
- };
167
- }
168
- async function remuxViaLibav(ctx, outputFormat, options) {
169
- let loadLibav;
170
- let pickLibavVariant;
171
- try {
172
- const loader = await import('./libav-loader-IV4AJ2HW.cjs');
173
- const routing = await import('./variant-routing-HONNAA6R.cjs');
174
- loadLibav = loader.loadLibav;
175
- pickLibavVariant = routing.pickLibavVariant;
176
- } catch {
177
- throw new Error(
178
- `Cannot remux ${ctx.container.toUpperCase()} source: libav.js is not available. Install @libav.js/variant-webcodecs and libavjs-webcodecs-bridge, or build the custom avbridge variant with scripts/build-libav.sh.`
179
- );
180
- }
181
- const variant = pickLibavVariant(ctx);
182
- const libav = await loadLibav(variant);
183
- const normalized = await chunk6UUT4BEA_cjs.normalizeSource(ctx.source);
184
- const filename = ctx.name ?? `remux-input-${Date.now()}`;
185
- const handle = await chunkZ33SBWL5_cjs.prepareLibavInput(libav, filename, normalized);
186
- try {
187
- return await doLibavRemux(libav, filename, ctx, outputFormat, options);
188
- } finally {
189
- await handle.detach().catch(() => {
74
+ if (options.outputStream) {
75
+ throw new chunk2IJ66NTD_cjs.AvbridgeError(
76
+ chunk2IJ66NTD_cjs.ERR_TRANSCODE_UNSUPPORTED_COMBO,
77
+ "outputStream is not yet supported for the libav-backed transcode path.",
78
+ "Remove the outputStream option to receive the transcoded blob in memory. Streaming output for this path is on the roadmap."
79
+ );
80
+ }
81
+ const bufferTarget = new mb.BufferTarget();
82
+ const output = new mb.Output({
83
+ format: createOutputFormat2(mb, outputFormat),
84
+ target: bufferTarget
190
85
  });
191
- }
192
- }
193
- async function doLibavRemux(libav, filename, ctx, outputFormat, options) {
194
- const mb = await import('mediabunny');
195
- const readPkt = await libav.av_packet_alloc();
196
- const [fmt_ctx, streams] = await libav.ff_init_demuxer_file(filename);
197
- const videoStream = streams.find((s) => s.codec_type === libav.AVMEDIA_TYPE_VIDEO) ?? null;
198
- const audioStream = streams.find((s) => s.codec_type === libav.AVMEDIA_TYPE_AUDIO) ?? null;
199
- const videoTrackInfo = ctx.videoTracks[0];
200
- const audioTrackInfo = ctx.audioTracks[0];
201
- const mbVideoCodec = videoTrackInfo ? chunk7RGG6ME7_cjs.avbridgeVideoToMediabunny(videoTrackInfo.codec) : null;
202
- const mbAudioCodec = audioTrackInfo ? chunk7RGG6ME7_cjs.avbridgeAudioToMediabunny(audioTrackInfo.codec) : null;
203
- const target = new mb.BufferTarget();
204
- const output = new mb.Output({
205
- format: createOutputFormat(mb, outputFormat),
206
- target
207
- });
208
- let videoSource = null;
209
- let audioSource = null;
210
- if (mbVideoCodec && videoStream) {
211
- videoSource = new mb.EncodedVideoPacketSource(mbVideoCodec);
212
- output.addVideoTrack(videoSource);
213
- }
214
- if (mbAudioCodec && audioStream) {
215
- audioSource = new mb.EncodedAudioPacketSource(mbAudioCodec);
216
- output.addAudioTrack(audioSource);
217
- }
218
- await output.start();
219
- const videoFps = videoTrackInfo?.fps && videoTrackInfo.fps > 0 ? videoTrackInfo.fps : 30;
220
- const videoFrameStepUs = Math.max(1, Math.round(1e6 / videoFps));
221
- let syntheticVideoUs = 0;
222
- let syntheticAudioUs = 0;
223
- const videoTimeBase = videoStream?.time_base_num && videoStream?.time_base_den ? [videoStream.time_base_num, videoStream.time_base_den] : void 0;
224
- const audioTimeBase = audioStream?.time_base_num && audioStream?.time_base_den ? [audioStream.time_base_num, audioStream.time_base_den] : void 0;
225
- let totalPackets = 0;
226
- const durationUs = ctx.duration ? ctx.duration * 1e6 : 0;
227
- let firstVideoMeta = true;
228
- let firstAudioMeta = true;
229
- while (true) {
230
- options.signal?.throwIfAborted();
231
- let readErr;
232
- let packets;
233
- try {
234
- [readErr, packets] = await libav.ff_read_frame_multi(fmt_ctx, readPkt, {
235
- limit: 64 * 1024
236
- });
237
- } catch (err) {
238
- throw new Error(`libav demux failed: ${err.message}`);
86
+ const bridge = await loadBridge();
87
+ let videoDecoder = null;
88
+ let videoSoftDec = null;
89
+ let videoSource = null;
90
+ let videoBsfCtx = null;
91
+ let videoBsfPkt = null;
92
+ let videoWidth = 0;
93
+ let videoHeight = 0;
94
+ let videoTimeBase;
95
+ const frameQueue = [];
96
+ const MAX_QUEUE = 16;
97
+ let draining = false;
98
+ let drainError = null;
99
+ let activeDrain = null;
100
+ const drain = () => {
101
+ if (draining) return activeDrain ?? Promise.resolve();
102
+ draining = true;
103
+ const run = (async () => {
104
+ try {
105
+ while (frameQueue.length > 0 && !drainError) {
106
+ const frame = frameQueue.shift();
107
+ try {
108
+ const sample = new mb.VideoSample(frame, {
109
+ timestamp: (frame.timestamp ?? 0) / 1e6
110
+ // µs s
111
+ });
112
+ await videoSource.add(sample);
113
+ } finally {
114
+ frame.close();
115
+ }
116
+ }
117
+ } catch (err) {
118
+ drainError = err;
119
+ while (frameQueue.length > 0) {
120
+ try {
121
+ frameQueue.shift().close();
122
+ } catch {
123
+ }
124
+ }
125
+ } finally {
126
+ draining = false;
127
+ activeDrain = null;
128
+ }
129
+ })();
130
+ activeDrain = run;
131
+ return run;
132
+ };
133
+ if (demux.videoStream && !options.dropVideo) {
134
+ try {
135
+ const bitDepth = ctx.videoTracks[0]?.bitDepth ?? 8;
136
+ if (bitDepth > 8) {
137
+ throw new chunk2IJ66NTD_cjs.AvbridgeError(
138
+ chunk2IJ66NTD_cjs.ERR_TRANSCODE_UNSUPPORTED_COMBO,
139
+ `transcode: 10-bit video is not supported in this release (source bit depth: ${bitDepth}).`,
140
+ `Phase 1 transcode handles 8-bit video only. 10-bit support is on the roadmap.`
141
+ );
142
+ }
143
+ if (demux.videoStream.time_base_num && demux.videoStream.time_base_den) {
144
+ videoTimeBase = [demux.videoStream.time_base_num, demux.videoStream.time_base_den];
145
+ }
146
+ let config = null;
147
+ try {
148
+ config = await bridge.videoStreamToConfig(demux.libav, demux.videoStream);
149
+ } catch {
150
+ config = null;
151
+ }
152
+ const supported = config ? await VideoDecoder.isConfigSupported(config).catch(() => ({ supported: false })) : { supported: false };
153
+ videoWidth = config?.codedWidth ?? ctx.videoTracks[0]?.width ?? 0;
154
+ videoHeight = config?.codedHeight ?? ctx.videoTracks[0]?.height ?? 0;
155
+ if (config && supported.supported) {
156
+ videoDecoder = new VideoDecoder({
157
+ output: (frame) => {
158
+ if (frameQueue.length >= MAX_QUEUE) {
159
+ frame.close();
160
+ return;
161
+ }
162
+ frameQueue.push(frame);
163
+ void drain();
164
+ },
165
+ error: (err) => {
166
+ drainError = err;
167
+ }
168
+ });
169
+ videoDecoder.configure(config);
170
+ } else {
171
+ const libavSoft = demux.libav;
172
+ const [, c, pkt, frame] = await libavSoft.ff_init_decoder(
173
+ demux.videoStream.codec_id,
174
+ { codecpar: demux.videoStream.codecpar }
175
+ );
176
+ videoSoftDec = { c, pkt, frame };
177
+ }
178
+ videoSource = new mb.VideoSampleSource({
179
+ codec: avbridgeVideoToMediabunny(videoCodec),
180
+ bitrate: qualityToMediabunny(mb, quality, options.videoBitrate),
181
+ ...options.frameRate !== void 0 ? { frameRate: options.frameRate } : {},
182
+ ...options.hardwareAcceleration !== void 0 ? { hardwareAcceleration: options.hardwareAcceleration } : {},
183
+ // Progress reporting: media-time-based via each encoded packet.
184
+ onEncodedPacket: options.onProgress ? (packet) => {
185
+ const t = packet.timestamp;
186
+ if (Number.isFinite(t) && ctx.duration && ctx.duration > 0) {
187
+ const pct = Math.min(100, t / ctx.duration * 100);
188
+ options.onProgress({ percent: pct, bytesWritten: 0 });
189
+ }
190
+ } : void 0
191
+ });
192
+ const videoMeta = {};
193
+ if (options.width !== void 0) videoMeta.width = options.width;
194
+ else if (videoWidth > 0) videoMeta.width = videoWidth;
195
+ if (options.height !== void 0) videoMeta.height = options.height;
196
+ else if (videoHeight > 0) videoMeta.height = videoHeight;
197
+ if (options.frameRate !== void 0) videoMeta.frameRate = options.frameRate;
198
+ output.addVideoTrack(videoSource, videoMeta);
199
+ if (ctx.videoTracks[0]?.codec === "mpeg4") {
200
+ const runtime = demux.libav;
201
+ try {
202
+ videoBsfCtx = await runtime.av_bsf_list_parse_str_js("mpeg4_unpack_bframes");
203
+ if (videoBsfCtx != null && videoBsfCtx >= 0) {
204
+ const parIn = await runtime.AVBSFContext_par_in(videoBsfCtx);
205
+ await runtime.avcodec_parameters_copy(parIn, demux.videoStream.codecpar);
206
+ await runtime.av_bsf_init(videoBsfCtx);
207
+ videoBsfPkt = await demux.libav.av_packet_alloc();
208
+ } else {
209
+ videoBsfCtx = null;
210
+ }
211
+ } catch {
212
+ videoBsfCtx = null;
213
+ }
214
+ }
215
+ } catch (err) {
216
+ if (err instanceof chunk2IJ66NTD_cjs.AvbridgeError) throw err;
217
+ throw new chunk2IJ66NTD_cjs.AvbridgeError(
218
+ chunk2IJ66NTD_cjs.ERR_CODEC_NOT_SUPPORTED,
219
+ `transcode: video decoder init failed: ${err.message}`,
220
+ `The source's video codec may not be supported by this browser's WebCodecs implementation.`
221
+ );
222
+ }
223
+ }
224
+ let audioDec = null;
225
+ let audioSource = null;
226
+ let audioTimeBase;
227
+ const includeAudio = demux.audioStream && !options.dropAudio;
228
+ if (includeAudio) {
229
+ try {
230
+ const libav = demux.libav;
231
+ const [, c, pkt, frame] = await libav.ff_init_decoder(
232
+ demux.audioStream.codec_id,
233
+ { codecpar: demux.audioStream.codecpar }
234
+ );
235
+ audioDec = { c, pkt, frame };
236
+ if (demux.audioStream.time_base_num && demux.audioStream.time_base_den) {
237
+ audioTimeBase = [
238
+ demux.audioStream.time_base_num,
239
+ demux.audioStream.time_base_den
240
+ ];
241
+ }
242
+ audioSource = new mb.AudioSampleSource({
243
+ codec: avbridgeAudioToMediabunny(audioCodec),
244
+ bitrate: qualityToMediabunny(mb, quality, options.audioBitrate)
245
+ });
246
+ output.addAudioTrack(audioSource);
247
+ } catch (err) {
248
+ const codecName = ctx.audioTracks[0]?.codec ?? "unknown";
249
+ throw new chunk2IJ66NTD_cjs.AvbridgeError(
250
+ chunk2IJ66NTD_cjs.ERR_CODEC_NOT_SUPPORTED,
251
+ `transcode: no decoder available for audio codec "${codecName}" in this libav variant (${err.message}).`,
252
+ `The file may still play via createPlayer() (fallback strategy). Pass { dropAudio: true } to transcode video-only.`
253
+ );
254
+ }
255
+ } else if (options.dropAudio) {
256
+ }
257
+ if (!videoSource && !audioSource) {
258
+ throw new chunk2IJ66NTD_cjs.AvbridgeError(
259
+ chunk2IJ66NTD_cjs.ERR_TRANSCODE_UNSUPPORTED_COMBO,
260
+ "transcode: no video or audio track to encode (did you set both dropVideo and dropAudio?).",
261
+ "Remove dropVideo or dropAudio to include at least one track."
262
+ );
263
+ }
264
+ await output.start();
265
+ const videoFps = ctx.videoTracks[0]?.fps && ctx.videoTracks[0].fps > 0 ? ctx.videoTracks[0].fps : 30;
266
+ const videoFrameStepUs = Math.max(1, Math.round(1e6 / videoFps));
267
+ let syntheticVideoUs = 0;
268
+ let syntheticAudioUs = 0;
269
+ const libavFull = demux.libav;
270
+ async function applyBSF(packets) {
271
+ if (!videoBsfCtx || !videoBsfPkt) return packets;
272
+ const out = [];
273
+ for (const pkt of packets) {
274
+ await libavFull.ff_copyin_packet(videoBsfPkt, pkt);
275
+ const sendErr = await libavFull.av_bsf_send_packet(videoBsfCtx, videoBsfPkt);
276
+ if (sendErr < 0) {
277
+ out.push(pkt);
278
+ continue;
279
+ }
280
+ while (true) {
281
+ const recvErr = await libavFull.av_bsf_receive_packet(videoBsfCtx, videoBsfPkt);
282
+ if (recvErr < 0) break;
283
+ out.push(await libavFull.ff_copyout_packet(videoBsfPkt));
284
+ }
285
+ }
286
+ return out;
239
287
  }
240
- const videoPackets = videoStream ? packets[videoStream.index] ?? [] : [];
241
- const audioPackets = audioStream ? packets[audioStream.index] ?? [] : [];
242
- if (videoSource) {
243
- for (const pkt of videoPackets) {
288
+ const ac = options.signal;
289
+ const onVideoPacketsWebCodecs = videoDecoder ? async (pkts) => {
290
+ throwIfAborted2();
291
+ throwIfDrainError2();
292
+ while (!ac?.aborted && (videoDecoder.decodeQueueSize > 16 || frameQueue.length >= MAX_QUEUE - 2)) {
293
+ await new Promise((r) => setTimeout(r, 10));
294
+ }
295
+ throwIfAborted2();
296
+ const processed = await applyBSF(pkts);
297
+ const bridgeAny = bridge;
298
+ for (const pkt of processed) {
244
299
  sanitizePacketTimestamp(pkt, () => {
245
300
  const ts = syntheticVideoUs;
246
301
  syntheticVideoUs += videoFrameStepUs;
247
302
  return ts;
248
303
  }, videoTimeBase);
249
- if (videoTrackInfo && (videoTrackInfo.codec === "h264" || videoTrackInfo.codec === "h265") && isAnnexB(pkt.data)) {
250
- pkt.data = annexBToAvcc(pkt.data);
304
+ try {
305
+ const chunk = bridgeAny.packetToEncodedVideoChunk(pkt, demux.videoStream);
306
+ videoDecoder.decode(chunk);
307
+ } catch (err) {
308
+ throw new chunk2IJ66NTD_cjs.AvbridgeError(
309
+ chunk2IJ66NTD_cjs.ERR_TRANSCODE_DECODE,
310
+ `transcode: packet \u2192 EncodedVideoChunk failed: ${err.message}`,
311
+ void 0
312
+ );
251
313
  }
252
- const mbPacket = libavPacketToMediAbunny(mb, pkt);
253
- await videoSource.add(
254
- mbPacket,
255
- firstVideoMeta ? { decoderConfig: buildVideoDecoderConfig(videoTrackInfo) } : void 0
314
+ }
315
+ } : void 0;
316
+ const onVideoPacketsSoftware = videoSoftDec ? async (pkts) => {
317
+ throwIfAborted2();
318
+ throwIfDrainError2();
319
+ while (!ac?.aborted && frameQueue.length >= MAX_QUEUE - 2) {
320
+ await new Promise((r) => setTimeout(r, 10));
321
+ }
322
+ throwIfAborted2();
323
+ const libavSoft = demux.libav;
324
+ let frames;
325
+ try {
326
+ frames = await libavSoft.ff_decode_multi(
327
+ videoSoftDec.c,
328
+ videoSoftDec.pkt,
329
+ videoSoftDec.frame,
330
+ pkts,
331
+ { ignoreErrors: true }
332
+ );
333
+ } catch (err) {
334
+ throw new chunk2IJ66NTD_cjs.AvbridgeError(
335
+ chunk2IJ66NTD_cjs.ERR_TRANSCODE_DECODE,
336
+ `transcode: software video decode failed: ${err.message}`,
337
+ void 0
256
338
  );
257
- firstVideoMeta = false;
258
339
  }
340
+ for (const f of frames) {
341
+ sanitizeFrameTimestamp(f, () => {
342
+ const ts = syntheticVideoUs;
343
+ syntheticVideoUs += videoFrameStepUs;
344
+ return ts;
345
+ }, videoTimeBase);
346
+ try {
347
+ const vf = bridge.laFrameToVideoFrame(f, { timeBase: [1, 1e6] });
348
+ if (frameQueue.length >= MAX_QUEUE) {
349
+ vf.close();
350
+ } else {
351
+ frameQueue.push(vf);
352
+ void drain();
353
+ }
354
+ } catch (err) {
355
+ throw new chunk2IJ66NTD_cjs.AvbridgeError(
356
+ chunk2IJ66NTD_cjs.ERR_TRANSCODE_DECODE,
357
+ `transcode: laFrameToVideoFrame failed: ${err.message}`,
358
+ void 0
359
+ );
360
+ }
361
+ }
362
+ } : void 0;
363
+ await demux.pump({
364
+ signal: ac,
365
+ onVideoPackets: onVideoPacketsWebCodecs ?? onVideoPacketsSoftware,
366
+ onAudioPackets: audioDec ? async (pkts) => {
367
+ throwIfAborted2();
368
+ await decodeAudioBatch(pkts, false);
369
+ } : void 0,
370
+ onEof: async () => {
371
+ if (videoDecoder && videoDecoder.state === "configured") {
372
+ try {
373
+ await videoDecoder.flush();
374
+ } catch {
375
+ }
376
+ }
377
+ if (videoSoftDec) {
378
+ const libavSoft = demux.libav;
379
+ try {
380
+ const tail = await libavSoft.ff_decode_multi(
381
+ videoSoftDec.c,
382
+ videoSoftDec.pkt,
383
+ videoSoftDec.frame,
384
+ [],
385
+ { fin: true, ignoreErrors: true }
386
+ );
387
+ for (const f of tail) {
388
+ sanitizeFrameTimestamp(f, () => {
389
+ const ts = syntheticVideoUs;
390
+ syntheticVideoUs += videoFrameStepUs;
391
+ return ts;
392
+ }, videoTimeBase);
393
+ try {
394
+ const vf = bridge.laFrameToVideoFrame(f, { timeBase: [1, 1e6] });
395
+ frameQueue.push(vf);
396
+ void drain();
397
+ } catch {
398
+ }
399
+ }
400
+ } catch {
401
+ }
402
+ }
403
+ await drain();
404
+ if (audioDec) {
405
+ await decodeAudioBatch([], true);
406
+ }
407
+ }
408
+ });
409
+ throwIfAborted2();
410
+ throwIfDrainError2();
411
+ videoSource?.close();
412
+ audioSource?.close();
413
+ await output.finalize();
414
+ if (!bufferTarget.buffer) {
415
+ throw new Error("transcode: mediabunny produced no output buffer");
259
416
  }
260
- if (audioSource) {
261
- for (const pkt of audioPackets) {
262
- sanitizePacketTimestamp(pkt, () => {
417
+ const mimeType = mimeForFormat2(outputFormat);
418
+ const blob = new Blob([bufferTarget.buffer], { type: mimeType });
419
+ options.onProgress?.({ percent: 100, bytesWritten: blob.size });
420
+ return {
421
+ blob,
422
+ mimeType,
423
+ container: outputFormat,
424
+ videoCodec: videoSource ? videoCodec : void 0,
425
+ audioCodec: audioSource ? audioCodec : void 0,
426
+ duration: ctx.duration,
427
+ filename: generateFilename2(ctx.name, outputFormat)
428
+ };
429
+ async function decodeAudioBatch(pkts, flush) {
430
+ if (!audioDec || !audioSource) return;
431
+ const libav = demux.libav;
432
+ let frames;
433
+ try {
434
+ frames = await libav.ff_decode_multi(
435
+ audioDec.c,
436
+ audioDec.pkt,
437
+ audioDec.frame,
438
+ pkts,
439
+ flush ? { fin: true, ignoreErrors: true } : { ignoreErrors: true }
440
+ );
441
+ } catch (err) {
442
+ throw new chunk2IJ66NTD_cjs.AvbridgeError(
443
+ chunk2IJ66NTD_cjs.ERR_TRANSCODE_DECODE,
444
+ `transcode: audio decode failed: ${err.message}`,
445
+ void 0
446
+ );
447
+ }
448
+ for (const f of frames) {
449
+ sanitizeFrameTimestamp(f, () => {
263
450
  const ts = syntheticAudioUs;
264
- const sampleRate = audioTrackInfo?.sampleRate ?? 44100;
265
- syntheticAudioUs += Math.round(1024 * 1e6 / sampleRate);
451
+ const samples = f.nb_samples ?? 1024;
452
+ const sampleRate = f.sample_rate ?? 44100;
453
+ syntheticAudioUs += Math.round(samples * 1e6 / sampleRate);
266
454
  return ts;
267
455
  }, audioTimeBase);
268
- const mbPacket = libavPacketToMediAbunny(mb, pkt);
269
- await audioSource.add(
270
- mbPacket,
271
- firstAudioMeta ? { decoderConfig: buildAudioDecoderConfig(audioTrackInfo) } : void 0
272
- );
273
- firstAudioMeta = false;
456
+ const pcm = libavFrameToInterleavedFloat32(f);
457
+ if (!pcm) continue;
458
+ const sample = new mb.AudioSample({
459
+ data: pcm.data,
460
+ format: "f32",
461
+ numberOfChannels: pcm.channels,
462
+ sampleRate: pcm.sampleRate,
463
+ timestamp: (f.pts ?? 0) / 1e6
464
+ });
465
+ await audioSource.add(sample);
274
466
  }
275
467
  }
276
- totalPackets += videoPackets.length + audioPackets.length;
277
- if (options.onProgress && durationUs > 0) {
278
- const lastVideoTs = videoPackets.length > 0 ? videoPackets[videoPackets.length - 1].pts ?? 0 : 0;
279
- const lastAudioTs = audioPackets.length > 0 ? audioPackets[audioPackets.length - 1].pts ?? 0 : 0;
280
- const currentUs = Math.max(lastVideoTs, lastAudioTs);
281
- const percent = Math.min(99, currentUs / durationUs * 100);
282
- options.onProgress({ percent, bytesWritten: 0 });
283
- }
284
- if (readErr === libav.AVERROR_EOF) break;
285
- if (readErr && readErr !== 0 && readErr !== -libav.EAGAIN) {
286
- console.warn("[avbridge] remux: ff_read_frame_multi returned", readErr);
287
- break;
468
+ } finally {
469
+ try {
470
+ await demux.destroy();
471
+ } catch {
288
472
  }
289
473
  }
290
- await output.finalize();
291
- try {
292
- await libav.av_packet_free?.(readPkt);
293
- } catch {
294
- }
474
+ }
475
+ async function loadBridge() {
295
476
  try {
296
- await libav.avformat_close_input_js(fmt_ctx);
297
- } catch {
298
- }
299
- if (!target.buffer) {
300
- throw new Error("Remux failed: mediabunny produced no output buffer.");
477
+ const wrapper = await import('./libav-import-2ZVKV2E7.cjs');
478
+ return wrapper.libavBridge;
479
+ } catch (err) {
480
+ throw new Error(`failed to load libavjs-webcodecs-bridge: ${err.message}`);
301
481
  }
302
- const mimeType = mimeForFormat(outputFormat);
303
- const blob = new Blob([target.buffer], { type: mimeType });
304
- const outputFilename = generateFilename(ctx.name, outputFormat);
305
- options.onProgress?.({ percent: 100, bytesWritten: blob.size });
306
- return {
307
- blob,
308
- mimeType,
309
- container: outputFormat,
310
- videoCodec: videoTrackInfo?.codec,
311
- audioCodec: audioTrackInfo?.codec,
312
- duration: ctx.duration,
313
- filename: outputFilename
314
- };
315
482
  }
316
- function sanitizePacketTimestamp(pkt, nextUs, fallbackTimeBase) {
317
- const lo = pkt.pts ?? 0;
318
- const hi = pkt.ptshi ?? 0;
319
- const isInvalid = hi === -2147483648 && lo === 0 || !Number.isFinite(lo);
320
- if (isInvalid) {
321
- const us2 = nextUs();
322
- pkt.pts = us2;
323
- pkt.ptshi = 0;
324
- pkt.time_base_num = 1;
325
- pkt.time_base_den = 1e6;
326
- return;
327
- }
328
- const tb = fallbackTimeBase ?? [1, 1e6];
329
- const pts64 = hi * 4294967296 + lo;
330
- const us = Math.round(pts64 * 1e6 * tb[0] / tb[1]);
331
- if (Number.isFinite(us) && Math.abs(us) <= Number.MAX_SAFE_INTEGER) {
332
- pkt.pts = us;
333
- pkt.ptshi = us < 0 ? -1 : 0;
334
- pkt.time_base_num = 1;
335
- pkt.time_base_den = 1e6;
336
- return;
483
+ function avbridgeVideoToMediabunny(c) {
484
+ switch (c) {
485
+ case "h264":
486
+ return "avc";
487
+ case "h265":
488
+ return "hevc";
489
+ case "vp9":
490
+ return "vp9";
491
+ case "av1":
492
+ return "av1";
337
493
  }
338
- const fallback = nextUs();
339
- pkt.pts = fallback;
340
- pkt.ptshi = 0;
341
- pkt.time_base_num = 1;
342
- pkt.time_base_den = 1e6;
343
494
  }
344
- function createOutputFormat(mb, format) {
345
- switch (format) {
346
- case "mp4":
347
- return new mb.Mp4OutputFormat({ fastStart: "in-memory" });
348
- case "webm":
349
- return new mb.WebMOutputFormat();
350
- case "mkv":
351
- return new mb.MkvOutputFormat();
352
- default:
353
- return new mb.Mp4OutputFormat({ fastStart: "in-memory" });
495
+ function avbridgeAudioToMediabunny(c) {
496
+ switch (c) {
497
+ case "aac":
498
+ return "aac";
499
+ case "opus":
500
+ return "opus";
501
+ case "flac":
502
+ return "flac";
354
503
  }
355
504
  }
356
- function mimeForFormat(format) {
357
- switch (format) {
358
- case "mp4":
359
- return "video/mp4";
360
- case "webm":
361
- return "video/webm";
362
- case "mkv":
363
- return "video/x-matroska";
364
- default:
365
- return "application/octet-stream";
505
+ function qualityToMediabunny(mb, quality, override) {
506
+ if (override !== void 0) return override;
507
+ switch (quality) {
508
+ case "low":
509
+ return mb.QUALITY_LOW;
510
+ case "medium":
511
+ return mb.QUALITY_MEDIUM;
512
+ case "high":
513
+ return mb.QUALITY_HIGH;
514
+ case "very-high":
515
+ return mb.QUALITY_VERY_HIGH;
366
516
  }
367
517
  }
368
- function generateFilename(originalName, format) {
369
- const ext = format === "mkv" ? "mkv" : format;
370
- if (!originalName) return `output.${ext}`;
371
- const base = originalName.replace(/\.[^.]+$/, "");
372
- return `${base}.${ext}`;
373
- }
374
- var _seqCounter = 0;
375
- function libavPacketToMediAbunny(mb, pkt) {
376
- const KEY_FRAME_FLAG = 1;
377
- const timestampSec = (pkt.pts ?? 0) / 1e6;
378
- const durationSec = (pkt.duration ?? 0) / 1e6;
379
- const type = pkt.flags & KEY_FRAME_FLAG ? "key" : "delta";
380
- return new mb.EncodedPacket(pkt.data, type, timestampSec, durationSec, _seqCounter++);
381
- }
382
- function buildVideoDecoderConfig(track) {
383
- return {
384
- codec: track.codecString ?? track.codec,
385
- codedWidth: track.width,
386
- codedHeight: track.height
387
- };
388
- }
389
- function buildAudioDecoderConfig(track) {
390
- return {
391
- codec: track.codecString ?? track.codec,
392
- numberOfChannels: track.channels,
393
- sampleRate: track.sampleRate
394
- };
395
- }
396
518
 
397
519
  // src/convert/transcode.ts
398
- var MEDIABUNNY_CONTAINERS2 = /* @__PURE__ */ new Set([
520
+ var MEDIABUNNY_CONTAINERS = /* @__PURE__ */ new Set([
399
521
  "mp4",
400
522
  "mov",
401
523
  "mkv",
@@ -413,11 +535,16 @@ async function transcode(source, options = {}) {
413
535
  const quality = options.quality ?? "medium";
414
536
  validateCodecCompatibility(outputFormat, videoCodec, audioCodec);
415
537
  options.signal?.throwIfAborted();
416
- const ctx = await chunk7RGG6ME7_cjs.probe(source);
538
+ const ctx = await chunkZCUXHW55_cjs.probe(source);
417
539
  options.signal?.throwIfAborted();
418
- if (!MEDIABUNNY_CONTAINERS2.has(ctx.container)) {
419
- throw new Error(
420
- `Cannot transcode "${ctx.container}" sources in v1. transcode() only supports inputs that mediabunny can read (MP4, MKV, WebM, OGG, MP3, FLAC, WAV, MOV). For AVI/ASF/FLV sources, use the player's playback strategies instead.`
540
+ if (isLibavTranscodeContainer(ctx.container)) {
541
+ return transcodeViaLibav(ctx, options);
542
+ }
543
+ if (!MEDIABUNNY_CONTAINERS.has(ctx.container)) {
544
+ throw new chunk2IJ66NTD_cjs.AvbridgeError(
545
+ chunk2IJ66NTD_cjs.ERR_CONTAINER_NOT_SUPPORTED,
546
+ `Cannot transcode "${ctx.container}" sources. transcode() supports mediabunny-readable containers (MP4, MKV, WebM, OGG, MP3, FLAC, WAV, MOV) and legacy containers via the libav path (AVI, ASF, FLV).`,
547
+ `If this is a legacy container we don't yet support, use createPlayer() to play it. Transcode support for more containers is on the roadmap.`
421
548
  );
422
549
  }
423
550
  return doTranscode(ctx, outputFormat, videoCodec, audioCodec, quality, options);
@@ -425,7 +552,7 @@ async function transcode(source, options = {}) {
425
552
  async function attemptTranscode(ctx, outputFormat, videoCodec, audioCodec, quality, options) {
426
553
  const mb = await import('mediabunny');
427
554
  const input = new mb.Input({
428
- source: await chunk7RGG6ME7_cjs.buildMediabunnySourceFromInput(mb, ctx.source),
555
+ source: await chunkZCUXHW55_cjs.buildMediabunnySourceFromInput(mb, ctx.source),
429
556
  formats: mb.ALL_FORMATS
430
557
  });
431
558
  let bytesWritten = 0;
@@ -439,12 +566,12 @@ async function attemptTranscode(ctx, outputFormat, videoCodec, audioCodec, quali
439
566
  }
440
567
  })) : null;
441
568
  const output = new mb.Output({
442
- format: createOutputFormat(mb, outputFormat),
569
+ format: chunkQ2VUO52Z_cjs.createOutputFormat(mb, outputFormat),
443
570
  target: streamTarget ?? bufferTarget
444
571
  });
445
572
  const videoOptions = options.dropVideo ? { discard: true } : {
446
573
  codec: avbridgeVideoToMediabunny2(videoCodec),
447
- bitrate: options.videoBitrate ?? qualityToMediabunny(mb, quality),
574
+ bitrate: options.videoBitrate ?? qualityToMediabunny2(mb, quality),
448
575
  forceTranscode: true,
449
576
  ...options.width !== void 0 ? { width: options.width } : {},
450
577
  ...options.height !== void 0 ? { height: options.height } : {},
@@ -454,7 +581,7 @@ async function attemptTranscode(ctx, outputFormat, videoCodec, audioCodec, quali
454
581
  };
455
582
  const audioOptions = options.dropAudio ? { discard: true } : {
456
583
  codec: avbridgeAudioToMediabunny2(audioCodec),
457
- bitrate: options.audioBitrate ?? qualityToMediabunny(mb, quality),
584
+ bitrate: options.audioBitrate ?? qualityToMediabunny2(mb, quality),
458
585
  forceTranscode: true
459
586
  };
460
587
  const conversion = await mb.Conversion.init({
@@ -530,8 +657,8 @@ async function doTranscode(ctx, outputFormat, videoCodec, audioCodec, quality, o
530
657
  await new Promise((r) => setTimeout(r, 50 * (attempt + 1)));
531
658
  }
532
659
  }
533
- const mimeType = mimeForFormat(outputFormat);
534
- const filename = generateFilename(ctx.name, outputFormat);
660
+ const mimeType = chunkQ2VUO52Z_cjs.mimeForFormat(outputFormat);
661
+ const filename = chunkQ2VUO52Z_cjs.generateFilename(ctx.name, outputFormat);
535
662
  if (options.outputStream) {
536
663
  options.onProgress?.({ percent: 100, bytesWritten: 0 });
537
664
  return {
@@ -617,7 +744,7 @@ function avbridgeAudioToMediabunny2(c) {
617
744
  return "flac";
618
745
  }
619
746
  }
620
- function qualityToMediabunny(mb, quality) {
747
+ function qualityToMediabunny2(mb, quality) {
621
748
  switch (quality) {
622
749
  case "low":
623
750
  return mb.QUALITY_LOW;
@@ -630,95 +757,98 @@ function qualityToMediabunny(mb, quality) {
630
757
  }
631
758
  }
632
759
 
760
+ Object.defineProperty(exports, "remux", {
761
+ enumerable: true,
762
+ get: function () { return chunkQ2VUO52Z_cjs.remux; }
763
+ });
633
764
  Object.defineProperty(exports, "FALLBACK_AUDIO_CODECS", {
634
765
  enumerable: true,
635
- get: function () { return chunk7RGG6ME7_cjs.FALLBACK_AUDIO_CODECS; }
766
+ get: function () { return chunk6SOFJV44_cjs.FALLBACK_AUDIO_CODECS; }
636
767
  });
637
768
  Object.defineProperty(exports, "FALLBACK_VIDEO_CODECS", {
638
769
  enumerable: true,
639
- get: function () { return chunk7RGG6ME7_cjs.FALLBACK_VIDEO_CODECS; }
770
+ get: function () { return chunk6SOFJV44_cjs.FALLBACK_VIDEO_CODECS; }
640
771
  });
641
772
  Object.defineProperty(exports, "NATIVE_AUDIO_CODECS", {
642
773
  enumerable: true,
643
- get: function () { return chunk7RGG6ME7_cjs.NATIVE_AUDIO_CODECS; }
774
+ get: function () { return chunk6SOFJV44_cjs.NATIVE_AUDIO_CODECS; }
644
775
  });
645
776
  Object.defineProperty(exports, "NATIVE_VIDEO_CODECS", {
646
777
  enumerable: true,
647
- get: function () { return chunk7RGG6ME7_cjs.NATIVE_VIDEO_CODECS; }
778
+ get: function () { return chunk6SOFJV44_cjs.NATIVE_VIDEO_CODECS; }
648
779
  });
649
780
  Object.defineProperty(exports, "UnifiedPlayer", {
650
781
  enumerable: true,
651
- get: function () { return chunk7RGG6ME7_cjs.UnifiedPlayer; }
782
+ get: function () { return chunk6SOFJV44_cjs.UnifiedPlayer; }
652
783
  });
653
784
  Object.defineProperty(exports, "classify", {
654
785
  enumerable: true,
655
- get: function () { return chunk7RGG6ME7_cjs.classifyContext; }
786
+ get: function () { return chunk6SOFJV44_cjs.classifyContext; }
656
787
  });
657
788
  Object.defineProperty(exports, "createPlayer", {
658
789
  enumerable: true,
659
- get: function () { return chunk7RGG6ME7_cjs.createPlayer; }
790
+ get: function () { return chunk6SOFJV44_cjs.createPlayer; }
660
791
  });
661
- Object.defineProperty(exports, "probe", {
792
+ Object.defineProperty(exports, "srtToVtt", {
662
793
  enumerable: true,
663
- get: function () { return chunk7RGG6ME7_cjs.probe; }
794
+ get: function () { return chunkS4WAZC2T_cjs.srtToVtt; }
664
795
  });
665
- Object.defineProperty(exports, "srtToVtt", {
796
+ Object.defineProperty(exports, "probe", {
666
797
  enumerable: true,
667
- get: function () { return chunk7RGG6ME7_cjs.srtToVtt; }
798
+ get: function () { return chunkZCUXHW55_cjs.probe; }
668
799
  });
669
800
  Object.defineProperty(exports, "AvbridgeError", {
670
801
  enumerable: true,
671
- get: function () { return chunk6UUT4BEA_cjs.AvbridgeError; }
802
+ get: function () { return chunk2IJ66NTD_cjs.AvbridgeError; }
672
803
  });
673
804
  Object.defineProperty(exports, "ERR_ALL_STRATEGIES_EXHAUSTED", {
674
805
  enumerable: true,
675
- get: function () { return chunk6UUT4BEA_cjs.ERR_ALL_STRATEGIES_EXHAUSTED; }
806
+ get: function () { return chunk2IJ66NTD_cjs.ERR_ALL_STRATEGIES_EXHAUSTED; }
676
807
  });
677
808
  Object.defineProperty(exports, "ERR_CODEC_NOT_SUPPORTED", {
678
809
  enumerable: true,
679
- get: function () { return chunk6UUT4BEA_cjs.ERR_CODEC_NOT_SUPPORTED; }
810
+ get: function () { return chunk2IJ66NTD_cjs.ERR_CODEC_NOT_SUPPORTED; }
680
811
  });
681
812
  Object.defineProperty(exports, "ERR_FETCH_FAILED", {
682
813
  enumerable: true,
683
- get: function () { return chunk6UUT4BEA_cjs.ERR_FETCH_FAILED; }
814
+ get: function () { return chunk2IJ66NTD_cjs.ERR_FETCH_FAILED; }
684
815
  });
685
816
  Object.defineProperty(exports, "ERR_LIBAV_NOT_REACHABLE", {
686
817
  enumerable: true,
687
- get: function () { return chunk6UUT4BEA_cjs.ERR_LIBAV_NOT_REACHABLE; }
818
+ get: function () { return chunk2IJ66NTD_cjs.ERR_LIBAV_NOT_REACHABLE; }
688
819
  });
689
820
  Object.defineProperty(exports, "ERR_MSE_CODEC_NOT_SUPPORTED", {
690
821
  enumerable: true,
691
- get: function () { return chunk6UUT4BEA_cjs.ERR_MSE_CODEC_NOT_SUPPORTED; }
822
+ get: function () { return chunk2IJ66NTD_cjs.ERR_MSE_CODEC_NOT_SUPPORTED; }
692
823
  });
693
824
  Object.defineProperty(exports, "ERR_MSE_NOT_SUPPORTED", {
694
825
  enumerable: true,
695
- get: function () { return chunk6UUT4BEA_cjs.ERR_MSE_NOT_SUPPORTED; }
826
+ get: function () { return chunk2IJ66NTD_cjs.ERR_MSE_NOT_SUPPORTED; }
696
827
  });
697
828
  Object.defineProperty(exports, "ERR_PLAYER_NOT_READY", {
698
829
  enumerable: true,
699
- get: function () { return chunk6UUT4BEA_cjs.ERR_PLAYER_NOT_READY; }
830
+ get: function () { return chunk2IJ66NTD_cjs.ERR_PLAYER_NOT_READY; }
700
831
  });
701
832
  Object.defineProperty(exports, "ERR_PROBE_FAILED", {
702
833
  enumerable: true,
703
- get: function () { return chunk6UUT4BEA_cjs.ERR_PROBE_FAILED; }
834
+ get: function () { return chunk2IJ66NTD_cjs.ERR_PROBE_FAILED; }
704
835
  });
705
836
  Object.defineProperty(exports, "ERR_PROBE_FETCH_FAILED", {
706
837
  enumerable: true,
707
- get: function () { return chunk6UUT4BEA_cjs.ERR_PROBE_FETCH_FAILED; }
838
+ get: function () { return chunk2IJ66NTD_cjs.ERR_PROBE_FETCH_FAILED; }
708
839
  });
709
840
  Object.defineProperty(exports, "ERR_PROBE_UNKNOWN_CONTAINER", {
710
841
  enumerable: true,
711
- get: function () { return chunk6UUT4BEA_cjs.ERR_PROBE_UNKNOWN_CONTAINER; }
842
+ get: function () { return chunk2IJ66NTD_cjs.ERR_PROBE_UNKNOWN_CONTAINER; }
712
843
  });
713
844
  Object.defineProperty(exports, "ERR_RANGE_NOT_SUPPORTED", {
714
845
  enumerable: true,
715
- get: function () { return chunk6UUT4BEA_cjs.ERR_RANGE_NOT_SUPPORTED; }
846
+ get: function () { return chunk2IJ66NTD_cjs.ERR_RANGE_NOT_SUPPORTED; }
716
847
  });
717
848
  Object.defineProperty(exports, "ERR_STRATEGY_FAILED", {
718
849
  enumerable: true,
719
- get: function () { return chunk6UUT4BEA_cjs.ERR_STRATEGY_FAILED; }
850
+ get: function () { return chunk2IJ66NTD_cjs.ERR_STRATEGY_FAILED; }
720
851
  });
721
- exports.remux = remux;
722
852
  exports.transcode = transcode;
723
853
  //# sourceMappingURL=index.cjs.map
724
854
  //# sourceMappingURL=index.cjs.map