From 794b84884f1e23cb6241689b3563190d138bbd9a Mon Sep 17 00:00:00 2001 From: Vanilagy <1696106+Vanilagy@users.noreply.github.com> Date: Sat, 18 Jul 2026 22:54:24 +0200 Subject: [PATCH] Make sure that samples are always closed in the Conversion API, even on error cases --- package-lock.json | 60 +++++++++++++++++++++++++++++++++++++++++++++++ package.json | 8 +++---- src/conversion.ts | 31 +++++++++++++----------- 3 files changed, 81 insertions(+), 18 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4e6ab80..bf05182 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2715,6 +2715,66 @@ "node": ">=14.0.0" } }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/core": { + "version": "1.4.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.0.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.4.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/wasi-threads": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.9", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.0", + "@emnapi/runtime": "^1.4.0", + "@tybys/wasm-util": "^0.9.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@tybys/wasm-util": { + "version": "0.9.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/tslib": { + "version": "2.8.0", + "dev": true, + "inBundle": true, + "license": "0BSD", + "optional": true + }, "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { "version": "4.1.7", "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.7.tgz", diff --git a/package.json b/package.json index 9c2cb05..f96aa99 100644 --- a/package.json +++ b/package.json @@ -56,10 +56,10 @@ "examples:build": "vite build", "fix-build-import-paths": "tsx scripts/add-import-extensions.ts", "append-namespace": "echo 'export as namespace Mediabunny;' >> dist/mediabunny.d.ts", - "bump-patch": "npm version patch --no-git-tag-version --workspaces && tsx scripts/sync-workspace-deps.ts && npm i", - "bump-minor": "npm version minor --no-git-tag-version --workspaces && tsx scripts/sync-workspace-deps.ts && npm i", - "bump-major": "npm version major --no-git-tag-version --workspaces && tsx scripts/sync-workspace-deps.ts && npm i", - "set-version": "npm version --no-git-tag-version --workspaces && tsx scripts/sync-workspace-deps.ts && npm i" + "bump-patch": "npm version patch --no-git-tag-version --workspaces && tsx scripts/sync-workspace-deps.ts && npm i --package-lock-only", + "bump-minor": "npm version minor --no-git-tag-version --workspaces && tsx scripts/sync-workspace-deps.ts && npm i --package-lock-only", + "bump-major": "npm version major --no-git-tag-version --workspaces && tsx scripts/sync-workspace-deps.ts && npm i --package-lock-only", + "set-version": "npm version --no-git-tag-version --workspaces && tsx scripts/sync-workspace-deps.ts && npm i --package-lock-only" }, "license": "MPL-2.0", "repository": { diff --git a/src/conversion.ts b/src/conversion.ts index bd15ba7..252e8cb 100644 --- a/src/conversion.ts +++ b/src/conversion.ts @@ -1321,7 +1321,7 @@ export class Conversion { await tempOutput.start(); const sink = new VideoSampleSink(track); - const firstSample = await sink.getSample(firstTimestamp); // Let's just use the first sample + using firstSample = await sink.getSample(firstTimestamp); // Let's just use the first sample if (firstSample) { try { @@ -1375,9 +1375,8 @@ export class Conversion { const sink = new VideoSampleSink(track); - for await (const sample of sink.samples(this._startTimestamp, this._endTimestamp)) { + for await (using sample of sink.samples(this._startTimestamp, this._endTimestamp)) { if (this._canceled) { - sample.close(); return; } @@ -1386,14 +1385,13 @@ export class Conversion { this._reportProgress(outputTrackId, sample.timestamp + sample.duration); await source.add(sample); + sample.close(); if (lastSampleTimestamp !== null) { if (this._synchronizer.shouldWait(outputTrackId, lastSampleTimestamp)) { await this._synchronizer.wait(lastSampleTimestamp); } } - - sample.close(); } source.close(); @@ -1595,9 +1593,8 @@ export class Conversion { await this._started; const sink = new AudioSampleSink(track); - for await (let sample of sink.samples(this._startTimestamp, this._endTimestamp)) { + for await (using sample of sink.samples(this._startTimestamp, this._endTimestamp)) { if (this._canceled) { - sample.close(); return; } @@ -1612,7 +1609,7 @@ export class Conversion { data.fill(2 ** 7); // Fill it with the silent value } - const silentSample = new AudioSample({ + using silentSample = new AudioSample({ data, // Use the same format the decoder is spitting out. This avoids feeding changing sample // formats to the audio encoder. @@ -1636,22 +1633,28 @@ export class Conversion { endFrame = Math.round((this._endTimestamp - sample.timestamp) * sample.sampleRate); } + // Can't assign to "using" identifiers so we gotta do this + let finalSampleLet: AudioSample; if (startFrame > 0 || endFrame < sample.numberOfFrames) { // Trim the sample if it sticks out of the trim region on either end const trimmedSample = sample.trim(startFrame, endFrame); sample.close(); - sample = trimmedSample; + finalSampleLet = trimmedSample; - if (sample.numberOfFrames === 0) { - sample.close(); + if (trimmedSample.numberOfFrames === 0) { + trimmedSample.close(); continue; } + } else { + finalSampleLet = sample; } - // Offset the timestamp as needed - sample.setTimestamp(sample.timestamp - this._startTimestamp); + using finalSample = finalSampleLet; - await this._registerAudioSample(sample, source, outputTrackId, () => lastSampleTimestamp); + // Offset the timestamp as needed + finalSample.setTimestamp(finalSample.timestamp - this._startTimestamp); + + await this._registerAudioSample(finalSample, source, outputTrackId, () => lastSampleTimestamp); } source.close();