@remotion/renderer
Version:
Render Remotion videos using Node.js or Bun
96 lines (95 loc) • 4.33 kB
JavaScript
;
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;