From 9738329f73a15d595198191aff916768a4a61d7e Mon Sep 17 00:00:00 2001 From: Yonatan Bendahan Date: Tue, 15 Apr 2025 15:09:15 +0300 Subject: [PATCH 1/3] make getSize and input source public --- src/input-format.ts | 10 +++++----- src/input.ts | 5 ++--- src/isobmff/isobmff-demuxer.ts | 6 +++--- src/matroska/matroska-demuxer.ts | 6 +++--- src/mp3/mp3-demuxer.ts | 2 +- src/ogg/ogg-demuxer.ts | 4 ++-- src/reader.ts | 2 +- src/source.ts | 3 +-- src/wave/wave-demuxer.ts | 2 +- 9 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/input-format.ts b/src/input-format.ts index 515ec9e..cc7e8aa 100644 --- a/src/input-format.ts +++ b/src/input-format.ts @@ -35,7 +35,7 @@ export abstract class InputFormat { export abstract class IsobmffInputFormat extends InputFormat { /** @internal */ protected async _getMajorBrand(input: Input) { - const sourceSize = await input._mainReader.source._getSize(); + const sourceSize = await input._mainReader.source.getSize(); if (sourceSize < 12) { return null; } @@ -104,7 +104,7 @@ export class QuickTimeInputFormat extends IsobmffInputFormat { export class MatroskaInputFormat extends InputFormat { /** @internal */ protected async isSupportedEBMLOfDocType(input: Input, desiredDocType: string) { - const sourceSize = await input._mainReader.source._getSize(); + const sourceSize = await input._mainReader.source.getSize(); if (sourceSize < 8) { return false; } @@ -209,7 +209,7 @@ export class WebMInputFormat extends MatroskaInputFormat { export class Mp3InputFormat extends InputFormat { /** @internal */ async _canReadInput(input: Input) { - const sourceSize = await input._mainReader.source._getSize(); + const sourceSize = await input._mainReader.source.getSize(); if (sourceSize < 4) { return false; } @@ -274,7 +274,7 @@ export class Mp3InputFormat extends InputFormat { export class WaveInputFormat extends InputFormat { /** @internal */ async _canReadInput(input: Input) { - const sourceSize = await input._mainReader.source._getSize(); + const sourceSize = await input._mainReader.source.getSize(); if (sourceSize < 12) { return false; } @@ -311,7 +311,7 @@ export class WaveInputFormat extends InputFormat { export class OggInputFormat extends InputFormat { /** @internal */ async _canReadInput(input: Input) { - const sourceSize = await input._mainReader.source._getSize(); + const sourceSize = await input._mainReader.source.getSize(); if (sourceSize < 4) { return false; } diff --git a/src/input.ts b/src/input.ts index ad022c4..33f7ff7 100644 --- a/src/input.ts +++ b/src/input.ts @@ -20,8 +20,7 @@ export type InputOptions = { * @public */ export class Input { - /** @internal */ - _source: Source; + source: Source; /** @internal */ _formats: InputFormat[]; /** @internal */ @@ -43,7 +42,7 @@ export class Input { } this._formats = options.formats; - this._source = options.source; + this.source = options.source; this._mainReader = new Reader(options.source); } diff --git a/src/isobmff/isobmff-demuxer.ts b/src/isobmff/isobmff-demuxer.ts index 7dc3a9a..87e2573 100644 --- a/src/isobmff/isobmff-demuxer.ts +++ b/src/isobmff/isobmff-demuxer.ts @@ -198,7 +198,7 @@ export class IsobmffDemuxer extends Demuxer { super(input); this.metadataReader = new IsobmffReader(input._mainReader); - this.chunkReader = new IsobmffReader(new Reader(input._source, 64 * 2 ** 20)); // Max 64 MiB of stored chunks + this.chunkReader = new IsobmffReader(new Reader(input.source, 64 * 2 ** 20)); // Max 64 MiB of stored chunks } override async computeDuration() { @@ -235,7 +235,7 @@ export class IsobmffDemuxer extends Demuxer { readMetadata() { return this.metadataPromise ??= (async () => { - const sourceSize = await this.metadataReader.reader.source._getSize(); + const sourceSize = await this.metadataReader.reader.source.getSize(); while (this.metadataReader.pos < sourceSize) { await this.metadataReader.reader.loadRange( @@ -2191,7 +2191,7 @@ abstract class IsobmffTrackBacking implements InputTrackBacking { } const metadataReader = demuxer.metadataReader; - const sourceSize = await metadataReader.reader.source._getSize(); + const sourceSize = await metadataReader.reader.source.getSize(); let prevFragment: Fragment | null = null; let bestFragmentIndex = fragmentIndex; diff --git a/src/matroska/matroska-demuxer.ts b/src/matroska/matroska-demuxer.ts index c2afde4..d7be74f 100644 --- a/src/matroska/matroska-demuxer.ts +++ b/src/matroska/matroska-demuxer.ts @@ -165,7 +165,7 @@ export class MatroskaDemuxer extends Demuxer { this.metadataReader = new EBMLReader(input._mainReader); // Max 64 MiB of stored clusters - this.clusterReader = new EBMLReader(new Reader(input._source, 64 * 2 ** 20)); + this.clusterReader = new EBMLReader(new Reader(input.source, 64 * 2 ** 20)); } override async computeDuration() { @@ -211,7 +211,7 @@ export class MatroskaDemuxer extends Demuxer { return this.readMetadataPromise ??= (async () => { this.metadataReader.pos = 0; - const fileSize = await this.input._source._getSize(); + const fileSize = await this.input.source.getSize(); while (this.metadataReader.pos < fileSize - MIN_HEADER_SIZE) { await this.metadataReader.reader.loadRange( @@ -258,7 +258,7 @@ export class MatroskaDemuxer extends Demuxer { dataStartPos: segmentDataStart, elementEndPos: dataSize === -1 - ? (await this.input._source._getSize() - MIN_HEADER_SIZE) + ? (await this.input.source.getSize() - MIN_HEADER_SIZE) : segmentDataStart + dataSize, clusterSeekStartPos: segmentDataStart, diff --git a/src/mp3/mp3-demuxer.ts b/src/mp3/mp3-demuxer.ts index 83a519d..ba9f16c 100644 --- a/src/mp3/mp3-demuxer.ts +++ b/src/mp3/mp3-demuxer.ts @@ -32,7 +32,7 @@ export class Mp3Demuxer extends Demuxer { async readMetadata() { return this.metadataPromise ??= (async () => { - const fileSize = await this.input._source._getSize(); + const fileSize = await this.input.source.getSize(); this.reader.fileSize = fileSize; // Just load the entire file. Primitive, but the only way to actually ensure 100% correct timestamps. diff --git a/src/ogg/ogg-demuxer.ts b/src/ogg/ogg-demuxer.ts index a9045d9..3626400 100644 --- a/src/ogg/ogg-demuxer.ts +++ b/src/ogg/ogg-demuxer.ts @@ -38,12 +38,12 @@ export class OggDemuxer extends Demuxer { super(input); // We don't need a persistent metadata reader as we read all metadata once at the start and then never again - this.reader = new OggReader(new Reader(input._source, 64 * 2 ** 20)); + this.reader = new OggReader(new Reader(input.source, 64 * 2 ** 20)); } async readMetadata() { return this.metadataPromise ??= (async () => { - this.fileSize = await this.input._source._getSize(); + this.fileSize = await this.input.source.getSize(); while (this.reader.pos < this.fileSize - MIN_PAGE_HEADER_SIZE) { await this.reader.reader.loadRange( diff --git a/src/reader.ts b/src/reader.ts index 6ac6eb6..8203fce 100644 --- a/src/reader.ts +++ b/src/reader.ts @@ -25,7 +25,7 @@ export class Reader { constructor(public source: Source, public maxStorableBytes = Infinity) {} async loadRange(start: number, end: number) { - end = Math.min(end, await this.source._getSize()); + end = Math.min(end, await this.source.getSize()); if (start >= end) { return; diff --git a/src/source.ts b/src/source.ts index bb0bb19..aa6365f 100644 --- a/src/source.ts +++ b/src/source.ts @@ -13,8 +13,7 @@ export abstract class Source { /** @internal */ _sizePromise: Promise | null = null; - /** @internal */ - _getSize() { + getSize() { return this._sizePromise ??= this._retrieveSize(); } diff --git a/src/wave/wave-demuxer.ts b/src/wave/wave-demuxer.ts index 79b1167..53ec8f0 100644 --- a/src/wave/wave-demuxer.ts +++ b/src/wave/wave-demuxer.ts @@ -37,7 +37,7 @@ export class WaveDemuxer extends Demuxer { super(input); this.metadataReader = new RiffReader(input._mainReader); - this.chunkReader = new RiffReader(new Reader(input._source, 64 * 2 ** 20)); + this.chunkReader = new RiffReader(new Reader(input.source, 64 * 2 ** 20)); } async readMetadata() { From 9a5e29ae118048f23e2b8ab8a6f63dcc8eb1c687 Mon Sep 17 00:00:00 2001 From: Yonatan Bendahan Date: Tue, 15 Apr 2025 15:13:31 +0300 Subject: [PATCH 2/3] make source readonly --- src/input.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/input.ts b/src/input.ts index 33f7ff7..e41631e 100644 --- a/src/input.ts +++ b/src/input.ts @@ -20,7 +20,8 @@ export type InputOptions = { * @public */ export class Input { - source: Source; + /** @internal */ + _source: Source; /** @internal */ _formats: InputFormat[]; /** @internal */ @@ -42,7 +43,7 @@ export class Input { } this._formats = options.formats; - this.source = options.source; + this._source = options.source; this._mainReader = new Reader(options.source); } @@ -63,6 +64,14 @@ export class Input { })(); } + /** + * Returns the source from which this input file reads its data. This is the same source that was passed to there + * constructor. + */ + get source() { + return this._source; + } + /** * Returns the format of the input file. You can compare this result directly to the InputFormat singletons or use * `instanceof` checks for subset-aware logic (for example, `format instanceof MatroskaInputFormat` is true for From 8288bf7a671499a4a0c831a9073b9c3ab60a6e66 Mon Sep 17 00:00:00 2001 From: Yonatan Bendahan Date: Tue, 15 Apr 2025 15:13:34 +0300 Subject: [PATCH 3/3] add docs --- src/source.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/source.ts b/src/source.ts index aa6365f..0a457f2 100644 --- a/src/source.ts +++ b/src/source.ts @@ -13,6 +13,10 @@ export abstract class Source { /** @internal */ _sizePromise: Promise | null = null; + /** + * Returns promise that resolves with the size of the file. + * If the size is not known, it will be retrieved from the source. + */ getSize() { return this._sizePromise ??= this._retrieveSize(); }