v0.0.1 released

This commit is contained in:
Ryan Ho 2023-06-30 15:47:52 +08:00
parent 23fc1c667e
commit dcddc6f60b
5 changed files with 74 additions and 98 deletions

View File

@ -1,5 +1,6 @@
MIT License MIT License
Copyright (c) 2023 Ryan He
Copyright (c) 2021 Théo Le Calvar Copyright (c) 2021 Théo Le Calvar
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy

View File

@ -1,61 +1,14 @@
# Hardware h264 encoding using vaapi # Hardware h264 encoding using NVIDIA NVENC
This plugin tries to enable hardware accelerated transcoding profiles using vaapi on linux. It should be considered experimental and tinkering will certainly be necessary to make this plugin work on your hardware. This plugin tries to enable hardware accelerated transcoding profiles using nvenc on linux. It should be considered experimental and tinkering will certainly be necessary to make this plugin work on your hardware.
For more information on vaapi and hardware acceleration: For more information on nvenc and hardware acceleration:
- https://jellyfin.org/docs/general/administration/hardware-acceleration.html#enabling-hardware-acceleration - https://jellyfin.org/docs/general/administration/hardware-acceleration.html#enabling-hardware-acceleration
- https://wiki.archlinux.org/index.php/Hardware_video_acceleration#Comparison_tables - https://wiki.archlinux.org/index.php/Hardware_video_acceleration#Comparison_tables
# Building a compatible docker image # Building and running a compatible docker image
Official docker images do not ship with required libraries for hardware transcode. - https://github.com/ryanho/peertube-hwaccel
You can build your own image with the following Dockerfile:
```Dockerfile
ARG VERSION=v4.2.0
FROM chocobozzz/peertube:${VERSION}-bullseye
# install dependencies for vaapi
RUN apt update \
&& apt install -y --no-install-recommends wget apt-transport-https \
&& echo "deb http://deb.debian.org/debian/ $( awk -F'=' '/^VERSION_CODENAME=/{ print $NF }' /etc/os-release ) non-free" | tee /etc/apt/sources.list.d/non-free.list \
&& apt update \
&& apt install -y --no-install-recommends vainfo i965-va-driver-shaders \
&& apt install -y --no-install-recommends python3 \
&& rm /var/lib/apt/lists/* -fR
```
If you are using a recent Intel CPU (generation 8 and newer), replace `i965-va-driver-shaders` by `intel-media-va-driver-non-free`.
# Running the docker image
In order to access the GPU inside docker, the `docker-compose.yml` should be adapted as follow.
Note that you must find the id of the `render` group on your machine.
You can use `grep render /etc/group | cut -d':' -f3` to find the id.
```yaml
version: "2"
services:
peertube:
# replace image key with
build:
context: .
args:
VERSION: v5.0.1
# usual peertube configuration
# ...
# add these keys
group_add:
- <replace with the id of the render group>
devices:
# VAAPI Devices
- /dev/dri:/dev/dri
```

24
package-lock.json generated
View File

