weblet-convert 0.0.4 → 0.0.5
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.
- package/README.md +38 -2
- package/dist/browser/index.cjs +253 -10
- package/dist/browser/index.cjs.map +1 -1
- package/dist/browser/index.d.cts +46 -1
- package/dist/browser/index.d.ts +46 -1
- package/dist/browser/index.js +253 -11
- package/dist/browser/index.js.map +1 -1
- package/dist/index.cjs +253 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +46 -1
- package/dist/index.d.ts +46 -1
- package/dist/index.js +253 -11
- package/dist/index.js.map +1 -1
- package/dist/node/index.cjs +77 -26
- package/dist/node/index.cjs.map +1 -1
- package/dist/node/index.js +77 -26
- package/dist/node/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -96,12 +96,48 @@ Notes:
|
|
|
96
96
|
|
|
97
97
|
Transcodes videos to WebM.
|
|
98
98
|
|
|
99
|
+
`video` options now support ffmpeg.wasm asset configuration in browser runtimes:
|
|
100
|
+
|
|
101
|
+
- `ffmpeg.baseURL` (auto-derives core/wasm/worker URLs)
|
|
102
|
+
- or explicit `ffmpeg.coreURL`, `ffmpeg.wasmURL`, `ffmpeg.workerURL`
|
|
103
|
+
|
|
104
|
+
### `videoToWebmDebug(input, options?, onEvent?)` (Ultimate debug mode)
|
|
105
|
+
|
|
106
|
+
Browser-only debug helper for diagnosing ffmpeg.wasm failures.
|
|
107
|
+
|
|
108
|
+
- Returns `{ ok: true, ...result, events, diagnostic }` on success
|
|
109
|
+
- Returns `{ ok: false, error, events, diagnostic }` on failure
|
|
110
|
+
- Emits stage events like `init`, `transcode`, `retry-reset`, and `done`
|
|
111
|
+
- `diagnostic` includes:
|
|
112
|
+
- `cause` (classified root-cause code, e.g. `ffmpeg-init-failed`, `input-too-large`)
|
|
113
|
+
- `stage` (where it failed)
|
|
114
|
+
- `rawError`
|
|
115
|
+
- `recoverable`
|
|
116
|
+
- `hints` (actionable fixes)
|
|
117
|
+
|
|
118
|
+
Example:
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
import { videoToWebmDebug } from "@weblet/convert"
|
|
122
|
+
|
|
123
|
+
const debug = await videoToWebmDebug(file, { maxInputBytes: 256 * 1024 * 1024 }, (e) => {
|
|
124
|
+
console.log(`[${e.stage}] ${e.message}`, e.detail ?? "")
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
if (!debug.ok) {
|
|
128
|
+
console.error("WebM conversion failed:", debug.error.message)
|
|
129
|
+
console.error("Cause:", debug.diagnostic.cause)
|
|
130
|
+
console.error("Hints:", debug.diagnostic.hints.join(" | "))
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
99
134
|
## Notes and limitations
|
|
100
135
|
|
|
101
136
|
- **Browser WebP support varies**: the browser build relies on Canvas/OffscreenCanvas WebP encoding support. When encoding isn’t available, the function can return the original input and set `isWebp: false`.
|
|
102
137
|
- **Metadata**: EXIF/IPTC metadata is not preserved.
|
|
103
138
|
- **Not a perfect “max bytes” guarantee**: `targetBytes` is a best-effort search within the provided quality range.
|
|
104
|
-
- **Browser video
|
|
139
|
+
- **Browser video input limit**: by default there is **no input-size limit** (`maxInputBytes: 0`).
|
|
140
|
+
If you want a safeguard in your app, set `video: { maxInputBytes: ... }` explicitly.
|
|
105
141
|
|
|
106
142
|
## Troubleshooting video conversion
|
|
107
143
|
|
|
@@ -115,7 +151,7 @@ Transcodes videos to WebM.
|
|
|
115
151
|
|
|
116
152
|
## Import paths
|
|
117
153
|
|
|
118
|
-
- **Browser**: `import { convert, imageToWebp, videoToWebm } from "@weblet/convert"`
|
|
154
|
+
- **Browser**: `import { convert, imageToWebp, videoToWebm, videoToWebmDebug } from "@weblet/convert"`
|
|
119
155
|
- **Node**: `import { convert, imageToWebp, videoToWebm } from "weblet-convert/node"`
|
|
120
156
|
|
|
121
157
|
## Build (contributors)
|
package/dist/browser/index.cjs
CHANGED
|
@@ -46,17 +46,68 @@ function defaultVideoName(input, fileName) {
|
|
|
46
46
|
var ffmpegSingleton = null;
|
|
47
47
|
var ffmpegLoadPromise = null;
|
|
48
48
|
var ffmpegJobQueue = Promise.resolve();
|
|
49
|
-
|
|
49
|
+
var ffmpegConfigKey = "{}";
|
|
50
|
+
function normalizeBrowserFfmpegLoadOptions(input) {
|
|
51
|
+
if (!input) return void 0;
|
|
52
|
+
const baseURL = input.baseURL?.trim();
|
|
53
|
+
const normalize = (v) => v?.trim() || void 0;
|
|
54
|
+
const make = (suffix) => {
|
|
55
|
+
if (!baseURL) return void 0;
|
|
56
|
+
return `${baseURL.replace(/\/+$/, "")}/${suffix}`;
|
|
57
|
+
};
|
|
58
|
+
return {
|
|
59
|
+
baseURL,
|
|
60
|
+
coreURL: normalize(input.coreURL) ?? make("ffmpeg-core.js"),
|
|
61
|
+
wasmURL: normalize(input.wasmURL) ?? make("ffmpeg-core.wasm"),
|
|
62
|
+
workerURL: normalize(input.workerURL) ?? make("ffmpeg-core.worker.js")
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function getFfmpegConfigKey(input) {
|
|
66
|
+
return JSON.stringify(normalizeBrowserFfmpegLoadOptions(input) ?? {});
|
|
67
|
+
}
|
|
68
|
+
async function getFfmpeg(loadOptions) {
|
|
69
|
+
const nextKey = getFfmpegConfigKey(loadOptions);
|
|
70
|
+
if (nextKey !== ffmpegConfigKey) {
|
|
71
|
+
await resetFfmpegRuntime();
|
|
72
|
+
ffmpegConfigKey = nextKey;
|
|
73
|
+
}
|
|
50
74
|
if (ffmpegSingleton) return ffmpegSingleton;
|
|
51
75
|
if (ffmpegLoadPromise) return ffmpegLoadPromise;
|
|
52
76
|
const ff = new ffmpeg.FFmpeg();
|
|
77
|
+
const normalized = normalizeBrowserFfmpegLoadOptions(loadOptions);
|
|
78
|
+
const loadParams = normalized && (normalized.coreURL || normalized.wasmURL || normalized.workerURL) ? {
|
|
79
|
+
...normalized.coreURL ? { coreURL: normalized.coreURL } : {},
|
|
80
|
+
...normalized.wasmURL ? { wasmURL: normalized.wasmURL } : {},
|
|
81
|
+
...normalized.workerURL ? { workerURL: normalized.workerURL } : {}
|
|
82
|
+
} : void 0;
|
|
53
83
|
ffmpegLoadPromise = (async () => {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
84
|
+
try {
|
|
85
|
+
await ff.load(loadParams);
|
|
86
|
+
ffmpegSingleton = ff;
|
|
87
|
+
return ff;
|
|
88
|
+
} catch (err) {
|
|
89
|
+
ffmpegLoadPromise = null;
|
|
90
|
+
const detail = [
|
|
91
|
+
"Failed to initialize ffmpeg.wasm.",
|
|
92
|
+
`error=${toErrorMessage(err)}`,
|
|
93
|
+
"hint=Ensure ffmpeg core/worker assets are reachable by your bundler/runtime and not blocked by CSP/CORS."
|
|
94
|
+
].join("\n");
|
|
95
|
+
throw new Error(detail);
|
|
96
|
+
}
|
|
57
97
|
})();
|
|
58
98
|
return ffmpegLoadPromise;
|
|
59
99
|
}
|
|
100
|
+
async function resetFfmpegRuntime() {
|
|
101
|
+
const current = ffmpegSingleton;
|
|
102
|
+
ffmpegSingleton = null;
|
|
103
|
+
ffmpegLoadPromise = null;
|
|
104
|
+
if (current && typeof current.terminate === "function") {
|
|
105
|
+
try {
|
|
106
|
+
await current.terminate();
|
|
107
|
+
} catch {
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
60
111
|
async function runWithFfmpegLock(job) {
|
|
61
112
|
const previous = ffmpegJobQueue;
|
|
62
113
|
let release;
|
|
@@ -73,15 +124,110 @@ async function runWithFfmpegLock(job) {
|
|
|
73
124
|
function createFsSafeId() {
|
|
74
125
|
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
75
126
|
}
|
|
127
|
+
function toErrorMessage(err) {
|
|
128
|
+
if (err instanceof Error && err.message) return err.message;
|
|
129
|
+
if (typeof err === "string") return err;
|
|
130
|
+
try {
|
|
131
|
+
return JSON.stringify(err);
|
|
132
|
+
} catch {
|
|
133
|
+
return String(err);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
function formatArgs(args) {
|
|
137
|
+
return args.map((v) => /\s/.test(v) ? `"${v}"` : v).join(" ");
|
|
138
|
+
}
|
|
139
|
+
function isRecoverableWasmError(err) {
|
|
140
|
+
const msg = toErrorMessage(err).toLowerCase();
|
|
141
|
+
return msg.includes("memory access out of bounds") || msg.includes("runtimeerror") || msg.includes("aborted") || msg.includes("wasm");
|
|
142
|
+
}
|
|
76
143
|
var VIDEO_DEFAULTS = {
|
|
77
144
|
crf: 32,
|
|
78
145
|
deadline: "good",
|
|
79
|
-
returnFile: false
|
|
146
|
+
returnFile: false,
|
|
147
|
+
maxInputBytes: 64 * 1024 * 1024
|
|
80
148
|
};
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
149
|
+
function assertVideoInputGuardrails(blob, opts) {
|
|
150
|
+
if (opts.maxInputBytes > 0 && blob.size > opts.maxInputBytes) {
|
|
151
|
+
throw new Error(
|
|
152
|
+
[
|
|
153
|
+
"videoToWebm guardrail: input too large for browser ffmpeg.wasm.",
|
|
154
|
+
`input_bytes=${blob.size}`,
|
|
155
|
+
`max_input_bytes=${opts.maxInputBytes}`,
|
|
156
|
+
"hint=Lower source resolution/bitrate, trim video, or increase maxInputBytes if your environment has enough memory."
|
|
157
|
+
].join("\n")
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
function buildVideoDiagnostic(stage, err) {
|
|
162
|
+
const raw = toErrorMessage(err);
|
|
163
|
+
const lower = raw.toLowerCase();
|
|
164
|
+
const recoverable = isRecoverableWasmError(err);
|
|
165
|
+
if (lower.includes("failed to fetch")) {
|
|
166
|
+
return {
|
|
167
|
+
cause: "input-fetch-failed",
|
|
168
|
+
stage,
|
|
169
|
+
rawError: raw,
|
|
170
|
+
recoverable: false,
|
|
171
|
+
hints: ["Verify URL reachability and CORS policy for browser fetch."]
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
if (lower.includes("input too large") || lower.includes("max_input_bytes")) {
|
|
175
|
+
return {
|
|
176
|
+
cause: "input-too-large",
|
|
177
|
+
stage,
|
|
178
|
+
rawError: raw,
|
|
179
|
+
recoverable: false,
|
|
180
|
+
hints: ["Increase maxInputBytes or reduce source size/resolution/duration."]
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
if (lower.includes("failed to initialize ffmpeg.wasm")) {
|
|
184
|
+
return {
|
|
185
|
+
cause: "ffmpeg-init-failed",
|
|
186
|
+
stage,
|
|
187
|
+
rawError: raw,
|
|
188
|
+
recoverable,
|
|
189
|
+
hints: [
|
|
190
|
+
"Provide video.ffmpeg.baseURL or explicit coreURL/wasmURL/workerURL.",
|
|
191
|
+
"Ensure CSP/CORS allows ffmpeg worker + wasm assets."
|
|
192
|
+
]
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
if (lower.includes("memory access out of bounds") || lower.includes("runtimeerror") || lower.includes("aborted")) {
|
|
196
|
+
return {
|
|
197
|
+
cause: "ffmpeg-wasm-runtime-crash",
|
|
198
|
+
stage,
|
|
199
|
+
rawError: raw,
|
|
200
|
+
recoverable: true,
|
|
201
|
+
hints: ["Reduce workload: trim duration, lower resolution/bitrate, or split video."]
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
if (lower.includes("videotowebm failed")) {
|
|
205
|
+
return {
|
|
206
|
+
cause: "ffmpeg-transcode-failed",
|
|
207
|
+
stage,
|
|
208
|
+
rawError: raw,
|
|
209
|
+
recoverable,
|
|
210
|
+
hints: ["Inspect ffmpeg_logs in rawError for codec/container-specific details."]
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
if (lower.includes("unsupported input type")) {
|
|
214
|
+
return {
|
|
215
|
+
cause: "unsupported-input",
|
|
216
|
+
stage,
|
|
217
|
+
rawError: raw,
|
|
218
|
+
recoverable: false,
|
|
219
|
+
hints: ["Use a valid image/* or video/* input and ensure proper MIME/magic bytes."]
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
return {
|
|
223
|
+
cause: "unknown",
|
|
224
|
+
stage,
|
|
225
|
+
rawError: raw,
|
|
226
|
+
recoverable,
|
|
227
|
+
hints: ["Use videoToWebmDebug() output to trace failing stage and share rawError."]
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
async function runVideoTranscodeJob(ffmpeg, blob, opts) {
|
|
85
231
|
const jobId = createFsSafeId();
|
|
86
232
|
const inName = `input-${jobId}`;
|
|
87
233
|
const outName = `output-${jobId}.webm`;
|
|
@@ -109,18 +255,114 @@ async function videoToWebm(input, options = {}) {
|
|
|
109
255
|
"libopus",
|
|
110
256
|
outName
|
|
111
257
|
];
|
|
258
|
+
const logs = [];
|
|
259
|
+
const onLog = ({ message }) => {
|
|
260
|
+
if (typeof message !== "string" || message.length === 0) return;
|
|
261
|
+
logs.push(message);
|
|
262
|
+
if (logs.length > 60) logs.shift();
|
|
263
|
+
};
|
|
112
264
|
try {
|
|
265
|
+
ffmpeg.on("log", onLog);
|
|
113
266
|
await ffmpeg.exec(args);
|
|
114
267
|
const outData = await ffmpeg.readFile(outName);
|
|
115
268
|
return outData instanceof Uint8Array ? outData : new Uint8Array(outData);
|
|
269
|
+
} catch (err) {
|
|
270
|
+
const detail = [
|
|
271
|
+
`videoToWebm failed.`,
|
|
272
|
+
`input=${inName}`,
|
|
273
|
+
`output=${outName}`,
|
|
274
|
+
`args=${formatArgs(args)}`,
|
|
275
|
+
`error=${toErrorMessage(err)}`,
|
|
276
|
+
logs.length ? `ffmpeg_logs:
|
|
277
|
+
${logs.join("\n")}` : "ffmpeg_logs: <none>"
|
|
278
|
+
].join("\n");
|
|
279
|
+
throw new Error(detail);
|
|
116
280
|
} finally {
|
|
281
|
+
ffmpeg.off("log", onLog);
|
|
117
282
|
await Promise.allSettled([ffmpeg.deleteFile(inName), ffmpeg.deleteFile(outName)]);
|
|
118
283
|
}
|
|
119
284
|
});
|
|
120
|
-
|
|
285
|
+
return new Blob([outBytes], { type: "video/webm" });
|
|
286
|
+
}
|
|
287
|
+
async function videoToWebm(input, options = {}) {
|
|
288
|
+
const opts = { ...VIDEO_DEFAULTS, ...options };
|
|
289
|
+
const blob = await inputToBlob(input);
|
|
290
|
+
assertVideoInputGuardrails(blob, opts);
|
|
291
|
+
let outBlob;
|
|
292
|
+
try {
|
|
293
|
+
const ffmpeg = await getFfmpeg(opts.ffmpeg);
|
|
294
|
+
outBlob = await runVideoTranscodeJob(ffmpeg, blob, opts);
|
|
295
|
+
} catch (err) {
|
|
296
|
+
if (!isRecoverableWasmError(err)) throw err;
|
|
297
|
+
await resetFfmpegRuntime();
|
|
298
|
+
const ffmpeg = await getFfmpeg(opts.ffmpeg);
|
|
299
|
+
outBlob = await runVideoTranscodeJob(ffmpeg, blob, opts);
|
|
300
|
+
}
|
|
121
301
|
const file = opts.returnFile ? new File([outBlob], defaultVideoName(input, opts.fileName), { type: outBlob.type }) : void 0;
|
|
122
302
|
return { blob: outBlob, file, isWebm: true };
|
|
123
303
|
}
|
|
304
|
+
async function videoToWebmDebug(input, options = {}, onEvent) {
|
|
305
|
+
const events = [];
|
|
306
|
+
let lastStage = "input";
|
|
307
|
+
const emit = (event) => {
|
|
308
|
+
lastStage = event.stage;
|
|
309
|
+
events.push(event);
|
|
310
|
+
onEvent?.(event);
|
|
311
|
+
};
|
|
312
|
+
try {
|
|
313
|
+
emit({ stage: "input", message: "Reading input as Blob." });
|
|
314
|
+
const opts = { ...VIDEO_DEFAULTS, ...options };
|
|
315
|
+
const blob = await inputToBlob(input);
|
|
316
|
+
emit({
|
|
317
|
+
stage: "guardrail",
|
|
318
|
+
message: "Checking browser ffmpeg.wasm memory guardrail.",
|
|
319
|
+
detail: `input_bytes=${blob.size};max_input_bytes=${opts.maxInputBytes}`
|
|
320
|
+
});
|
|
321
|
+
assertVideoInputGuardrails(blob, opts);
|
|
322
|
+
let outBlob;
|
|
323
|
+
try {
|
|
324
|
+
emit({ stage: "init", message: "Initializing ffmpeg.wasm runtime." });
|
|
325
|
+
const ffmpeg = await getFfmpeg(opts.ffmpeg);
|
|
326
|
+
emit({ stage: "transcode", message: "Running video transcode job (VP9 + Opus)." });
|
|
327
|
+
outBlob = await runVideoTranscodeJob(ffmpeg, blob, opts);
|
|
328
|
+
} catch (err) {
|
|
329
|
+
if (!isRecoverableWasmError(err)) throw err;
|
|
330
|
+
emit({
|
|
331
|
+
stage: "retry-reset",
|
|
332
|
+
message: "Recoverable wasm error detected, resetting runtime.",
|
|
333
|
+
detail: toErrorMessage(err)
|
|
334
|
+
});
|
|
335
|
+
await resetFfmpegRuntime();
|
|
336
|
+
emit({ stage: "retry-init", message: "Reinitializing ffmpeg.wasm runtime." });
|
|
337
|
+
const ffmpeg = await getFfmpeg(opts.ffmpeg);
|
|
338
|
+
emit({ stage: "retry-transcode", message: "Retrying video transcode job." });
|
|
339
|
+
outBlob = await runVideoTranscodeJob(ffmpeg, blob, opts);
|
|
340
|
+
}
|
|
341
|
+
const file = opts.returnFile ? new File([outBlob], defaultVideoName(input, opts.fileName), { type: outBlob.type }) : void 0;
|
|
342
|
+
emit({
|
|
343
|
+
stage: "done",
|
|
344
|
+
message: "Video converted to WebM.",
|
|
345
|
+
detail: `output_bytes=${outBlob.size};mime=${outBlob.type}`
|
|
346
|
+
});
|
|
347
|
+
return {
|
|
348
|
+
ok: true,
|
|
349
|
+
blob: outBlob,
|
|
350
|
+
file,
|
|
351
|
+
isWebm: true,
|
|
352
|
+
events,
|
|
353
|
+
diagnostic: { cause: "none", stage: "done", recoverable: false, hints: [] }
|
|
354
|
+
};
|
|
355
|
+
} catch (err) {
|
|
356
|
+
const error = err instanceof Error ? err : new Error(toErrorMessage(err));
|
|
357
|
+
const diagnostic = buildVideoDiagnostic(lastStage, error);
|
|
358
|
+
emit({
|
|
359
|
+
stage: "done",
|
|
360
|
+
message: "Video conversion failed.",
|
|
361
|
+
detail: `cause=${diagnostic.cause};${error.message}`
|
|
362
|
+
});
|
|
363
|
+
return { ok: false, error, events, diagnostic };
|
|
364
|
+
}
|
|
365
|
+
}
|
|
124
366
|
async function detectKindBrowser(input) {
|
|
125
367
|
if (typeof input !== "string") {
|
|
126
368
|
const t = (input.type || "").toLowerCase();
|
|
@@ -274,5 +516,6 @@ async function imageToWebp(input, options = {}) {
|
|
|
274
516
|
exports.convert = convert;
|
|
275
517
|
exports.imageToWebp = imageToWebp;
|
|
276
518
|
exports.videoToWebm = videoToWebm;
|
|
519
|
+
exports.videoToWebmDebug = videoToWebmDebug;
|
|
277
520
|
//# sourceMappingURL=index.cjs.map
|
|
278
521
|
//# sourceMappingURL=index.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/browser/index.ts"],"names":["FFmpeg","fetchFile","fileTypeFromBuffer","canvas","ctx","fileName","file"],"mappings":"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","file":"index.cjs","sourcesContent":["import { FFmpeg } from \"@ffmpeg/ffmpeg\"\r\nimport { fetchFile } from \"@ffmpeg/util\"\r\nimport { fileTypeFromBuffer } from \"file-type\"\r\n\r\nimport type { ConvertResult } from \"../shared/types.js\"\r\n\r\nexport type ImageToWebpInput = Blob | File | string\r\n\r\nexport type ImageToWebpOptions = {\r\n /**\r\n * Hard cap for output dimensions, preserving aspect ratio.\r\n * If the input is larger, it will be downscaled.\r\n */\r\n maxWidth?: number\r\n maxHeight?: number\r\n\r\n /**\r\n * Target maximum output size in bytes.\r\n * If provided, the encoder will try to reach <= targetBytes by reducing quality.\r\n */\r\n targetBytes?: number\r\n\r\n /**\r\n * Quality search range (0..1). Higher is better quality, larger file.\r\n */\r\n maxQuality?: number\r\n minQuality?: number\r\n\r\n /**\r\n * If true, always return WebP even if it can't reach targetBytes.\r\n * If false, will return the original input when WebP isn't supported.\r\n */\r\n force?: boolean\r\n\r\n /**\r\n * Optional output filename (only used when returning a File).\r\n * If omitted and input is a File, the name is derived from it.\r\n */\r\n fileName?: string\r\n\r\n /**\r\n * Return a File instead of a Blob.\r\n */\r\n returnFile?: boolean\r\n}\r\n\r\nexport type ImageToWebpResult = {\r\n blob: Blob\r\n file?: File\r\n width: number\r\n height: number\r\n quality: number\r\n /**\r\n * True if output is `image/webp`.\r\n */\r\n isWebp: boolean\r\n}\r\n\r\nconst DEFAULTS: Required<\r\n Pick<\r\n ImageToWebpOptions,\r\n \"maxWidth\" | \"maxHeight\" | \"maxQuality\" | \"minQuality\" | \"force\" | \"returnFile\"\r\n >\r\n> = {\r\n maxWidth: 2048,\r\n maxHeight: 2048,\r\n maxQuality: 0.82,\r\n minQuality: 0.45,\r\n force: true,\r\n returnFile: false,\r\n}\r\n\r\nfunction clamp01(n: number) {\r\n return Math.max(0, Math.min(1, n))\r\n}\r\n\r\nfunction toWebpName(name: string) {\r\n const base = name.replace(/\\.[^/.]+$/, \"\")\r\n return `${base || \"image\"}.webp`\r\n}\r\n\r\nfunction getInputName(input: ImageToWebpInput) {\r\n if (typeof input === \"string\") return \"image.webp\"\r\n if (input instanceof File && input.name) return toWebpName(input.name)\r\n return \"image.webp\"\r\n}\r\n\r\nasync function inputToBlob(input: ImageToWebpInput): Promise<Blob> {\r\n if (typeof input === \"string\") {\r\n const res = await fetch(input)\r\n if (!res.ok) throw new Error(`Failed to fetch: ${res.status} ${res.statusText}`)\r\n return await res.blob()\r\n }\r\n return input\r\n}\r\n\r\nfunction toWebmName(name: string) {\r\n const base = name.replace(/\\.[^/.]+$/, \"\")\r\n return `${base || \"video\"}.webm`\r\n}\r\n\r\nfunction defaultVideoName(input: Blob | File | string, fileName?: string) {\r\n if (fileName && fileName.trim().length > 0) return fileName\r\n if (typeof input === \"string\") return \"video.webm\"\r\n if (input instanceof File && input.name) return toWebmName(input.name)\r\n return \"video.webm\"\r\n}\r\n\r\nlet ffmpegSingleton: FFmpeg | null = null\r\nlet ffmpegLoadPromise: Promise<FFmpeg> | null = null\r\nlet ffmpegJobQueue: Promise<void> = Promise.resolve()\r\n\r\nasync function getFfmpeg(): Promise<FFmpeg> {\r\n if (ffmpegSingleton) return ffmpegSingleton\r\n if (ffmpegLoadPromise) return ffmpegLoadPromise\r\n const ff = new FFmpeg()\r\n ffmpegLoadPromise = (async () => {\r\n await ff.load()\r\n ffmpegSingleton = ff\r\n return ff\r\n })()\r\n return ffmpegLoadPromise\r\n}\r\n\r\nasync function runWithFfmpegLock<T>(job: () => Promise<T>): Promise<T> {\r\n const previous = ffmpegJobQueue\r\n let release!: () => void\r\n ffmpegJobQueue = new Promise<void>((resolve) => {\r\n release = resolve\r\n })\r\n await previous\r\n try {\r\n return await job()\r\n } finally {\r\n release()\r\n }\r\n}\r\n\r\nfunction createFsSafeId(): string {\r\n return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`\r\n}\r\n\r\nexport type VideoToWebmInput = Blob | File | string\r\n\r\nexport type VideoToWebmOptions = {\r\n crf?: number\r\n deadline?: \"good\" | \"best\" | \"realtime\"\r\n maxDurationSeconds?: number\r\n fileName?: string\r\n returnFile?: boolean\r\n}\r\n\r\nexport type VideoToWebmResult = {\r\n blob: Blob\r\n file?: File\r\n isWebm: boolean\r\n}\r\n\r\nconst VIDEO_DEFAULTS: Required<Pick<VideoToWebmOptions, \"crf\" | \"deadline\" | \"returnFile\">> = {\r\n crf: 32,\r\n deadline: \"good\",\r\n returnFile: false,\r\n}\r\n\r\nexport async function videoToWebm(\r\n input: VideoToWebmInput,\r\n options: VideoToWebmOptions = {}\r\n): Promise<VideoToWebmResult> {\r\n const opts = { ...VIDEO_DEFAULTS, ...options }\r\n const blob = await inputToBlob(input)\r\n const ffmpeg = await getFfmpeg()\r\n const jobId = createFsSafeId()\r\n const inName = `input-${jobId}`\r\n const outName = `output-${jobId}.webm`\r\n\r\n const outBytes = await runWithFfmpegLock(async () => {\r\n await ffmpeg.writeFile(inName, await fetchFile(blob))\r\n\r\n const args: string[] = [\r\n ...(opts.maxDurationSeconds && opts.maxDurationSeconds > 0 ? [\"-t\", String(opts.maxDurationSeconds)] : []),\r\n \"-i\",\r\n inName,\r\n \"-map\",\r\n \"0:v:0\",\r\n \"-map\",\r\n \"0:a?\",\r\n \"-c:v\",\r\n \"libvpx-vp9\",\r\n \"-b:v\",\r\n \"0\",\r\n \"-crf\",\r\n String(opts.crf),\r\n \"-deadline\",\r\n opts.deadline,\r\n \"-row-mt\",\r\n \"1\",\r\n \"-c:a\",\r\n \"libopus\",\r\n outName,\r\n ]\r\n\r\n try {\r\n await ffmpeg.exec(args)\r\n const outData = await ffmpeg.readFile(outName)\r\n return outData instanceof Uint8Array ? outData : new Uint8Array(outData as any)\r\n } finally {\r\n await Promise.allSettled([ffmpeg.deleteFile(inName), ffmpeg.deleteFile(outName)])\r\n }\r\n })\r\n\r\n const outBlob = new Blob([outBytes], { type: \"video/webm\" })\r\n const file = opts.returnFile ? new File([outBlob], defaultVideoName(input, opts.fileName), { type: outBlob.type }) : undefined\r\n return { blob: outBlob, file, isWebm: true }\r\n}\r\n\r\nexport type ConvertInput = ImageToWebpInput\r\n\r\nexport type ConvertOptions = {\r\n image?: ImageToWebpOptions\r\n video?: VideoToWebmOptions\r\n returnFile?: boolean\r\n fileName?: string\r\n}\r\n\r\nasync function detectKindBrowser(input: ConvertInput): Promise<\"image\" | \"video\" | \"unknown\"> {\r\n if (typeof input !== \"string\") {\r\n const t = (input.type || \"\").toLowerCase()\r\n if (t.startsWith(\"image/\")) return \"image\"\r\n if (t.startsWith(\"video/\")) return \"video\"\r\n }\r\n\r\n const blob = await inputToBlob(input)\r\n const buf = new Uint8Array(await blob.slice(0, 4100).arrayBuffer())\r\n const ft = await fileTypeFromBuffer(buf)\r\n if (!ft) return \"unknown\"\r\n if (ft.mime.startsWith(\"image/\")) return \"image\"\r\n if (ft.mime.startsWith(\"video/\")) return \"video\"\r\n return \"unknown\"\r\n}\r\n\r\nexport async function convert(input: ConvertInput, options: ConvertOptions = {}): Promise<ConvertResult> {\r\n const kind = await detectKindBrowser(input)\r\n const returnFile = options.returnFile ?? false\r\n\r\n if (kind === \"image\") {\r\n const res = await imageToWebp(input, { ...options.image, returnFile, fileName: options.fileName })\r\n return { kind: \"image\", ...res }\r\n }\r\n\r\n if (kind === \"video\") {\r\n const res = await videoToWebm(input, { ...options.video, returnFile, fileName: options.fileName })\r\n return { kind: \"video\", ...res }\r\n }\r\n\r\n throw new Error(\"Unsupported input type. Expected an image/* or video/* asset.\")\r\n}\r\n\r\nfunction computeTargetSize(\r\n srcW: number,\r\n srcH: number,\r\n maxW: number,\r\n maxH: number\r\n): { width: number; height: number } {\r\n if (srcW <= 0 || srcH <= 0) return { width: srcW, height: srcH }\r\n const scale = Math.min(1, maxW / srcW, maxH / srcH)\r\n return {\r\n width: Math.max(1, Math.round(srcW * scale)),\r\n height: Math.max(1, Math.round(srcH * scale)),\r\n }\r\n}\r\n\r\nasync function decodeImage(blob: Blob): Promise<{ bitmap: ImageBitmap; width: number; height: number }> {\r\n if (typeof createImageBitmap === \"function\") {\r\n const bitmap = await createImageBitmap(blob, { imageOrientation: \"from-image\" as any })\r\n return { bitmap, width: bitmap.width, height: bitmap.height }\r\n }\r\n\r\n const url = URL.createObjectURL(blob)\r\n try {\r\n const img = await new Promise<HTMLImageElement>((resolve, reject) => {\r\n const el = new Image()\r\n el.onload = () => resolve(el)\r\n el.onerror = () => reject(new Error(\"Failed to decode image\"))\r\n el.src = url\r\n })\r\n\r\n const canvas = document.createElement(\"canvas\")\r\n canvas.width = img.naturalWidth || img.width\r\n canvas.height = img.naturalHeight || img.height\r\n const ctx = canvas.getContext(\"2d\")\r\n if (!ctx) throw new Error(\"Canvas 2D context not available\")\r\n ctx.drawImage(img, 0, 0)\r\n\r\n const dataUrl = canvas.toDataURL(\"image/png\")\r\n const pngBlob = await (await fetch(dataUrl)).blob()\r\n const bitmap = await createImageBitmap(pngBlob)\r\n return { bitmap, width: bitmap.width, height: bitmap.height }\r\n } finally {\r\n URL.revokeObjectURL(url)\r\n }\r\n}\r\n\r\nasync function encodeWebpFromBitmap(\r\n bitmap: ImageBitmap,\r\n width: number,\r\n height: number,\r\n quality: number\r\n): Promise<Blob | null> {\r\n const q = clamp01(quality)\r\n\r\n const hasOffscreen = typeof OffscreenCanvas !== \"undefined\"\r\n if (hasOffscreen) {\r\n const canvas = new OffscreenCanvas(width, height)\r\n const ctx = canvas.getContext(\"2d\")\r\n if (!ctx) return null\r\n ctx.drawImage(bitmap, 0, 0, width, height)\r\n try {\r\n return await canvas.convertToBlob({ type: \"image/webp\", quality: q })\r\n } catch {\r\n return null\r\n }\r\n }\r\n\r\n const canvas = document.createElement(\"canvas\")\r\n canvas.width = width\r\n canvas.height = height\r\n const ctx = canvas.getContext(\"2d\")\r\n if (!ctx) return null\r\n ctx.drawImage(bitmap, 0, 0, width, height)\r\n\r\n const blob = await new Promise<Blob | null>((resolve) => {\r\n canvas.toBlob((b) => resolve(b), \"image/webp\", q)\r\n })\r\n return blob\r\n}\r\n\r\n/**\r\n * Convert an image (png/jpg/etc) to WebP and shrink size while keeping similar quality.\r\n *\r\n * - Downscales to `maxWidth`/`maxHeight` (keeps aspect ratio).\r\n * - Encodes as WebP with a quality search to try meeting `targetBytes` (if provided).\r\n */\r\nexport async function imageToWebp(\r\n input: ImageToWebpInput,\r\n options: ImageToWebpOptions = {}\r\n): Promise<ImageToWebpResult> {\r\n const opts = { ...DEFAULTS, ...options }\r\n const blob = await inputToBlob(input)\r\n\r\n const { bitmap, width: srcW, height: srcH } = await decodeImage(blob)\r\n try {\r\n const { width, height } = computeTargetSize(srcW, srcH, opts.maxWidth, opts.maxHeight)\r\n\r\n if (!opts.targetBytes || opts.targetBytes <= 0) {\r\n const out = await encodeWebpFromBitmap(bitmap, width, height, opts.maxQuality)\r\n if (!out) {\r\n if (!opts.force) return { blob, width: srcW, height: srcH, quality: 1, isWebp: false }\r\n return { blob, width: srcW, height: srcH, quality: 1, isWebp: false }\r\n }\r\n\r\n const fileName = opts.fileName ?? getInputName(input)\r\n const file = opts.returnFile ? new File([out], fileName, { type: out.type }) : undefined\r\n return { blob: out, file, width, height, quality: opts.maxQuality, isWebp: true }\r\n }\r\n\r\n const maxQ = clamp01(opts.maxQuality)\r\n const minQ = clamp01(Math.min(opts.minQuality, maxQ))\r\n\r\n const atMax = await encodeWebpFromBitmap(bitmap, width, height, maxQ)\r\n if (!atMax) {\r\n if (!opts.force) return { blob, width: srcW, height: srcH, quality: 1, isWebp: false }\r\n return { blob, width: srcW, height: srcH, quality: 1, isWebp: false }\r\n }\r\n if (atMax.size <= opts.targetBytes) {\r\n const fileName = opts.fileName ?? getInputName(input)\r\n const file = opts.returnFile ? new File([atMax], fileName, { type: atMax.type }) : undefined\r\n return { blob: atMax, file, width, height, quality: maxQ, isWebp: true }\r\n }\r\n\r\n const atMin = await encodeWebpFromBitmap(bitmap, width, height, minQ)\r\n if (!atMin) {\r\n const fileName = opts.fileName ?? getInputName(input)\r\n const file = opts.returnFile ? new File([atMax], fileName, { type: atMax.type }) : undefined\r\n return { blob: atMax, file, width, height, quality: maxQ, isWebp: true }\r\n }\r\n if (atMin.size > opts.targetBytes) {\r\n const fileName = opts.fileName ?? getInputName(input)\r\n const file = opts.returnFile ? new File([atMin], fileName, { type: atMin.type }) : undefined\r\n return { blob: atMin, file, width, height, quality: minQ, isWebp: true }\r\n }\r\n\r\n let lo = minQ\r\n let hi = maxQ\r\n let bestBlob: Blob = atMin\r\n let bestQ = minQ\r\n\r\n for (let i = 0; i < 7; i++) {\r\n const mid = (lo + hi) / 2\r\n const enc = await encodeWebpFromBitmap(bitmap, width, height, mid)\r\n if (!enc) break\r\n\r\n if (enc.size <= opts.targetBytes) {\r\n bestBlob = enc\r\n bestQ = mid\r\n lo = mid\r\n } else {\r\n hi = mid\r\n }\r\n }\r\n\r\n const fileName = opts.fileName ?? getInputName(input)\r\n const file = opts.returnFile ? new File([bestBlob], fileName, { type: bestBlob.type }) : undefined\r\n return { blob: bestBlob, file, width, height, quality: bestQ, isWebp: true }\r\n } finally {\r\n bitmap.close()\r\n }\r\n}\r\n\r\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/browser/index.ts"],"names":["FFmpeg","fetchFile","fileTypeFromBuffer","canvas","ctx","fileName","file"],"mappings":"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","file":"index.cjs","sourcesContent":["import { FFmpeg } from \"@ffmpeg/ffmpeg\"\r\nimport { fetchFile } from \"@ffmpeg/util\"\r\nimport { fileTypeFromBuffer } from \"file-type\"\r\n\r\nimport type { ConvertResult } from \"../shared/types.js\"\r\n\r\nexport type ImageToWebpInput = Blob | File | string\r\n\r\nexport type ImageToWebpOptions = {\r\n /**\r\n * Hard cap for output dimensions, preserving aspect ratio.\r\n * If the input is larger, it will be downscaled.\r\n */\r\n maxWidth?: number\r\n maxHeight?: number\r\n\r\n /**\r\n * Target maximum output size in bytes.\r\n * If provided, the encoder will try to reach <= targetBytes by reducing quality.\r\n */\r\n targetBytes?: number\r\n\r\n /**\r\n * Quality search range (0..1). Higher is better quality, larger file.\r\n */\r\n maxQuality?: number\r\n minQuality?: number\r\n\r\n /**\r\n * If true, always return WebP even if it can't reach targetBytes.\r\n * If false, will return the original input when WebP isn't supported.\r\n */\r\n force?: boolean\r\n\r\n /**\r\n * Optional output filename (only used when returning a File).\r\n * If omitted and input is a File, the name is derived from it.\r\n */\r\n fileName?: string\r\n\r\n /**\r\n * Return a File instead of a Blob.\r\n */\r\n returnFile?: boolean\r\n}\r\n\r\nexport type ImageToWebpResult = {\r\n blob: Blob\r\n file?: File\r\n width: number\r\n height: number\r\n quality: number\r\n /**\r\n * True if output is `image/webp`.\r\n */\r\n isWebp: boolean\r\n}\r\n\r\nconst DEFAULTS: Required<\r\n Pick<\r\n ImageToWebpOptions,\r\n \"maxWidth\" | \"maxHeight\" | \"maxQuality\" | \"minQuality\" | \"force\" | \"returnFile\"\r\n >\r\n> = {\r\n maxWidth: 2048,\r\n maxHeight: 2048,\r\n maxQuality: 0.82,\r\n minQuality: 0.45,\r\n force: true,\r\n returnFile: false,\r\n}\r\n\r\nfunction clamp01(n: number) {\r\n return Math.max(0, Math.min(1, n))\r\n}\r\n\r\nfunction toWebpName(name: string) {\r\n const base = name.replace(/\\.[^/.]+$/, \"\")\r\n return `${base || \"image\"}.webp`\r\n}\r\n\r\nfunction getInputName(input: ImageToWebpInput) {\r\n if (typeof input === \"string\") return \"image.webp\"\r\n if (input instanceof File && input.name) return toWebpName(input.name)\r\n return \"image.webp\"\r\n}\r\n\r\nasync function inputToBlob(input: ImageToWebpInput): Promise<Blob> {\r\n if (typeof input === \"string\") {\r\n const res = await fetch(input)\r\n if (!res.ok) throw new Error(`Failed to fetch: ${res.status} ${res.statusText}`)\r\n return await res.blob()\r\n }\r\n return input\r\n}\r\n\r\nfunction toWebmName(name: string) {\r\n const base = name.replace(/\\.[^/.]+$/, \"\")\r\n return `${base || \"video\"}.webm`\r\n}\r\n\r\nfunction defaultVideoName(input: Blob | File | string, fileName?: string) {\r\n if (fileName && fileName.trim().length > 0) return fileName\r\n if (typeof input === \"string\") return \"video.webm\"\r\n if (input instanceof File && input.name) return toWebmName(input.name)\r\n return \"video.webm\"\r\n}\r\n\r\nlet ffmpegSingleton: FFmpeg | null = null\r\nlet ffmpegLoadPromise: Promise<FFmpeg> | null = null\r\nlet ffmpegJobQueue: Promise<void> = Promise.resolve()\r\nlet ffmpegConfigKey = \"{}\"\r\n\r\nfunction normalizeBrowserFfmpegLoadOptions(input?: BrowserFfmpegLoadOptions): BrowserFfmpegLoadOptions | undefined {\r\n if (!input) return undefined\r\n const baseURL = input.baseURL?.trim()\r\n const normalize = (v?: string) => v?.trim() || undefined\r\n const make = (suffix: string) => {\r\n if (!baseURL) return undefined\r\n return `${baseURL.replace(/\\/+$/, \"\")}/${suffix}`\r\n }\r\n return {\r\n baseURL,\r\n coreURL: normalize(input.coreURL) ?? make(\"ffmpeg-core.js\"),\r\n wasmURL: normalize(input.wasmURL) ?? make(\"ffmpeg-core.wasm\"),\r\n workerURL: normalize(input.workerURL) ?? make(\"ffmpeg-core.worker.js\"),\r\n }\r\n}\r\n\r\nfunction getFfmpegConfigKey(input?: BrowserFfmpegLoadOptions): string {\r\n return JSON.stringify(normalizeBrowserFfmpegLoadOptions(input) ?? {})\r\n}\r\n\r\nasync function getFfmpeg(loadOptions?: BrowserFfmpegLoadOptions): Promise<FFmpeg> {\r\n const nextKey = getFfmpegConfigKey(loadOptions)\r\n if (nextKey !== ffmpegConfigKey) {\r\n await resetFfmpegRuntime()\r\n ffmpegConfigKey = nextKey\r\n }\r\n if (ffmpegSingleton) return ffmpegSingleton\r\n if (ffmpegLoadPromise) return ffmpegLoadPromise\r\n const ff = new FFmpeg()\r\n const normalized = normalizeBrowserFfmpegLoadOptions(loadOptions)\r\n const loadParams =\r\n normalized && (normalized.coreURL || normalized.wasmURL || normalized.workerURL)\r\n ? {\r\n ...(normalized.coreURL ? { coreURL: normalized.coreURL } : {}),\r\n ...(normalized.wasmURL ? { wasmURL: normalized.wasmURL } : {}),\r\n ...(normalized.workerURL ? { workerURL: normalized.workerURL } : {}),\r\n }\r\n : undefined\r\n ffmpegLoadPromise = (async () => {\r\n try {\r\n await ff.load(loadParams as any)\r\n ffmpegSingleton = ff\r\n return ff\r\n } catch (err) {\r\n ffmpegLoadPromise = null\r\n const detail = [\r\n \"Failed to initialize ffmpeg.wasm.\",\r\n `error=${toErrorMessage(err)}`,\r\n \"hint=Ensure ffmpeg core/worker assets are reachable by your bundler/runtime and not blocked by CSP/CORS.\",\r\n ].join(\"\\n\")\r\n throw new Error(detail)\r\n }\r\n })()\r\n return ffmpegLoadPromise\r\n}\r\n\r\nasync function resetFfmpegRuntime(): Promise<void> {\r\n const current = ffmpegSingleton\r\n ffmpegSingleton = null\r\n ffmpegLoadPromise = null\r\n if (current && typeof (current as any).terminate === \"function\") {\r\n try {\r\n await (current as any).terminate()\r\n } catch {\r\n // Best-effort reset only.\r\n }\r\n }\r\n}\r\n\r\nasync function runWithFfmpegLock<T>(job: () => Promise<T>): Promise<T> {\r\n const previous = ffmpegJobQueue\r\n let release!: () => void\r\n ffmpegJobQueue = new Promise<void>((resolve) => {\r\n release = resolve\r\n })\r\n await previous\r\n try {\r\n return await job()\r\n } finally {\r\n release()\r\n }\r\n}\r\n\r\nfunction createFsSafeId(): string {\r\n return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`\r\n}\r\n\r\nfunction toErrorMessage(err: unknown): string {\r\n if (err instanceof Error && err.message) return err.message\r\n if (typeof err === \"string\") return err\r\n try {\r\n return JSON.stringify(err)\r\n } catch {\r\n return String(err)\r\n }\r\n}\r\n\r\nfunction formatArgs(args: string[]): string {\r\n return args.map((v) => (/\\s/.test(v) ? `\"${v}\"` : v)).join(\" \")\r\n}\r\n\r\nfunction isRecoverableWasmError(err: unknown): boolean {\r\n const msg = toErrorMessage(err).toLowerCase()\r\n return (\r\n msg.includes(\"memory access out of bounds\") ||\r\n msg.includes(\"runtimeerror\") ||\r\n msg.includes(\"aborted\") ||\r\n msg.includes(\"wasm\")\r\n )\r\n}\r\n\r\nexport type VideoToWebmInput = Blob | File | string\r\n\r\nexport type BrowserFfmpegLoadOptions = {\r\n /**\r\n * Base URL where ffmpeg.wasm assets live.\r\n * Missing specific URLs are derived from this.\r\n */\r\n baseURL?: string\r\n coreURL?: string\r\n wasmURL?: string\r\n workerURL?: string\r\n}\r\n\r\nexport type VideoToWebmOptions = {\r\n crf?: number\r\n deadline?: \"good\" | \"best\" | \"realtime\"\r\n maxDurationSeconds?: number\r\n /**\r\n * Guardrail for browser wasm memory pressure.\r\n * Throws before transcoding when input exceeds this limit.\r\n */\r\n maxInputBytes?: number\r\n /**\r\n * Optional browser ffmpeg.wasm asset URL configuration.\r\n */\r\n ffmpeg?: BrowserFfmpegLoadOptions\r\n fileName?: string\r\n returnFile?: boolean\r\n}\r\n\r\nexport type VideoToWebmResult = {\r\n blob: Blob\r\n file?: File\r\n isWebm: boolean\r\n}\r\n\r\nexport type VideoToWebmDebugStage =\r\n | \"input\"\r\n | \"guardrail\"\r\n | \"init\"\r\n | \"transcode\"\r\n | \"retry-reset\"\r\n | \"retry-init\"\r\n | \"retry-transcode\"\r\n | \"done\"\r\n\r\nexport type VideoToWebmDebugEvent = {\r\n stage: VideoToWebmDebugStage\r\n message: string\r\n detail?: string\r\n}\r\n\r\nexport type VideoToWebmDebugCause =\r\n | \"none\"\r\n | \"input-fetch-failed\"\r\n | \"input-too-large\"\r\n | \"ffmpeg-init-failed\"\r\n | \"ffmpeg-transcode-failed\"\r\n | \"ffmpeg-wasm-runtime-crash\"\r\n | \"unsupported-input\"\r\n | \"unknown\"\r\n\r\nexport type VideoToWebmDiagnostic = {\r\n cause: VideoToWebmDebugCause\r\n stage: VideoToWebmDebugStage\r\n rawError?: string\r\n recoverable: boolean\r\n hints: string[]\r\n}\r\n\r\nexport type VideoToWebmDebugResult =\r\n | ({ ok: true } & VideoToWebmResult & { events: VideoToWebmDebugEvent[]; diagnostic: VideoToWebmDiagnostic })\r\n | { ok: false; error: Error; events: VideoToWebmDebugEvent[]; diagnostic: VideoToWebmDiagnostic }\r\n\r\nconst VIDEO_DEFAULTS: Required<Pick<VideoToWebmOptions, \"crf\" | \"deadline\" | \"returnFile\" | \"maxInputBytes\">> = {\r\n crf: 32,\r\n deadline: \"good\",\r\n returnFile: false,\r\n maxInputBytes: 64 * 1024 * 1024,\r\n}\r\n\r\nfunction assertVideoInputGuardrails(blob: Blob, opts: Required<Pick<VideoToWebmOptions, \"maxInputBytes\">>) {\r\n if (opts.maxInputBytes > 0 && blob.size > opts.maxInputBytes) {\r\n throw new Error(\r\n [\r\n \"videoToWebm guardrail: input too large for browser ffmpeg.wasm.\",\r\n `input_bytes=${blob.size}`,\r\n `max_input_bytes=${opts.maxInputBytes}`,\r\n \"hint=Lower source resolution/bitrate, trim video, or increase maxInputBytes if your environment has enough memory.\",\r\n ].join(\"\\n\")\r\n )\r\n }\r\n}\r\n\r\ntype NormalizedVideoOptions = Required<Pick<VideoToWebmOptions, \"crf\" | \"deadline\" | \"returnFile\" | \"maxInputBytes\">> &\r\n Pick<VideoToWebmOptions, \"maxDurationSeconds\" | \"fileName\" | \"ffmpeg\">\r\n\r\nfunction buildVideoDiagnostic(stage: VideoToWebmDebugStage, err: unknown): VideoToWebmDiagnostic {\r\n const raw = toErrorMessage(err)\r\n const lower = raw.toLowerCase()\r\n const recoverable = isRecoverableWasmError(err)\r\n\r\n if (lower.includes(\"failed to fetch\")) {\r\n return {\r\n cause: \"input-fetch-failed\",\r\n stage,\r\n rawError: raw,\r\n recoverable: false,\r\n hints: [\"Verify URL reachability and CORS policy for browser fetch.\"],\r\n }\r\n }\r\n\r\n if (lower.includes(\"input too large\") || lower.includes(\"max_input_bytes\")) {\r\n return {\r\n cause: \"input-too-large\",\r\n stage,\r\n rawError: raw,\r\n recoverable: false,\r\n hints: [\"Increase maxInputBytes or reduce source size/resolution/duration.\"],\r\n }\r\n }\r\n\r\n if (lower.includes(\"failed to initialize ffmpeg.wasm\")) {\r\n return {\r\n cause: \"ffmpeg-init-failed\",\r\n stage,\r\n rawError: raw,\r\n recoverable,\r\n hints: [\r\n \"Provide video.ffmpeg.baseURL or explicit coreURL/wasmURL/workerURL.\",\r\n \"Ensure CSP/CORS allows ffmpeg worker + wasm assets.\",\r\n ],\r\n }\r\n }\r\n\r\n if (lower.includes(\"memory access out of bounds\") || lower.includes(\"runtimeerror\") || lower.includes(\"aborted\")) {\r\n return {\r\n cause: \"ffmpeg-wasm-runtime-crash\",\r\n stage,\r\n rawError: raw,\r\n recoverable: true,\r\n hints: [\"Reduce workload: trim duration, lower resolution/bitrate, or split video.\"],\r\n }\r\n }\r\n\r\n if (lower.includes(\"videotowebm failed\")) {\r\n return {\r\n cause: \"ffmpeg-transcode-failed\",\r\n stage,\r\n rawError: raw,\r\n recoverable,\r\n hints: [\"Inspect ffmpeg_logs in rawError for codec/container-specific details.\"],\r\n }\r\n }\r\n\r\n if (lower.includes(\"unsupported input type\")) {\r\n return {\r\n cause: \"unsupported-input\",\r\n stage,\r\n rawError: raw,\r\n recoverable: false,\r\n hints: [\"Use a valid image/* or video/* input and ensure proper MIME/magic bytes.\"],\r\n }\r\n }\r\n\r\n return {\r\n cause: \"unknown\",\r\n stage,\r\n rawError: raw,\r\n recoverable,\r\n hints: [\"Use videoToWebmDebug() output to trace failing stage and share rawError.\"],\r\n }\r\n}\r\n\r\nasync function runVideoTranscodeJob(ffmpeg: FFmpeg, blob: Blob, opts: NormalizedVideoOptions) {\r\n const jobId = createFsSafeId()\r\n const inName = `input-${jobId}`\r\n const outName = `output-${jobId}.webm`\r\n\r\n const outBytes = await runWithFfmpegLock(async () => {\r\n await ffmpeg.writeFile(inName, await fetchFile(blob))\r\n\r\n const args: string[] = [\r\n ...(opts.maxDurationSeconds && opts.maxDurationSeconds > 0 ? [\"-t\", String(opts.maxDurationSeconds)] : []),\r\n \"-i\",\r\n inName,\r\n \"-map\",\r\n \"0:v:0\",\r\n \"-map\",\r\n \"0:a?\",\r\n \"-c:v\",\r\n \"libvpx-vp9\",\r\n \"-b:v\",\r\n \"0\",\r\n \"-crf\",\r\n String(opts.crf),\r\n \"-deadline\",\r\n opts.deadline,\r\n \"-row-mt\",\r\n \"1\",\r\n \"-c:a\",\r\n \"libopus\",\r\n outName,\r\n ]\r\n\r\n const logs: string[] = []\r\n const onLog = ({ message }: { message: string }) => {\r\n if (typeof message !== \"string\" || message.length === 0) return\r\n logs.push(message)\r\n if (logs.length > 60) logs.shift()\r\n }\r\n\r\n try {\r\n ffmpeg.on(\"log\", onLog)\r\n await ffmpeg.exec(args)\r\n const outData = await ffmpeg.readFile(outName)\r\n return outData instanceof Uint8Array ? outData : new Uint8Array(outData as any)\r\n } catch (err) {\r\n const detail = [\r\n `videoToWebm failed.`,\r\n `input=${inName}`,\r\n `output=${outName}`,\r\n `args=${formatArgs(args)}`,\r\n `error=${toErrorMessage(err)}`,\r\n logs.length ? `ffmpeg_logs:\\n${logs.join(\"\\n\")}` : \"ffmpeg_logs: <none>\",\r\n ].join(\"\\n\")\r\n throw new Error(detail)\r\n } finally {\r\n ffmpeg.off(\"log\", onLog)\r\n await Promise.allSettled([ffmpeg.deleteFile(inName), ffmpeg.deleteFile(outName)])\r\n }\r\n })\r\n\r\n return new Blob([outBytes], { type: \"video/webm\" })\r\n}\r\n\r\nexport async function videoToWebm(\r\n input: VideoToWebmInput,\r\n options: VideoToWebmOptions = {}\r\n): Promise<VideoToWebmResult> {\r\n const opts = { ...VIDEO_DEFAULTS, ...options }\r\n const blob = await inputToBlob(input)\r\n assertVideoInputGuardrails(blob, opts)\r\n\r\n let outBlob: Blob\r\n try {\r\n const ffmpeg = await getFfmpeg(opts.ffmpeg)\r\n outBlob = await runVideoTranscodeJob(ffmpeg, blob, opts)\r\n } catch (err) {\r\n if (!isRecoverableWasmError(err)) throw err\r\n await resetFfmpegRuntime()\r\n const ffmpeg = await getFfmpeg(opts.ffmpeg)\r\n outBlob = await runVideoTranscodeJob(ffmpeg, blob, opts)\r\n }\r\n\r\n const file = opts.returnFile ? new File([outBlob], defaultVideoName(input, opts.fileName), { type: outBlob.type }) : undefined\r\n return { blob: outBlob, file, isWebm: true }\r\n}\r\n\r\nexport async function videoToWebmDebug(\r\n input: VideoToWebmInput,\r\n options: VideoToWebmOptions = {},\r\n onEvent?: (event: VideoToWebmDebugEvent) => void\r\n): Promise<VideoToWebmDebugResult> {\r\n const events: VideoToWebmDebugEvent[] = []\r\n let lastStage: VideoToWebmDebugStage = \"input\"\r\n const emit = (event: VideoToWebmDebugEvent) => {\r\n lastStage = event.stage\r\n events.push(event)\r\n onEvent?.(event)\r\n }\r\n\r\n try {\r\n emit({ stage: \"input\", message: \"Reading input as Blob.\" })\r\n const opts = { ...VIDEO_DEFAULTS, ...options }\r\n const blob = await inputToBlob(input)\r\n\r\n emit({\r\n stage: \"guardrail\",\r\n message: \"Checking browser ffmpeg.wasm memory guardrail.\",\r\n detail: `input_bytes=${blob.size};max_input_bytes=${opts.maxInputBytes}`,\r\n })\r\n assertVideoInputGuardrails(blob, opts)\r\n\r\n let outBlob: Blob\r\n try {\r\n emit({ stage: \"init\", message: \"Initializing ffmpeg.wasm runtime.\" })\r\n const ffmpeg = await getFfmpeg(opts.ffmpeg)\r\n emit({ stage: \"transcode\", message: \"Running video transcode job (VP9 + Opus).\" })\r\n outBlob = await runVideoTranscodeJob(ffmpeg, blob, opts)\r\n } catch (err) {\r\n if (!isRecoverableWasmError(err)) throw err\r\n emit({\r\n stage: \"retry-reset\",\r\n message: \"Recoverable wasm error detected, resetting runtime.\",\r\n detail: toErrorMessage(err),\r\n })\r\n await resetFfmpegRuntime()\r\n emit({ stage: \"retry-init\", message: \"Reinitializing ffmpeg.wasm runtime.\" })\r\n const ffmpeg = await getFfmpeg(opts.ffmpeg)\r\n emit({ stage: \"retry-transcode\", message: \"Retrying video transcode job.\" })\r\n outBlob = await runVideoTranscodeJob(ffmpeg, blob, opts)\r\n }\r\n\r\n const file = opts.returnFile ? new File([outBlob], defaultVideoName(input, opts.fileName), { type: outBlob.type }) : undefined\r\n emit({\r\n stage: \"done\",\r\n message: \"Video converted to WebM.\",\r\n detail: `output_bytes=${outBlob.size};mime=${outBlob.type}`,\r\n })\r\n return {\r\n ok: true,\r\n blob: outBlob,\r\n file,\r\n isWebm: true,\r\n events,\r\n diagnostic: { cause: \"none\", stage: \"done\", recoverable: false, hints: [] },\r\n }\r\n } catch (err) {\r\n const error = err instanceof Error ? err : new Error(toErrorMessage(err))\r\n const diagnostic = buildVideoDiagnostic(lastStage, error)\r\n emit({\r\n stage: \"done\",\r\n message: \"Video conversion failed.\",\r\n detail: `cause=${diagnostic.cause};${error.message}`,\r\n })\r\n return { ok: false, error, events, diagnostic }\r\n }\r\n}\r\n\r\nexport type ConvertInput = ImageToWebpInput\r\n\r\nexport type ConvertOptions = {\r\n image?: ImageToWebpOptions\r\n video?: VideoToWebmOptions\r\n returnFile?: boolean\r\n fileName?: string\r\n}\r\n\r\nasync function detectKindBrowser(input: ConvertInput): Promise<\"image\" | \"video\" | \"unknown\"> {\r\n if (typeof input !== \"string\") {\r\n const t = (input.type || \"\").toLowerCase()\r\n if (t.startsWith(\"image/\")) return \"image\"\r\n if (t.startsWith(\"video/\")) return \"video\"\r\n }\r\n\r\n const blob = await inputToBlob(input)\r\n const buf = new Uint8Array(await blob.slice(0, 4100).arrayBuffer())\r\n const ft = await fileTypeFromBuffer(buf)\r\n if (!ft) return \"unknown\"\r\n if (ft.mime.startsWith(\"image/\")) return \"image\"\r\n if (ft.mime.startsWith(\"video/\")) return \"video\"\r\n return \"unknown\"\r\n}\r\n\r\nexport async function convert(input: ConvertInput, options: ConvertOptions = {}): Promise<ConvertResult> {\r\n const kind = await detectKindBrowser(input)\r\n const returnFile = options.returnFile ?? false\r\n\r\n if (kind === \"image\") {\r\n const res = await imageToWebp(input, { ...options.image, returnFile, fileName: options.fileName })\r\n return { kind: \"image\", ...res }\r\n }\r\n\r\n if (kind === \"video\") {\r\n const res = await videoToWebm(input, { ...options.video, returnFile, fileName: options.fileName })\r\n return { kind: \"video\", ...res }\r\n }\r\n\r\n throw new Error(\"Unsupported input type. Expected an image/* or video/* asset.\")\r\n}\r\n\r\nfunction computeTargetSize(\r\n srcW: number,\r\n srcH: number,\r\n maxW: number,\r\n maxH: number\r\n): { width: number; height: number } {\r\n if (srcW <= 0 || srcH <= 0) return { width: srcW, height: srcH }\r\n const scale = Math.min(1, maxW / srcW, maxH / srcH)\r\n return {\r\n width: Math.max(1, Math.round(srcW * scale)),\r\n height: Math.max(1, Math.round(srcH * scale)),\r\n }\r\n}\r\n\r\nasync function decodeImage(blob: Blob): Promise<{ bitmap: ImageBitmap; width: number; height: number }> {\r\n if (typeof createImageBitmap === \"function\") {\r\n const bitmap = await createImageBitmap(blob, { imageOrientation: \"from-image\" as any })\r\n return { bitmap, width: bitmap.width, height: bitmap.height }\r\n }\r\n\r\n const url = URL.createObjectURL(blob)\r\n try {\r\n const img = await new Promise<HTMLImageElement>((resolve, reject) => {\r\n const el = new Image()\r\n el.onload = () => resolve(el)\r\n el.onerror = () => reject(new Error(\"Failed to decode image\"))\r\n el.src = url\r\n })\r\n\r\n const canvas = document.createElement(\"canvas\")\r\n canvas.width = img.naturalWidth || img.width\r\n canvas.height = img.naturalHeight || img.height\r\n const ctx = canvas.getContext(\"2d\")\r\n if (!ctx) throw new Error(\"Canvas 2D context not available\")\r\n ctx.drawImage(img, 0, 0)\r\n\r\n const dataUrl = canvas.toDataURL(\"image/png\")\r\n const pngBlob = await (await fetch(dataUrl)).blob()\r\n const bitmap = await createImageBitmap(pngBlob)\r\n return { bitmap, width: bitmap.width, height: bitmap.height }\r\n } finally {\r\n URL.revokeObjectURL(url)\r\n }\r\n}\r\n\r\nasync function encodeWebpFromBitmap(\r\n bitmap: ImageBitmap,\r\n width: number,\r\n height: number,\r\n quality: number\r\n): Promise<Blob | null> {\r\n const q = clamp01(quality)\r\n\r\n const hasOffscreen = typeof OffscreenCanvas !== \"undefined\"\r\n if (hasOffscreen) {\r\n const canvas = new OffscreenCanvas(width, height)\r\n const ctx = canvas.getContext(\"2d\")\r\n if (!ctx) return null\r\n ctx.drawImage(bitmap, 0, 0, width, height)\r\n try {\r\n return await canvas.convertToBlob({ type: \"image/webp\", quality: q })\r\n } catch {\r\n return null\r\n }\r\n }\r\n\r\n const canvas = document.createElement(\"canvas\")\r\n canvas.width = width\r\n canvas.height = height\r\n const ctx = canvas.getContext(\"2d\")\r\n if (!ctx) return null\r\n ctx.drawImage(bitmap, 0, 0, width, height)\r\n\r\n const blob = await new Promise<Blob | null>((resolve) => {\r\n canvas.toBlob((b) => resolve(b), \"image/webp\", q)\r\n })\r\n return blob\r\n}\r\n\r\n/**\r\n * Convert an image (png/jpg/etc) to WebP and shrink size while keeping similar quality.\r\n *\r\n * - Downscales to `maxWidth`/`maxHeight` (keeps aspect ratio).\r\n * - Encodes as WebP with a quality search to try meeting `targetBytes` (if provided).\r\n */\r\nexport async function imageToWebp(\r\n input: ImageToWebpInput,\r\n options: ImageToWebpOptions = {}\r\n): Promise<ImageToWebpResult> {\r\n const opts = { ...DEFAULTS, ...options }\r\n const blob = await inputToBlob(input)\r\n\r\n const { bitmap, width: srcW, height: srcH } = await decodeImage(blob)\r\n try {\r\n const { width, height } = computeTargetSize(srcW, srcH, opts.maxWidth, opts.maxHeight)\r\n\r\n if (!opts.targetBytes || opts.targetBytes <= 0) {\r\n const out = await encodeWebpFromBitmap(bitmap, width, height, opts.maxQuality)\r\n if (!out) {\r\n if (!opts.force) return { blob, width: srcW, height: srcH, quality: 1, isWebp: false }\r\n return { blob, width: srcW, height: srcH, quality: 1, isWebp: false }\r\n }\r\n\r\n const fileName = opts.fileName ?? getInputName(input)\r\n const file = opts.returnFile ? new File([out], fileName, { type: out.type }) : undefined\r\n return { blob: out, file, width, height, quality: opts.maxQuality, isWebp: true }\r\n }\r\n\r\n const maxQ = clamp01(opts.maxQuality)\r\n const minQ = clamp01(Math.min(opts.minQuality, maxQ))\r\n\r\n const atMax = await encodeWebpFromBitmap(bitmap, width, height, maxQ)\r\n if (!atMax) {\r\n if (!opts.force) return { blob, width: srcW, height: srcH, quality: 1, isWebp: false }\r\n return { blob, width: srcW, height: srcH, quality: 1, isWebp: false }\r\n }\r\n if (atMax.size <= opts.targetBytes) {\r\n const fileName = opts.fileName ?? getInputName(input)\r\n const file = opts.returnFile ? new File([atMax], fileName, { type: atMax.type }) : undefined\r\n return { blob: atMax, file, width, height, quality: maxQ, isWebp: true }\r\n }\r\n\r\n const atMin = await encodeWebpFromBitmap(bitmap, width, height, minQ)\r\n if (!atMin) {\r\n const fileName = opts.fileName ?? getInputName(input)\r\n const file = opts.returnFile ? new File([atMax], fileName, { type: atMax.type }) : undefined\r\n return { blob: atMax, file, width, height, quality: maxQ, isWebp: true }\r\n }\r\n if (atMin.size > opts.targetBytes) {\r\n const fileName = opts.fileName ?? getInputName(input)\r\n const file = opts.returnFile ? new File([atMin], fileName, { type: atMin.type }) : undefined\r\n return { blob: atMin, file, width, height, quality: minQ, isWebp: true }\r\n }\r\n\r\n let lo = minQ\r\n let hi = maxQ\r\n let bestBlob: Blob = atMin\r\n let bestQ = minQ\r\n\r\n for (let i = 0; i < 7; i++) {\r\n const mid = (lo + hi) / 2\r\n const enc = await encodeWebpFromBitmap(bitmap, width, height, mid)\r\n if (!enc) break\r\n\r\n if (enc.size <= opts.targetBytes) {\r\n bestBlob = enc\r\n bestQ = mid\r\n lo = mid\r\n } else {\r\n hi = mid\r\n }\r\n }\r\n\r\n const fileName = opts.fileName ?? getInputName(input)\r\n const file = opts.returnFile ? new File([bestBlob], fileName, { type: bestBlob.type }) : undefined\r\n return { blob: bestBlob, file, width, height, quality: bestQ, isWebp: true }\r\n } finally {\r\n bitmap.close()\r\n }\r\n}\r\n\r\n"]}
|
package/dist/browser/index.d.cts
CHANGED
|
@@ -62,10 +62,29 @@ type ImageToWebpResult = {
|
|
|
62
62
|
isWebp: boolean;
|
|
63
63
|
};
|
|
64
64
|
type VideoToWebmInput = Blob | File | string;
|
|
65
|
+
type BrowserFfmpegLoadOptions = {
|
|
66
|
+
/**
|
|
67
|
+
* Base URL where ffmpeg.wasm assets live.
|
|
68
|
+
* Missing specific URLs are derived from this.
|
|
69
|
+
*/
|
|
70
|
+
baseURL?: string;
|
|
71
|
+
coreURL?: string;
|
|
72
|
+
wasmURL?: string;
|
|
73
|
+
workerURL?: string;
|
|
74
|
+
};
|
|
65
75
|
type VideoToWebmOptions = {
|
|
66
76
|
crf?: number;
|
|
67
77
|
deadline?: "good" | "best" | "realtime";
|
|
68
78
|
maxDurationSeconds?: number;
|
|
79
|
+
/**
|
|
80
|
+
* Guardrail for browser wasm memory pressure.
|
|
81
|
+
* Throws before transcoding when input exceeds this limit.
|
|
82
|
+
*/
|
|
83
|
+
maxInputBytes?: number;
|
|
84
|
+
/**
|
|
85
|
+
* Optional browser ffmpeg.wasm asset URL configuration.
|
|
86
|
+
*/
|
|
87
|
+
ffmpeg?: BrowserFfmpegLoadOptions;
|
|
69
88
|
fileName?: string;
|
|
70
89
|
returnFile?: boolean;
|
|
71
90
|
};
|
|
@@ -74,7 +93,33 @@ type VideoToWebmResult = {
|
|
|
74
93
|
file?: File;
|
|
75
94
|
isWebm: boolean;
|
|
76
95
|
};
|
|
96
|
+
type VideoToWebmDebugStage = "input" | "guardrail" | "init" | "transcode" | "retry-reset" | "retry-init" | "retry-transcode" | "done";
|
|
97
|
+
type VideoToWebmDebugEvent = {
|
|
98
|
+
stage: VideoToWebmDebugStage;
|
|
99
|
+
message: string;
|
|
100
|
+
detail?: string;
|
|
101
|
+
};
|
|
102
|
+
type VideoToWebmDebugCause = "none" | "input-fetch-failed" | "input-too-large" | "ffmpeg-init-failed" | "ffmpeg-transcode-failed" | "ffmpeg-wasm-runtime-crash" | "unsupported-input" | "unknown";
|
|
103
|
+
type VideoToWebmDiagnostic = {
|
|
104
|
+
cause: VideoToWebmDebugCause;
|
|
105
|
+
stage: VideoToWebmDebugStage;
|
|
106
|
+
rawError?: string;
|
|
107
|
+
recoverable: boolean;
|
|
108
|
+
hints: string[];
|
|
109
|
+
};
|
|
110
|
+
type VideoToWebmDebugResult = ({
|
|
111
|
+
ok: true;
|
|
112
|
+
} & VideoToWebmResult & {
|
|
113
|
+
events: VideoToWebmDebugEvent[];
|
|
114
|
+
diagnostic: VideoToWebmDiagnostic;
|
|
115
|
+
}) | {
|
|
116
|
+
ok: false;
|
|
117
|
+
error: Error;
|
|
118
|
+
events: VideoToWebmDebugEvent[];
|
|
119
|
+
diagnostic: VideoToWebmDiagnostic;
|
|
120
|
+
};
|
|
77
121
|
declare function videoToWebm(input: VideoToWebmInput, options?: VideoToWebmOptions): Promise<VideoToWebmResult>;
|
|
122
|
+
declare function videoToWebmDebug(input: VideoToWebmInput, options?: VideoToWebmOptions, onEvent?: (event: VideoToWebmDebugEvent) => void): Promise<VideoToWebmDebugResult>;
|
|
78
123
|
type ConvertInput = ImageToWebpInput;
|
|
79
124
|
type ConvertOptions = {
|
|
80
125
|
image?: ImageToWebpOptions;
|
|
@@ -91,4 +136,4 @@ declare function convert(input: ConvertInput, options?: ConvertOptions): Promise
|
|
|
91
136
|
*/
|
|
92
137
|
declare function imageToWebp(input: ImageToWebpInput, options?: ImageToWebpOptions): Promise<ImageToWebpResult>;
|
|
93
138
|
|
|
94
|
-
export { type ConvertInput, type ConvertOptions, type ImageToWebpInput, type ImageToWebpOptions, type ImageToWebpResult, type VideoToWebmInput, type VideoToWebmOptions, type VideoToWebmResult, convert, imageToWebp, videoToWebm };
|
|
139
|
+
export { type BrowserFfmpegLoadOptions, type ConvertInput, type ConvertOptions, type ImageToWebpInput, type ImageToWebpOptions, type ImageToWebpResult, type VideoToWebmDebugCause, type VideoToWebmDebugEvent, type VideoToWebmDebugResult, type VideoToWebmDebugStage, type VideoToWebmDiagnostic, type VideoToWebmInput, type VideoToWebmOptions, type VideoToWebmResult, convert, imageToWebp, videoToWebm, videoToWebmDebug };
|