mirror of
https://github.com/arcodange-org/mediabunny.git
synced 2026-10-02 21:33:52 +02:00
Circumvent flush() being called on sources when cancelling output, surface error before doing cleanup
This commit is contained in:
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "mediabunny",
|
"name": "mediabunny",
|
||||||
"author": "Vanilagy",
|
"author": "Vanilagy",
|
||||||
"version": "1.5.0",
|
"version": "1.6.0",
|
||||||
"description": "Pure TypeScript media toolkit for reading, writing, and converting media files, directly in the browser.",
|
"description": "Pure TypeScript media toolkit for reading, writing, and converting media files, directly in the browser.",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@mediabunny/mp3-encoder",
|
"name": "@mediabunny/mp3-encoder",
|
||||||
"version": "0.0.1",
|
"version": "1.6.0",
|
||||||
"main": "./dist/bundles/mediabunny-mp3-encoder.mjs",
|
"main": "./dist/bundles/mediabunny-mp3-encoder.mjs",
|
||||||
"module": "./dist/bundles/mediabunny-mp3-encoder.mjs",
|
"module": "./dist/bundles/mediabunny-mp3-encoder.mjs",
|
||||||
"types": "./dist/modules/src/index.d.ts",
|
"types": "./dist/modules/src/index.d.ts",
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import type { WorkerCommand, WorkerResponse, WorkerResponseData } from './shared
|
|||||||
import createWorker from './encode.worker';
|
import createWorker from './encode.worker';
|
||||||
|
|
||||||
class Mp3Encoder extends CustomAudioEncoder {
|
class Mp3Encoder extends CustomAudioEncoder {
|
||||||
private worker!: Worker;
|
private worker: Worker | null = null;
|
||||||
private nextMessageId = 0;
|
private nextMessageId = 0;
|
||||||
private pendingMessages = new Map<number, {
|
private pendingMessages = new Map<number, {
|
||||||
resolve: (value: WorkerResponseData) => void;
|
resolve: (value: WorkerResponseData) => void;
|
||||||
@@ -23,7 +23,7 @@ class Mp3Encoder extends CustomAudioEncoder {
|
|||||||
private buffer = new Uint8Array(2 ** 16);
|
private buffer = new Uint8Array(2 ** 16);
|
||||||
private currentBufferOffset = 0;
|
private currentBufferOffset = 0;
|
||||||
private currentTimestamp = 0;
|
private currentTimestamp = 0;
|
||||||
private chunkMetadata!: EncodedAudioChunkMetadata;
|
private chunkMetadata: EncodedAudioChunkMetadata = {};
|
||||||
|
|
||||||
static override supports(codec: AudioCodec, config: AudioDecoderConfig): boolean {
|
static override supports(codec: AudioCodec, config: AudioDecoderConfig): boolean {
|
||||||
return codec === 'mp3'
|
return codec === 'mp3'
|
||||||
@@ -113,7 +113,7 @@ class Mp3Encoder extends CustomAudioEncoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
close() {
|
close() {
|
||||||
this.worker.terminate();
|
this.worker?.terminate();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -174,6 +174,8 @@ class Mp3Encoder extends CustomAudioEncoder {
|
|||||||
const id = this.nextMessageId++;
|
const id = this.nextMessageId++;
|
||||||
this.pendingMessages.set(id, { resolve, reject });
|
this.pendingMessages.set(id, { resolve, reject });
|
||||||
|
|
||||||
|
assert(this.worker);
|
||||||
|
|
||||||
if (transferables) {
|
if (transferables) {
|
||||||
this.worker.postMessage({ id, command }, transferables);
|
this.worker.postMessage({ id, command }, transferables);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+1
-1
@@ -410,7 +410,7 @@ export class Conversion {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (!this._canceled) {
|
if (!this._canceled) {
|
||||||
// Make sure to cancel to stop other encoding processes and clean up resources
|
// Make sure to cancel to stop other encoding processes and clean up resources
|
||||||
await this.cancel();
|
void this.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
throw error;
|
throw error;
|
||||||
|
|||||||
+35
-22
@@ -80,7 +80,8 @@ export abstract class MediaSource {
|
|||||||
/** @internal */
|
/** @internal */
|
||||||
async _start() {}
|
async _start() {}
|
||||||
/** @internal */
|
/** @internal */
|
||||||
async _flushAndClose() {}
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
async _flushAndClose(forceClose: boolean) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes this source. This prevents future samples from being added and signals to the output file that no further
|
* Closes this source. This prevents future samples from being added and signals to the output file that no further
|
||||||
@@ -103,7 +104,7 @@ export abstract class MediaSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this._closingPromise = (async () => {
|
this._closingPromise = (async () => {
|
||||||
await this._flushAndClose();
|
await this._flushAndClose(false);
|
||||||
|
|
||||||
this._closed = true;
|
this._closed = true;
|
||||||
|
|
||||||
@@ -116,12 +117,12 @@ export abstract class MediaSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
async _flushOrWaitForClose() {
|
async _flushOrWaitForOngoingClose(forceClose: boolean) {
|
||||||
if (this._closingPromise) {
|
if (this._closingPromise) {
|
||||||
// Since closing also flushes, we don't want to do it twice
|
// Since closing also flushes, we don't want to do it twice
|
||||||
return this._closingPromise;
|
return this._closingPromise;
|
||||||
} else {
|
} else {
|
||||||
return this._flushAndClose();
|
return this._flushAndClose(forceClose);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -451,14 +452,20 @@ class VideoEncoderWrapper {
|
|||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
|
|
||||||
async flushAndClose() {
|
async flushAndClose(forceClose: boolean) {
|
||||||
this.checkForEncoderError();
|
this.checkForEncoderError();
|
||||||
|
|
||||||
if (this.customEncoder) {
|
if (this.customEncoder) {
|
||||||
void this.customEncoderCallSerializer.call(() => this.customEncoder!.flush());
|
if (!forceClose) {
|
||||||
|
void this.customEncoderCallSerializer.call(() => this.customEncoder!.flush());
|
||||||
|
}
|
||||||
|
|
||||||
await this.customEncoderCallSerializer.call(() => this.customEncoder!.close());
|
await this.customEncoderCallSerializer.call(() => this.customEncoder!.close());
|
||||||
} else if (this.encoder) {
|
} else if (this.encoder) {
|
||||||
await this.encoder.flush();
|
if (!forceClose) {
|
||||||
|
await this.encoder.flush();
|
||||||
|
}
|
||||||
|
|
||||||
this.encoder.close();
|
this.encoder.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -512,8 +519,8 @@ export class VideoSampleSource extends VideoSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
override _flushAndClose() {
|
override _flushAndClose(forceClose: boolean) {
|
||||||
return this._encoder.flushAndClose();
|
return this._encoder.flushAndClose(forceClose);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -564,8 +571,8 @@ export class CanvasSource extends VideoSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
override _flushAndClose() {
|
override _flushAndClose(forceClose: boolean) {
|
||||||
return this._encoder.flushAndClose();
|
return this._encoder.flushAndClose(forceClose);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -714,7 +721,7 @@ export class MediaStreamVideoTrackSource extends VideoSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
override async _flushAndClose() {
|
override async _flushAndClose(forceClose: boolean) {
|
||||||
if (this._abortController) {
|
if (this._abortController) {
|
||||||
this._abortController.abort();
|
this._abortController.abort();
|
||||||
this._abortController = null;
|
this._abortController = null;
|
||||||
@@ -746,7 +753,7 @@ export class MediaStreamVideoTrackSource extends VideoSource {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
await this._encoder.flushAndClose();
|
await this._encoder.flushAndClose(forceClose);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1226,14 +1233,20 @@ class AudioEncoderWrapper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async flushAndClose() {
|
async flushAndClose(forceClose: boolean) {
|
||||||
this.checkForEncoderError();
|
this.checkForEncoderError();
|
||||||
|
|
||||||
if (this.customEncoder) {
|
if (this.customEncoder) {
|
||||||
void this.customEncoderCallSerializer.call(() => this.customEncoder!.flush());
|
if (!forceClose) {
|
||||||
|
void this.customEncoderCallSerializer.call(() => this.customEncoder!.flush());
|
||||||
|
}
|
||||||
|
|
||||||
await this.customEncoderCallSerializer.call(() => this.customEncoder!.close());
|
await this.customEncoderCallSerializer.call(() => this.customEncoder!.close());
|
||||||
} else if (this.encoder) {
|
} else if (this.encoder) {
|
||||||
await this.encoder.flush();
|
if (!forceClose) {
|
||||||
|
await this.encoder.flush();
|
||||||
|
}
|
||||||
|
|
||||||
this.encoder.close();
|
this.encoder.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1289,8 +1302,8 @@ export class AudioSampleSource extends AudioSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
override _flushAndClose() {
|
override _flushAndClose(forceClose: boolean) {
|
||||||
return this._encoder.flushAndClose();
|
return this._encoder.flushAndClose(forceClose);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1333,8 +1346,8 @@ export class AudioBufferSource extends AudioSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
override _flushAndClose() {
|
override _flushAndClose(forceClose: boolean) {
|
||||||
return this._encoder.flushAndClose();
|
return this._encoder.flushAndClose(forceClose);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1480,7 +1493,7 @@ export class MediaStreamAudioTrackSource extends AudioSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
override async _flushAndClose() {
|
override async _flushAndClose(forceClose: boolean) {
|
||||||
if (this._abortController) {
|
if (this._abortController) {
|
||||||
this._abortController.abort();
|
this._abortController.abort();
|
||||||
this._abortController = null;
|
this._abortController = null;
|
||||||
@@ -1493,7 +1506,7 @@ export class MediaStreamAudioTrackSource extends AudioSource {
|
|||||||
await this._audioContext.suspend();
|
await this._audioContext.suspend();
|
||||||
}
|
}
|
||||||
|
|
||||||
await this._encoder.flushAndClose();
|
await this._encoder.flushAndClose(forceClose);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -380,7 +380,7 @@ export class Output<
|
|||||||
|
|
||||||
const release = await this._mutex.acquire();
|
const release = await this._mutex.acquire();
|
||||||
|
|
||||||
const promises = this._tracks.map(x => x.source._flushOrWaitForClose());
|
const promises = this._tracks.map(x => x.source._flushOrWaitForOngoingClose(true)); // Force close
|
||||||
await Promise.all(promises);
|
await Promise.all(promises);
|
||||||
|
|
||||||
await this._writer.close();
|
await this._writer.close();
|
||||||
@@ -410,7 +410,7 @@ export class Output<
|
|||||||
|
|
||||||
const release = await this._mutex.acquire();
|
const release = await this._mutex.acquire();
|
||||||
|
|
||||||
const promises = this._tracks.map(x => x.source._flushOrWaitForClose());
|
const promises = this._tracks.map(x => x.source._flushOrWaitForOngoingClose(false));
|
||||||
await Promise.all(promises);
|
await Promise.all(promises);
|
||||||
|
|
||||||
await this._muxer.finalize();
|
await this._muxer.finalize();
|
||||||
|
|||||||
Reference in New Issue
Block a user