This commit is contained in:
matty 2024-03-10 17:26:43 -04:00
parent acaf777612
commit 9c7a2de2e9
6 changed files with 3190 additions and 6117 deletions

2
.gitignore vendored
View File

@ -1,2 +1,2 @@
node_modules/
dist/
# dist/

212
dist/main.js vendored Normal file
View File

@ -0,0 +1,212 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.unregister = exports.register = void 0;
let logger;
let transcodingManager;
const DEFAULT_HARDWARE_DECODE = false;
const DEFAULT_VOD_QUALITY = "p7";
const DEFAULT_LIVE_QUALITY = "hq";
const DEFAULT_BITRATES = new Map([
[0, 64 * 1000],
[144, 320 * 1000],
[360, 780 * 1000],
[480, 1500 * 1000],
[720, 2800 * 1000],
[1080, 5200 * 1000],
[1440, 10000 * 1000],
[2160, 22000 * 1000]
]);
let pluginSettings = {
hardwareDecode: DEFAULT_HARDWARE_DECODE,
vodQuality: DEFAULT_VOD_QUALITY,
liveQuality: DEFAULT_LIVE_QUALITY,
baseBitrate: new Map(DEFAULT_BITRATES)
};
let latestStreamNum = 9999;
async function register({ settingsManager, peertubeHelpers, transcodingManager: transcode, registerSetting }) {
logger = peertubeHelpers.logger;
transcodingManager = transcode;
logger.info("Registering peertube-plugin-nctv-hardware-encode");
const encoder = 'h264_nvenc';
const profileName = 'nvenc';
transcodingManager.addVODProfile(encoder, profileName, vodBuilder);
transcodingManager.addVODEncoderPriority('video', encoder, 1000);
transcodingManager.addLiveProfile(encoder, profileName, liveBuilder);
transcodingManager.addLiveEncoderPriority('video', encoder, 1000);
await loadSettings(settingsManager);
registerSetting({
name: 'hardware-decode',
label: 'Hardware decode',
type: 'input-checkbox',
descriptionHTML: 'Use hardware video decoder instead of software decoder. This will slightly improve performance but may cause some issues with some videos. If you encounter issues, disable this option and restart failed jobs.',
default: DEFAULT_HARDWARE_DECODE,
private: false
});
registerSetting({
name: 'vod-quality',
label: 'VOD Quality',
type: 'select',
options: [
{ label: 'fastest', value: 'p1' },
{ label: 'faster', value: 'p2' },
{ label: 'fast', value: 'p3' },
{ label: 'medium (default)', value: 'p4' },
{ label: 'slow', value: 'p5' },
{ label: 'slower', value: 'p6' },
{ label: 'slowest', value: 'p7' }
],
descriptionHTML: 'This parameter controls the speed / quality tradeoff. Slower speed mean better quality. Faster speed mean lower quality. This setting is hardware dependent, you may need to experiment to find the best value for your hardware.',
default: DEFAULT_VOD_QUALITY.toString(),
private: false
});
registerSetting({
name: 'live-quality',
label: 'Live Quality',
type: 'select',
options: [
{ label: 'low latency', value: 'll' },
{ label: 'high quality (default)', value: 'hq' },
{ label: 'low latency high performance', value: 'ull' }
],
descriptionHTML: 'This parameter controls the speed / quality tradeoff. High performance mean lower quality.',
default: DEFAULT_LIVE_QUALITY.toString(),
private: false
});
registerSetting({
name: 'base-bitrate-description',
label: 'Base bitrate',
type: 'html',
html: '',
descriptionHTML: `The base bitrate for video in bits. We take the min bitrate between the bitrate setting and video bitrate.<br/>This is the bitrate used when the video is transcoded at 30 FPS. The bitrate will be scaled linearly between this value and the maximum bitrate when the video is transcoded at 60 FPS. Wrong values are replaced by default values.`,
private: true,
});
for (const [resolution, bitrate] of pluginSettings.baseBitrate) {
logger.info("registering bitrate setting: " + bitrate.toString());
registerSetting({
name: `base-bitrate-${resolution}`,
label: `Base bitrate for ${printResolution(resolution)}`,
type: 'input',
default: DEFAULT_BITRATES.get(resolution)?.toString(),
descriptionHTML: `Default value: ${DEFAULT_BITRATES.get(resolution)}`,
private: false
});
}
settingsManager.onSettingsChange(async (settings) => {
loadSettings(settingsManager);
});
}
exports.register = register;
async function unregister() {
logger.info("Unregistering peertube-plugin-nctv-hardware-encode");
transcodingManager.removeAllProfilesAndEncoderPriorities();
return true;
}
exports.unregister = unregister;
async function loadSettings(settingsManager) {
pluginSettings.hardwareDecode = await settingsManager.getSetting('hardware-decode') == "true";
pluginSettings.vodQuality = parseInt(await settingsManager.getSetting('vod-quality')) || DEFAULT_VOD_QUALITY;
pluginSettings.liveQuality = parseInt(await settingsManager.getSetting('live-quality')) || DEFAULT_LIVE_QUALITY;
for (const [resolution, bitrate] of DEFAULT_BITRATES) {
const key = `base-bitrate-${resolution}`;
const storedValue = await settingsManager.getSetting(key);
pluginSettings.baseBitrate.set(resolution, parseInt(storedValue) || bitrate);
logger.info(`Bitrate ${printResolution(resolution)}: ${pluginSettings.baseBitrate.get(resolution)}`);
}
logger.info(`Hardware decode: ${pluginSettings.hardwareDecode}`);
logger.info(`VOD Quality: ${pluginSettings.vodQuality}`);
logger.info(`Live Quality: ${pluginSettings.liveQuality}`);
}
function printResolution(resolution) {
switch (resolution) {
case 0: return 'audio only';
case 144:
case 360:
case 480:
case 720:
case 1080:
case 1440:
return `${resolution}p`;
case 2160: return '4K';
default: return 'Unknown';
}
}
function buildInitOptions() {
if (pluginSettings.hardwareDecode) {
return [
'-hwaccel cuda',
'-hwaccel_output_format cuda'
];
}
else {
return [
'-hwaccel cuda'
];
}
}
async function vodBuilder(params) {
const { resolution, fps, streamNum, inputBitrate } = params;
const streamSuffix = streamNum == undefined ? '' : `:${streamNum}`;
let targetBitrate = getTargetBitrate(resolution, fps);
let shouldInitVaapi = (streamNum == undefined || streamNum <= latestStreamNum);
if (targetBitrate > inputBitrate) {
targetBitrate = inputBitrate;
}
logger.info(`Building encoder options, received ${JSON.stringify(params)}`);
if (shouldInitVaapi && streamNum != undefined) {
latestStreamNum = streamNum;
}
let options = {
scaleFilter: {
name: 'scale'
},
inputOptions: shouldInitVaapi ? buildInitOptions() : [],
outputOptions: [
`-preset ${pluginSettings.vodQuality}`,
`-b:v${streamSuffix} ${targetBitrate}`,
`-bufsize ${targetBitrate * 2}`,
`-cq 19`,
`-profile:v${streamSuffix} high`
]
};
logger.info(`EncoderOptions: ${JSON.stringify(options)}`);
return options;
}
async function liveBuilder(params) {
const { resolution, fps, streamNum, inputBitrate } = params;
const streamSuffix = streamNum == undefined ? '' : `:${streamNum}`;
let targetBitrate = getTargetBitrate(resolution, fps);
let shouldInitVaapi = (streamNum == undefined || streamNum <= latestStreamNum);
if (targetBitrate > inputBitrate) {
targetBitrate = inputBitrate;
}
logger.info(`Building encoder options, received ${JSON.stringify(params)}`);
if (shouldInitVaapi && streamNum != undefined) {
latestStreamNum = streamNum;
}
const options = {
scaleFilter: {
name: 'scale'
},
inputOptions: shouldInitVaapi ? buildInitOptions() : [],
outputOptions: [
`-tune ${pluginSettings.liveQuality}`,
`-r:v${streamSuffix} ${fps}`,
`-profile:v${streamSuffix} high`,
// `-level:v${streamSuffix} `,
`-g:v${streamSuffix} ${fps * 2}`,
`-b:v${streamSuffix} ${targetBitrate}`,
`-bufsize ${targetBitrate * 2}`,
`-cq 21`
]
};
logger.info(`EncoderOptions: ${JSON.stringify(options)}`);
return options;
}
function getTargetBitrate(resolution, fps) {
const baseBitrate = pluginSettings.baseBitrate.get(resolution) || 0;
const maxBitrate = baseBitrate * 1.4;
const maxBitrateDifference = maxBitrate - baseBitrate;
const maxFpsDifference = 60 - 30;
return Math.floor(baseBitrate + (fps - 30) * (maxBitrateDifference / maxFpsDifference));
}
//# sourceMappingURL=main.js.map

1
dist/main.js.map vendored Normal file

File diff suppressed because one or more lines are too long

6595
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "peertube-plugin-nctv-nvenc-transcode",
"version": "1.0.4",
"version": "1.0.5",
"license": "MIT",
"description": "Plugin that adds transcode profiles which use NVIDIA NVENC for hardware acceleration",
"engine": {

2495
yarn.lock

File diff suppressed because it is too large Load Diff