Drain -> Sink

This commit is contained in:
David Payr
2025-01-08 14:26:49 +01:00
parent dc81afa1d9
commit b6b82084d4
7 changed files with 56 additions and 56 deletions
+4 -4
View File
@@ -55,7 +55,7 @@
const audioTrack = await input.getPrimaryAudioTrack();
const videoTrack = await input.getPrimaryVideoTrack();
const drain = new Metamuxer.EncodedAudioSampleDrain(audioTrack);
const sink = new Metamuxer.EncodedAudioSampleSink(audioTrack);
const decoderConfig = await audioTrack.getDecoderConfig();
const sampleSource = new Metamuxer.EncodedAudioSampleSource(await audioTrack.getCodec());
@@ -72,7 +72,7 @@
/*
for await (const sample of drain.samples()) {
for await (const sample of sink.samples()) {
//console.log(sample.timestamp);
//sample.timestamp *= 2;
//console.log(sample);
@@ -80,13 +80,13 @@
await sampleSource.digest(sample, { decoderConfig });
}
*/
for await (const { data, timestamp } of new Metamuxer.AudioDataDrain(audioTrack).data()) {
for await (const { data, timestamp } of new Metamuxer.AudioDataSink(audioTrack).data()) {
//console.log("wow", data.timestamp);
//console.log(sample)
await audioDataSource.digest(data);
}
/*
for await (const sample of new Metamuxer.EncodedVideoSampleDrain(videoTrack).samples()) {
for await (const sample of new Metamuxer.EncodedVideoSampleSink(videoTrack).samples()) {
//console.log(sample)
await videoSampleSource.digest(sample, { decoderConfig: videoDecoderConfig });
}
+4 -4
View File
@@ -68,8 +68,8 @@ durationElement.textContent = formatSeconds(totalDuration);
playerDiv.style.display = 'flex';
const videoDrain = videoTrack && new Metamuxer.CanvasDrain(videoTrack);
const audioDrain = audioTrack && new Metamuxer.AudioBufferDrain(audioTrack);
const videoSink = videoTrack && new Metamuxer.CanvasSink(videoTrack);
const audioSink = audioTrack && new Metamuxer.AudioBufferSink(audioTrack);
let startTime = null;
let playing = false;
@@ -92,7 +92,7 @@ function getPlaybackTime() {
function play() {
audioBufferIterator?.return();
audioBufferIterator = audioDrain?.buffers(getPlaybackTime());
audioBufferIterator = audioSink?.buffers(getPlaybackTime());
startTime = audioContext.currentTime;
playing = true;
runAudioIterator();
@@ -135,7 +135,7 @@ async function seek() {
await videoFrameIterator?.return();
videoFrameIterator = videoDrain.canvases(getPlaybackTime());
videoFrameIterator = videoSink.canvases(getPlaybackTime());
const newCurrentFrame = (await videoFrameIterator.next()).value;
const newNextFrame = (await videoFrameIterator.next()).value;
+9 -9
View File
@@ -71,18 +71,18 @@ export {
} from './sample';
export {
SampleRetrievalOptions,
BaseSampleDrain,
BaseSampleSink,
WrappedMediaFrame,
BaseMediaFrameDrain,
EncodedVideoSampleDrain,
VideoFrameDrain,
EncodedAudioSampleDrain,
CanvasDrain,
BaseMediaFrameSink,
EncodedVideoSampleSink,
VideoFrameSink,
EncodedAudioSampleSink,
CanvasSink,
WrappedCanvas,
AudioDataDrain,
AudioDataSink,
WrappedAudioData,
AudioBufferDrain,
AudioBufferSink,
WrappedAudioBuffer,
} from './media-drain';
} from './media-sink';
// 🐡🦔
+5 -5
View File
@@ -1,5 +1,5 @@
import { AudioCodec, MediaCodec, VideoCodec } from './codec';
import { EncodedAudioSampleDrain, EncodedVideoSampleDrain, SampleRetrievalOptions } from './media-drain';
import { EncodedAudioSampleSink, EncodedVideoSampleSink, SampleRetrievalOptions } from './media-sink';
import { Rotation } from './misc';
import { EncodedAudioSample, EncodedVideoSample } from './sample';
@@ -116,7 +116,7 @@ export class InputVideoTrack extends InputTrack {
}
computeSampleStats() {
return computeSampleStats(new EncodedVideoSampleDrain(this));
return computeSampleStats(new EncodedVideoSampleSink(this));
}
}
@@ -185,7 +185,7 @@ export class InputAudioTrack extends InputTrack {
}
computeSampleStats() {
return computeSampleStats(new EncodedAudioSampleDrain(this));
return computeSampleStats(new EncodedAudioSampleSink(this));
}
}
@@ -196,13 +196,13 @@ export type SampleStats = {
averageBitrate: number;
};
const computeSampleStats = async (drain: EncodedVideoSampleDrain | EncodedAudioSampleDrain): Promise<SampleStats> => {
const computeSampleStats = async (sink: EncodedVideoSampleSink | EncodedAudioSampleSink): Promise<SampleStats> => {
let startTimestamp = Infinity;
let endTimestamp = -Infinity;
let sampleCount = 0;
let totalSampleBytes = 0;
for await (const sample of drain.samples(undefined, undefined, { metadataOnly: true })) {
for await (const sample of sink.samples(undefined, undefined, { metadataOnly: true })) {
startTimestamp = Math.min(startTimestamp, sample.timestamp);
endTimestamp = Math.max(endTimestamp, sample.timestamp + sample.duration);
+1 -1
View File
@@ -20,7 +20,7 @@ import {
InputVideoTrack,
InputVideoTrackBacking,
} from '../input-track';
import { SampleRetrievalOptions } from '../media-drain';
import { SampleRetrievalOptions } from '../media-sink';
import {
assert,
COLOR_PRIMARIES_MAP_INVERSE,
+32 -32
View File
@@ -35,7 +35,7 @@ const validateTimestamp = (timestamp: number) => {
};
/** @public */
export abstract class BaseSampleDrain<Sample extends EncodedVideoSample | EncodedAudioSample> {
export abstract class BaseSampleSink<Sample extends EncodedVideoSample | EncodedAudioSample> {
abstract getFirstSample(options?: SampleRetrievalOptions): Promise<Sample | null>;
abstract getSample(timestamp: number, options?: SampleRetrievalOptions): Promise<Sample | null>;
abstract getNextSample(sample: Sample, options?: SampleRetrievalOptions): Promise<Sample | null>;
@@ -162,7 +162,7 @@ abstract class DecoderWrapper<
}
/** @public */
export abstract class BaseMediaFrameDrain<
export abstract class BaseMediaFrameSink<
Sample extends EncodedVideoSample | EncodedAudioSample,
MediaFrame extends VideoFrame | AudioData,
WrappedFrame extends WrappedMediaFrame<MediaFrame> = WrappedMediaFrame<MediaFrame>,
@@ -173,7 +173,7 @@ export abstract class BaseMediaFrameDrain<
onError: (error: DOMException) => unknown
): Promise<DecoderWrapper<Sample, MediaFrame>>;
/** @internal */
abstract _createSampleDrain(): BaseSampleDrain<Sample>;
abstract _createSampleSink(): BaseSampleSink<Sample>;
/** @internal */
private _duplicateFrame(frame: WrappedFrame) {
@@ -248,8 +248,8 @@ export abstract class BaseMediaFrameDrain<
}
});
const sampleDrain = this._createSampleDrain();
const keySample = await sampleDrain.getKeySample(startTimestamp) ?? await sampleDrain.getFirstSample();
const sampleSink = this._createSampleSink();
const keySample = await sampleSink.getKeySample(startTimestamp) ?? await sampleSink.getFirstSample();
if (!keySample) {
return;
}
@@ -262,19 +262,19 @@ export abstract class BaseMediaFrameDrain<
// frames (B-frames). Instead, we'll need to keep decoding samples until we get a frame that exceeds
// this end time. However, we can still put a bound on it: Since key frames are by definition never
// out of order, we can stop at the first key frame after the end timestamp.
const endSample = await sampleDrain.getSample(endTimestamp);
const endSample = await sampleSink.getSample(endTimestamp);
const endKeySample = !endSample
? null
: endSample.type === 'key' && endSample.timestamp === endTimestamp
? endSample
: await sampleDrain.getNextKeySample(endSample);
: await sampleSink.getNextKeySample(endSample);
if (endKeySample) {
samplesEndTimestamp = endKeySample.timestamp;
}
}
const samples = sampleDrain.samples(keySample, samplesEndTimestamp);
const samples = sampleSink.samples(keySample, samplesEndTimestamp);
await samples.next(); // Skip the start sample as we already have it
while (currentSample && !ended) {
@@ -409,7 +409,7 @@ export abstract class BaseMediaFrameDrain<
}
});
const sampleDrain = this._createSampleDrain();
const sampleSink = this._createSampleSink();
let lastKeySample: Sample | null = null;
let lastSample: Sample | null = null;
@@ -425,13 +425,13 @@ export abstract class BaseMediaFrameDrain<
break;
}
const targetSample = await sampleDrain.getSample(timestamp);
const targetSample = await sampleSink.getSample(timestamp);
if (!targetSample) {
pushToQueue(null);
continue;
}
const keySample = await sampleDrain.getKeySample(timestamp);
const keySample = await sampleSink.getKeySample(timestamp);
if (!keySample) {
pushToQueue(null);
continue;
@@ -461,7 +461,7 @@ export abstract class BaseMediaFrameDrain<
}
while (lastSample.timestamp !== targetSample.timestamp) {
const nextSample = await sampleDrain.getNextSample(lastSample);
const nextSample = await sampleSink.getNextSample(lastSample);
assert(nextSample);
lastSample = nextSample;
@@ -523,7 +523,7 @@ export abstract class BaseMediaFrameDrain<
}
/** @public */
export class EncodedVideoSampleDrain extends BaseSampleDrain<EncodedVideoSample> {
export class EncodedVideoSampleSink extends BaseSampleSink<EncodedVideoSample> {
/** @internal */
_videoTrack: InputVideoTrack;
@@ -620,7 +620,7 @@ class VideoDecoderWrapper extends DecoderWrapper<EncodedVideoSample, VideoFrame>
}
/** @public */
export class VideoFrameDrain extends BaseMediaFrameDrain<EncodedVideoSample, VideoFrame> {
export class VideoFrameSink extends BaseMediaFrameSink<EncodedVideoSample, VideoFrame> {
/** @internal */
_videoTrack: InputVideoTrack;
@@ -653,8 +653,8 @@ export class VideoFrameDrain extends BaseMediaFrameDrain<EncodedVideoSample, Vid
}
/** @internal */
_createSampleDrain() {
return new EncodedVideoSampleDrain(this._videoTrack);
_createSampleSink() {
return new EncodedVideoSampleSink(this._videoTrack);
}
async getFrame(timestamp: number) {
@@ -683,13 +683,13 @@ export type WrappedCanvas = {
};
/** @public */
export class CanvasDrain {
export class CanvasSink {
/** @internal */
_videoTrack: InputVideoTrack;
/** @internal */
_dimensions?: { width: number; height: number };
/** @internal */
_videoFrameDrain: VideoFrameDrain;
_videoFrameSink: VideoFrameSink;
constructor(videoTrack: InputVideoTrack, dimensions?: { width: number; height: number }) {
if (!(videoTrack instanceof InputVideoTrack)) {
@@ -707,7 +707,7 @@ export class CanvasDrain {
this._videoTrack = videoTrack;
this._dimensions = dimensions;
this._videoFrameDrain = new VideoFrameDrain(videoTrack);
this._videoFrameSink = new VideoFrameSink(videoTrack);
}
/** @internal */
@@ -746,27 +746,27 @@ export class CanvasDrain {
async getCanvas(timestamp: number) {
validateTimestamp(timestamp);
const frame = await this._videoFrameDrain.getFrame(timestamp);
const frame = await this._videoFrameSink.getFrame(timestamp);
return frame && this._videoFrameToWrappedCanvas(frame);
}
canvases(startTimestamp = 0, endTimestamp = Infinity) {
return mapAsyncGenerator(
this._videoFrameDrain.frames(startTimestamp, endTimestamp),
this._videoFrameSink.frames(startTimestamp, endTimestamp),
frame => this._videoFrameToWrappedCanvas(frame),
);
}
canvasesAtTimestamps(timestamps: AnyIterable<number>) {
return mapAsyncGenerator(
this._videoFrameDrain.framesAtTimestamps(timestamps),
this._videoFrameSink.framesAtTimestamps(timestamps),
async frame => frame && this._videoFrameToWrappedCanvas(frame),
);
}
}
/** @public */
export class EncodedAudioSampleDrain extends BaseSampleDrain<EncodedAudioSample> {
export class EncodedAudioSampleSink extends BaseSampleSink<EncodedAudioSample> {
/** @internal */
_audioTrack: InputAudioTrack;
@@ -1023,7 +1023,7 @@ export type WrappedAudioData = {
};
/** @public */
export class AudioDataDrain extends BaseMediaFrameDrain<EncodedAudioSample, AudioData> {
export class AudioDataSink extends BaseMediaFrameSink<EncodedAudioSample, AudioData> {
/** @internal */
_audioTrack: InputAudioTrack;
@@ -1069,8 +1069,8 @@ export class AudioDataDrain extends BaseMediaFrameDrain<EncodedAudioSample, Audi
}
/** @internal */
_createSampleDrain() {
return new EncodedAudioSampleDrain(this._audioTrack);
_createSampleSink() {
return new EncodedAudioSampleSink(this._audioTrack);
}
async getData(timestamp: number) {
@@ -1105,16 +1105,16 @@ export type WrappedAudioBuffer = {
};
/** @public */
export class AudioBufferDrain {
export class AudioBufferSink {
/** @internal */
_audioDataDrain: AudioDataDrain;
_audioDataSink: AudioDataSink;
constructor(audioTrack: InputAudioTrack) {
if (!(audioTrack instanceof InputAudioTrack)) {
throw new TypeError('audioTrack must be an InputAudioTrack.');
}
this._audioDataDrain = new AudioDataDrain(audioTrack);
this._audioDataSink = new AudioDataSink(audioTrack);
}
/** @internal */
@@ -1146,20 +1146,20 @@ export class AudioBufferDrain {
async getBuffer(timestamp: number) {
validateTimestamp(timestamp);
const data = await this._audioDataDrain.getData(timestamp);
const data = await this._audioDataSink.getData(timestamp);
return data && this._audioDataToWrappedArrayBuffer(data);
}
buffers(startTimestamp = 0, endTimestamp = Infinity) {
return mapAsyncGenerator(
this._audioDataDrain.data(startTimestamp, endTimestamp),
this._audioDataSink.data(startTimestamp, endTimestamp),
async data => this._audioDataToWrappedArrayBuffer(data),
);
}
buffersAtTimestamps(timestamps: AnyIterable<number>) {
return mapAsyncGenerator(
this._audioDataDrain.dataAtTimestamps(timestamps),
this._audioDataSink.dataAtTimestamps(timestamps),
async data => data && this._audioDataToWrappedArrayBuffer(data),
);
}
+1 -1
View File
@@ -2,7 +2,7 @@ import { AudioCodec } from '../codec';
import { Demuxer } from '../demuxer';
import { Input } from '../input';
import { InputAudioTrack, InputAudioTrackBacking } from '../input-track';
import { SampleRetrievalOptions } from '../media-drain';
import { SampleRetrievalOptions } from '../media-sink';
import { assert } from '../misc';
import { Reader } from '../reader';
import { EncodedAudioSample, PLACEHOLDER_DATA } from '../sample';