@ -1,17 +1,17 @@
{ {
"name": "peertube-plugin-hardware-transcode-vaapi", "name": "peertube-plugin-hardware-transcode-nvenc",
"version": "0.2.3", "version": "0.0.1",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "peertube-plugin-hardware-transcode-vaapi", "name": "peertube-plugin-hardware-transcode-nvenc",
"version": "0.2.3", "version": "0.0.1",
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"@peertube/peertube-types": "^5.1.0", "@peertube/peertube-types": "^5.1.0",
"@tsconfig/node16": "^1.0.3", "@tsconfig/node16": "^1.0.3",
"typescript": "^5.0.4" "typescript": "^5.1.6"
} }
}, },
"node_modules/@aws-crypto/crc32": { "node_modules/@aws-crypto/crc32": {
@ -4556,16 +4556,16 @@
"dev": true "dev": true
}, },
"node_modules/typescript": { "node_modules/typescript": {
"version": "5.0.4", "version": "5.1.6",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz",
"integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==",
"dev": true, "dev": true,
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
"tsserver": "bin/tsserver" "tsserver": "bin/tsserver"
}, },
"engines": { "engines": {
"node": ">=12.20" "node": ">=14.17"
} }
}, },
"node_modules/uid-safe": { "node_modules/uid-safe": {
@ -8409,9 +8409,9 @@
"dev": true "dev": true
}, },
"typescript": { "typescript": {
"version": "5.0.4", "version": "5.1.6",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz",
"integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==",
"dev": true "dev": true
}, },
"uid-safe": { "uid-safe": {

View File

@ -1,8 +1,8 @@
{ {
"name": "peertube-plugin-hardware-transcode-vaapi", "name": "peertube-plugin-hardware-transcode-nvenc",
"version": "0.2.9", "version": "0.0.1",
"license": "MIT", "license": "MIT",
"description": "Plugin that adds transcode profiles which use vaapi for hardware acceleration", "description": "Plugin that adds transcode profiles which use NVIDIA NVENC for hardware acceleration",
"engine": { "engine": {
"peertube": ">=5.1.0" "peertube": ">=5.1.0"
}, },
@ -10,9 +10,9 @@
"peertube", "peertube",
"plugin" "plugin"
], ],
"homepage": "https://github.com/TheoLeCalvar/peertube-plugin-hardware-transcode-vaapi", "homepage": "https://github.com/ryanho/peertube-plugin-hardware-transcode-nvenc",
"author": "gdsn", "author": "ryanho",
"bugs": "https://github.com/TheoLeCalvar/peertube-plugin-hardware-transcode-vaapi", "bugs": "https://github.com/ryanho/peertube-plugin-hardware-transcode-nvenc/issues",
"library": "./dist/main.js", "library": "./dist/main.js",
"files": [ "files": [
"/dist" "/dist"
@ -30,6 +30,6 @@
"devDependencies": { "devDependencies": {
"@peertube/peertube-types": "^5.1.0", "@peertube/peertube-types": "^5.1.0",
"@tsconfig/node16": "^1.0.3", "@tsconfig/node16": "^1.0.3",
"typescript": "^5.0.4" "typescript": "^5.1.6"
} }
} }

View File

@ -6,7 +6,8 @@ let logger : Logger
let transcodingManager : PluginTranscodingManager let transcodingManager : PluginTranscodingManager
const DEFAULT_HARDWARE_DECODE : boolean = false const DEFAULT_HARDWARE_DECODE : boolean = false
const DEFAULT_QUALITY : number = -1 const DEFAULT_VOD_QUALITY : number = 15
const DEFAULT_LIVE_QUALITY : number = 7
const DEFAULT_BITRATES : Map<VideoResolution, number> = new Map([ const DEFAULT_BITRATES : Map<VideoResolution, number> = new Map([
[VideoResolution.H_NOVIDEO, 64 * 1000], [VideoResolution.H_NOVIDEO, 64 * 1000],
[VideoResolution.H_144P, 320 * 1000], [VideoResolution.H_144P, 320 * 1000],
@ -20,12 +21,14 @@ const DEFAULT_BITRATES : Map<VideoResolution, number> = new Map([
interface PluginSettings { interface PluginSettings {
hardwareDecode : boolean hardwareDecode : boolean
quality: number vodQuality: number
liveQuality: number
baseBitrate: Map<VideoResolution, number> baseBitrate: Map<VideoResolution, number>
} }
let pluginSettings : PluginSettings = { let pluginSettings : PluginSettings = {
hardwareDecode: DEFAULT_HARDWARE_DECODE, hardwareDecode: DEFAULT_HARDWARE_DECODE,
quality: DEFAULT_QUALITY, vodQuality: DEFAULT_VOD_QUALITY,
liveQuality: DEFAULT_LIVE_QUALITY,
baseBitrate: new Map(DEFAULT_BITRATES) baseBitrate: new Map(DEFAULT_BITRATES)
} }
@ -37,8 +40,8 @@ export async function register({settingsManager, peertubeHelpers, transcodingMan
logger.info("Registering peertube-plugin-hardware-encode"); logger.info("Registering peertube-plugin-hardware-encode");
const encoder = 'h264_vaapi' const encoder = 'h264_nvenc'
const profileName = 'vaapi' const profileName = 'nvenc'
// Add trasncoding profiles // Add trasncoding profiles
transcodingManager.addVODProfile(encoder, profileName, vodBuilder) transcodingManager.addVODProfile(encoder, profileName, vodBuilder)
@ -62,24 +65,40 @@ export async function register({settingsManager, peertubeHelpers, transcodingMan
private: false private: false
}) })
registerSetting({ registerSetting({
name: 'quality', name: 'vod-quality',
label: 'Quality', label: 'VOD Quality',
type: 'select', type: 'select',
options: [ options: [
{ label: 'Automatic', value: '-1' }, { label: 'fastest', value: '12' },
{ label: '1', value: '1' }, { label: 'faster', value: '13' },
{ label: '2', value: '2' }, { label: 'fast', value: '14' },
{ label: '3', value: '3' }, { label: 'medium (default)', value: '15' },
{ label: '4', value: '4' }, { label: 'slow', value: '16' },
{ label: '5', value: '5' }, { label: 'slower', value: '17' },
{ label: '6', value: '6' }, { label: 'slowest', value: '18' }
{ label: '7', value: '7' }
], ],
descriptionHTML: 'This parameter controls the speed / quality tradeoff. Lower values mean better quality but slower encoding. Higher values mean faster encoding but lower quality. This setting is hardware dependent, you may need to experiment to find the best value for your hardware. Some hardware may have less than 7 levels of compression.', 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_QUALITY.toString(), default: DEFAULT_VOD_QUALITY.toString(),
private: false
})
registerSetting({
name: 'live-quality',
label: 'Live Quality',
type: 'select',
options: [
{ label: 'low latency (default)', value: '7' },
{ label: 'low latency high quality', value: '8' },
{ label: 'low latency high performance', value: '9' }
],
descriptionHTML: 'This parameter controls the speed / quality tradeoff. High performance mean lower quality.',
default: DEFAULT_LIVE_QUALITY.toString(),
private: false private: false
}) })
@ -121,7 +140,8 @@ export async function unregister() {
async function loadSettings(settingsManager: PluginSettingsManager) { async function loadSettings(settingsManager: PluginSettingsManager) {
pluginSettings.hardwareDecode = await settingsManager.getSetting('hardware-decode') == "true" pluginSettings.hardwareDecode = await settingsManager.getSetting('hardware-decode') == "true"
pluginSettings.quality = parseInt(await settingsManager.getSetting('quality') as string) || DEFAULT_QUALITY pluginSettings.vodQuality = parseInt(await settingsManager.getSetting('vod-quality') as string) || DEFAULT_VOD_QUALITY
pluginSettings.liveQuality = parseInt(await settingsManager.getSetting('live-quality') as string) || DEFAULT_LIVE_QUALITY
for (const [resolution, bitrate] of DEFAULT_BITRATES) { for (const [resolution, bitrate] of DEFAULT_BITRATES) {
const key = `base-bitrate-${resolution}` const key = `base-bitrate-${resolution}`
@ -131,7 +151,8 @@ async function loadSettings(settingsManager: PluginSettingsManager) {
} }
logger.info(`Hardware decode: ${pluginSettings.hardwareDecode}`) logger.info(`Hardware decode: ${pluginSettings.hardwareDecode}`)
logger.info(`Quality: ${pluginSettings.quality}`) logger.info(`VOD Quality: ${pluginSettings.vodQuality}`)
logger.info(`Live Quality: ${pluginSettings.liveQuality}`)
} }
function printResolution(resolution : VideoResolution) : string { function printResolution(resolution : VideoResolution) : string {
@ -153,13 +174,12 @@ function printResolution(resolution : VideoResolution) : string {
function buildInitOptions() { function buildInitOptions() {
if (pluginSettings.hardwareDecode) { if (pluginSettings.hardwareDecode) {
return [ return [
'-hwaccel vaapi', '-hwaccel cuda',
'-vaapi_device /dev/dri/renderD128', '-hwaccel_output_format cuda'
'-hwaccel_output_format vaapi',
] ]
} else { } else {
return [ return [
'-vaapi_device /dev/dri/renderD128' '-hwaccel cuda'
] ]
} }
} }
@ -183,11 +203,12 @@ async function vodBuilder(params: EncoderOptionsBuilderParams) : Promise<Encoder
let options : EncoderOptions = { let options : EncoderOptions = {
scaleFilter: { scaleFilter: {
// software decode requires specifying pixel format for hardware filter and upload it to GPU // software decode requires specifying pixel format for hardware filter and upload it to GPU
name: pluginSettings.hardwareDecode ? 'scale_vaapi' : 'format=nv12,hwupload,scale_vaapi' // name: pluginSettings.hardwareDecode ? 'scale_vaapi' : 'format=nv12,hwupload,scale_vaapi'
name: 'scale'
}, },
inputOptions: shouldInitVaapi ? buildInitOptions() : [], inputOptions: shouldInitVaapi ? buildInitOptions() : [],
outputOptions: [ outputOptions: [
`-quality ${pluginSettings.quality}`, `-preset ${pluginSettings.vodQuality}`,
`-b:v${streamSuffix} ${targetBitrate}`, `-b:v${streamSuffix} ${targetBitrate}`,
`-bufsize ${targetBitrate * 2}` `-bufsize ${targetBitrate * 2}`
] ]
@ -216,11 +237,12 @@ async function liveBuilder(params: EncoderOptionsBuilderParams) : Promise<Encode
// You can also return a promise // You can also return a promise
const options = { const options = {
scaleFilter: { scaleFilter: {
name: pluginSettings.hardwareDecode ? 'scale_vaapi' : 'format=nv12,hwupload,scale_vaapi' // name: pluginSettings.hardwareDecode ? 'scale_vaapi' : 'format=nv12,hwupload,scale_vaapi'
name: 'scale'
}, },
inputOptions: shouldInitVaapi ? buildInitOptions() : [], inputOptions: shouldInitVaapi ? buildInitOptions() : [],
outputOptions: [ outputOptions: [
`-quality ${pluginSettings.quality}`, `-preset ${pluginSettings.liveQuality}`,
`-r:v${streamSuffix} ${fps}`, `-r:v${streamSuffix} ${fps}`,
`-profile:v${streamSuffix} high`, `-profile:v${streamSuffix} high`,
`-level:v${streamSuffix} 3.1`, `-level:v${streamSuffix} 3.1`,