diff --git a/.gitignore b/.gitignore index 32d518cec..1c4bf3485 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,7 @@ ### VS Code ### .vscode/ + +/Local +/FlowPluginsTs/LocalFlowPlugins +/FlowPlugins/LocalFlowPlugins \ No newline at end of file diff --git a/FlowPlugins/CommunityFlowPlugins/ffmpegCommand/ffmpegCommandSetVideoEncoder/1.0.0/index.js b/FlowPlugins/CommunityFlowPlugins/ffmpegCommand/ffmpegCommandSetVideoEncoder/1.0.0/index.js index ca53d0ab3..2be8e86a3 100644 --- a/FlowPlugins/CommunityFlowPlugins/ffmpegCommand/ffmpegCommandSetVideoEncoder/1.0.0/index.js +++ b/FlowPlugins/CommunityFlowPlugins/ffmpegCommand/ffmpegCommandSetVideoEncoder/1.0.0/index.js @@ -64,6 +64,7 @@ var details = function () { return ({ // 'vp9', 'h264', // 'vp8', + 'av1', ], }, tooltip: 'Specify codec of the output file', @@ -185,7 +186,7 @@ var plugin = function (args) { return __awaiter(void 0, void 0, void 0, function else { stream.outputArgs.push('-crf', ffmpegQuality); } - if (ffmpegPreset) { + if (targetCodec !== 'av1' && ffmpegPreset) { stream.outputArgs.push('-preset', ffmpegPreset); } if (hardwareDecoding) { diff --git a/FlowPlugins/CommunityFlowPlugins/tools/checkNodeHardwareEncoder/1.0.0/index.js b/FlowPlugins/CommunityFlowPlugins/tools/checkNodeHardwareEncoder/1.0.0/index.js new file mode 100644 index 000000000..8d30474ca --- /dev/null +++ b/FlowPlugins/CommunityFlowPlugins/tools/checkNodeHardwareEncoder/1.0.0/index.js @@ -0,0 +1,111 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.plugin = exports.details = void 0; +var hardwareUtils_1 = require("../../../../FlowHelpers/1.0.0/hardwareUtils"); +/* eslint no-plusplus: ["error", { "allowForLoopAfterthoughts": true }] */ +var details = function () { return ({ + name: 'Check Node Hardware Encoder', + description: "\n Check if node hardware encoder is available. Can also be used to check for specific hardware.\n For example:\n\n hevc_nvenc = Nvidia\n hevc_amf = AMD\n hevc_vaapi = Intel\n hevc_qsv = Intel\n hevc_videotoolbox = Apple\n ", + style: { + borderColor: 'orange', + }, + tags: '', + isStartPlugin: false, + pType: '', + requiresVersion: '2.11.01', + sidebarPosition: -1, + icon: 'faQuestion', + inputs: [ + { + name: 'hardwareEncoder', + type: 'string', + defaultValue: 'hevc_nvenc', + inputUI: { + type: 'dropdown', + options: [ + 'hevc_nvenc', + 'hevc_amf', + 'hevc_vaapi', + 'hevc_qsv', + 'hevc_videotoolbox', + ], + }, + tooltip: 'Specify hardware (based on encoder) to check for', + }, + ], + outputs: [ + { + number: 1, + tooltip: 'Node has hardware', + }, + { + number: 2, + tooltip: 'Node does not have hardware', + }, + ], +}); }; +exports.details = details; +// eslint-disable-next-line @typescript-eslint/no-unused-vars +var plugin = function (args) { return __awaiter(void 0, void 0, void 0, function () { + var lib, hardwareEncoder, encoderProperties, nodeHasHardware; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + lib = require('../../../../../methods/lib')(); + // eslint-disable-next-line @typescript-eslint/no-unused-vars,no-param-reassign + args.inputs = lib.loadDefaultValues(args.inputs, details); + hardwareEncoder = args.inputs.hardwareEncoder; + return [4 /*yield*/, (0, hardwareUtils_1.getEncoder)({ + targetCodec: 'hevc', + hardwareEncoding: true, + args: args, + })]; + case 1: + encoderProperties = _a.sent(); + nodeHasHardware = encoderProperties.enabledDevices.some(function (row) { return row.encoder === hardwareEncoder; }); + args.jobLog("Node has hardwareEncoder ".concat(hardwareEncoder, ": ").concat(nodeHasHardware)); + return [2 /*return*/, { + outputFileObj: args.inputFileObj, + outputNumber: nodeHasHardware ? 1 : 2, + variables: args.variables, + }]; + } + }); +}); }; +exports.plugin = plugin; diff --git a/FlowPlugins/FlowHelpers/1.0.0/hardwareUtils.js b/FlowPlugins/FlowHelpers/1.0.0/hardwareUtils.js index 44fad7bb4..7e903c84b 100644 --- a/FlowPlugins/FlowHelpers/1.0.0/hardwareUtils.js +++ b/FlowPlugins/FlowHelpers/1.0.0/hardwareUtils.js @@ -154,6 +154,9 @@ var encoderFilter = function (encoder, targetCodec) { if (targetCodec === 'h264' && encoder.includes('h264')) { return true; } + if (targetCodec === 'av1' && encoder.includes('av1')) { + return true; + } return false; }; var getEncoder = function (_a) { @@ -165,7 +168,7 @@ var getEncoder = function (_a) { case 0: if (!(args.workerType && args.workerType.includes('gpu') - && hardwareEncoding && (targetCodec === 'hevc' || targetCodec === 'h264'))) return [3 /*break*/, 5]; + && hardwareEncoding && (['hevc', 'h264', 'av1'].includes(targetCodec)))) return [3 /*break*/, 5]; gpuEncoders = [ { encoder: 'hevc_nvenc', @@ -218,6 +221,7 @@ var getEncoder = function (_a) { outputArgs: [], filter: '', }, + // h264 { encoder: 'h264_nvenc', enabled: false, @@ -255,8 +259,38 @@ var getEncoder = function (_a) { outputArgs: [], filter: '', }, + // av1 + { + encoder: 'av1_nvenc', + enabled: false, + inputArgs: [], + outputArgs: [], + filter: '', + }, + { + encoder: 'av1_amf', + enabled: false, + inputArgs: [], + outputArgs: [], + filter: '', + }, + { + encoder: 'av1_vaapi', + enabled: false, + inputArgs: [], + outputArgs: [], + filter: '', + }, + { + encoder: 'av1_qsv', + enabled: false, + inputArgs: [], + outputArgs: [], + filter: '', + }, ]; filteredGpuEncoders = gpuEncoders.filter(function (device) { return encoderFilter(device.encoder, targetCodec); }); + args.jobLog(JSON.stringify({ filteredGpuEncoders: filteredGpuEncoders })); _i = 0, filteredGpuEncoders_1 = filteredGpuEncoders; _c.label = 1; case 1: @@ -279,19 +313,21 @@ var getEncoder = function (_a) { return [3 /*break*/, 1]; case 4: enabledDevices = gpuEncoders.filter(function (device) { return device.enabled === true; }); + args.jobLog(JSON.stringify({ enabledDevices: enabledDevices })); if (enabledDevices.length > 0) { if (enabledDevices[0].encoder.includes('nvenc')) { res = (0, exports.getBestNvencDevice)({ args: args, nvencDevice: enabledDevices[0], }); - return [2 /*return*/, __assign(__assign({}, res), { isGpu: true })]; + return [2 /*return*/, __assign(__assign({}, res), { isGpu: true, enabledDevices: enabledDevices })]; } return [2 /*return*/, { encoder: enabledDevices[0].encoder, inputArgs: enabledDevices[0].inputArgs, outputArgs: enabledDevices[0].outputArgs, isGpu: true, + enabledDevices: enabledDevices, }]; } _c.label = 5; @@ -302,6 +338,7 @@ var getEncoder = function (_a) { inputArgs: [], outputArgs: [], isGpu: false, + enabledDevices: [], }]; } if (targetCodec === 'h264') { @@ -310,6 +347,16 @@ var getEncoder = function (_a) { inputArgs: [], outputArgs: [], isGpu: false, + enabledDevices: [], + }]; + } + if (targetCodec === 'av1') { + return [2 /*return*/, { + encoder: 'libsvtav1', + inputArgs: [], + outputArgs: [], + isGpu: false, + enabledDevices: [], }]; } return [2 /*return*/, { @@ -317,6 +364,7 @@ var getEncoder = function (_a) { inputArgs: [], outputArgs: [], isGpu: false, + enabledDevices: [], }]; } }); diff --git a/FlowPluginsTs/CommunityFlowPlugins/ffmpegCommand/ffmpegCommandSetVideoEncoder/1.0.0/index.ts b/FlowPluginsTs/CommunityFlowPlugins/ffmpegCommand/ffmpegCommandSetVideoEncoder/1.0.0/index.ts index 30c44e470..5cde50f15 100644 --- a/FlowPluginsTs/CommunityFlowPlugins/ffmpegCommand/ffmpegCommandSetVideoEncoder/1.0.0/index.ts +++ b/FlowPluginsTs/CommunityFlowPlugins/ffmpegCommand/ffmpegCommandSetVideoEncoder/1.0.0/index.ts @@ -32,6 +32,7 @@ const details = (): IpluginDetails => ({ // 'vp9', 'h264', // 'vp8', + 'av1', ], }, tooltip: 'Specify codec of the output file', @@ -153,7 +154,7 @@ const plugin = async (args: IpluginInputArgs): Promise => { stream.outputArgs.push('-crf', ffmpegQuality); } - if (ffmpegPreset) { + if (targetCodec !== 'av1' && ffmpegPreset) { stream.outputArgs.push('-preset', ffmpegPreset); } diff --git a/FlowPluginsTs/CommunityFlowPlugins/tools/checkNodeHardwareEncoder/1.0.0/index.ts b/FlowPluginsTs/CommunityFlowPlugins/tools/checkNodeHardwareEncoder/1.0.0/index.ts new file mode 100644 index 000000000..577937ab8 --- /dev/null +++ b/FlowPluginsTs/CommunityFlowPlugins/tools/checkNodeHardwareEncoder/1.0.0/index.ts @@ -0,0 +1,88 @@ +import { getEncoder } from '../../../../FlowHelpers/1.0.0/hardwareUtils'; +import { + IpluginDetails, + IpluginInputArgs, + IpluginOutputArgs, +} from '../../../../FlowHelpers/1.0.0/interfaces/interfaces'; + +/* eslint no-plusplus: ["error", { "allowForLoopAfterthoughts": true }] */ +const details = (): IpluginDetails => ({ + name: 'Check Node Hardware Encoder', + description: ` + Check if node hardware encoder is available. Can also be used to check for specific hardware. + For example: + + hevc_nvenc = Nvidia + hevc_amf = AMD + hevc_vaapi = Intel + hevc_qsv = Intel + hevc_videotoolbox = Apple + `, + style: { + borderColor: 'orange', + }, + tags: '', + isStartPlugin: false, + pType: '', + requiresVersion: '2.11.01', + sidebarPosition: -1, + icon: 'faQuestion', + inputs: [ + { + name: 'hardwareEncoder', + type: 'string', + defaultValue: 'hevc_nvenc', + inputUI: { + type: 'dropdown', + options: [ + 'hevc_nvenc', + 'hevc_amf', + 'hevc_vaapi', + 'hevc_qsv', + 'hevc_videotoolbox', + ], + }, + tooltip: 'Specify hardware (based on encoder) to check for', + }, + ], + outputs: [ + { + number: 1, + tooltip: 'Node has hardware', + }, + { + number: 2, + tooltip: 'Node does not have hardware', + }, + ], +}); + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +const plugin = async (args: IpluginInputArgs): Promise => { + const lib = require('../../../../../methods/lib')(); + // eslint-disable-next-line @typescript-eslint/no-unused-vars,no-param-reassign + args.inputs = lib.loadDefaultValues(args.inputs, details); + + const { hardwareEncoder } = args.inputs; + + // eslint-disable-next-line no-await-in-loop + const encoderProperties = await getEncoder({ + targetCodec: 'hevc', + hardwareEncoding: true, + args, + }); + + const nodeHasHardware = encoderProperties.enabledDevices.some((row) => row.encoder === hardwareEncoder); + + args.jobLog(`Node has hardwareEncoder ${hardwareEncoder}: ${nodeHasHardware}`); + + return { + outputFileObj: args.inputFileObj, + outputNumber: nodeHasHardware ? 1 : 2, + variables: args.variables, + }; +}; +export { + details, + plugin, +}; diff --git a/FlowPluginsTs/FlowHelpers/1.0.0/hardwareUtils.ts b/FlowPluginsTs/FlowHelpers/1.0.0/hardwareUtils.ts index 47cc3b188..39adb8ce5 100644 --- a/FlowPluginsTs/FlowHelpers/1.0.0/hardwareUtils.ts +++ b/FlowPluginsTs/FlowHelpers/1.0.0/hardwareUtils.ts @@ -117,6 +117,8 @@ const encoderFilter = (encoder:string, targetCodec:string) => { return true; } if (targetCodec === 'h264' && encoder.includes('h264')) { return true; + } if (targetCodec === 'av1' && encoder.includes('av1')) { + return true; } return false; @@ -135,11 +137,12 @@ export const getEncoder = async ({ inputArgs: string[], outputArgs: string[], isGpu: boolean, + enabledDevices: IgpuEncoder[], }> => { if ( args.workerType && args.workerType.includes('gpu') - && hardwareEncoding && (targetCodec === 'hevc' || targetCodec === 'h264')) { + && hardwareEncoding && (['hevc', 'h264', 'av1'].includes(targetCodec))) { const gpuEncoders: IgpuEncoder[] = [ { encoder: 'hevc_nvenc', @@ -193,6 +196,7 @@ export const getEncoder = async ({ filter: '', }, + // h264 { encoder: 'h264_nvenc', enabled: false, @@ -230,10 +234,42 @@ export const getEncoder = async ({ outputArgs: [], filter: '', }, + + // av1 + { + encoder: 'av1_nvenc', + enabled: false, + inputArgs: [], + outputArgs: [], + filter: '', + }, + { + encoder: 'av1_amf', + enabled: false, + inputArgs: [], + outputArgs: [], + filter: '', + }, + { + encoder: 'av1_vaapi', + enabled: false, + inputArgs: [], + outputArgs: [], + filter: '', + }, + { + encoder: 'av1_qsv', + enabled: false, + inputArgs: [], + outputArgs: [], + filter: '', + }, ]; const filteredGpuEncoders = gpuEncoders.filter((device) => encoderFilter(device.encoder, targetCodec)); + args.jobLog(JSON.stringify({ filteredGpuEncoders })); + // eslint-disable-next-line no-restricted-syntax for (const gpuEncoder of filteredGpuEncoders) { // eslint-disable-next-line no-await-in-loop @@ -247,6 +283,8 @@ export const getEncoder = async ({ const enabledDevices = gpuEncoders.filter((device) => device.enabled === true); + args.jobLog(JSON.stringify({ enabledDevices })); + if (enabledDevices.length > 0) { if (enabledDevices[0].encoder.includes('nvenc')) { const res = getBestNvencDevice({ @@ -257,6 +295,7 @@ export const getEncoder = async ({ return { ...res, isGpu: true, + enabledDevices, }; } return { @@ -264,6 +303,7 @@ export const getEncoder = async ({ inputArgs: enabledDevices[0].inputArgs, outputArgs: enabledDevices[0].outputArgs, isGpu: true, + enabledDevices, }; } } @@ -274,6 +314,7 @@ export const getEncoder = async ({ inputArgs: [], outputArgs: [], isGpu: false, + enabledDevices: [], }; } if (targetCodec === 'h264') { return { @@ -281,6 +322,15 @@ export const getEncoder = async ({ inputArgs: [], outputArgs: [], isGpu: false, + enabledDevices: [], + }; + } if (targetCodec === 'av1') { + return { + encoder: 'libsvtav1', + inputArgs: [], + outputArgs: [], + isGpu: false, + enabledDevices: [], }; } @@ -289,5 +339,6 @@ export const getEncoder = async ({ inputArgs: [], outputArgs: [], isGpu: false, + enabledDevices: [], }; }; diff --git a/FlowPluginsTs/FlowHelpers/1.0.0/interfaces/interfaces.ts b/FlowPluginsTs/FlowHelpers/1.0.0/interfaces/interfaces.ts index 817339911..794be8b51 100644 --- a/FlowPluginsTs/FlowHelpers/1.0.0/interfaces/interfaces.ts +++ b/FlowPluginsTs/FlowHelpers/1.0.0/interfaces/interfaces.ts @@ -77,7 +77,8 @@ export interface IffmpegCommand { } export interface Ivariables { - ffmpegCommand: IffmpegCommand + ffmpegCommand: IffmpegCommand, + flowFailed: boolean, } export interface IpluginOutputArgs { @@ -133,8 +134,11 @@ export interface IpluginInputArgs { mvdir: any, // eslint-disable-next-line @typescript-eslint/no-explicit-any axios: any, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + crudTransDBN: (collection: string, mode: string, docID: string, obj: any)=> any, }, - installClassicPluginDeps: (deps: string[]) => void, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + installClassicPluginDeps: (deps: string[]) => Promise, } export interface IflowTemplate {