UNPKG

@omnimedia/omnitool

Version:

open source video processing tools

97 lines 3.63 kB
import { Comrade, tune } from "@e280/comrade"; import { ALL_FORMATS, Input } from "mediabunny"; import { Machina } from "./parts/machina.js"; import { setupDriverHost } from "./fns/host.js"; import { loadDecoderSource } from "./utils/load-decoder-source.js"; export class Driver { machina; thread; static async setup(options) { const machina = new Machina(); const thread = await Comrade.thread({ label: "OmnitoolDriver", workerUrl: options.workerUrl, setupHost: setupDriverHost(machina), }); return new this(machina, thread); } constructor(machina, thread) { this.machina = machina; this.thread = thread; } 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(); 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(); } decode(input) { let lastFrame = null; const videoTransform = new TransformStream({ async transform(chunk, controller) { const frame = await input.onFrame?.(chunk) ?? chunk; // below code is to prevent mem leaks and hardware accelerated decoder stall lastFrame?.close(); controller.enqueue(frame); lastFrame = frame; } }); const audioTransform = new TransformStream(); this.thread.work.decode[tune]({ transfer: [videoTransform.writable, audioTransform.writable] })({ source: input.source, video: videoTransform.writable, audio: audioTransform.writable, }); return { audio: audioTransform.readable, video: videoTransform.readable }; } async encode({ readables, config }) { const handle = await window.showSaveFilePicker(); const writable = await handle.createWritable(); // making bridge because file picker writable is not transferable const bridge = new WritableStream({ async write(chunk) { await writable.write(chunk); }, async close() { await writable.close(); } }); return await this.thread.work.encode[tune]({ transfer: [readables.audio, readables.video, bridge] })({ readables, config, bridge }); } async composite(composition) { const transfer = this.#collectTransferablesFromComposition(composition); return await this.thread.work.composite[tune]({ transfer })(composition); } #collectTransferablesFromComposition(composition) { const transferables = []; const visit = (node) => { if (Array.isArray(node)) { for (const child of node) visit(child); } else if (node && typeof node === 'object' && 'kind' in node) { if (node.kind === 'image' && node.frame instanceof VideoFrame) transferables.push(node.frame); } }; visit(composition); return transferables; } } //# sourceMappingURL=driver.js.map