mirror of
https://github.com/arcodange-org/mediabunny.git
synced 2026-09-30 12:23:52 +02:00
Unpromise many input track methods
This commit is contained in:
+29
-35
@@ -257,8 +257,7 @@ class Conversion {
|
||||
continue;
|
||||
}
|
||||
|
||||
const type = track.getType();
|
||||
if (this.addedCounts[type] === outputTrackCounts[type].max) {
|
||||
if (this.addedCounts[track.type] === outputTrackCounts[track.type].max) {
|
||||
this.result.discardedTracks.push({
|
||||
track,
|
||||
reason: 'maxTrackCountOfTypeReached',
|
||||
@@ -310,9 +309,7 @@ class Conversion {
|
||||
}
|
||||
|
||||
async processVideoTrack(track: InputVideoTrack) {
|
||||
const trackId = track.getId();
|
||||
|
||||
const sourceCodec = await track.getCodec();
|
||||
const sourceCodec = track.codec;
|
||||
if (!sourceCodec) {
|
||||
this.result.discardedTracks.push({
|
||||
track,
|
||||
@@ -323,8 +320,8 @@ class Conversion {
|
||||
|
||||
let videoSource: VideoSource;
|
||||
|
||||
const originalWidth = await track.getCodedWidth();
|
||||
const originalHeight = await track.getCodedHeight();
|
||||
const originalWidth = track.codedWidth;
|
||||
const originalHeight = track.codedHeight;
|
||||
const originalAspectRatio = originalWidth / originalHeight;
|
||||
|
||||
let width = originalWidth;
|
||||
@@ -368,16 +365,16 @@ class Conversion {
|
||||
const meta: EncodedVideoChunkMetadata = { decoderConfig: decoderConfig ?? undefined };
|
||||
|
||||
for await (const sample of sink.samples(undefined, this.endTimestamp)) {
|
||||
if (this.synchronizer.shouldWait(trackId, sample.timestamp)) {
|
||||
if (this.synchronizer.shouldWait(track.id, sample.timestamp)) {
|
||||
await this.synchronizer.wait(sample.timestamp);
|
||||
}
|
||||
|
||||
await source.digest(sample, meta);
|
||||
this.reportProgress(trackId, sample.timestamp + sample.duration);
|
||||
this.reportProgress(track.id, sample.timestamp + sample.duration);
|
||||
}
|
||||
|
||||
await source.close();
|
||||
this.synchronizer.closeTrack(trackId);
|
||||
this.synchronizer.closeTrack(track.id);
|
||||
})());
|
||||
} else {
|
||||
// We need to decode & reencode the video
|
||||
@@ -396,8 +393,8 @@ class Conversion {
|
||||
}
|
||||
|
||||
const encodableCodecs = await getEncodableVideoCodecs(videoCodecs, {
|
||||
width: needsResize ? width : await track.getCodedWidth(),
|
||||
height: needsResize ? height : await track.getCodedHeight(),
|
||||
width: needsResize ? width : track.codedWidth,
|
||||
height: needsResize ? height : track.codedHeight,
|
||||
});
|
||||
if (encodableCodecs.length === 0) {
|
||||
this.result.discardedTracks.push({
|
||||
@@ -410,7 +407,7 @@ class Conversion {
|
||||
const encodingConfig: VideoEncodingConfig = {
|
||||
codec: encodableCodecs[0]!,
|
||||
bitrate: this.options.video?.bitrate ?? QUALITY_HIGH,
|
||||
onEncodedSample: sample => this.reportProgress(trackId, sample.timestamp + sample.duration),
|
||||
onEncodedSample: sample => this.reportProgress(track.id, sample.timestamp + sample.duration),
|
||||
};
|
||||
|
||||
if (needsResize) {
|
||||
@@ -432,7 +429,7 @@ class Conversion {
|
||||
const iterator = sink.canvases(this.startTimestamp, this.endTimestamp);
|
||||
|
||||
for await (const { canvas, timestamp, duration } of iterator) {
|
||||
if (this.synchronizer.shouldWait(trackId, timestamp)) {
|
||||
if (this.synchronizer.shouldWait(track.id, timestamp)) {
|
||||
await this.synchronizer.wait(timestamp);
|
||||
}
|
||||
|
||||
@@ -458,7 +455,7 @@ class Conversion {
|
||||
}
|
||||
|
||||
await source.close();
|
||||
this.synchronizer.closeTrack(trackId);
|
||||
this.synchronizer.closeTrack(track.id);
|
||||
})());
|
||||
} else {
|
||||
const source = new VideoFrameSource(encodingConfig);
|
||||
@@ -470,7 +467,7 @@ class Conversion {
|
||||
const sink = new VideoFrameSink(track);
|
||||
|
||||
for await (const { frame, timestamp } of sink.frames(this.startTimestamp, this.endTimestamp)) {
|
||||
if (this.synchronizer.shouldWait(trackId, timestamp)) {
|
||||
if (this.synchronizer.shouldWait(track.id, timestamp)) {
|
||||
await this.synchronizer.wait(timestamp);
|
||||
}
|
||||
|
||||
@@ -483,16 +480,16 @@ class Conversion {
|
||||
}
|
||||
|
||||
await source.close();
|
||||
this.synchronizer.closeTrack(trackId);
|
||||
this.synchronizer.closeTrack(track.id);
|
||||
})());
|
||||
}
|
||||
}
|
||||
|
||||
// Rotation metadata is reset if we do resizing
|
||||
const baseRotation = needsResize ? 0 : await track.getRotation();
|
||||
const baseRotation = needsResize ? 0 : track.rotation;
|
||||
|
||||
this.output.addVideoTrack(videoSource, {
|
||||
languageCode: await track.getLanguageCode(),
|
||||
languageCode: track.languageCode,
|
||||
rotation: (baseRotation + (this.options.video?.rotate ?? 0)) % 360 as Rotation,
|
||||
});
|
||||
this.addedCounts.video++;
|
||||
@@ -502,9 +499,7 @@ class Conversion {
|
||||
}
|
||||
|
||||
async processAudioTrack(track: InputAudioTrack) {
|
||||
const trackId = track.getId();
|
||||
|
||||
const sourceCodec = await track.getCodec();
|
||||
const sourceCodec = track.codec;
|
||||
if (!sourceCodec) {
|
||||
this.result.discardedTracks.push({
|
||||
track,
|
||||
@@ -515,8 +510,8 @@ class Conversion {
|
||||
|
||||
let audioSource: AudioSource;
|
||||
|
||||
const originalNumberOfChannels = await track.getNumberOfChannels();
|
||||
const originalSampleRate = await track.getSampleRate();
|
||||
const originalNumberOfChannels = track.numberOfChannels;
|
||||
const originalSampleRate = track.sampleRate;
|
||||
|
||||
let numberOfChannels = this.options.audio?.numberOfChannels ?? originalNumberOfChannels;
|
||||
let sampleRate = this.options.audio?.sampleRate ?? originalSampleRate;
|
||||
@@ -545,16 +540,16 @@ class Conversion {
|
||||
const meta: EncodedAudioChunkMetadata = { decoderConfig: decoderConfig ?? undefined };
|
||||
|
||||
for await (const sample of sink.samples(undefined, this.endTimestamp)) {
|
||||
if (this.synchronizer.shouldWait(trackId, sample.timestamp)) {
|
||||
if (this.synchronizer.shouldWait(track.id, sample.timestamp)) {
|
||||
await this.synchronizer.wait(sample.timestamp);
|
||||
}
|
||||
|
||||
await source.digest(sample, meta);
|
||||
this.reportProgress(trackId, sample.timestamp + sample.duration);
|
||||
this.reportProgress(track.id, sample.timestamp + sample.duration);
|
||||
}
|
||||
|
||||
await source.close();
|
||||
this.synchronizer.closeTrack(trackId);
|
||||
this.synchronizer.closeTrack(track.id);
|
||||
})());
|
||||
} else {
|
||||
// We need to decode & reencode the audio
|
||||
@@ -621,7 +616,7 @@ class Conversion {
|
||||
const source = new AudioDataSource({
|
||||
codec: codecOfChoice,
|
||||
bitrate: this.options.audio?.bitrate ?? QUALITY_HIGH,
|
||||
onEncodedSample: sample => this.reportProgress(trackId, sample.timestamp + sample.duration),
|
||||
onEncodedSample: sample => this.reportProgress(track.id, sample.timestamp + sample.duration),
|
||||
});
|
||||
audioSource = source;
|
||||
|
||||
@@ -630,7 +625,7 @@ class Conversion {
|
||||
|
||||
const sink = new AudioDataSink(track);
|
||||
for await (const { data, timestamp } of sink.data(undefined, this.startTimestamp)) {
|
||||
if (this.synchronizer.shouldWait(trackId, timestamp)) {
|
||||
if (this.synchronizer.shouldWait(track.id, timestamp)) {
|
||||
await this.synchronizer.wait(timestamp);
|
||||
}
|
||||
|
||||
@@ -639,13 +634,13 @@ class Conversion {
|
||||
}
|
||||
|
||||
await source.close();
|
||||
this.synchronizer.closeTrack(trackId);
|
||||
this.synchronizer.closeTrack(track.id);
|
||||
})());
|
||||
}
|
||||
}
|
||||
|
||||
this.output.addAudioTrack(audioSource, {
|
||||
languageCode: await track.getLanguageCode(),
|
||||
languageCode: track.languageCode,
|
||||
});
|
||||
this.addedCounts.audio++;
|
||||
this.totalTrackCount++;
|
||||
@@ -663,11 +658,10 @@ class Conversion {
|
||||
targetNumberOfChannels: number,
|
||||
targetSampleRate: number,
|
||||
) {
|
||||
const trackId = track.getId();
|
||||
const source = new AudioBufferSource({
|
||||
codec,
|
||||
bitrate: this.options.audio?.bitrate ?? QUALITY_HIGH,
|
||||
onEncodedSample: sample => this.reportProgress(trackId, sample.timestamp + sample.duration),
|
||||
onEncodedSample: sample => this.reportProgress(track.id, sample.timestamp + sample.duration),
|
||||
});
|
||||
|
||||
this.trackPromises.push((async () => {
|
||||
@@ -690,7 +684,7 @@ class Conversion {
|
||||
|
||||
const sink = new AudioBufferSink(track);
|
||||
for await (const { buffer, timestamp, duration } of sink.buffers(this.startTimestamp, this.endTimestamp)) {
|
||||
if (this.synchronizer.shouldWait(trackId, timestamp)) {
|
||||
if (this.synchronizer.shouldWait(track.id, timestamp)) {
|
||||
await this.synchronizer.wait(timestamp);
|
||||
}
|
||||
|
||||
@@ -746,7 +740,7 @@ class Conversion {
|
||||
}
|
||||
|
||||
await source.close();
|
||||
this.synchronizer.closeTrack(trackId);
|
||||
this.synchronizer.closeTrack(track.id);
|
||||
})());
|
||||
|
||||
return source;
|
||||
|
||||
+38
-38
@@ -7,11 +7,11 @@ import { EncodedAudioSample, EncodedVideoSample } from './sample';
|
||||
|
||||
export interface InputTrackBacking {
|
||||
getId(): number;
|
||||
getCodec(): Promise<MediaCodec | null>;
|
||||
getCodec(): MediaCodec | null;
|
||||
getLanguageCode(): string;
|
||||
getTimeResolution(): number;
|
||||
getFirstTimestamp(): Promise<number>;
|
||||
computeDuration(): Promise<number>;
|
||||
getLanguageCode(): Promise<string>;
|
||||
getTimeResolution(): Promise<number>;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
@@ -24,8 +24,8 @@ export abstract class InputTrack {
|
||||
this._backing = backing;
|
||||
}
|
||||
|
||||
abstract getType(): TrackType;
|
||||
abstract getCodec(): Promise<MediaCodec | null>;
|
||||
abstract get type(): TrackType;
|
||||
abstract get codec(): MediaCodec | null;
|
||||
abstract getCodecMimeType(): Promise<string | null>;
|
||||
abstract canDecode(): Promise<boolean>;
|
||||
abstract computeSampleStats(): Promise<SampleStats>;
|
||||
@@ -38,10 +38,18 @@ export abstract class InputTrack {
|
||||
return this instanceof InputAudioTrack;
|
||||
}
|
||||
|
||||
getId() {
|
||||
get id() {
|
||||
return this._backing.getId();
|
||||
}
|
||||
|
||||
get languageCode() {
|
||||
return this._backing.getLanguageCode();
|
||||
}
|
||||
|
||||
get timeResolution() {
|
||||
return this._backing.getTimeResolution();
|
||||
}
|
||||
|
||||
getFirstTimestamp() {
|
||||
return this._backing.getFirstTimestamp();
|
||||
}
|
||||
@@ -49,21 +57,13 @@ export abstract class InputTrack {
|
||||
computeDuration() {
|
||||
return this._backing.computeDuration();
|
||||
}
|
||||
|
||||
getLanguageCode() {
|
||||
return this._backing.getLanguageCode();
|
||||
}
|
||||
|
||||
getTimeResolution() {
|
||||
return this._backing.getTimeResolution();
|
||||
}
|
||||
}
|
||||
|
||||
export interface InputVideoTrackBacking extends InputTrackBacking {
|
||||
getCodec(): Promise<VideoCodec | null>;
|
||||
getCodedWidth(): Promise<number>;
|
||||
getCodedHeight(): Promise<number>;
|
||||
getRotation(): Promise<Rotation>;
|
||||
getCodec(): VideoCodec | null;
|
||||
getCodedWidth(): number;
|
||||
getCodedHeight(): number;
|
||||
getRotation(): Rotation;
|
||||
getColorSpace(): Promise<VideoColorSpaceInit>;
|
||||
getDecoderConfig(): Promise<VideoDecoderConfig | null>;
|
||||
getFirstSample(options: SampleRetrievalOptions): Promise<EncodedVideoSample | null>;
|
||||
@@ -85,33 +85,33 @@ export class InputVideoTrack extends InputTrack {
|
||||
this._backing = backing;
|
||||
}
|
||||
|
||||
getType(): TrackType {
|
||||
get type(): TrackType {
|
||||
return 'video';
|
||||
}
|
||||
|
||||
getCodec(): Promise<VideoCodec | null> {
|
||||
get codec() {
|
||||
return this._backing.getCodec();
|
||||
}
|
||||
|
||||
getCodedWidth() {
|
||||
get codedWidth() {
|
||||
return this._backing.getCodedWidth();
|
||||
}
|
||||
|
||||
getCodedHeight() {
|
||||
get codedHeight() {
|
||||
return this._backing.getCodedHeight();
|
||||
}
|
||||
|
||||
getRotation() {
|
||||
get rotation() {
|
||||
return this._backing.getRotation();
|
||||
}
|
||||
|
||||
async getDisplayWidth() {
|
||||
const rotation = await this._backing.getRotation();
|
||||
get displayWidth() {
|
||||
const rotation = this._backing.getRotation();
|
||||
return rotation % 180 === 0 ? this._backing.getCodedWidth() : this._backing.getCodedHeight();
|
||||
}
|
||||
|
||||
async getDisplayHeight() {
|
||||
const rotation = await this._backing.getRotation();
|
||||
get displayHeight() {
|
||||
const rotation = this._backing.getRotation();
|
||||
return rotation % 180 === 0 ? this._backing.getCodedHeight() : this._backing.getCodedWidth();
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ export class InputVideoTrack extends InputTrack {
|
||||
}
|
||||
|
||||
async getCodecMimeType() {
|
||||
const decoderConfig = await this.getDecoderConfig();
|
||||
const decoderConfig = await this._backing.getDecoderConfig();
|
||||
return decoderConfig?.codec ?? null;
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ export class InputVideoTrack extends InputTrack {
|
||||
return false;
|
||||
}
|
||||
|
||||
const codec = await this.getCodec();
|
||||
const codec = this._backing.getCodec();
|
||||
assert(codec !== null);
|
||||
|
||||
if (customVideoDecoders.some(x => x.supports(codec, decoderConfig))) {
|
||||
@@ -168,9 +168,9 @@ export class InputVideoTrack extends InputTrack {
|
||||
}
|
||||
|
||||
export interface InputAudioTrackBacking extends InputTrackBacking {
|
||||
getCodec(): Promise<AudioCodec | null>;
|
||||
getNumberOfChannels(): Promise<number>;
|
||||
getSampleRate(): Promise<number>;
|
||||
getCodec(): AudioCodec | null;
|
||||
getNumberOfChannels(): number;
|
||||
getSampleRate(): number;
|
||||
getDecoderConfig(): Promise<AudioDecoderConfig | null>;
|
||||
getFirstSample(options: SampleRetrievalOptions): Promise<EncodedAudioSample | null>;
|
||||
getSample(timestamp: number, options: SampleRetrievalOptions): Promise<EncodedAudioSample | null>;
|
||||
@@ -191,19 +191,19 @@ export class InputAudioTrack extends InputTrack {
|
||||
this._backing = backing;
|
||||
}
|
||||
|
||||
getType(): TrackType {
|
||||
get type(): TrackType {
|
||||
return 'audio';
|
||||
}
|
||||
|
||||
getCodec(): Promise<AudioCodec | null> {
|
||||
get codec(): AudioCodec | null {
|
||||
return this._backing.getCodec();
|
||||
}
|
||||
|
||||
getNumberOfChannels() {
|
||||
get numberOfChannels() {
|
||||
return this._backing.getNumberOfChannels();
|
||||
}
|
||||
|
||||
getSampleRate() {
|
||||
get sampleRate() {
|
||||
return this._backing.getSampleRate();
|
||||
}
|
||||
|
||||
@@ -212,7 +212,7 @@ export class InputAudioTrack extends InputTrack {
|
||||
}
|
||||
|
||||
async getCodecMimeType() {
|
||||
const decoderConfig = await this.getDecoderConfig();
|
||||
const decoderConfig = await this._backing.getDecoderConfig();
|
||||
return decoderConfig?.codec ?? null;
|
||||
}
|
||||
|
||||
@@ -223,7 +223,7 @@ export class InputAudioTrack extends InputTrack {
|
||||
return false;
|
||||
}
|
||||
|
||||
const codec = await this.getCodec();
|
||||
const codec = this._backing.getCodec();
|
||||
assert(codec !== null);
|
||||
|
||||
if (customAudioDecoders.some(x => x.supports(codec, decoderConfig))) {
|
||||
|
||||
@@ -1725,28 +1725,28 @@ abstract class IsobmffTrackBacking<
|
||||
return this.internalTrack.id;
|
||||
}
|
||||
|
||||
getCodec(): Promise<MediaCodec | null> {
|
||||
getCodec(): MediaCodec | null {
|
||||
throw new Error('Not implemented on base class.');
|
||||
}
|
||||
|
||||
getLanguageCode() {
|
||||
return this.internalTrack.languageCode;
|
||||
}
|
||||
|
||||
getTimeResolution() {
|
||||
return this.internalTrack.timescale;
|
||||
}
|
||||
|
||||
async computeDuration() {
|
||||
const lastSample = await this.getSample(Infinity, { metadataOnly: true });
|
||||
return (lastSample?.timestamp ?? 0) + (lastSample?.duration ?? 0);
|
||||
}
|
||||
|
||||
async getLanguageCode() {
|
||||
return this.internalTrack.languageCode;
|
||||
}
|
||||
|
||||
async getFirstTimestamp() {
|
||||
const firstSample = await this.getFirstSample({ metadataOnly: true });
|
||||
return firstSample?.timestamp ?? 0;
|
||||
}
|
||||
|
||||
async getTimeResolution() {
|
||||
return this.internalTrack.timescale;
|
||||
}
|
||||
|
||||
abstract createSample(
|
||||
data: Uint8Array,
|
||||
byteLength: number,
|
||||
@@ -2264,19 +2264,19 @@ class IsobmffVideoTrackBacking extends IsobmffTrackBacking<EncodedVideoSample> i
|
||||
this.internalTrack = internalTrack;
|
||||
}
|
||||
|
||||
override async getCodec(): Promise<VideoCodec | null> {
|
||||
override getCodec(): VideoCodec | null {
|
||||
return this.internalTrack.info.codec;
|
||||
}
|
||||
|
||||
async getCodedWidth() {
|
||||
getCodedWidth() {
|
||||
return this.internalTrack.info.width;
|
||||
}
|
||||
|
||||
async getCodedHeight() {
|
||||
getCodedHeight() {
|
||||
return this.internalTrack.info.height;
|
||||
}
|
||||
|
||||
async getRotation() {
|
||||
getRotation() {
|
||||
return this.internalTrack.rotation;
|
||||
}
|
||||
|
||||
@@ -2294,12 +2294,12 @@ class IsobmffVideoTrackBacking extends IsobmffTrackBacking<EncodedVideoSample> i
|
||||
return null;
|
||||
}
|
||||
|
||||
if (this.internalTrack.info.codec === 'vp9' && !this.internalTrack.info.vp9CodecInfo) {
|
||||
const firstSample = await this.getFirstSample({});
|
||||
this.internalTrack.info.vp9CodecInfo = firstSample && extractVp9CodecInfoFromFrame(firstSample.data);
|
||||
}
|
||||
|
||||
return this.decoderConfigPromise ??= (async (): Promise<VideoDecoderConfig> => {
|
||||
if (this.internalTrack.info.codec === 'vp9' && !this.internalTrack.info.vp9CodecInfo) {
|
||||
const firstSample = await this.getFirstSample({});
|
||||
this.internalTrack.info.vp9CodecInfo = firstSample && extractVp9CodecInfoFromFrame(firstSample.data);
|
||||
}
|
||||
|
||||
return {
|
||||
codec: extractVideoCodecString(this.internalTrack.info),
|
||||
codedWidth: this.internalTrack.info.width,
|
||||
@@ -2323,22 +2323,22 @@ class IsobmffVideoTrackBacking extends IsobmffTrackBacking<EncodedVideoSample> i
|
||||
|
||||
class IsobmffAudioTrackBacking extends IsobmffTrackBacking<EncodedAudioSample> implements InputAudioTrackBacking {
|
||||
override internalTrack: InternalAudioTrack;
|
||||
decoderConfigPromise: Promise<AudioDecoderConfig> | null = null;
|
||||
decoderConfig: AudioDecoderConfig | null = null;
|
||||
|
||||
constructor(internalTrack: InternalAudioTrack) {
|
||||
super(internalTrack);
|
||||
this.internalTrack = internalTrack;
|
||||
}
|
||||
|
||||
override async getCodec(): Promise<AudioCodec | null> {
|
||||
override getCodec(): AudioCodec | null {
|
||||
return this.internalTrack.info.codec;
|
||||
}
|
||||
|
||||
async getNumberOfChannels() {
|
||||
getNumberOfChannels() {
|
||||
return this.internalTrack.info.numberOfChannels;
|
||||
}
|
||||
|
||||
async getSampleRate() {
|
||||
getSampleRate() {
|
||||
return this.internalTrack.info.sampleRate;
|
||||
}
|
||||
|
||||
@@ -2347,14 +2347,12 @@ class IsobmffAudioTrackBacking extends IsobmffTrackBacking<EncodedAudioSample> i
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.decoderConfigPromise ??= (async (): Promise<AudioDecoderConfig> => {
|
||||
return {
|
||||
codec: extractAudioCodecString(this.internalTrack.info),
|
||||
numberOfChannels: this.internalTrack.info.numberOfChannels,
|
||||
sampleRate: this.internalTrack.info.sampleRate,
|
||||
description: this.internalTrack.info.codecDescription ?? undefined,
|
||||
};
|
||||
})();
|
||||
return this.decoderConfig ??= {
|
||||
codec: extractAudioCodecString(this.internalTrack.info),
|
||||
numberOfChannels: this.internalTrack.info.numberOfChannels,
|
||||
sampleRate: this.internalTrack.info.sampleRate,
|
||||
description: this.internalTrack.info.codecDescription ?? undefined,
|
||||
};
|
||||
}
|
||||
|
||||
createSample(
|
||||
|
||||
@@ -980,7 +980,7 @@ abstract class MatroskaTrackBacking<
|
||||
return this.internalTrack.id;
|
||||
}
|
||||
|
||||
getCodec(): Promise<MediaCodec | null> {
|
||||
getCodec(): MediaCodec | null {
|
||||
throw new Error('Not implemented on base class.');
|
||||
}
|
||||
|
||||
@@ -989,7 +989,7 @@ abstract class MatroskaTrackBacking<
|
||||
return (lastSample?.timestamp ?? 0) + (lastSample?.duration ?? 0);
|
||||
}
|
||||
|
||||
async getLanguageCode() {
|
||||
getLanguageCode() {
|
||||
return this.internalTrack.languageCode;
|
||||
}
|
||||
|
||||
@@ -998,7 +998,7 @@ abstract class MatroskaTrackBacking<
|
||||
return firstSample?.timestamp ?? 0;
|
||||
}
|
||||
|
||||
async getTimeResolution() {
|
||||
getTimeResolution() {
|
||||
return this.internalTrack.segment.timestampFactor;
|
||||
}
|
||||
|
||||
@@ -1439,19 +1439,19 @@ class MatroskaVideoTrackBacking extends MatroskaTrackBacking<EncodedVideoSample>
|
||||
this.internalTrack = internalTrack;
|
||||
}
|
||||
|
||||
override async getCodec(): Promise<VideoCodec | null> {
|
||||
override getCodec(): VideoCodec | null {
|
||||
return this.internalTrack.info.codec;
|
||||
}
|
||||
|
||||
async getCodedWidth() {
|
||||
getCodedWidth() {
|
||||
return this.internalTrack.info.width;
|
||||
}
|
||||
|
||||
async getCodedHeight() {
|
||||
getCodedHeight() {
|
||||
return this.internalTrack.info.height;
|
||||
}
|
||||
|
||||
async getRotation() {
|
||||
getRotation() {
|
||||
return this.internalTrack.info.rotation;
|
||||
}
|
||||
|
||||
@@ -1513,22 +1513,22 @@ class MatroskaVideoTrackBacking extends MatroskaTrackBacking<EncodedVideoSample>
|
||||
|
||||
class MatroskaAudioTrackBacking extends MatroskaTrackBacking<EncodedAudioSample> implements InputAudioTrackBacking {
|
||||
override internalTrack: InternalAudioTrack;
|
||||
decoderConfigPromise: Promise<AudioDecoderConfig> | null = null;
|
||||
decoderConfig: AudioDecoderConfig | null = null;
|
||||
|
||||
constructor(internalTrack: InternalAudioTrack) {
|
||||
super(internalTrack);
|
||||
this.internalTrack = internalTrack;
|
||||
}
|
||||
|
||||
override async getCodec(): Promise<AudioCodec | null> {
|
||||
override getCodec(): AudioCodec | null {
|
||||
return this.internalTrack.info.codec;
|
||||
}
|
||||
|
||||
async getNumberOfChannels() {
|
||||
getNumberOfChannels() {
|
||||
return this.internalTrack.info.numberOfChannels;
|
||||
}
|
||||
|
||||
async getSampleRate() {
|
||||
getSampleRate() {
|
||||
return this.internalTrack.info.sampleRate;
|
||||
}
|
||||
|
||||
@@ -1537,18 +1537,16 @@ class MatroskaAudioTrackBacking extends MatroskaTrackBacking<EncodedAudioSample>
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.decoderConfigPromise ??= (async (): Promise<AudioDecoderConfig> => {
|
||||
return {
|
||||
codec: extractAudioCodecString({
|
||||
codec: this.internalTrack.info.codec,
|
||||
codecDescription: this.internalTrack.codecPrivate,
|
||||
aacCodecInfo: this.internalTrack.info.aacCodecInfo,
|
||||
}),
|
||||
numberOfChannels: this.internalTrack.info.numberOfChannels,
|
||||
sampleRate: this.internalTrack.info.sampleRate,
|
||||
description: this.internalTrack.codecPrivate ?? undefined,
|
||||
};
|
||||
})();
|
||||
return this.decoderConfig ??= {
|
||||
codec: extractAudioCodecString({
|
||||
codec: this.internalTrack.info.codec,
|
||||
codecDescription: this.internalTrack.codecPrivate,
|
||||
aacCodecInfo: this.internalTrack.info.aacCodecInfo,
|
||||
}),
|
||||
numberOfChannels: this.internalTrack.info.numberOfChannels,
|
||||
sampleRate: this.internalTrack.info.sampleRate,
|
||||
description: this.internalTrack.codecPrivate ?? undefined,
|
||||
};
|
||||
}
|
||||
|
||||
createSample(
|
||||
|
||||
+15
-15
@@ -693,9 +693,9 @@ export class VideoFrameSink extends BaseMediaFrameSink<EncodedVideoSample, Video
|
||||
);
|
||||
}
|
||||
|
||||
const codec = await this._videoTrack.getCodec();
|
||||
const codec = this._videoTrack.codec;
|
||||
const decoderConfig = await this._videoTrack.getDecoderConfig();
|
||||
const timeResolution = await this._videoTrack.getTimeResolution();
|
||||
const timeResolution = this._videoTrack.timeResolution;
|
||||
assert(codec && decoderConfig);
|
||||
|
||||
return new VideoDecoderWrapper(onFrame, onError, codec, decoderConfig, timeResolution);
|
||||
@@ -727,14 +727,14 @@ export class VideoFrameSink extends BaseMediaFrameSink<EncodedVideoSample, Video
|
||||
frames(startTimestamp = 0, endTimestamp = Infinity) {
|
||||
return mapAsyncGenerator(
|
||||
this.mediaFramesInRange(startTimestamp, endTimestamp),
|
||||
async frame => this._wrappedFrameToWrappedVideoFrame(frame),
|
||||
frame => this._wrappedFrameToWrappedVideoFrame(frame),
|
||||
);
|
||||
}
|
||||
|
||||
framesAtTimestamps(timestamps: AnyIterable<number>) {
|
||||
return mapAsyncGenerator(
|
||||
this.mediaFramesAtTimestamps(timestamps),
|
||||
async frame => frame && this._wrappedFrameToWrappedVideoFrame(frame),
|
||||
frame => frame && this._wrappedFrameToWrappedVideoFrame(frame),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -775,10 +775,10 @@ export class CanvasSink {
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
async _videoFrameToWrappedCanvas(frame: WrappedVideoFrame): Promise<WrappedCanvas> {
|
||||
const width = this._dimensions?.width ?? await this._videoTrack.getDisplayWidth();
|
||||
const height = this._dimensions?.height ?? await this._videoTrack.getDisplayHeight();
|
||||
const rotation = await this._videoTrack.getRotation();
|
||||
_videoFrameToWrappedCanvas(frame: WrappedVideoFrame): WrappedCanvas {
|
||||
const width = this._dimensions?.width ?? this._videoTrack.displayWidth;
|
||||
const height = this._dimensions?.height ?? this._videoTrack.displayHeight;
|
||||
const rotation = this._videoTrack.rotation;
|
||||
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = width;
|
||||
@@ -822,7 +822,7 @@ export class CanvasSink {
|
||||
canvasesAtTimestamps(timestamps: AnyIterable<number>) {
|
||||
return mapAsyncGenerator(
|
||||
this._videoFrameSink.framesAtTimestamps(timestamps),
|
||||
async frame => frame && this._videoFrameToWrappedCanvas(frame),
|
||||
frame => frame && this._videoFrameToWrappedCanvas(frame),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1161,14 +1161,14 @@ export class AudioDataSink extends BaseMediaFrameSink<EncodedAudioSample, AudioD
|
||||
);
|
||||
}
|
||||
|
||||
const codec = await this._audioTrack.getCodec();
|
||||
const codec = this._audioTrack.codec;
|
||||
const decoderConfig = await this._audioTrack.getDecoderConfig();
|
||||
assert(codec && decoderConfig);
|
||||
|
||||
if ((PCM_AUDIO_CODECS as readonly string[]).includes(decoderConfig.codec)) {
|
||||
return new PcmAudioDecoderWrapper(onData, onError, decoderConfig);
|
||||
} else {
|
||||
const timeResolution = await this._audioTrack.getTimeResolution();
|
||||
const timeResolution = this._audioTrack.timeResolution;
|
||||
return new AudioDecoderWrapper(onData, onError, codec, decoderConfig, timeResolution);
|
||||
}
|
||||
}
|
||||
@@ -1199,14 +1199,14 @@ export class AudioDataSink extends BaseMediaFrameSink<EncodedAudioSample, AudioD
|
||||
data(startTimestamp = 0, endTimestamp = Infinity) {
|
||||
return mapAsyncGenerator(
|
||||
this.mediaFramesInRange(startTimestamp, endTimestamp),
|
||||
async data => this._wrappedFrameToWrappedAudioData(data),
|
||||
data => this._wrappedFrameToWrappedAudioData(data),
|
||||
);
|
||||
}
|
||||
|
||||
dataAtTimestamps(timestamps: AnyIterable<number>) {
|
||||
return mapAsyncGenerator(
|
||||
this.mediaFramesAtTimestamps(timestamps),
|
||||
async data => data && this._wrappedFrameToWrappedAudioData(data),
|
||||
data => data && this._wrappedFrameToWrappedAudioData(data),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1267,14 +1267,14 @@ export class AudioBufferSink {
|
||||
buffers(startTimestamp = 0, endTimestamp = Infinity) {
|
||||
return mapAsyncGenerator(
|
||||
this._audioDataSink.data(startTimestamp, endTimestamp),
|
||||
async data => this._audioDataToWrappedArrayBuffer(data),
|
||||
data => this._audioDataToWrappedArrayBuffer(data),
|
||||
);
|
||||
}
|
||||
|
||||
buffersAtTimestamps(timestamps: AnyIterable<number>) {
|
||||
return mapAsyncGenerator(
|
||||
this._audioDataSink.dataAtTimestamps(timestamps),
|
||||
async data => data && this._audioDataToWrappedArrayBuffer(data),
|
||||
data => data && this._audioDataToWrappedArrayBuffer(data),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -335,7 +335,7 @@ export const setInt24 = (view: DataView, byteOffset: number, value: number, litt
|
||||
*/
|
||||
export const mapAsyncGenerator = <T, U>(
|
||||
generator: AsyncGenerator<T, void, unknown>,
|
||||
map: (t: T) => Promise<U>,
|
||||
map: (t: T) => U,
|
||||
): AsyncGenerator<U, void, unknown> => {
|
||||
return {
|
||||
async next() {
|
||||
@@ -343,7 +343,7 @@ export const mapAsyncGenerator = <T, U>(
|
||||
if (result.done) {
|
||||
return { value: undefined, done: true };
|
||||
} else {
|
||||
return { value: await map(result.value), done: false };
|
||||
return { value: map(result.value), done: false };
|
||||
}
|
||||
},
|
||||
return() {
|
||||
|
||||
@@ -119,7 +119,7 @@ class Mp3AudioTrackBacking implements InputAudioTrackBacking {
|
||||
return 0;
|
||||
}
|
||||
|
||||
async getTimeResolution() {
|
||||
getTimeResolution() {
|
||||
assert(this.demuxer.firstFrameHeader);
|
||||
return this.demuxer.firstFrameHeader.sampleRate / this.demuxer.firstFrameHeader.audioSamplesInFrame;
|
||||
}
|
||||
@@ -128,20 +128,20 @@ class Mp3AudioTrackBacking implements InputAudioTrackBacking {
|
||||
return this.demuxer.computeDuration();
|
||||
}
|
||||
|
||||
async getLanguageCode() {
|
||||
getLanguageCode() {
|
||||
return UNDETERMINED_LANGUAGE;
|
||||
}
|
||||
|
||||
async getCodec(): Promise<AudioCodec> {
|
||||
getCodec(): AudioCodec {
|
||||
return 'mp3';
|
||||
}
|
||||
|
||||
async getNumberOfChannels() {
|
||||
getNumberOfChannels() {
|
||||
assert(this.demuxer.firstFrameHeader);
|
||||
return this.demuxer.firstFrameHeader.channel === 3 ? 1 : 2;
|
||||
}
|
||||
|
||||
async getSampleRate() {
|
||||
getSampleRate() {
|
||||
assert(this.demuxer.firstFrameHeader);
|
||||
return this.demuxer.firstFrameHeader.sampleRate;
|
||||
}
|
||||
|
||||
@@ -410,19 +410,19 @@ class OggAudioTrackBacking implements InputAudioTrackBacking {
|
||||
return this.bitstream.serialNumber;
|
||||
}
|
||||
|
||||
async getNumberOfChannels() {
|
||||
getNumberOfChannels() {
|
||||
return this.bitstream.numberOfChannels;
|
||||
}
|
||||
|
||||
async getSampleRate() {
|
||||
getSampleRate() {
|
||||
return this.bitstream.sampleRate;
|
||||
}
|
||||
|
||||
async getTimeResolution() {
|
||||
getTimeResolution() {
|
||||
return this.bitstream.sampleRate;
|
||||
}
|
||||
|
||||
async getCodec() {
|
||||
getCodec() {
|
||||
return this.bitstream.codec;
|
||||
}
|
||||
|
||||
@@ -437,7 +437,7 @@ class OggAudioTrackBacking implements InputAudioTrackBacking {
|
||||
};
|
||||
}
|
||||
|
||||
async getLanguageCode() {
|
||||
getLanguageCode() {
|
||||
return UNDETERMINED_LANGUAGE;
|
||||
}
|
||||
|
||||
|
||||
@@ -187,7 +187,7 @@ class WaveAudioTrackBacking implements InputAudioTrackBacking {
|
||||
return 1;
|
||||
}
|
||||
|
||||
async getCodec() {
|
||||
getCodec() {
|
||||
return this.demuxer.getCodec();
|
||||
}
|
||||
|
||||
@@ -209,22 +209,22 @@ class WaveAudioTrackBacking implements InputAudioTrackBacking {
|
||||
return this.demuxer.computeDuration();
|
||||
}
|
||||
|
||||
async getNumberOfChannels() {
|
||||
getNumberOfChannels() {
|
||||
assert(this.demuxer.audioInfo);
|
||||
return this.demuxer.audioInfo.numberOfChannels;
|
||||
}
|
||||
|
||||
async getSampleRate() {
|
||||
getSampleRate() {
|
||||
assert(this.demuxer.audioInfo);
|
||||
return this.demuxer.audioInfo.sampleRate;
|
||||
}
|
||||
|
||||
async getTimeResolution() {
|
||||
getTimeResolution() {
|
||||
assert(this.demuxer.audioInfo);
|
||||
return this.demuxer.audioInfo.sampleRate;
|
||||
}
|
||||
|
||||
async getLanguageCode() {
|
||||
getLanguageCode() {
|
||||
return UNDETERMINED_LANGUAGE;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user