mirror of
https://github.com/arcodange-org/mediabunny.git
synced 2026-10-03 05:43:50 +02:00
Merge branch 'main' of https://github.com/Vanilagy/metamuxer
This commit is contained in:
+5
-5
@@ -35,7 +35,7 @@ export abstract class InputFormat {
|
|||||||
export abstract class IsobmffInputFormat extends InputFormat {
|
export abstract class IsobmffInputFormat extends InputFormat {
|
||||||
/** @internal */
|
/** @internal */
|
||||||
protected async _getMajorBrand(input: Input) {
|
protected async _getMajorBrand(input: Input) {
|
||||||
const sourceSize = await input._mainReader.source._getSize();
|
const sourceSize = await input._mainReader.source.getSize();
|
||||||
if (sourceSize < 12) {
|
if (sourceSize < 12) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -104,7 +104,7 @@ export class QuickTimeInputFormat extends IsobmffInputFormat {
|
|||||||
export class MatroskaInputFormat extends InputFormat {
|
export class MatroskaInputFormat extends InputFormat {
|
||||||
/** @internal */
|
/** @internal */
|
||||||
protected async isSupportedEBMLOfDocType(input: Input, desiredDocType: string) {
|
protected async isSupportedEBMLOfDocType(input: Input, desiredDocType: string) {
|
||||||
const sourceSize = await input._mainReader.source._getSize();
|
const sourceSize = await input._mainReader.source.getSize();
|
||||||
if (sourceSize < 8) {
|
if (sourceSize < 8) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -209,7 +209,7 @@ export class WebMInputFormat extends MatroskaInputFormat {
|
|||||||
export class Mp3InputFormat extends InputFormat {
|
export class Mp3InputFormat extends InputFormat {
|
||||||
/** @internal */
|
/** @internal */
|
||||||
async _canReadInput(input: Input) {
|
async _canReadInput(input: Input) {
|
||||||
const sourceSize = await input._mainReader.source._getSize();
|
const sourceSize = await input._mainReader.source.getSize();
|
||||||
if (sourceSize < 4) {
|
if (sourceSize < 4) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -274,7 +274,7 @@ export class Mp3InputFormat extends InputFormat {
|
|||||||
export class WaveInputFormat extends InputFormat {
|
export class WaveInputFormat extends InputFormat {
|
||||||
/** @internal */
|
/** @internal */
|
||||||
async _canReadInput(input: Input) {
|
async _canReadInput(input: Input) {
|
||||||
const sourceSize = await input._mainReader.source._getSize();
|
const sourceSize = await input._mainReader.source.getSize();
|
||||||
if (sourceSize < 12) {
|
if (sourceSize < 12) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -311,7 +311,7 @@ export class WaveInputFormat extends InputFormat {
|
|||||||
export class OggInputFormat extends InputFormat {
|
export class OggInputFormat extends InputFormat {
|
||||||
/** @internal */
|
/** @internal */
|
||||||
async _canReadInput(input: Input) {
|
async _canReadInput(input: Input) {
|
||||||
const sourceSize = await input._mainReader.source._getSize();
|
const sourceSize = await input._mainReader.source.getSize();
|
||||||
if (sourceSize < 4) {
|
if (sourceSize < 4) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-5
@@ -8,20 +8,20 @@ import { Source } from './source';
|
|||||||
* The options for creating an Input object.
|
* The options for creating an Input object.
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
export type InputOptions = {
|
export type InputOptions<S extends Source = Source> = {
|
||||||
/** A list of supported formats. If the source file is not of one of these formats, then it cannot be read. */
|
/** A list of supported formats. If the source file is not of one of these formats, then it cannot be read. */
|
||||||
formats: InputFormat[];
|
formats: InputFormat[];
|
||||||
/** The source from which data will be read. */
|
/** The source from which data will be read. */
|
||||||
source: Source;
|
source: S;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an input media file. This is the root object from which all media read operations start.
|
* Represents an input media file. This is the root object from which all media read operations start.
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
export class Input {
|
export class Input<S extends Source = Source> {
|
||||||
/** @internal */
|
/** @internal */
|
||||||
_source: Source;
|
_source: S;
|
||||||
/** @internal */
|
/** @internal */
|
||||||
_formats: InputFormat[];
|
_formats: InputFormat[];
|
||||||
/** @internal */
|
/** @internal */
|
||||||
@@ -31,7 +31,7 @@ export class Input {
|
|||||||
/** @internal */
|
/** @internal */
|
||||||
_format: InputFormat | null = null;
|
_format: InputFormat | null = null;
|
||||||
|
|
||||||
constructor(options: InputOptions) {
|
constructor(options: InputOptions<S>) {
|
||||||
if (!options || typeof options !== 'object') {
|
if (!options || typeof options !== 'object') {
|
||||||
throw new TypeError('options must be an object.');
|
throw new TypeError('options must be an object.');
|
||||||
}
|
}
|
||||||
@@ -64,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 the
|
||||||
|
* 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
|
* 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
|
* `instanceof` checks for subset-aware logic (for example, `format instanceof MatroskaInputFormat` is true for
|
||||||
|
|||||||
@@ -198,7 +198,7 @@ export class IsobmffDemuxer extends Demuxer {
|
|||||||
super(input);
|
super(input);
|
||||||
|
|
||||||
this.metadataReader = new IsobmffReader(input._mainReader);
|
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() {
|
override async computeDuration() {
|
||||||
@@ -235,7 +235,7 @@ export class IsobmffDemuxer extends Demuxer {
|
|||||||
|
|
||||||
readMetadata() {
|
readMetadata() {
|
||||||
return this.metadataPromise ??= (async () => {
|
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) {
|
while (this.metadataReader.pos < sourceSize) {
|
||||||
await this.metadataReader.reader.loadRange(
|
await this.metadataReader.reader.loadRange(
|
||||||
@@ -2191,7 +2191,7 @@ abstract class IsobmffTrackBacking implements InputTrackBacking {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const metadataReader = demuxer.metadataReader;
|
const metadataReader = demuxer.metadataReader;
|
||||||
const sourceSize = await metadataReader.reader.source._getSize();
|
const sourceSize = await metadataReader.reader.source.getSize();
|
||||||
|
|
||||||
let prevFragment: Fragment | null = null;
|
let prevFragment: Fragment | null = null;
|
||||||
let bestFragmentIndex = fragmentIndex;
|
let bestFragmentIndex = fragmentIndex;
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ export class MatroskaDemuxer extends Demuxer {
|
|||||||
this.metadataReader = new EBMLReader(input._mainReader);
|
this.metadataReader = new EBMLReader(input._mainReader);
|
||||||
|
|
||||||
// Max 64 MiB of stored clusters
|
// 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() {
|
override async computeDuration() {
|
||||||
@@ -211,7 +211,7 @@ export class MatroskaDemuxer extends Demuxer {
|
|||||||
return this.readMetadataPromise ??= (async () => {
|
return this.readMetadataPromise ??= (async () => {
|
||||||
this.metadataReader.pos = 0;
|
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) {
|
while (this.metadataReader.pos < fileSize - MIN_HEADER_SIZE) {
|
||||||
await this.metadataReader.reader.loadRange(
|
await this.metadataReader.reader.loadRange(
|
||||||
@@ -258,7 +258,7 @@ export class MatroskaDemuxer extends Demuxer {
|
|||||||
|
|
||||||
dataStartPos: segmentDataStart,
|
dataStartPos: segmentDataStart,
|
||||||
elementEndPos: dataSize === -1
|
elementEndPos: dataSize === -1
|
||||||
? (await this.input._source._getSize() - MIN_HEADER_SIZE)
|
? (await this.input.source.getSize() - MIN_HEADER_SIZE)
|
||||||
: segmentDataStart + dataSize,
|
: segmentDataStart + dataSize,
|
||||||
clusterSeekStartPos: segmentDataStart,
|
clusterSeekStartPos: segmentDataStart,
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export class Mp3Demuxer extends Demuxer {
|
|||||||
|
|
||||||
async readMetadata() {
|
async readMetadata() {
|
||||||
return this.metadataPromise ??= (async () => {
|
return this.metadataPromise ??= (async () => {
|
||||||
const fileSize = await this.input._source._getSize();
|
const fileSize = await this.input.source.getSize();
|
||||||
this.reader.fileSize = fileSize;
|
this.reader.fileSize = fileSize;
|
||||||
|
|
||||||
// Just load the entire file. Primitive, but the only way to actually ensure 100% correct timestamps.
|
// Just load the entire file. Primitive, but the only way to actually ensure 100% correct timestamps.
|
||||||
|
|||||||
@@ -38,12 +38,12 @@ export class OggDemuxer extends Demuxer {
|
|||||||
super(input);
|
super(input);
|
||||||
|
|
||||||
// We don't need a persistent metadata reader as we read all metadata once at the start and then never again
|
// 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() {
|
async readMetadata() {
|
||||||
return this.metadataPromise ??= (async () => {
|
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) {
|
while (this.reader.pos < this.fileSize - MIN_PAGE_HEADER_SIZE) {
|
||||||
await this.reader.reader.loadRange(
|
await this.reader.reader.loadRange(
|
||||||
|
|||||||
+1
-1
@@ -25,7 +25,7 @@ export class Reader {
|
|||||||
constructor(public source: Source, public maxStorableBytes = Infinity) {}
|
constructor(public source: Source, public maxStorableBytes = Infinity) {}
|
||||||
|
|
||||||
async loadRange(start: number, end: number) {
|
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) {
|
if (start >= end) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
+5
-2
@@ -13,8 +13,11 @@ export abstract class Source {
|
|||||||
/** @internal */
|
/** @internal */
|
||||||
_sizePromise: Promise<number> | null = null;
|
_sizePromise: Promise<number> | null = null;
|
||||||
|
|
||||||
/** @internal */
|
/**
|
||||||
_getSize() {
|
* Resolves with the total size of the file in bytes. This function is memoized, meaning only the first call
|
||||||
|
* will retrieve the size.
|
||||||
|
*/
|
||||||
|
getSize() {
|
||||||
return this._sizePromise ??= this._retrieveSize();
|
return this._sizePromise ??= this._retrieveSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ export class WaveDemuxer extends Demuxer {
|
|||||||
super(input);
|
super(input);
|
||||||
|
|
||||||
this.metadataReader = new RiffReader(input._mainReader);
|
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() {
|
async readMetadata() {
|
||||||
|
|||||||
@@ -2,3 +2,4 @@
|
|||||||
- cross-track offset for streaming sources
|
- cross-track offset for streaming sources
|
||||||
- textsubtitlesource, chunked piping
|
- textsubtitlesource, chunked piping
|
||||||
- More efficient MP3 loading when reading sequentially
|
- More efficient MP3 loading when reading sequentially
|
||||||
|
- Validate types returned by custom coders
|
||||||
Reference in New Issue
Block a user