web: draft libav functionality
This commit is contained in:
89
web/src/lib/libav.ts
Normal file
89
web/src/lib/libav.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import mime from "mime";
|
||||
import LibAV, { type LibAV as LibAVInstance } from "@imput/libav.js-remux-cli";
|
||||
|
||||
type InputFileKind = "video" | "audio";
|
||||
|
||||
type FileInfo = {
|
||||
type?: string | null,
|
||||
kind: InputFileKind,
|
||||
extension: string,
|
||||
}
|
||||
|
||||
type RenderParams = {
|
||||
file: File,
|
||||
output?: FileInfo,
|
||||
args: string[],
|
||||
}
|
||||
|
||||
export default class LibAVWrapper {
|
||||
libav!: LibAVInstance | null;
|
||||
concurrency: number;
|
||||
|
||||
constructor() {
|
||||
this.concurrency = Math.min(4, navigator.hardwareConcurrency);
|
||||
}
|
||||
|
||||
async init() {
|
||||
if (!this.libav) {
|
||||
this.libav = await LibAV.LibAV({
|
||||
yesthreads: true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async renderFile({ file, output, args }: RenderParams) {
|
||||
if (!this.libav) throw new Error("LibAV wasn't initialized");
|
||||
|
||||
const inputKind = file.type.split("/")[0];
|
||||
const inputExtension = mime.getExtension(file.type);
|
||||
|
||||
if (inputKind !== "video" && inputKind !== "audio") return;
|
||||
if (!inputExtension) return;
|
||||
|
||||
const input: FileInfo = {
|
||||
kind: inputKind,
|
||||
extension: inputExtension,
|
||||
}
|
||||
|
||||
if (!output) output = input;
|
||||
|
||||
output.type = mime.getType(output.extension);
|
||||
if (!output.type) return;
|
||||
|
||||
const outputName = `output.${output.extension}`;
|
||||
|
||||
const buffer = new Blob([await file.arrayBuffer()]);
|
||||
await this.libav.mkreadaheadfile("input", buffer);
|
||||
|
||||
// https://github.com/Yahweasel/libav.js/blob/7d359f69/docs/IO.md#block-writer-devices
|
||||
await this.libav.mkwriterdev(outputName);
|
||||
let writtenData = new Uint8Array(0);
|
||||
|
||||
this.libav.onwrite = (name, pos, data) => {
|
||||
const newLen = Math.max(writtenData.length, pos + data.length);
|
||||
if (newLen > writtenData.length) {
|
||||
const newData = new Uint8Array(newLen);
|
||||
newData.set(writtenData);
|
||||
writtenData = newData;
|
||||
}
|
||||
writtenData.set(data, pos);
|
||||
};
|
||||
|
||||
await this.libav.ffmpeg([
|
||||
'-threads', this.concurrency.toString(),
|
||||
'-i', 'input',
|
||||
...args,
|
||||
outputName
|
||||
]);
|
||||
|
||||
await this.libav.unlinkmkreadaheadfile("input");
|
||||
|
||||
const renderBlob = new Blob(
|
||||
[writtenData],
|
||||
{ type: output.type }
|
||||
);
|
||||
|
||||
if (renderBlob.size === 0) return;
|
||||
return renderBlob;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user