web: draft libav functionality
This commit is contained in:
parent
778eb51502
commit
57054c24b2
2 changed files with 97 additions and 0 deletions
|
@ -100,6 +100,9 @@ importers:
|
||||||
'@imput/ffmpeg.wasm':
|
'@imput/ffmpeg.wasm':
|
||||||
specifier: ^0.12.11
|
specifier: ^0.12.11
|
||||||
version: 0.12.11
|
version: 0.12.11
|
||||||
|
'@imput/libav.js-remux-cli':
|
||||||
|
specifier: ^5.4.6
|
||||||
|
version: 5.4.6
|
||||||
'@imput/version-info':
|
'@imput/version-info':
|
||||||
specifier: workspace:^
|
specifier: workspace:^
|
||||||
version: link:../packages/version-info
|
version: link:../packages/version-info
|
||||||
|
@ -533,6 +536,9 @@ packages:
|
||||||
resolution: {integrity: sha512-/krk6BPy7TdDN73KHj/g0TVNDNLvvtlTv2T8di4GwrbuIcqfv5wCa2iMR2II/Vhf7zFYJvC2m5kDYHTtDQWS5Q==}
|
resolution: {integrity: sha512-/krk6BPy7TdDN73KHj/g0TVNDNLvvtlTv2T8di4GwrbuIcqfv5wCa2iMR2II/Vhf7zFYJvC2m5kDYHTtDQWS5Q==}
|
||||||
engines: {node: '>=18.x'}
|
engines: {node: '>=18.x'}
|
||||||
|
|
||||||
|
'@imput/libav.js-remux-cli@5.4.6':
|
||||||
|
resolution: {integrity: sha512-lO83tppljyCyJAks2cfA0YULnPstAYE/5LQVoFAFu+CSwUcgZqB9OmBNHufMj3GnTXzYE35OORSuYHYZEyiC5w==}
|
||||||
|
|
||||||
'@isaacs/cliui@8.0.2':
|
'@isaacs/cliui@8.0.2':
|
||||||
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
|
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
@ -2496,6 +2502,8 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@imput/ffmpeg-types': 0.12.3
|
'@imput/ffmpeg-types': 0.12.3
|
||||||
|
|
||||||
|
'@imput/libav.js-remux-cli@5.4.6': {}
|
||||||
|
|
||||||
'@isaacs/cliui@8.0.2':
|
'@isaacs/cliui@8.0.2':
|
||||||
dependencies:
|
dependencies:
|
||||||
string-width: 5.1.2
|
string-width: 5.1.2
|
||||||
|
|
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;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue