@omnimedia/omnitool
Version:
open source video processing tools
111 lines • 3.95 kB
JavaScript
import { is } from "@e280/stz";
import { Comrade, tune } from "@e280/comrade";
import { ALL_FORMATS, Input } from "mediabunny";
import { Machina } from "./parts/machina.js";
import { Compositor } from "./parts/compositor.js";
import { setupDriverHost } from "./fns/host.js";
import { loadDecoderSource } from "./utils/load-decoder-source.js";
export class Driver {
machina;
thread;
compositor;
static async setup(options) {
const machina = new Machina();
const thread = await Comrade.thread({
label: "OmnitoolDriver",
workerUrl: options?.workerUrl ?? "/node_modules/@omnimedia/omnitool/x/driver/driver.worker.bundle.min.js",
setupHost: setupDriverHost(machina),
});
const compositor = await Compositor.setup();
return new this(machina, thread, compositor);
}
constructor(machina, thread, compositor) {
this.machina = machina;
this.thread = thread;
this.compositor = compositor;
}
async hello() {
return this.thread.work.hello();
}
async getAudioDuration(source) {
const input = new Input({
source: await loadDecoderSource(source),
formats: ALL_FORMATS
});
const audioTrack = await input.getPrimaryAudioTrack();
if (!audioTrack)
throw new Error("primary audio track not found");
return await audioTrack.computeDuration();
}
async getVideoDuration(source) {
const input = new Input({
source: await loadDecoderSource(source),
formats: ALL_FORMATS
});
const videoTrack = await input.getPrimaryVideoTrack();
return await videoTrack?.computeDuration();
}
decodeVideo(input) {
let lastFrame = null;
const { port1, port2 } = new MessageChannel();
const videoTransform = new TransformStream({
async transform(chunk, controller) {
const frame = await input.onFrame?.(chunk) ?? chunk;
lastFrame?.close();
controller.enqueue(frame);
lastFrame = frame;
}
});
this.thread.work.decodeVideo[tune]({ transfer: [videoTransform.writable, port2] })({
source: input.source,
cancel: port2,
video: videoTransform.writable,
start: input.start,
end: input.end
});
return {
readable: videoTransform.readable,
/**
* use this to stop decoding (premature interruption)
* */
cancel() {
port1.postMessage("close");
port1.close();
}
};
}
decodeAudio(input) {
const audioTransform = new TransformStream();
const { port1, port2 } = new MessageChannel();
this.thread.work.decodeAudio[tune]({ transfer: [audioTransform.writable, port2] })({
source: input.source,
cancel: port2,
audio: audioTransform.writable,
start: input.start,
end: input.end
});
return {
readable: audioTransform.readable,
/**
* use this to stop decoding (premature interruption)
* */
cancel() {
port1.postMessage("close");
port1.close();
}
};
}
encode({ audio, video, config }) {
const { readable, writable } = new TransformStream();
const transfer = [audio, video, writable].filter(is.happy);
const done = this.thread.work.encode[tune]({ transfer })({ audio, video, config, writable });
return { readable, done };
}
async composite(composition) {
return await this.compositor.composite(composition);
}
resize(width, height) {
this.compositor.resize(width, height);
}
}
//# sourceMappingURL=driver.js.map