2024-03-10 21:26:43 +00:00
"use strict" ;
Object . defineProperty ( exports , "__esModule" , { value : true } ) ;
exports . unregister = exports . register = void 0 ;
let logger ;
let transcodingManager ;
const DEFAULT _HARDWARE _DECODE = false ;
2024-04-13 18:05:18 +00:00
const DEFAULT _VOD _QUALITY = "p7" ;
2024-04-14 18:39:10 +00:00
const DEFAULT _HEVC _PROFILE = "main10" ;
2024-03-10 21:26:43 +00:00
const DEFAULT _LIVE _QUALITY = "hq" ;
2024-04-14 20:12:26 +00:00
const DEFAULT _CQ _H264 = 26 ;
const DEFAULT _CQ _HEVC = 28 ;
2024-03-10 21:26:43 +00:00
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 ,
2024-04-14 18:39:10 +00:00
hevcProfile : DEFAULT _HEVC _PROFILE ,
2024-04-14 20:12:26 +00:00
cqH264 : DEFAULT _CQ _H264 ,
cqHEVC : DEFAULT _CQ _HEVC ,
2024-03-10 21:26:43 +00:00
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' ;
2024-04-14 19:31:21 +00:00
const hevc = 'hevc_nvenc' ;
2024-03-10 21:36:43 +00:00
const profileName = 'nctv-nvenc' ;
2024-04-14 19:41:29 +00:00
const hevcProfile = 'nctv-hevc' ;
2024-03-10 21:26:43 +00:00
transcodingManager . addVODProfile ( encoder , profileName , vodBuilder ) ;
transcodingManager . addVODEncoderPriority ( 'video' , encoder , 1000 ) ;
2024-04-14 19:35:50 +00:00
2024-03-10 21:26:43 +00:00
transcodingManager . addLiveProfile ( encoder , profileName , liveBuilder ) ;
transcodingManager . addLiveEncoderPriority ( 'video' , encoder , 1000 ) ;
2024-04-14 19:35:50 +00:00
transcodingManager . addVODProfile ( hevc , hevcProfile , hevcVODBuilder ) ;
2024-04-14 19:41:29 +00:00
transcodingManager . addVODEncoderPriority ( 'video' , hevc , 900 ) ;
2024-04-14 19:35:50 +00:00
transcodingManager . addLiveProfile ( hevc , hevcProfile , hevcLiveBuilder ) ;
2024-04-14 19:41:29 +00:00
transcodingManager . addLiveEncoderPriority ( 'video' , hevc , 900 ) ;
2024-03-10 21:26:43 +00:00
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
} ) ;
2024-04-14 20:12:26 +00:00
registerSetting ( {
name : 'cq-h264' ,
label : 'CQ Value for H264_nvenc' ,
type : 'input' ,
descriptionHTML : 'Sets the -cq value for h264_nvenc encoder. Valid values are between 0 and 51 (lossess and AIDS, respectively)' ,
default : DEFAULT _CQ _H264 ,
private : false
} ) ;
registerSetting ( {
name : 'cq-hevc' ,
label : 'CQ Value for hevc_nvenc' ,
type : 'input' ,
descriptionHTML : 'Sets the -cq value for hevc_nvenc encoder. Valid values are between 0 and 51 (lossess and AIDS, respectively)' ,
default : DEFAULT _CQ _HEVC ,
private : false
} ) ;
2024-03-10 21:26:43 +00:00
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
} ) ;
2024-04-14 18:39:10 +00:00
registerSetting ( {
name : 'hevc-profile' ,
label : 'HEVC Profile' ,
type : 'select' ,
options : [
{ label : 'main' , value : 'main' } ,
{ label : 'main10 (default)' , value : 'main10' } ,
{ label : 'rext' , value : 'rext' }
] ,
descriptionHTML : 'Set the HEVC profile' ,
2024-04-14 18:53:50 +00:00
default : DEFAULT _HEVC _PROFILE . toString ( ) ,
2024-04-14 18:39:10 +00:00
private : false
} ) ;
2024-03-10 21:26:43 +00:00
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 ) {
2024-04-14 19:09:54 +00:00
pluginSettings . hardwareDecode = await settingsManager . getSetting ( 'hardware-decode' ) || DEFAULT _HARDWARE _DECODE ;
2024-03-10 21:26:43 +00:00
pluginSettings . vodQuality = parseInt ( await settingsManager . getSetting ( 'vod-quality' ) ) || DEFAULT _VOD _QUALITY ;
pluginSettings . liveQuality = parseInt ( await settingsManager . getSetting ( 'live-quality' ) ) || DEFAULT _LIVE _QUALITY ;
2024-04-14 18:39:10 +00:00
pluginSettings . hevcProfile = parseInt ( await settingsManager . getSetting ( 'hevc-profile' ) ) || DEFAULT _HEVC _PROFILE ;
2024-04-14 20:12:26 +00:00
pluginSettings . cqH264 = parseInt ( await settingsManager . getSetting ( 'cq-h264' ) ) || DEFAULT _CQ _H264 ;
pluginSettings . cqHEVC = parseInt ( await settingsManager . getSetting ( 'cq-hevc' ) ) || DEFAULT _CQ _HEVC ;
2024-03-10 21:26:43 +00:00
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 } ` ) ;
2024-04-14 18:39:10 +00:00
logger . info ( ` HEVC profile: ${ pluginSettings . hevcProfile } ` ) ;
2024-03-10 21:26:43 +00:00
}
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'
] ;
}
}
2024-04-14 19:31:21 +00:00
//H264_NVENC VOD BUILDER
2024-03-10 21:26:43 +00:00
async function vodBuilder ( params ) {
const { resolution , fps , streamNum , inputBitrate } = params ;
const streamSuffix = streamNum == undefined ? '' : ` : ${ streamNum } ` ;
2024-04-14 05:32:46 +00:00
let targetBitrate = getTargetBitrate ( resolution , fps ) ;
// let targetBitrate = inputBitrate;
2024-03-10 21:26:43 +00:00
let shouldInitVaapi = ( streamNum == undefined || streamNum <= latestStreamNum ) ;
2024-04-14 05:32:46 +00:00
if ( targetBitrate > inputBitrate ) {
2024-04-14 18:39:10 +00:00
targetBitrate = inputBitrate ;
2024-04-14 05:32:46 +00:00
}
2024-04-14 20:32:11 +00:00
logger . info ( ` Building encoder options, received ${ JSON . stringify ( params ) } ` ) ;
2024-03-10 21:26:43 +00:00
if ( shouldInitVaapi && streamNum != undefined ) {
latestStreamNum = streamNum ;
}
2024-04-14 19:31:21 +00:00
let options = {
2024-04-14 18:39:10 +00:00
scaleFilter : {
name : 'scale'
} ,
inputOptions : shouldInitVaapi ? buildInitOptions ( ) : [ ] ,
outputOptions : [
2024-04-14 19:12:36 +00:00
` -preset ${ pluginSettings . vodQuality } ` ,
2024-04-14 18:39:10 +00:00
` -b:v ${ streamSuffix } ${ targetBitrate } ` ,
` -bufsize ${ targetBitrate * 2 } ` ,
` -profile:v ${ streamSuffix } high ` ,
2024-04-14 20:12:26 +00:00
` -cq ${ pluginSettings . cqH264 } ` ,
2024-04-14 18:39:10 +00:00
` -bf 4 `
]
} ;
2024-04-14 19:31:21 +00:00
logger . info ( ` EncoderOptions: ${ JSON . stringify ( options ) } ` ) ;
return options ;
}
//HEVC VOD builder
async function hevcVODBuilder ( params ) {
const { resolution , fps , streamNum , inputBitrate } = params ;
const streamSuffix = streamNum == undefined ? '' : ` : ${ streamNum } ` ;
let targetBitrate = getTargetBitrate ( resolution , fps ) ;
// let targetBitrate = inputBitrate;
let shouldInitVaapi = ( streamNum == undefined || streamNum <= latestStreamNum ) ;
if ( targetBitrate > inputBitrate ) {
targetBitrate = inputBitrate ;
2024-04-14 18:39:10 +00:00
}
2024-04-14 20:32:11 +00:00
logger . info ( ` Building encoder options, received ${ JSON . stringify ( params ) } ` ) ;
2024-04-14 19:31:21 +00:00
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 } ` ,
` -profile:v ${ streamSuffix } ${ pluginSettings . hevcProfile } ` ,
2024-04-14 20:12:26 +00:00
` -cq ${ pluginSettings . cqHEVC } `
2024-04-14 19:31:21 +00:00
]
} ;
2024-03-10 21:26:43 +00:00
logger . info ( ` EncoderOptions: ${ JSON . stringify ( options ) } ` ) ;
return options ;
2024-04-14 19:31:21 +00:00
2024-03-10 21:26:43 +00:00
}
2024-04-14 19:31:21 +00:00
//HEVC Live builder
async function hevcLiveBuilder ( params ) {
2024-03-10 21:26:43 +00:00
const { resolution , fps , streamNum , inputBitrate } = params ;
const streamSuffix = streamNum == undefined ? '' : ` : ${ streamNum } ` ;
2024-04-14 05:32:46 +00:00
let targetBitrate = getTargetBitrate ( resolution , fps ) ;
// let targetBitrate = inputBitrate;
2024-03-10 21:26:43 +00:00
let shouldInitVaapi = ( streamNum == undefined || streamNum <= latestStreamNum ) ;
2024-04-14 05:32:46 +00:00
if ( targetBitrate > inputBitrate ) {
targetBitrate = inputBitrate ;
}
2024-04-14 20:32:11 +00:00
logger . info ( ` Building encoder options, received ${ JSON . stringify ( params ) } ` ) ;
2024-03-10 21:26:43 +00:00
if ( shouldInitVaapi && streamNum != undefined ) {
latestStreamNum = streamNum ;
}
2024-04-14 18:39:10 +00:00
2024-04-14 19:31:21 +00:00
let options = {
scaleFilter : {
name : 'scale'
} ,
inputOptions : shouldInitVaapi ? buildInitOptions ( ) : [ ] ,
outputOptions : [
` -tune ${ pluginSettings . liveQuality } ` ,
` -r:v ${ streamSuffix } ${ fps } ` ,
` -profile:v ${ streamSuffix } ${ pluginSettings . hevcProfile } ` ,
` -g:v ${ streamSuffix } ${ fps * 2 } ` ,
` -b:v ${ streamSuffix } ${ targetBitrate } ` ,
2024-04-14 20:12:26 +00:00
` -cq ${ pluginSettings . cqHEVC } ` ,
2024-04-14 19:31:21 +00:00
` -bufsize ${ targetBitrate * 2 } `
]
} ;
2024-04-14 18:39:10 +00:00
2024-04-14 19:31:21 +00:00
logger . info ( ` EncoderOptions: ${ JSON . stringify ( options ) } ` ) ;
return options ;
}
2024-04-14 18:39:10 +00:00
2024-04-14 19:31:21 +00:00
//H264 Live builder
2024-04-14 18:39:10 +00:00
2024-04-14 19:31:21 +00:00
async function liveBuilder ( params ) {
const { resolution , fps , streamNum , inputBitrate } = params ;
const streamSuffix = streamNum == undefined ? '' : ` : ${ streamNum } ` ;
let targetBitrate = getTargetBitrate ( resolution , fps ) ;
// let targetBitrate = inputBitrate;
let shouldInitVaapi = ( streamNum == undefined || streamNum <= latestStreamNum ) ;
if ( targetBitrate > inputBitrate ) {
targetBitrate = inputBitrate ;
2024-04-14 18:39:10 +00:00
}
2024-04-14 20:32:11 +00:00
logger . info ( ` Building encoder options, received ${ JSON . stringify ( params ) } ` ) ;
2024-04-14 19:31:21 +00:00
if ( shouldInitVaapi && streamNum != undefined ) {
latestStreamNum = streamNum ;
}
let options = {
scaleFilter : {
name : 'scale'
} ,
inputOptions : shouldInitVaapi ? buildInitOptions ( ) : [ ] ,
outputOptions : [
` -tune ${ pluginSettings . liveQuality } ` ,
` -r:v ${ streamSuffix } ${ fps } ` ,
` -profile:v ${ streamSuffix } high ` ,
2024-04-14 20:12:26 +00:00
` -cq ${ pluginSettings . cqH264 } ` ,
2024-04-14 19:31:21 +00:00
` -g:v ${ streamSuffix } ${ fps * 2 } ` ,
` -b:v ${ streamSuffix } ${ targetBitrate } ` ,
` -bufsize ${ targetBitrate * 2 } ` ,
` -bf 4 `
]
} ;
2024-03-10 21:26:43 +00:00
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