diff --git a/web/src/lib/libav/encode.ts b/web/src/lib/libav/encode.ts index a1415796..fd358462 100644 --- a/web/src/lib/libav/encode.ts +++ b/web/src/lib/libav/encode.ts @@ -4,53 +4,31 @@ import * as LibAVWebCodecs from "libavjs-webcodecs-bridge"; import { BufferStream } from "./buffer-stream"; import { BufferStream } from "../buffer-stream"; import WebCodecsWrapper from "./webcodecs"; -import { browser } from "$app/environment"; +import LibAVWrapper from "./instance"; const QUEUE_THRESHOLD_MIN = 16; const QUEUE_THRESHOLD_MAX = 128; -export default class LibAVWrapper { - libav: Promise | null; - webcodecs: WebCodecsWrapper | null; - concurrency: number; - onProgress?: FFmpegProgressCallback; +export default class EncodeLibAV extends LibAVWrapper { + webcodecs: WebCodecsWrapper | null = null; - constructor(onProgress?: FFmpegProgressCallback) { - this.libav = null; - this.webcodecs = null; - this.concurrency = Math.min(4, browser ? navigator.hardwareConcurrency : 0); - this.onProgress = onProgress; + constructor() { + super(LibAV); } - init() { - if (this.concurrency && !this.libav) { - this.libav = LibAV.LibAV({ - yesthreads: true, - base: '/_libav' - }); - - this.webcodecs = new WebCodecsWrapper(this.libav); - } - } - - async terminate() { - if (this.libav) { - const libav = await this.libav; - libav.terminate(); + async init() { + await super.init(); + if (!this.webcodecs) { + this.webcodecs = new WebCodecsWrapper( + super.get().then(({ libav }) => libav) + ); } } async #get() { - if (!this.libav) throw new Error("LibAV wasn't initialized"); - const libav = await this.libav; - - if (!this.webcodecs) { - throw new Error("unreachable"); - } - return { - libav, - webcodecs: this.webcodecs + ...await super.get(), + webcodecs: this.webcodecs! }; } diff --git a/web/src/lib/libav/instance.ts b/web/src/lib/libav/instance.ts new file mode 100644 index 00000000..4327897f --- /dev/null +++ b/web/src/lib/libav/instance.ts @@ -0,0 +1,56 @@ +import mime from "mime"; +import LibAV, { type LibAV as LibAVInstance } from "@imput/libav.js-remux-cli"; +import { browser } from "$app/environment"; + +export default class LibAVWrapper { + #libav__constructor: typeof LibAV; + #libav: Promise | null; + #useThreads: boolean; + concurrency: number; + + constructor(ctor: typeof LibAV, threads = true) { + this.#libav = null; + this.#useThreads = threads; + this.#libav__constructor = ctor; + this.concurrency = Math.min(4, browser ? navigator.hardwareConcurrency : 0); + } + + async init() { + if (!this.#libav) { + this.#libav = this.#libav__constructor.LibAV({ + yesthreads: this.#useThreads, + base: '/_libav' + }); + } + } + + async terminate() { + if (this.#libav) { + const libav = await this.#libav; + libav.terminate(); + } + } + + protected async get() { + if (!this.#libav) throw new Error("LibAV wasn't initialized"); + + return { + libav: await this.#libav + }; + } + + static getExtensionFromType(blob: Blob) { + const extensions = mime.getAllExtensions(blob.type); + const overrides = ['mp3', 'mov']; + + if (!extensions) + return; + + for (const override of overrides) + if (extensions?.has(override)) + return override; + + return [...extensions][0]; + } + +} diff --git a/web/src/lib/libav/remux.ts b/web/src/lib/libav/remux.ts index c3371a5e..3a19b2ed 100644 --- a/web/src/lib/libav/remux.ts +++ b/web/src/lib/libav/remux.ts @@ -1,38 +1,19 @@ import mime from "mime"; -import LibAV, { type LibAV as LibAVInstance } from "@imput/libav.js-remux-cli"; +import LibAV from "@imput/libav.js-remux-cli"; import type { FFmpegProgressCallback, FFmpegProgressEvent, FFmpegProgressStatus, FileInfo, RenderParams } from "../types/libav"; import type { FfprobeData } from "fluent-ffmpeg"; +import LibAVWrapper from "./instance"; -export default class LibAVWrapper { - libav: Promise | null; - concurrency: number; +export default class RemuxLibAV extends LibAVWrapper { onProgress?: FFmpegProgressCallback; constructor(onProgress?: FFmpegProgressCallback) { - this.libav = null; - this.concurrency = Math.min(4, navigator.hardwareConcurrency); + super(LibAV); this.onProgress = onProgress; } - async init() { - if (!this.libav) { - this.libav = LibAV.LibAV({ - yesthreads: true, - base: '/_libav' - }); - } - } - - async #get() { - if (!this.libav) throw new Error("LibAV wasn't initialized"); - - return { - libav: await this.libav - }; - } - async probe(blob: Blob) { - const { libav } = await this.#get(); + const { libav } = await this.get(); const OUT_FILE = 'output.json'; await libav.mkreadaheadfile('input', blob); @@ -69,22 +50,8 @@ export default class LibAVWrapper { return JSON.parse(text) as FfprobeData; } - static getExtensionFromType(blob: Blob) { - const extensions = mime.getAllExtensions(blob.type); - const overrides = ['mp3', 'mov']; - - if (!extensions) - return; - - for (const override of overrides) - if (extensions?.has(override)) - return override; - - return [...extensions][0]; - } - async remux({ blob, output, args }: RenderParams) { - const { libav } = await this.#get(); + const { libav } = await this.get(); const inputKind = blob.type.split("/")[0]; const inputExtension = LibAVWrapper.getExtensionFromType(blob);