web/libav/wrapper: make sure libav is initialized only once

This commit is contained in:
dumbmoron 2024-08-13 14:42:32 +00:00
parent 72545ffb5d
commit 4636f7b0d4
No known key found for this signature in database

View file

@ -3,7 +3,7 @@ import LibAV, { type LibAV as LibAVInstance } from "@imput/libav.js-remux-cli";
import type { FFmpegProgressCallback, FFmpegProgressEvent, FFmpegProgressStatus, FileInfo, RenderParams } from "./types/libav"; import type { FFmpegProgressCallback, FFmpegProgressEvent, FFmpegProgressStatus, FileInfo, RenderParams } from "./types/libav";
export default class LibAVWrapper { export default class LibAVWrapper {
libav: LibAVInstance | null; libav: Promise<LibAVInstance> | null;
concurrency: number; concurrency: number;
onProgress?: FFmpegProgressCallback; onProgress?: FFmpegProgressCallback;
@ -15,7 +15,7 @@ export default class LibAVWrapper {
async init() { async init() {
if (!this.libav) { if (!this.libav) {
this.libav = await LibAV.LibAV({ this.libav = LibAV.LibAV({
yesthreads: true, yesthreads: true,
base: '/_libav' base: '/_libav'
}); });
@ -24,7 +24,7 @@ export default class LibAVWrapper {
async render({ blob, output, args }: RenderParams) { async render({ blob, output, args }: RenderParams) {
if (!this.libav) throw new Error("LibAV wasn't initialized"); if (!this.libav) throw new Error("LibAV wasn't initialized");
const libav = await this.libav;
const inputKind = blob.type.split("/")[0]; const inputKind = blob.type.split("/")[0];
const inputExtension = mime.getExtension(blob.type); const inputExtension = mime.getExtension(blob.type);
@ -43,19 +43,23 @@ export default class LibAVWrapper {
const outputName = `output.${output.extension}`; const outputName = `output.${output.extension}`;
await this.libav.mkreadaheadfile("input", blob); await libav.mkreadaheadfile("input", blob);
// https://github.com/Yahweasel/libav.js/blob/7d359f69/docs/IO.md#block-writer-devices // https://github.com/Yahweasel/libav.js/blob/7d359f69/docs/IO.md#block-writer-devices
await this.libav.mkwriterdev(outputName); await libav.mkwriterdev(outputName);
await this.libav.mkwriterdev('progress.txt'); await libav.mkwriterdev('progress.txt');
// since we expect the output file to be roughly the same size // since we expect the output file to be roughly the same size
// as the original, preallocate its size for the output // as the original, preallocate its size for the output
let writtenData = new Uint8Array(blob.size), actualSize = 0; let writtenData = new Uint8Array(blob.size), actualSize = 0;
this.libav.onwrite = (name, pos, data) => { libav.onwrite = (name, pos, data) => {
if (name === 'progress.txt') { if (name === 'progress.txt') {
return this.#emitProgress(data); try {
return this.#emitProgress(data);
} catch(e) {
console.error(e);
}
} else if (name !== outputName) return; } else if (name !== outputName) return;
actualSize = Math.max(pos + data.length, actualSize); actualSize = Math.max(pos + data.length, actualSize);
@ -68,7 +72,7 @@ export default class LibAVWrapper {
writtenData.set(data, pos); writtenData.set(data, pos);
}; };
await this.libav.ffmpeg([ await libav.ffmpeg([
'-nostdin', '-y', '-nostdin', '-y',
'-loglevel', 'error', '-loglevel', 'error',
'-progress', 'progress.txt', '-progress', 'progress.txt',
@ -78,9 +82,9 @@ export default class LibAVWrapper {
outputName outputName
]); ]);
await this.libav.unlink(outputName); await libav.unlink(outputName);
await this.libav.unlink('progress.txt'); await libav.unlink('progress.txt');
await this.libav.unlinkreadaheadfile("input"); await libav.unlinkreadaheadfile("input");
// if we didn't need as much space as we allocated for some reason, // if we didn't need as much space as we allocated for some reason,
// shrink the buffer so that we don't inflate the file with zeros // shrink the buffer so that we don't inflate the file with zeros
@ -98,6 +102,8 @@ export default class LibAVWrapper {
} }
#emitProgress(data: Uint8Array | Int8Array) { #emitProgress(data: Uint8Array | Int8Array) {
if (!this.onProgress) return;
const copy = new Uint8Array(data); const copy = new Uint8Array(data);
const text = new TextDecoder().decode(copy); const text = new TextDecoder().decode(copy);
const entries = Object.fromEntries( const entries = Object.fromEntries(