UNPKG

@remotion/renderer

Version:

Render Remotion videos using Node.js or Bun

96 lines (95 loc) 4.33 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.resolveHardwareAcceleration = exports.probeEncoderAvailability = void 0; const node_child_process_1 = require("node:child_process"); const path_1 = __importDefault(require("path")); const get_executable_path_1 = require("./compositor/get-executable-path"); const get_explicit_env_1 = require("./compositor/get-explicit-env"); const make_file_executable_1 = require("./compositor/make-file-executable"); const get_codec_name_1 = require("./get-codec-name"); const logger_1 = require("./logger"); /** * Probes FFmpeg to check if a specific encoder is available. * Returns true if the encoder is supported, false otherwise. */ const probeEncoderAvailability = ({ encoderName, binariesDirectory, indent, logLevel, }) => { try { const executablePath = (0, get_executable_path_1.getExecutablePath)({ type: 'ffmpeg', indent, logLevel, binariesDirectory, }); (0, make_file_executable_1.makeFileExecutableIfItIsNot)(executablePath); const cwd = path_1.default.dirname(executablePath); const result = (0, node_child_process_1.execFileSync)(executablePath, ['-encoders'], { encoding: 'utf-8', env: (0, get_explicit_env_1.getExplicitEnv)(cwd), stdio: ['pipe', 'pipe', 'pipe'], timeout: 10000, }); // FFmpeg -encoders output format: " V..... encoder_name" // Escape regex metacharacters and use word-boundary to avoid false positives const escaped = encoderName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); const encoderRegex = new RegExp(`\\b${escaped}\\b`); const hasEncoder = encoderRegex.test(result); if (!hasEncoder) { logger_1.Log.verbose({ indent, logLevel, tag: 'probeEncoderAvailability()' }, `Encoder "${encoderName}" not found in FFmpeg build. Falling back to software encoding.`); } return hasEncoder; } catch (err) { logger_1.Log.verbose({ indent, logLevel, tag: 'probeEncoderAvailability()' }, `Failed to probe FFmpeg for encoder "${encoderName}": ${err}. Falling back to software encoding.`); return false; } }; exports.probeEncoderAvailability = probeEncoderAvailability; /** * Resolves the effective hardware acceleration setting by probing FFmpeg * for encoder availability. If the preferred hw encoder is not available: * - `if-possible` mode: falls back to software encoding * - `required` mode: throws a clear error */ const resolveHardwareAcceleration = ({ codec, hardwareAcceleration, binariesDirectory, indent, logLevel, crf, encodingMaxRate, encodingBufferSize, }) => { if (hardwareAcceleration === 'disable') { return 'disable'; } const preferred = (0, get_codec_name_1.getCodecName)({ codec, hardwareAcceleration, crf, encodingMaxRate, encodingBufferSize, logLevel, indent, }); // Audio codecs return null, no probing needed if (preferred === null) { return hardwareAcceleration; } // Only probe if getCodecName selected a hardware-accelerated encoder if (!preferred.hardwareAccelerated) { return hardwareAcceleration; } const encoderAvailable = (0, exports.probeEncoderAvailability)({ encoderName: preferred.encoderName, binariesDirectory, indent, logLevel, }); if (encoderAvailable) { return hardwareAcceleration; } // Encoder not available in FFmpeg if (hardwareAcceleration === 'if-possible') { logger_1.Log.verbose({ indent, logLevel, tag: 'resolveHardwareAcceleration()' }, `Hardware encoder "${preferred.encoderName}" not available. Falling back to software encoding.`); return 'disable'; } // hardwareAcceleration === 'required' throw new Error(`Hardware encoder "${preferred.encoderName}" is not available in your FFmpeg build. ` + `Install an FFmpeg with ${preferred.encoderName} support, or use "if-possible" mode instead of "required".`); }; exports.resolveHardwareAcceleration = resolveHardwareAcceleration;