UNPKG

@omnimedia/omnitool

Version:

open source video processing tools

111 lines 3.95 kB
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