From a043f410fd789f361d4acf004522fa1f70966ccc Mon Sep 17 00:00:00 2001 From: Vanilagy <1696106+Vanilagy@users.noreply.github.com> Date: Wed, 24 Sep 2025 21:41:52 +0200 Subject: [PATCH] Make samples disposable --- docs/guide/introduction.md | 2 +- src/input.ts | 8 +++----- src/misc.ts | 6 ++++++ src/sample.ts | 17 +++++++++++++++-- 4 files changed, 25 insertions(+), 8 deletions(-) diff --git a/docs/guide/introduction.md b/docs/guide/introduction.md index da8aa3e..20b86a5 100644 --- a/docs/guide/introduction.md +++ b/docs/guide/introduction.md @@ -12,7 +12,7 @@ Here's a long list of stuff this library does: - Converting media files - Hardware-accelerated decoding & encoding (via the WebCodecs API) - Support for multiple video, audio and subtitle tracks -- Read & write support for many container formats (.mp4, .mov, .webm, .mkv, .mp3, .wav, .ogg, .aac, .flac), including variations such as MP4 with Fast Start, fragmented MP4, or streamable Matroska +- Read & write support for many container formats (.mp4, .mov, .webm, .mkv, .mp3, .wav, .ogg, .aac, .flac), including variations such as MP4 with Fast Start, fragmented MP4, streamable Matroska, transparent WebM, etc. - Support for 25 different codecs - Lazy, optimized, on-demand file reading - Input and output streaming, arbitrary file size support diff --git a/src/input.ts b/src/input.ts index 875aeb6..5e78243 100644 --- a/src/input.ts +++ b/src/input.ts @@ -8,10 +8,12 @@ import { Demuxer } from './demuxer'; import { InputFormat } from './input-format'; -import { assert } from './misc'; +import { assert, polyfillSymbolDispose } from './misc'; import { Reader } from './reader'; import { Source } from './source'; +polyfillSymbolDispose(); + /** * The options for creating an Input object. * @group Input files & tracks @@ -24,10 +26,6 @@ export type InputOptions = { source: S; }; -// https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-2.html -// @ts-expect-error Readonly -Symbol.dispose ??= Symbol('Symbol.dispose'); - /** * Represents an input media file. This is the root object from which all media read operations start. * @group Input files & tracks diff --git a/src/misc.ts b/src/misc.ts index bb5c300..3df6e2f 100644 --- a/src/misc.ts +++ b/src/misc.ts @@ -780,3 +780,9 @@ export const uint8ArraysAreEqual = (a: Uint8Array, b: Uint8Array) => { return true; }; + +export const polyfillSymbolDispose = () => { + // https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-2.html + // @ts-expect-error Readonly + Symbol.dispose ??= Symbol('Symbol.dispose'); +}; diff --git a/src/sample.ts b/src/sample.ts index 924d016..5f537da 100644 --- a/src/sample.ts +++ b/src/sample.ts @@ -16,8 +16,11 @@ import { toUint8Array, SetRequired, isFirefox, + polyfillSymbolDispose, } from './misc'; +polyfillSymbolDispose(); + /** * Metadata used for VideoSample initialization. * @group Samples @@ -49,7 +52,7 @@ export type VideoSampleInit = { * @group Samples * @public */ -export class VideoSample { +export class VideoSample implements Disposable { /** @internal */ _data!: VideoFrame | OffscreenCanvas | Uint8Array | null; /** @internal */ @@ -736,6 +739,11 @@ export class VideoSample { // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion (this.duration as number) = newDuration; } + + /** Calls `.close()`. */ + [Symbol.dispose]() { + this.close(); + } } const isVideoFrame = (x: unknown): x is VideoFrame => { @@ -840,7 +848,7 @@ export type AudioSampleCopyToOptions = { * @group Samples * @public */ -export class AudioSample { +export class AudioSample implements Disposable { /** @internal */ _data: AudioData | Uint8Array; /** @internal */ @@ -1276,6 +1284,11 @@ export class AudioSample { (this.timestamp as number) = newTimestamp; } + /** Calls `.close()`. */ + [Symbol.dispose]() { + this.close(); + } + /** @internal */ static* _fromAudioBuffer(audioBuffer: AudioBuffer, timestamp: number) { if (!(audioBuffer instanceof AudioBuffer)) {