add hardware encoding to ffmpeg, binary choice
This commit is contained in:
parent
8c3f2db3b2
commit
e580b8fd76
6 changed files with 298 additions and 38 deletions
|
@ -1,10 +1,33 @@
|
||||||
import type {RequestHandler as Middleware, NextFunction} from "express";
|
import type {RequestHandler as Middleware, NextFunction} from "express";
|
||||||
|
|
||||||
import ffmpeg from "fluent-ffmpeg";
|
import ffmpeg from 'fluent-ffmpeg';
|
||||||
import ffmpegpath from "@ffmpeg-installer/ffmpeg";
|
import ffmpegInstaller from '@ffmpeg-installer/ffmpeg';
|
||||||
import ffprobepath from "@ffprobe-installer/ffprobe";
|
import ffprobeInstaller from '@ffprobe-installer/ffprobe';
|
||||||
ffmpeg.setFfmpegPath(ffmpegpath.path);
|
import which from 'which';
|
||||||
ffmpeg.setFfprobePath(ffprobepath.path);
|
|
||||||
|
//weird error that occurs where if I use the alias 'process', node cannot access it
|
||||||
|
import Process from 'node:process';
|
||||||
|
|
||||||
|
const getExecutablePath = (envVar: string, executable: string, installer: { path: string }) => {
|
||||||
|
if (Process.env[envVar]) {
|
||||||
|
return Process.env[envVar];
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return which.sync(executable);
|
||||||
|
} catch (error) {
|
||||||
|
return installer.path;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const ffmpegPath = getExecutablePath('EB_FFMPEG_PATH', 'ffmpeg', ffmpegInstaller);
|
||||||
|
const ffprobePath = getExecutablePath('EB_FFPROBE_PATH', 'ffprobe', ffprobeInstaller);
|
||||||
|
|
||||||
|
console.log(`Using ffmpeg from path: ${ffmpegPath}`);
|
||||||
|
console.log(`Using ffprobe from path: ${ffprobePath}`);
|
||||||
|
|
||||||
|
ffmpeg.setFfmpegPath(ffmpegPath!);
|
||||||
|
ffmpeg.setFfprobePath(ffprobePath!);
|
||||||
|
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import process from "process";
|
import process from "process";
|
||||||
|
@ -12,6 +35,20 @@ import process from "process";
|
||||||
import {extension, videoExtensions, imageExtensions} from "./lib";
|
import {extension, videoExtensions, imageExtensions} from "./lib";
|
||||||
import {db, MediaParams, insertToDB} from "./db";
|
import {db, MediaParams, insertToDB} from "./db";
|
||||||
|
|
||||||
|
enum EncodingType {
|
||||||
|
CPU = 'libx264',
|
||||||
|
NVIDIA = 'h264_nvenc',
|
||||||
|
AMD = 'h264_vmf',
|
||||||
|
INTEL = 'h264_qsv',
|
||||||
|
APPLE = 'h264_videotoolbox'
|
||||||
|
}
|
||||||
|
|
||||||
|
let currentEncoding: EncodingType = EncodingType.CPU;
|
||||||
|
|
||||||
|
export const setEncodingType = (type: EncodingType) => {
|
||||||
|
currentEncoding = type;
|
||||||
|
};
|
||||||
|
|
||||||
export const checkAuth: Middleware = (req, res, next) => {
|
export const checkAuth: Middleware = (req, res, next) => {
|
||||||
if (!req.user) {
|
if (!req.user) {
|
||||||
return res.status(401);
|
return res.status(401);
|
||||||
|
@ -73,11 +110,12 @@ export const convert: Middleware = (req, res, next) => {
|
||||||
|
|
||||||
if (videoExtensions.includes(nameAndExtension[1])) {
|
if (videoExtensions.includes(nameAndExtension[1])) {
|
||||||
console.log("Converting " + nameAndExtension[0] + nameAndExtension[1] + " to gif");
|
console.log("Converting " + nameAndExtension[0] + nameAndExtension[1] + " to gif");
|
||||||
|
console.log(`Using ${currentEncoding} as encoder`);
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
ffmpeg()
|
ffmpeg()
|
||||||
.input(`uploads/${nameAndExtension[0]}${nameAndExtension[1]}`)
|
.input(`uploads/${nameAndExtension[0]}${nameAndExtension[1]}`)
|
||||||
.inputFormat(nameAndExtension[1].substring(1))
|
.inputFormat(nameAndExtension[1].substring(1))
|
||||||
|
.outputOptions(`-c:v ${currentEncoding}`)
|
||||||
.outputFormat("gif")
|
.outputFormat("gif")
|
||||||
.output(`uploads/${nameAndExtension[0]}.gif`)
|
.output(`uploads/${nameAndExtension[0]}.gif`)
|
||||||
.on("end", function() {
|
.on("end", function() {
|
||||||
|
@ -88,6 +126,7 @@ export const convert: Middleware = (req, res, next) => {
|
||||||
.run();
|
.run();
|
||||||
} else if (nameAndExtension[1] == ".gif") {
|
} else if (nameAndExtension[1] == ".gif") {
|
||||||
console.log(`Converting ${nameAndExtension[0]}${nameAndExtension[1]} to mp4`);
|
console.log(`Converting ${nameAndExtension[0]}${nameAndExtension[1]} to mp4`);
|
||||||
|
console.log(`Using ${currentEncoding} as encoder`);
|
||||||
|
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
ffmpeg(`uploads/${nameAndExtension[0]}${nameAndExtension[1]}`)
|
ffmpeg(`uploads/${nameAndExtension[0]}${nameAndExtension[1]}`)
|
||||||
|
@ -95,7 +134,7 @@ export const convert: Middleware = (req, res, next) => {
|
||||||
.outputFormat("mp4")
|
.outputFormat("mp4")
|
||||||
.outputOptions([
|
.outputOptions([
|
||||||
"-pix_fmt yuv420p",
|
"-pix_fmt yuv420p",
|
||||||
"-c:v libx264",
|
`-c:v ${currentEncoding}`,
|
||||||
"-movflags +faststart"
|
"-movflags +faststart"
|
||||||
])
|
])
|
||||||
.noAudio()
|
.noAudio()
|
||||||
|
@ -128,17 +167,20 @@ export const convertTo720p: Middleware = (req, res, next) => {
|
||||||
|
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
|
|
||||||
|
const outputOptions = [
|
||||||
|
'-vf', 'scale=-2:720',
|
||||||
|
'-c:v', currentEncoding,
|
||||||
|
];
|
||||||
|
|
||||||
ffmpeg()
|
ffmpeg()
|
||||||
.input(`uploads/${nameAndExtension[0]}${nameAndExtension[1]}`)
|
.input(`uploads/${nameAndExtension[0]}${nameAndExtension[1]}`)
|
||||||
.inputFormat(nameAndExtension[1].substring(1))
|
.inputFormat('mp4')
|
||||||
.outputOptions("-vf", "scale=-2:720")
|
.outputOptions(outputOptions)
|
||||||
.output(`uploads/720p-${nameAndExtension[0]}${nameAndExtension[1]}`)
|
.output(`uploads/720p-${nameAndExtension[0]}${nameAndExtension[1]}`)
|
||||||
.on("end", function() {
|
.on('end', () => {
|
||||||
console.log(`720p copy complete, took ${Date.now() - startTime} to complete`);
|
console.log(`720p copy complete using ${currentEncoding}, took ${Date.now() - startTime}ms to complete`);
|
||||||
console.log(`Uploaded to uploads/720p-${nameAndExtension[0]}${nameAndExtension[1]}`);
|
|
||||||
next();
|
|
||||||
})
|
})
|
||||||
.on("error", (e) => console.log(e))
|
.on('error', (e) => console.log(e))
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
139
package-lock.json
generated
139
package-lock.json
generated
|
@ -25,7 +25,8 @@
|
||||||
"passport": "^0.6.0",
|
"passport": "^0.6.0",
|
||||||
"passport-local": "^1.0.0",
|
"passport-local": "^1.0.0",
|
||||||
"probe-image-size": "^7.2.3",
|
"probe-image-size": "^7.2.3",
|
||||||
"sqlite3": "^5.0.2"
|
"sqlite3": "^5.0.2",
|
||||||
|
"which": "^4.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/connect-sqlite3": "^0.9.1",
|
"@types/connect-sqlite3": "^0.9.1",
|
||||||
|
@ -36,10 +37,11 @@
|
||||||
"@types/fluent-ffmpeg": "^2.1.20",
|
"@types/fluent-ffmpeg": "^2.1.20",
|
||||||
"@types/mkdirp": "^1.0.2",
|
"@types/mkdirp": "^1.0.2",
|
||||||
"@types/multer": "^1.4.7",
|
"@types/multer": "^1.4.7",
|
||||||
"@types/node": "^18.11.10",
|
"@types/node": "^18.18.7",
|
||||||
"@types/passport": "^1.0.11",
|
"@types/passport": "^1.0.11",
|
||||||
"@types/passport-local": "^1.0.34",
|
"@types/passport-local": "^1.0.34",
|
||||||
"@types/probe-image-size": "^7.2.0",
|
"@types/probe-image-size": "^7.2.0",
|
||||||
|
"@types/which": "^3.0.1",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.46.1",
|
"@typescript-eslint/eslint-plugin": "^5.46.1",
|
||||||
"@typescript-eslint/parser": "^5.46.1",
|
"@typescript-eslint/parser": "^5.46.1",
|
||||||
"copyfiles": "^2.4.1",
|
"copyfiles": "^2.4.1",
|
||||||
|
@ -668,10 +670,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "18.11.10",
|
"version": "18.18.7",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.10.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.7.tgz",
|
||||||
"integrity": "sha512-juG3RWMBOqcOuXC643OAdSA525V44cVgGV6dUDuiFtss+8Fk5x1hI93Rsld43VeJVIeqlP9I7Fn9/qaVqoEAuQ==",
|
"integrity": "sha512-bw+lEsxis6eqJYW8Ql6+yTqkE6RuFtsQPSe5JxXbqYRFQEER5aJA9a5UH9igqDWm3X4iLHIKOHlnAXLM4mi7uQ==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"undici-types": "~5.26.4"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/passport": {
|
"node_modules/@types/passport": {
|
||||||
"version": "1.0.11",
|
"version": "1.0.11",
|
||||||
|
@ -753,6 +758,12 @@
|
||||||
"integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==",
|
"integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/which": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/which/-/which-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-OJWjr4k8gS1HXuOnCmQbBrQez+xqt/zqfp5PhgbKtsmEFEuojAg23arr+TiTZZ1TORdUF9RKXb/WKEpT1dwgSg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||||
"version": "5.46.1",
|
"version": "5.46.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.46.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.46.1.tgz",
|
||||||
|
@ -1744,6 +1755,21 @@
|
||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/cross-spawn/node_modules/which": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"isexe": "^2.0.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"node-which": "bin/node-which"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/debug": {
|
"node_modules/debug": {
|
||||||
"version": "2.6.9",
|
"version": "2.6.9",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||||
|
@ -3485,6 +3511,21 @@
|
||||||
"node": "^12.13.0 || ^14.15.0 || >=16.0.0"
|
"node": "^12.13.0 || ^14.15.0 || >=16.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/node-gyp/node_modules/which": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"isexe": "^2.0.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"node-which": "bin/node-which"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/noms": {
|
"node_modules/noms": {
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/noms/-/noms-0.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/noms/-/noms-0.0.0.tgz",
|
||||||
|
@ -4749,6 +4790,12 @@
|
||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/undici-types": {
|
||||||
|
"version": "5.26.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
||||||
|
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/unique-filename": {
|
"node_modules/unique-filename": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz",
|
||||||
|
@ -4835,18 +4882,25 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/which": {
|
"node_modules/which": {
|
||||||
"version": "2.0.2",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz",
|
||||||
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
"integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==",
|
||||||
"devOptional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"isexe": "^2.0.0"
|
"isexe": "^3.1.1"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"node-which": "bin/node-which"
|
"node-which": "bin/which.js"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 8"
|
"node": "^16.13.0 || >=18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/which/node_modules/isexe": {
|
||||||
|
"version": "3.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz",
|
||||||
|
"integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/wide-align": {
|
"node_modules/wide-align": {
|
||||||
|
@ -5416,10 +5470,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/node": {
|
"@types/node": {
|
||||||
"version": "18.11.10",
|
"version": "18.18.7",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.10.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.7.tgz",
|
||||||
"integrity": "sha512-juG3RWMBOqcOuXC643OAdSA525V44cVgGV6dUDuiFtss+8Fk5x1hI93Rsld43VeJVIeqlP9I7Fn9/qaVqoEAuQ==",
|
"integrity": "sha512-bw+lEsxis6eqJYW8Ql6+yTqkE6RuFtsQPSe5JxXbqYRFQEER5aJA9a5UH9igqDWm3X4iLHIKOHlnAXLM4mi7uQ==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"undici-types": "~5.26.4"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"@types/passport": {
|
"@types/passport": {
|
||||||
"version": "1.0.11",
|
"version": "1.0.11",
|
||||||
|
@ -5501,6 +5558,12 @@
|
||||||
"integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==",
|
"integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@types/which": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/which/-/which-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-OJWjr4k8gS1HXuOnCmQbBrQez+xqt/zqfp5PhgbKtsmEFEuojAg23arr+TiTZZ1TORdUF9RKXb/WKEpT1dwgSg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"@typescript-eslint/eslint-plugin": {
|
"@typescript-eslint/eslint-plugin": {
|
||||||
"version": "5.46.1",
|
"version": "5.46.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.46.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.46.1.tgz",
|
||||||
|
@ -6213,6 +6276,17 @@
|
||||||
"path-key": "^3.1.0",
|
"path-key": "^3.1.0",
|
||||||
"shebang-command": "^2.0.0",
|
"shebang-command": "^2.0.0",
|
||||||
"which": "^2.0.1"
|
"which": "^2.0.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"which": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"isexe": "^2.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"debug": {
|
"debug": {
|
||||||
|
@ -7529,6 +7603,15 @@
|
||||||
"gauge": "^4.0.3",
|
"gauge": "^4.0.3",
|
||||||
"set-blocking": "^2.0.0"
|
"set-blocking": "^2.0.0"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"which": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
||||||
|
"optional": true,
|
||||||
|
"requires": {
|
||||||
|
"isexe": "^2.0.0"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -8443,6 +8526,12 @@
|
||||||
"random-bytes": "~1.0.0"
|
"random-bytes": "~1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"undici-types": {
|
||||||
|
"version": "5.26.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
||||||
|
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"unique-filename": {
|
"unique-filename": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz",
|
||||||
|
@ -8517,12 +8606,18 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"which": {
|
"which": {
|
||||||
"version": "2.0.2",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz",
|
||||||
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
"integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==",
|
||||||
"devOptional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"isexe": "^2.0.0"
|
"isexe": "^3.1.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"isexe": {
|
||||||
|
"version": "3.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz",
|
||||||
|
"integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ=="
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"wide-align": {
|
"wide-align": {
|
||||||
|
|
|
@ -44,7 +44,8 @@
|
||||||
"passport": "^0.6.0",
|
"passport": "^0.6.0",
|
||||||
"passport-local": "^1.0.0",
|
"passport-local": "^1.0.0",
|
||||||
"probe-image-size": "^7.2.3",
|
"probe-image-size": "^7.2.3",
|
||||||
"sqlite3": "^5.0.2"
|
"sqlite3": "^5.0.2",
|
||||||
|
"which": "^4.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/connect-sqlite3": "^0.9.1",
|
"@types/connect-sqlite3": "^0.9.1",
|
||||||
|
@ -55,10 +56,11 @@
|
||||||
"@types/fluent-ffmpeg": "^2.1.20",
|
"@types/fluent-ffmpeg": "^2.1.20",
|
||||||
"@types/mkdirp": "^1.0.2",
|
"@types/mkdirp": "^1.0.2",
|
||||||
"@types/multer": "^1.4.7",
|
"@types/multer": "^1.4.7",
|
||||||
"@types/node": "^18.11.10",
|
"@types/node": "^18.18.7",
|
||||||
"@types/passport": "^1.0.11",
|
"@types/passport": "^1.0.11",
|
||||||
"@types/passport-local": "^1.0.34",
|
"@types/passport-local": "^1.0.34",
|
||||||
"@types/probe-image-size": "^7.2.0",
|
"@types/probe-image-size": "^7.2.0",
|
||||||
|
"@types/which": "^3.0.1",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.46.1",
|
"@typescript-eslint/eslint-plugin": "^5.46.1",
|
||||||
"@typescript-eslint/parser": "^5.46.1",
|
"@typescript-eslint/parser": "^5.46.1",
|
||||||
"copyfiles": "^2.4.1",
|
"copyfiles": "^2.4.1",
|
||||||
|
|
65
tests/ffmpeg.ts
Normal file
65
tests/ffmpeg.ts
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
import ffmpeg from 'fluent-ffmpeg';
|
||||||
|
import ffmpegInstaller from '@ffmpeg-installer/ffmpeg';
|
||||||
|
import ffprobeInstaller from '@ffprobe-installer/ffprobe';
|
||||||
|
import which from 'which';
|
||||||
|
|
||||||
|
const getExecutablePath = (envVar: string, executable: string, installer: { path: string }) => {
|
||||||
|
if (process.env[envVar]) {
|
||||||
|
return process.env[envVar];
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return which.sync(executable);
|
||||||
|
} catch (error) {
|
||||||
|
return installer.path;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const ffmpegPath = getExecutablePath('EB_FFMPEG_PATH', 'ffmpeg', ffmpegInstaller);
|
||||||
|
const ffprobePath = getExecutablePath('EB_FFPROBE_PATH', 'ffprobe', ffprobeInstaller);
|
||||||
|
|
||||||
|
console.log(`Using ffmpeg from path: ${ffmpegPath}`);
|
||||||
|
console.log(`Using ffprobe from path: ${ffprobePath}`);
|
||||||
|
|
||||||
|
ffmpeg.setFfmpegPath(ffmpegPath!);
|
||||||
|
ffmpeg.setFfprobePath(ffprobePath!);
|
||||||
|
|
||||||
|
export enum EncodingType {
|
||||||
|
CPU = 'libx264',
|
||||||
|
NVIDIA = 'h264_nvenc',
|
||||||
|
AMD = 'h264_vmf',
|
||||||
|
INTEL = 'h264_qsv',
|
||||||
|
APPLE = 'h264_videotoolbox',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const generateTestVideo = async (encodingType: EncodingType): Promise<void> => {
|
||||||
|
console.log(`Generating test video using ${encodingType}...`);
|
||||||
|
|
||||||
|
const startTime = Date.now();
|
||||||
|
|
||||||
|
const outputOptions = [
|
||||||
|
'-vf', 'scale=-2:720',
|
||||||
|
'-c:v', encodingType,
|
||||||
|
];
|
||||||
|
|
||||||
|
return new Promise<void>((resolve, reject) => {
|
||||||
|
ffmpeg()
|
||||||
|
.input('test.mp4')
|
||||||
|
.inputFormat('mp4')
|
||||||
|
.outputOptions(outputOptions)
|
||||||
|
.output(`720p-test-${encodingType}.mp4`)
|
||||||
|
.on('end', () => {
|
||||||
|
console.log(`720p copy complete using ${encodingType}, took ${Date.now() - startTime}ms to complete`);
|
||||||
|
resolve();
|
||||||
|
})
|
||||||
|
.on('error', (e) => reject(new Error(e)))
|
||||||
|
.run();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Test commands (uncomment to use)
|
||||||
|
// generateTestVideo(EncodingType.CPU).catch(console.error);
|
||||||
|
// generateTestVideo(EncodingType.AMD).catch(console.error);
|
||||||
|
// generateTestVideo(EncodingType.INTEL).catch(console.error);
|
||||||
|
// generateTestVideo(EncodingType.NVIDIA).catch(console.error);
|
||||||
|
// generateTestVideo(EncodingType.APPLE).catch(console.error);
|
BIN
tests/test.mp4
Normal file
BIN
tests/test.mp4
Normal file
Binary file not shown.
56
tests/test.ts
Normal file
56
tests/test.ts
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
import readline from 'readline';
|
||||||
|
import { generateTestVideo, EncodingType } from "./ffmpeg";
|
||||||
|
|
||||||
|
const rl = readline.createInterface({
|
||||||
|
input: process.stdin,
|
||||||
|
output: process.stdout
|
||||||
|
});
|
||||||
|
|
||||||
|
const questionAsync = (query: string) => {
|
||||||
|
return new Promise<string>(resolve => {
|
||||||
|
rl.question(query, resolve);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const main = async () => {
|
||||||
|
console.log("Testing software encoder: ");
|
||||||
|
await generateTestVideo(EncodingType.CPU).catch(console.error);
|
||||||
|
|
||||||
|
const answer = await questionAsync('Would you like to test other hardware encoders? (yes/no): ');
|
||||||
|
|
||||||
|
if (answer.toLowerCase() === 'yes') {
|
||||||
|
const encoder = await questionAsync('Which hardware encoder would you like to test? (INTEL/NVIDIA/AMD/APPLE): ');
|
||||||
|
let selectedEncoder: EncodingType;
|
||||||
|
|
||||||
|
switch (encoder.toUpperCase()) {
|
||||||
|
case 'INTEL':
|
||||||
|
selectedEncoder = EncodingType.INTEL;
|
||||||
|
break;
|
||||||
|
case 'NVIDIA':
|
||||||
|
selectedEncoder = EncodingType.NVIDIA;
|
||||||
|
break;
|
||||||
|
case 'AMD':
|
||||||
|
selectedEncoder = EncodingType.AMD;
|
||||||
|
break;
|
||||||
|
case 'APPLE':
|
||||||
|
selectedEncoder = EncodingType.APPLE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.log('Invalid choice. Exiting.');
|
||||||
|
rl.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Testing ${selectedEncoder} encoder:`);
|
||||||
|
await generateTestVideo(selectedEncoder).catch(console.error);
|
||||||
|
} else {
|
||||||
|
console.log("Exiting.");
|
||||||
|
}
|
||||||
|
|
||||||
|
rl.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
main().catch(err => {
|
||||||
|
console.error("An error occurred:", err);
|
||||||
|
rl.close();
|
||||||
|
});
|
Loading…
Add table
Add a link
Reference in a new issue