mirror of
https://github.com/arcodange-org/mediabunny.git
synced 2026-09-27 10:53:50 +02:00
Manually close file readers to avoid indefinite memory leak (fixes #144)
This commit is contained in:
+17
-4
@@ -496,6 +496,14 @@ export type BlobSourceOptions = {
|
|||||||
useStreamReader?: boolean;
|
useStreamReader?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const blobReaderRegistry = typeof FinalizationRegistry !== 'undefined'
|
||||||
|
? new FinalizationRegistry<ReadableStreamDefaultReader<Uint8Array>>((reader) => {
|
||||||
|
// Browsers don't GC readers that aren't "done", which creates indefinite memory leaks,
|
||||||
|
// see https://github.com/Vanilagy/mediabunny/issues/144#issuecomment-5465467062. So, we need to do it instead.
|
||||||
|
void reader.cancel().catch(() => {});
|
||||||
|
})
|
||||||
|
: null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A source backed by a [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob). Since a
|
* A source backed by a [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob). Since a
|
||||||
* [`File`](https://developer.mozilla.org/en-US/docs/Web/API/File) is also a `Blob`, this is the source to use when
|
* [`File`](https://developer.mozilla.org/en-US/docs/Web/API/File) is also a `Blob`, this is the source to use when
|
||||||
@@ -510,6 +518,8 @@ export class BlobSource extends Source {
|
|||||||
_options: BlobSourceOptions;
|
_options: BlobSourceOptions;
|
||||||
/** @internal */
|
/** @internal */
|
||||||
_orchestrator: ReadOrchestrator;
|
_orchestrator: ReadOrchestrator;
|
||||||
|
/** @internal */
|
||||||
|
_readers = new WeakMap<ReadWorker, ReadableStreamDefaultReader<Uint8Array> | null>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link BlobSource} backed by the specified
|
* Creates a new {@link BlobSource} backed by the specified
|
||||||
@@ -562,9 +572,6 @@ export class BlobSource extends Source {
|
|||||||
return this._orchestrator.read(start, end, minReadPosition, maxReadPosition);
|
return this._orchestrator.read(start, end, minReadPosition, maxReadPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @internal */
|
|
||||||
_readers = new WeakMap<ReadWorker, ReadableStreamDefaultReader<Uint8Array> | null>();
|
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
private async _runWorker(worker: ReadWorker) {
|
private async _runWorker(worker: ReadWorker) {
|
||||||
assert(worker.strictTarget);
|
assert(worker.strictTarget);
|
||||||
@@ -578,10 +585,16 @@ export class BlobSource extends Source {
|
|||||||
// - ReadableStream stalls under backpressure (especially video)
|
// - ReadableStream stalls under backpressure (especially video)
|
||||||
// Affects Safari and all iOS browsers (Chrome, Firefox, etc.).
|
// Affects Safari and all iOS browsers (Chrome, Firefox, etc.).
|
||||||
// Use arrayBuffer() fallback for WebKit browsers.
|
// Use arrayBuffer() fallback for WebKit browsers.
|
||||||
if ('stream' in this._blob && !isWebKit() && this._options.useStreamReader !== false) {
|
if (
|
||||||
|
'stream' in this._blob && !isWebKit()
|
||||||
|
&& this._options.useStreamReader !== false
|
||||||
|
&& blobReaderRegistry // Without it, we cannot guarantee cleanup of abandoned readers
|
||||||
|
) {
|
||||||
// Get a reader of the blob starting at the required offset, and then keep it around
|
// Get a reader of the blob starting at the required offset, and then keep it around
|
||||||
const slice = this._blob.slice(worker.currentPos);
|
const slice = this._blob.slice(worker.currentPos);
|
||||||
reader = slice.stream().getReader();
|
reader = slice.stream().getReader();
|
||||||
|
|
||||||
|
blobReaderRegistry.register(worker, reader);
|
||||||
} else {
|
} else {
|
||||||
// We'll need to use more primitive ways
|
// We'll need to use more primitive ways
|
||||||
reader = null;
|
reader = null;
|
||||||
|
|||||||
Reference in New Issue
Block a user