@eleven-am/transcoder
Version:
High-performance HLS transcoding library with hardware acceleration, intelligent client management, and distributed processing support for Node.js
312 lines • 11.1 kB
JavaScript
;
/*
* @eleven-am/transcoder
* Copyright (C) 2025 Roy OSSAI
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.HardwareOptimizer = void 0;
const fp_1 = require("@eleven-am/fp");
const types_1 = require("./types");
/**
* Provides hardware-specific optimizations for different acceleration methods
* Optimizes encoder settings based on hardware capabilities
*/
class HardwareOptimizer {
/**
* Get optimal settings for specific hardware acceleration method
*/
getOptimalSettings(options) {
const methodHandlers = [
{
predicate: (o) => o.method === types_1.HardwareAccelerationMethod.CUDA,
run: (o) => this.getNvidiaOptimalSettings(o),
},
{
predicate: (o) => o.method === types_1.HardwareAccelerationMethod.VIDEOTOOLBOX,
run: (o) => this.getVideoToolboxOptimalSettings(o),
},
{
predicate: (o) => o.method === types_1.HardwareAccelerationMethod.QSV,
run: (o) => this.getQuickSyncOptimalSettings(o),
},
{
predicate: (o) => o.method === types_1.HardwareAccelerationMethod.VAAPI,
run: (o) => this.getVaapiOptimalSettings(o),
},
{
predicate: (o) => o.method === types_1.HardwareAccelerationMethod.AMF,
run: (o) => this.getAMFOptimalSettings(o),
},
{
predicate: () => true, // Default case
run: (o) => this.getSoftwareOptimalSettings(o),
},
];
return fp_1.Either.of(options).match(methodHandlers);
}
/**
* NVIDIA GPU optimizations
*/
getNvidiaOptimalSettings(options) {
const selectEncoder = (codec) => codec === 'h265' ? 'hevc_nvenc' : 'h264_nvenc';
const baseInputOptions = () => [
'-hwaccel', 'cuda',
'-hwaccel_output_format', 'cuda',
];
const baseOutputOptions = (encoder) => [
'-c:v', encoder,
'-preset', 'p4',
'-tune', 'hq',
'-rc', 'vbr',
'-rc-lookahead', '32',
'-temporal-aq', '1',
'-spatial-aq', '1',
'-b_ref_mode', 'middle',
];
const addResolutionOptions = (height, frameRate) => {
const gopSize = String(frameRate * 2);
return height >= 2160 ? ['-tier', 'high', '-level', '5.1', '-g', gopSize] :
height >= 1440 ? ['-level', '5.0', '-g', gopSize] :
['-g', gopSize];
};
const addLiveStreamOptions = (isLive) => isLive ? ['-zerolatency', '1', '-preset', 'p2'] : [];
const addBFrameOptions = (codec) => ['-bf', codec === 'h264' ? '3' : '4'];
const encoder = selectEncoder(options.codec);
return fp_1.Either.of({
inputOptions: baseInputOptions(),
outputOptions: [
...baseOutputOptions(encoder),
...addResolutionOptions(options.height, options.frameRate),
...addLiveStreamOptions(options.isLiveStream),
...addBFrameOptions(options.codec),
],
videoFilters: undefined,
}).toValue();
}
/**
* Apple VideoToolbox optimizations
*/
getVideoToolboxOptimalSettings(options) {
const encoder = options.codec === 'h265' ? 'hevc_videotoolbox' : 'h264_videotoolbox';
const inputOptions = [
'-hwaccel', 'videotoolbox',
];
const outputOptions = [
'-c:v', encoder,
'-profile:v', options.codec === 'h265' ? 'main' : 'high',
'-realtime', options.isLiveStream ? '1' : '0',
];
// Quality vs speed trade-off
if (!options.isLiveStream) {
outputOptions.push('-allow_sw', '1', // Allow software fallback for better quality
'-alpha_quality', '0.75', '-compression_level', '0.5');
}
// Frame rate specific
if (options.frameRate > 30) {
outputOptions.push('-max_slice_bytes', '1500'); // For high frame rates
}
// Resolution specific
if (options.height >= 2160) {
outputOptions.push('-pix_fmt', 'yuv420p10le');
}
else {
outputOptions.push('-pix_fmt', 'yuv420p');
}
return {
inputOptions,
outputOptions,
videoFilters: undefined,
};
}
/**
* Intel Quick Sync optimizations
*/
getQuickSyncOptimalSettings(options) {
const encoder = options.codec === 'h265' ? 'hevc_qsv' : 'h264_qsv';
const inputOptions = [
'-hwaccel', 'qsv',
'-hwaccel_output_format', 'qsv',
];
const outputOptions = [
'-c:v', encoder,
'-preset', 'medium', // Better than 'fast' for quality
'-global_quality', '25', // Quality parameter for QSV
'-look_ahead', '1', // Enable lookahead
'-look_ahead_depth', '40', // Lookahead depth
];
// Adaptive encoding features
if (!options.isLiveStream) {
outputOptions.push('-adaptive_i', '1', // Adaptive I-frame placement
'-adaptive_b', '1', // Adaptive B-frame placement
'-b_strategy', '1');
}
// High resolution optimizations
if (options.height >= 1440) {
outputOptions.push('-rdo', '1', // Rate distortion optimization
'-max_frame_size', String(Math.round(options.bitrate / options.frameRate / 8 * 1.5)));
}
return {
inputOptions,
outputOptions,
videoFilters: undefined,
};
}
/**
* VAAPI (AMD/Intel integrated) optimizations
*/
getVaapiOptimalSettings(options) {
const encoder = options.codec === 'h265' ? 'hevc_vaapi' : 'h264_vaapi';
const inputOptions = [
'-hwaccel', 'vaapi',
'-hwaccel_device', '/dev/dri/renderD128',
'-hwaccel_output_format', 'vaapi',
];
const outputOptions = [
'-c:v', encoder,
'-quality', '1', // Quality mode
'-compression_level', '1', // Better compression
];
// Rate control
if (options.isLiveStream) {
outputOptions.push('-rc_mode', 'CBR');
}
else {
outputOptions.push('-rc_mode', 'VBR');
}
// Profile settings
if (options.codec === 'h264') {
outputOptions.push('-profile', '100', // High profile
'-level', '41');
}
return {
inputOptions,
outputOptions,
videoFilters: 'format=nv12|vaapi,hwupload', // Upload to VAAPI surface
};
}
/**
* AMD AMF optimizations
*/
getAMFOptimalSettings(options) {
const encoder = options.codec === 'h265' ? 'hevc_amf' : 'h264_amf';
const outputOptions = [
'-c:v', encoder,
'-quality', 'balanced', // Quality preset
'-rc', 'vbr_peak', // Peak constrained VBR
'-preanalysis', '1', // Enable pre-analysis
];
// Quality enhancements
if (!options.isLiveStream) {
outputOptions.push('-preencode', '1', // Pre-encode for better quality
'-vbaq', '1');
}
// Resolution specific
if (options.height >= 1440) {
outputOptions.push('-pa_activity_type', 'y', // Luma-based activity
'-pa_scene_change_detection', '1');
}
return {
inputOptions: [],
outputOptions,
videoFilters: undefined,
};
}
/**
* Software encoding optimizations
*/
getSoftwareOptimalSettings(options) {
const encoder = options.codec === 'h265' ? 'libx265' : 'libx264';
const outputOptions = [
'-c:v', encoder,
];
if (encoder === 'libx264') {
outputOptions.push('-preset', options.isLiveStream ? 'faster' : 'medium', '-tune', this.getX264Tune(options), '-x264-params', this.getX264Params(options));
}
else {
outputOptions.push('-preset', options.isLiveStream ? 'faster' : 'medium', '-x265-params', this.getX265Params(options));
}
return {
inputOptions: [],
outputOptions,
videoFilters: undefined,
};
}
/**
* Get x264 tuning based on content
*/
getX264Tune(options) {
if (options.isLiveStream) {
return 'zerolatency';
}
// Could be extended to detect content type
return 'film'; // Good default
}
/**
* Get x264 specific parameters
*/
getX264Params(options) {
const params = [
'aq-mode=3', // AQ mode 3 is good for most content
'aq-strength=0.8',
'deblock=-1,-1', // Slight deblocking
];
if (!options.isLiveStream) {
params.push('rc-lookahead=60', 'b-adapt=2', 'direct=auto');
}
return params.join(':');
}
/**
* Get x265 specific parameters
*/
getX265Params(options) {
const params = [
'aq-mode=3',
'aq-strength=0.8',
'deblock=-1:-1',
];
if (options.height >= 2160) {
params.push('ctu=64', // Larger CTU for 4K
'min-cu-size=8');
}
if (!options.isLiveStream) {
params.push('rc-lookahead=40', 'b-adapt=2', 'weightb=1');
}
return params.join(':');
}
/**
* Get recommended thread count based on resolution and hardware
*/
getOptimalThreadCount(width, height, method) {
// Hardware encoders handle threading internally
if (method !== types_1.HardwareAccelerationMethod.NONE) {
return undefined;
}
// For software encoding
const pixels = width * height;
if (pixels >= 3840 * 2160) { // 4K
return 8;
}
else if (pixels >= 1920 * 1080) { // 1080p
return 6;
}
else if (pixels >= 1280 * 720) { // 720p
return 4;
}
return 3; // Lower resolutions
}
}
exports.HardwareOptimizer = HardwareOptimizer;
//# sourceMappingURL=hardwareOptimizer.js.map