mirror of
https://github.com/arcodange-org/mediabunny.git
synced 2026-09-27 02:43:48 +02:00
Drain -> Sink
This commit is contained in:
+4
-4
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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),
|
||||
);
|
||||
}
|
||||
@@ -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';
|
||||
|
||||
Reference in New Issue
Block a user