Remote Runners Hardware Acceleration #5213

Open
opened 2026-02-22 11:14:23 -05:00 by deekerman · 37 comments
Owner

Originally created by @MattyBoombalatty on GitHub (Nov 20, 2023).

Describe the problem to be solved

Remote runners are great, but they could be better.

Describe the solution you would like

Some people may use remote runners for transcoding, so if those runners utilize graphics cards or other hardware that could accelerate transcoding, it would be good to be able to add a configuration option to the .toml file to pass flags to FFMPEG to enable hardware acceleration.

Originally created by @MattyBoombalatty on GitHub (Nov 20, 2023). ### Describe the problem to be solved Remote runners are great, but they could be better. ### Describe the solution you would like Some people may use remote runners for transcoding, so if those runners utilize graphics cards or other hardware that could accelerate transcoding, it would be good to be able to add a configuration option to the `.toml` file to pass flags to FFMPEG to enable hardware acceleration.
Author
Owner

@kodxana commented on GitHub (Nov 23, 2023):

Was thinking at the same thing would love to have support for quick sync support.

@kodxana commented on GitHub (Nov 23, 2023): Was thinking at the same thing would love to have support for quick sync support.
Author
Owner

@normen commented on GitHub (Nov 28, 2023):

For a quick workaround hack you can "intercept" the runners command by just placing a bash script / bat file called ffmpeg in the path of the runner, which it will then use as if it was the real ffmpeg. Then you can modify what it does.

For example I wanted to remove the scaling:

#!/usr/bin/env bash
arguments="$@"
pattern='(.*) -vcodec copy (.*) -vf scale[^ ]* (.*)'
if [[ "$arguments" =~ $pattern ]];then
  command_str="/usr/bin/ffmpeg ${BASH_REMATCH[1]} -vcodec copy ${BASH_REMATCH[2]} ${BASH_REMATCH[3]}"
  $command_str
else
  /usr/bin/ffmpeg $@
fi
@normen commented on GitHub (Nov 28, 2023): For a quick workaround hack you can "intercept" the runners command by just placing a bash script / bat file called `ffmpeg` in the path of the runner, which it will then use as if it was the real ffmpeg. Then you can modify what it does. For example I wanted to remove the scaling: ```bash #!/usr/bin/env bash arguments="$@" pattern='(.*) -vcodec copy (.*) -vf scale[^ ]* (.*)' if [[ "$arguments" =~ $pattern ]];then command_str="/usr/bin/ffmpeg ${BASH_REMATCH[1]} -vcodec copy ${BASH_REMATCH[2]} ${BASH_REMATCH[3]}" $command_str else /usr/bin/ffmpeg $@ fi ```
Author
Owner

@MattyBoombalatty commented on GitHub (Dec 1, 2023):

Cool idea, but I wouldn't know how to do this. If you could provide a short guide I'd appreciate it!

@MattyBoombalatty commented on GitHub (Dec 1, 2023): Cool idea, but I wouldn't know how to do this. If you could provide a short guide I'd appreciate it!
Author
Owner

@normen commented on GitHub (Dec 2, 2023):

I don't know how your setup looks but you could put that above script into your /usr/local/bin folder as a file called ffmpeg and make it executable (chmod +x). Then peertube-runner will call that script instead when it wants to execute ffmpeg. What it currently does is take the arguments that peertube-runner sends and change them. If you just want to change the "-vcodec libx264" part for example it would look something like this:

#!/usr/bin/env bash
# get arguments into variable
arguments="$@"
# create regex pattern to split up arguments
pattern='(.*) -vcodec libx264 (.*)'
# do pattern search
if [[ "$arguments" =~ $pattern ]];then
  # construct new command from (.*) parts (BASH_REMATCH)
  command_str="/usr/bin/ffmpeg ${BASH_REMATCH[1]} -vcodec h264_nvenc ${BASH_REMATCH[2]}"
  # execute new command
  $command_str
else
  # just execute ffmpeg with arguments if the pattern wasn't found
  /usr/bin/ffmpeg $@
fi
@normen commented on GitHub (Dec 2, 2023): I don't know how your setup looks but you could put that above script into your `/usr/local/bin` folder as a file called `ffmpeg` and make it executable (`chmod +x`). Then peertube-runner will call that script instead when it wants to execute ffmpeg. What it currently does is take the arguments that peertube-runner sends and change them. If you just want to change the "-vcodec libx264" part for example it would look something like this: ```bash #!/usr/bin/env bash # get arguments into variable arguments="$@" # create regex pattern to split up arguments pattern='(.*) -vcodec libx264 (.*)' # do pattern search if [[ "$arguments" =~ $pattern ]];then # construct new command from (.*) parts (BASH_REMATCH) command_str="/usr/bin/ffmpeg ${BASH_REMATCH[1]} -vcodec h264_nvenc ${BASH_REMATCH[2]}" # execute new command $command_str else # just execute ffmpeg with arguments if the pattern wasn't found /usr/bin/ffmpeg $@ fi ```
Author
Owner

@MattyBoombalatty commented on GitHub (Dec 2, 2023):

That's a pretty interesting way to do it. I don't do much with regex or really bash scripting, but I'll definitely keep this in mind and test it as well. Thank you!

@MattyBoombalatty commented on GitHub (Dec 2, 2023): That's a pretty interesting way to do it. I don't do much with regex or really bash scripting, but I'll definitely keep this in mind and test it as well. Thank you!
Author
Owner

@MattyBoombalatty commented on GitHub (Dec 3, 2023):

I tried many variations of this, including creating a wrapper in /usr/local/bin/, creating an alias and so on and so forth but to no avail.. It works when I manually enter the FFMPEG command (libx264 is changed to h264_nvenc automatically), but for some reason it is just not working with the PeerTube runner. I wonder if the fluent-ffmpeg NPM package handles the commands differently.

@MattyBoombalatty commented on GitHub (Dec 3, 2023): I tried many variations of this, including creating a wrapper in `/usr/local/bin/`, creating an alias and so on and so forth but to no avail.. It works when I manually enter the FFMPEG command (libx264 is changed to h264_nvenc automatically), but for some reason it is just not working with the PeerTube runner. I wonder if the `fluent-ffmpeg` NPM package handles the commands differently.
Author
Owner

@normen commented on GitHub (Dec 3, 2023):

Hm, I have this working on a linux machine but I didn't update the runner in a while.. Did you also try to replace the actual /usr/bin/ffmpeg? Just to see if the runner doesn't by now use its own packaged ffmpeg or something?

Edit: Also I think it picked it up if it was in the same folder I run peertube-runner from..

@normen commented on GitHub (Dec 3, 2023): Hm, I have this working on a linux machine but I didn't update the runner in a while.. Did you also try to replace the actual `/usr/bin/ffmpeg`? Just to see if the runner doesn't by now use its own packaged ffmpeg or something? Edit: Also I think it picked it up if it was in the same folder I run peertube-runner from..
Author
Owner

@MattyBoombalatty commented on GitHub (Dec 3, 2023):

I tried that, and then had it reference another ffmpeg binary but that didn't work. At the moment I'm looking through the peertube-runner NPM module and seeing if I can edit the -vcodec flag manually so that it's just passed to FFMPEG as the required flag rather than trying to rig it another way. Probably best to edit the source and maybe fork it. My JavaScript is a little rusty :)

86694 function getDefaultEncodersToTry() {
86695   return {
86696     vod: {
86697       video: ["libx264"],
86698       audio: ["libfdk_aac", "aac"]
86699     },
86700     live: {
86701       video: ["libx264"],
86702       audio: ["libfdk_aac", "aac"]
86703     }
86704   };
@MattyBoombalatty commented on GitHub (Dec 3, 2023): I tried that, and then had it reference another ffmpeg binary but that didn't work. At the moment I'm looking through the `peertube-runner` NPM module and seeing if I can edit the `-vcodec` flag manually so that it's just passed to FFMPEG as the required flag rather than trying to rig it another way. Probably best to edit the source and maybe fork it. My JavaScript is a little rusty :) ``` 86694 function getDefaultEncodersToTry() { 86695 return { 86696 vod: { 86697 video: ["libx264"], 86698 audio: ["libfdk_aac", "aac"] 86699 }, 86700 live: { 86701 video: ["libx264"], 86702 audio: ["libfdk_aac", "aac"] 86703 } 86704 }; ```
Author
Owner

@MattyBoombalatty commented on GitHub (Dec 4, 2023):

@normen , what node version are you using for the PeerTube runner? If your intercept works I'd like to try it with your version.

@MattyBoombalatty commented on GitHub (Dec 4, 2023): @normen , what node version are you using for the PeerTube runner? If your intercept works I'd like to try it with your version.
Author
Owner

@normen commented on GitHub (Dec 5, 2023):

That would be peertube-runner 0.0.5 on node 18 on that machine.

@normen commented on GitHub (Dec 5, 2023): That would be peertube-runner 0.0.5 on node 18 on that machine.
Author
Owner

@MattyBoombalatty commented on GitHub (Dec 5, 2023):

I tried downgrading but unfortunately that didn't work. It looks like the PeerTube runner has its own FFMPEG integration, so I think the settings would have to be changed/added within the runner JavaScript file.

@MattyBoombalatty commented on GitHub (Dec 5, 2023): I tried downgrading but unfortunately that didn't work. It looks like the PeerTube runner has its own FFMPEG integration, so I think the settings would have to be changed/added within the runner JavaScript file.
Author
Owner

@normen commented on GitHub (Dec 5, 2023):

Thats strange, you sure you're not running in some docker environment or something? I see no trace of any ffmpeg on that machine except the system installed ones. peertube-runner instantly fails when theres no ffmpeg installed.

@normen commented on GitHub (Dec 5, 2023): Thats strange, you sure you're not running in some docker environment or something? I see no trace of any ffmpeg on that machine except the system installed ones. peertube-runner instantly fails when theres no ffmpeg installed.
Author
Owner

@MattyBoombalatty commented on GitHub (Dec 5, 2023):

Nope, no crazy weird environments. Just Ubuntu. Perhaps I'm missing something I was supposed to do with FFMPEG? Maybe I had to compile it? I have no idea. When I send a test command to FFMPEG it works fine and redirects to using hardware acceleration but when it comes from the runner, it doesn't. I don't know how that's possible because in theory the interception should come after the runner builds the command, right?

@MattyBoombalatty commented on GitHub (Dec 5, 2023): Nope, no crazy weird environments. Just Ubuntu. Perhaps I'm missing something I was supposed to do with FFMPEG? Maybe I had to compile it? I have no idea. When I send a test command to FFMPEG it works fine and redirects to using hardware acceleration but when it comes from the runner, it doesn't. I don't know how that's possible because in theory the interception should come after the runner builds the command, right?
Author
Owner

@Chocobozzz commented on GitHub (Dec 6, 2023):

Hi,

To use a custom ffmpeg command you can set FFMPEG_PATH and FFPROBE_PATH environment variables when running peertube runner in server mode.

@Chocobozzz commented on GitHub (Dec 6, 2023): Hi, To use a custom ffmpeg command you can set `FFMPEG_PATH` and `FFPROBE_PATH` environment variables when running peertube runner in server mode.
Author
Owner

@MattyBoombalatty commented on GitHub (Dec 6, 2023):

In that case, we'd have to compile FFMPEG with the rule enabled? I'll try just using the script as the path, see what happens.

@MattyBoombalatty commented on GitHub (Dec 6, 2023): In that case, we'd have to compile FFMPEG with the rule enabled? I'll try just using the script as the path, see what happens.
Author
Owner

@MattyBoombalatty commented on GitHub (Dec 6, 2023):

Tried adding this to ~/.bashrc but it didn't seem to work. Still being encoded with libx264.

export FFMPEG_PATH='/usr/bin/ffmpeg -vcodec h264_nvenc'

@MattyBoombalatty commented on GitHub (Dec 6, 2023): Tried adding this to `~/.bashrc` but it didn't seem to work. Still being encoded with `libx264`. `export FFMPEG_PATH='/usr/bin/ffmpeg -vcodec h264_nvenc'`
Author
Owner

@normen commented on GitHub (Dec 6, 2023):

Tried adding this to ~/.bashrc but it didn't seem to work. Still being encoded with libx264.

export FFMPEG_PATH='/usr/bin/ffmpeg -vcodec h264_nvenc'

Nah, you have to set FFMPEG_PATH to the location of your script (e.g. /usr/local/bin/ffmpeg)

@normen commented on GitHub (Dec 6, 2023): > Tried adding this to `~/.bashrc` but it didn't seem to work. Still being encoded with `libx264`. > > `export FFMPEG_PATH='/usr/bin/ffmpeg -vcodec h264_nvenc'` Nah, you have to set FFMPEG_PATH to the location of your script (e.g. `/usr/local/bin/ffmpeg`)
Author
Owner

@MattyBoombalatty commented on GitHub (Dec 6, 2023):

I finally got the transcoding redirection to work, and the HLS videos transcode correctly but the web-video runner job does not complete correctly, and an error from ffprobe is given that it cannot find the moov atom. I'll post the script and error below.

Error:

[mov,mp4,m4a,3gp,3g2,mj2 @ 0x564d944d6ec0] Format mov,mp4,m4a,3gp,3g2,mj2 detected only with low score of 1, misdetection possible!
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x564d944d6ec0] moov atom not found

Script which is located at /usr/bin/ffmpeg

#!/bin/bash

# Path to the original ffmpeg binary
ORIGINAL_FFMPEG="/usr/bin/ffmpeg.bak"

# Log all output to a file
log_file="/var/log/ffmpeg/exec.log"
exec > >(tee -a "$log_file")
exec 2>&1

# Intercept the command-line arguments
input_command=("$@")

# Log the original command to syslog
logger "Original Command: ${input_command[*]}"

# Find the index of the video codec option ("-vcodec")
codec_index=-1

for ((i=0; i<${#input_command[@]}; i++)); do
    if [[ "${input_command[i]}" == "-vcodec" ]]; then
        codec_index=$i
        break
    fi
done

# If video codec option is found, replace it with h264_nvenc
if [ $codec_index -ne -1 ]; then
    input_command[$((codec_index + 1))]="h264_nvenc"
fi

# Find the index of the preset option ("-preset")
preset_index=-1

for ((i=0; i<${#input_command[@]}; i++)); do
    if [[ "${input_command[i]}" == "-preset" && "${input_command[i+1]}" == "veryfast" ]]; then
        preset_index=$i
        break
    fi
done

# If preset option is found, replace it with medium
if [ $preset_index -ne -1 ]; then
    input_command[$preset_index + 1]="medium"
fi

# Find the index of the output file option
output_index=-1

for ((i=0; i<${#input_command[@]}; i++)); do
    if [[ "${input_command[i]}" == "-hls_segment_filename" ]]; then
        output_index=$i
        break
    fi
done

# Add -bf 4 and -gpu 0 options before the output file
if [ $output_index -ne -1 ]; then
    input_command=("${input_command[@]:0:$output_index}" "-bf" "4" "-gpu" "0" "${input_command[@]:$output_index}")
fi

# Log the modified command to syslog
logger "Modified Command: ${input_command[*]}"

# Execute the modified command with the original ffmpeg binary
eval "$ORIGINAL_FFMPEG ${input_command[*]}" 2>&1 | tee -a "$log_file"
@MattyBoombalatty commented on GitHub (Dec 6, 2023): I finally got the transcoding redirection to work, and the HLS videos transcode correctly but the `web-video` runner job does not complete correctly, and an error from `ffprobe` is given that it cannot find the `moov` atom. I'll post the script and error below. Error: ``` [mov,mp4,m4a,3gp,3g2,mj2 @ 0x564d944d6ec0] Format mov,mp4,m4a,3gp,3g2,mj2 detected only with low score of 1, misdetection possible! [mov,mp4,m4a,3gp,3g2,mj2 @ 0x564d944d6ec0] moov atom not found ``` Script which is located at `/usr/bin/ffmpeg` ``` #!/bin/bash # Path to the original ffmpeg binary ORIGINAL_FFMPEG="/usr/bin/ffmpeg.bak" # Log all output to a file log_file="/var/log/ffmpeg/exec.log" exec > >(tee -a "$log_file") exec 2>&1 # Intercept the command-line arguments input_command=("$@") # Log the original command to syslog logger "Original Command: ${input_command[*]}" # Find the index of the video codec option ("-vcodec") codec_index=-1 for ((i=0; i<${#input_command[@]}; i++)); do if [[ "${input_command[i]}" == "-vcodec" ]]; then codec_index=$i break fi done # If video codec option is found, replace it with h264_nvenc if [ $codec_index -ne -1 ]; then input_command[$((codec_index + 1))]="h264_nvenc" fi # Find the index of the preset option ("-preset") preset_index=-1 for ((i=0; i<${#input_command[@]}; i++)); do if [[ "${input_command[i]}" == "-preset" && "${input_command[i+1]}" == "veryfast" ]]; then preset_index=$i break fi done # If preset option is found, replace it with medium if [ $preset_index -ne -1 ]; then input_command[$preset_index + 1]="medium" fi # Find the index of the output file option output_index=-1 for ((i=0; i<${#input_command[@]}; i++)); do if [[ "${input_command[i]}" == "-hls_segment_filename" ]]; then output_index=$i break fi done # Add -bf 4 and -gpu 0 options before the output file if [ $output_index -ne -1 ]; then input_command=("${input_command[@]:0:$output_index}" "-bf" "4" "-gpu" "0" "${input_command[@]:$output_index}") fi # Log the modified command to syslog logger "Modified Command: ${input_command[*]}" # Execute the modified command with the original ffmpeg binary eval "$ORIGINAL_FFMPEG ${input_command[*]}" 2>&1 | tee -a "$log_file" ```
Author
Owner

@MattyBoombalatty commented on GitHub (Dec 6, 2023):

Never mind, I found the issue. I had to make sure that the -bf 4 and -gpu 0 switches were added after the -g:v [value] rather than after the -hls_segment_filename switch since the web-videos don't contain that. It works now. However I think it would definitely be cool to have native support for this.

@MattyBoombalatty commented on GitHub (Dec 6, 2023): Never mind, I found the issue. I had to make sure that the `-bf 4` and `-gpu 0` switches were added after the `-g:v [value]` rather than after the `-hls_segment_filename` switch since the `web-videos` don't contain that. It works now. However I think it would definitely be cool to have native support for this.
Author
Owner

@MattyBoombalatty commented on GitHub (Dec 6, 2023):

It works for VODs, but not livestreams. This was the final script I came up with and the RTMP errors I got when trying to use it. So close to getting it to work.

Script:

#!/bin/bash

# Path to the original ffmpeg binary
ORIGINAL_FFMPEG="/usr/bin/ffmpeg"

# Log all output to a file
log_file="/var/log/ffmpeg/exec.log"
exec > >(tee -a "$log_file")
exec 2>&1

# Intercept the command-line arguments
input_command=("$@")

# Log the original command to syslog
logger "Original Command: ${input_command[*]}"

# Find the index of the video codec option ("-vcodec")
codec_index=-1

for ((i=0; i<${#input_command[@]}; i++)); do
    if [[ "${input_command[i]}" == "-vcodec" ]]; then
        codec_index=$i
        break
    fi
done

# If video codec option is found, replace it with h264_nvenc
if [ $codec_index -ne -1 ]; then
    input_command[$((codec_index + 1))]="h264_nvenc"
fi

# Find the index of the preset option ("-preset")
preset_index=-1

for ((i=0; i<${#input_command[@]}; i++)); do
    if [[ "${input_command[i]}" == "-preset" && "${input_command[i+1]}" == "veryfast" ]]; then
        preset_index=$i
        break
    fi
done

# If preset option is found, replace it with medium
if [ $preset_index -ne -1 ]; then
    input_command[$preset_index + 1]="medium"
fi

# Find the index of the output file option
output_index=-1

for ((i=0; i<${#input_command[@]}; i++)); do
    if [[ "${input_command[i]}" == "-g:v" ]]; then
        output_index=$i
        break
    fi
done

# Add -bf 4 and -gpu 0 options after -g:v value
if [ $output_index -ne -1 ]; then
    input_command=("${input_command[@]:0:$output_index+2}" "-bf" "4" "-gpu" "0" "${input_command[@]:$output_index+2}")
fi

# Log the modified command to syslog
logger "Modified Command: ${input_command[*]}"

# Execute the modified command with the original ffmpeg binary
eval "$ORIGINAL_FFMPEG ${input_command[*]}" 2>&1 | tee -a "$log_file"

RTMP errors:

Filter split has an unconnected output
Filter split has an unconnected output
/usr/local/bin/ffmpeg: line 57: [vtemp960]scale=w=-2:h=960[vout960]: command not found
/usr/local/bin/ffmpeg: line 57: [vtemp960]scale=w=-2:h=960[vout960]: command not found
@MattyBoombalatty commented on GitHub (Dec 6, 2023): It works for VODs, but not livestreams. This was the final script I came up with and the RTMP errors I got when trying to use it. So close to getting it to work. Script: ``` #!/bin/bash # Path to the original ffmpeg binary ORIGINAL_FFMPEG="/usr/bin/ffmpeg" # Log all output to a file log_file="/var/log/ffmpeg/exec.log" exec > >(tee -a "$log_file") exec 2>&1 # Intercept the command-line arguments input_command=("$@") # Log the original command to syslog logger "Original Command: ${input_command[*]}" # Find the index of the video codec option ("-vcodec") codec_index=-1 for ((i=0; i<${#input_command[@]}; i++)); do if [[ "${input_command[i]}" == "-vcodec" ]]; then codec_index=$i break fi done # If video codec option is found, replace it with h264_nvenc if [ $codec_index -ne -1 ]; then input_command[$((codec_index + 1))]="h264_nvenc" fi # Find the index of the preset option ("-preset") preset_index=-1 for ((i=0; i<${#input_command[@]}; i++)); do if [[ "${input_command[i]}" == "-preset" && "${input_command[i+1]}" == "veryfast" ]]; then preset_index=$i break fi done # If preset option is found, replace it with medium if [ $preset_index -ne -1 ]; then input_command[$preset_index + 1]="medium" fi # Find the index of the output file option output_index=-1 for ((i=0; i<${#input_command[@]}; i++)); do if [[ "${input_command[i]}" == "-g:v" ]]; then output_index=$i break fi done # Add -bf 4 and -gpu 0 options after -g:v value if [ $output_index -ne -1 ]; then input_command=("${input_command[@]:0:$output_index+2}" "-bf" "4" "-gpu" "0" "${input_command[@]:$output_index+2}") fi # Log the modified command to syslog logger "Modified Command: ${input_command[*]}" # Execute the modified command with the original ffmpeg binary eval "$ORIGINAL_FFMPEG ${input_command[*]}" 2>&1 | tee -a "$log_file" ``` RTMP errors: ``` Filter split has an unconnected output Filter split has an unconnected output /usr/local/bin/ffmpeg: line 57: [vtemp960]scale=w=-2:h=960[vout960]: command not found /usr/local/bin/ffmpeg: line 57: [vtemp960]scale=w=-2:h=960[vout960]: command not found ```
Author
Owner

@MattyBoombalatty commented on GitHub (Dec 7, 2023):

I have an updated script that works pretty well. But, does not work well with the remote studio. The quality gets all messed up.

@MattyBoombalatty commented on GitHub (Dec 7, 2023): I have an updated script that works pretty well. But, does not work well with the remote studio. The quality gets all messed up.
Author
Owner

@emansom commented on GitHub (Apr 10, 2024):

Working on this: emansom/PeerTube@932c2336ae in the branch emansom/PeerTube@feature/ffmpeg-hwaccel.

I'll open a PR once I've integrated it within the admin web UI and once it's working with multiple vendors. Currently i've only tested it on Intel and AMD using VAAPI acceleration. I plan on supporting VAAPI initially, NVENC and QSV later.

ETA until PR is about one month from now.

NVENC and QSV will come later as I currently do not have any NVIDIA GPU nor Intel Core Gen 8+ hardware to test with.

@emansom commented on GitHub (Apr 10, 2024): Working on this: emansom/PeerTube@932c2336ae175562b59e3c5077e3d1c44215b1d6 in the branch [emansom/PeerTube@feature/ffmpeg-hwaccel](https://github.com/emansom/PeerTube/tree/feature/ffmpeg-hwaccel/apps/peertube-runner). I'll open a PR once I've integrated it within the admin web UI and once it's working with multiple vendors. Currently i've only tested it on Intel and AMD using VAAPI acceleration. I plan on supporting VAAPI initially, NVENC and QSV later. ETA until PR is about one month from now. NVENC and QSV will come later as I currently do not have any NVIDIA GPU nor Intel Core Gen 8+ hardware to test with.
Author
Owner

@SimplyCorbett commented on GitHub (May 3, 2024):

@emansom

What's the status on this? I'd like to setup some remote runners on some orange pis and use the built in hardware acceleration on the GPU. (mostly to tinker with / see how it works in production).

They use a different encoder though but I don't mind modifying files to get things working.

@SimplyCorbett commented on GitHub (May 3, 2024): @emansom What's the status on this? I'd like to setup some remote runners on some orange pis and use the built in hardware acceleration on the GPU. (mostly to tinker with / see how it works in production). They use a different encoder though but I don't mind modifying files to get things working.
Author
Owner

@emansom commented on GitHub (May 3, 2024):

@emansom

What's the status on this? I'd like to setup some remote runners on some orange pis and use the built in hardware acceleration on the GPU. (mostly to tinker with / see how it works in production).

They use a different encoder though but I don't mind modifying files to get things working.

I've run into some hardware QoS problems. My current workstation has an i7-4790 and RX 580. Both have too slow hardware encoders to test things at reasonable speed.

At the end of this month I'll be building a more modern AM5 based system. RDNA2/RDNA3 comes with improved hardware encoders, which I hope are fast enough to iterate, test and develop with.

The branch I linked is in a functional state, as long as you're comfortable with tweaking it yourself you can give it a go.

@emansom commented on GitHub (May 3, 2024): > @emansom > > What's the status on this? I'd like to setup some remote runners on some orange pis and use the built in hardware acceleration on the GPU. (mostly to tinker with / see how it works in production). > > They use a different encoder though but I don't mind modifying files to get things working. I've run into some hardware QoS problems. My current workstation has an i7-4790 and RX 580. Both have too slow hardware encoders to test things at reasonable speed. At the end of this month I'll be building a more modern AM5 based system. RDNA2/RDNA3 comes with improved hardware encoders, which I hope are fast enough to iterate, test and develop with. The branch I linked is in a functional state, as long as you're comfortable with tweaking it yourself you can give it a go.
Author
Owner

@kanoriano commented on GitHub (Jan 7, 2025):

Working on this: emansom/PeerTube@932c233 in the branch emansom/PeerTube@feature/ffmpeg-hwaccel.

I'll open a PR once I've integrated it within the admin web UI and once it's working with multiple vendors. Currently i've only tested it on Intel and AMD using VAAPI acceleration. I plan on supporting VAAPI initially, NVENC and QSV later.

ETA until PR is about one month from now.

NVENC and QSV will come later as I currently do not have any NVIDIA GPU nor Intel Core Gen 8+ hardware to test with.

I hope everything will work out. The ffmpeg launch scripts described above did not help to process the video.

Regarding h264_nvenc processing, I can say that the plugin hardware-transcode-nvenc works great on peertube host machine with gpu. And the most incredible thing is that with forced hevc_nvenc codec my GTX970 video card transcodes video without errors and that plays normally in chrome browser. Unfortunately I didn't know that hevc is not supported modern browsers..

My build is on proxmox. Separate containers postgres, redis, prometheus, nginx proxy manager, peertube. On a separate virtual machine with passthru gpu remote-runner. And I noticed that in this configuration peertube is almost not loaded storage server 😄 This is ideal. All that remains is to replace old maxwell gpu with pascal+ for 10bit encode/decode boost.

@kanoriano commented on GitHub (Jan 7, 2025): > Working on this: [emansom/PeerTube@932c233](https://github.com/emansom/PeerTube/commit/932c2336ae175562b59e3c5077e3d1c44215b1d6) in the branch [emansom/PeerTube@feature/ffmpeg-hwaccel](https://github.com/emansom/PeerTube/tree/feature/ffmpeg-hwaccel/apps/peertube-runner). > > I'll open a PR once I've integrated it within the admin web UI and once it's working with multiple vendors. Currently i've only tested it on Intel and AMD using VAAPI acceleration. I plan on supporting VAAPI initially, NVENC and QSV later. > > ETA until PR is about one month from now. > > NVENC and QSV will come later as I currently do not have any NVIDIA GPU nor Intel Core Gen 8+ hardware to test with. I hope everything will work out. The ffmpeg launch scripts described above did not help to process the video. Regarding h264_nvenc processing, I can say that the plugin [hardware-transcode-nvenc](https://github.com/ryanho/peertube-plugin-hardware-transcode-nvenc) works great on peertube host machine with gpu. And the most incredible thing is that with forced hevc_nvenc codec my GTX970 video card transcodes video without errors and that plays normally in chrome browser. Unfortunately I didn't know that hevc is not supported modern browsers.. My build is on proxmox. Separate containers postgres, redis, prometheus, nginx proxy manager, peertube. On a separate virtual machine with passthru gpu remote-runner. And I noticed that in this configuration peertube is almost not loaded storage server 😄 This is ideal. All that remains is to replace old maxwell gpu with pascal+ for 10bit encode/decode boost.
Author
Owner

@frenzybiscuit commented on GitHub (Jan 8, 2025):

Unfortunately I didn't know that hevc is not supported modern browsers..

I thought this changed and HEVC is supported on all major browsers now?

https://caniuse.com/hevc

So every major browser other then firefox.

@frenzybiscuit commented on GitHub (Jan 8, 2025): > Unfortunately I didn't know that hevc is not supported modern browsers.. I thought this changed and HEVC is supported on all major browsers now? https://caniuse.com/hevc So every major browser other then firefox.
Author
Owner

@frenzybiscuit commented on GitHub (Jan 8, 2025):

@Chocobozzz I know you intend for peertube to be accessible for the masses but hardware encoding really is a basic feature that should be implemented on the remote runners.

Most modern CPUs now have integrated graphics and can hardware accelerate videos without any fancy dedicated graphic cards.

@kanoriano you don't need that plugin. You can use the transcoding profile debug plugin and use basically any setting (including hardware transcoding) on the host node. Doesn't help you with the remote runners though.

@frenzybiscuit commented on GitHub (Jan 8, 2025): @Chocobozzz I know you intend for peertube to be accessible for the masses but hardware encoding really is a basic feature that should be implemented on the remote runners. Most modern CPUs now have integrated graphics and can hardware accelerate videos without any fancy dedicated graphic cards. @kanoriano you don't need that plugin. You can use the transcoding profile debug plugin and use basically any setting (including hardware transcoding) on the host node. Doesn't help you with the remote runners though.
Author
Owner

@piotr-sikora-v commented on GitHub (Feb 2, 2025):

BTW if you add to ffmpeg -hwaccel cuda -hwaccel_output_format cuda you will have same fps, but much less load on CPU (for me from 400% to 40%) and on GPU (from 22% to 3%)!

Image
@piotr-sikora-v commented on GitHub (Feb 2, 2025): BTW if you add to ffmpeg `-hwaccel cuda -hwaccel_output_format cuda` you will have same fps, but much less load on CPU (for me from 400% to 40%) and on GPU (from 22% to 3%)! <img width="750" alt="Image" src="https://github.com/user-attachments/assets/a16cef8a-6b70-4772-ac5e-a0536a5c9154" />
Author
Owner

@piotr-sikora-v commented on GitHub (Feb 3, 2025):

@frenzybiscuit @Chocobozzz

I spent the last 24 hours analyzing transcoding with CUDA. Based on my analysis, there’s no way to match x264’s quality using h264_nvenc (Nvidia’s hardware encoder). The only option is to significantly increase the bitrate—by a lot. To get similar quality, you need about triple the bitrate, and to make it look identical, roughly four times. With a bit more work, I might get similar quality with double the bitrate.
But also, speed is a lot better. On my setup it was 1.5x on CPU vs 13x GPU (3060 ti)

Alternatively, you can use a mix of CPU and GPU. In that scenario, you do the transcoding on the CPU with x264, but for example, handle scaling on the GPU. Unfortunately, transferring frames and so on adds overhead, so you won’t really speed up the transcoding process. However, it will reduce CPU usage, allowing more simultaneous transcodes on one machine by offloading some tasks to the GPU.

Conclusion: We have two options for GPU acceleration without losing quality:

1/ Significantly increase the file size/transfer rate, but speed up transcoding.
2/ Use only a partial offload to the GPU.

examples:
1/ full gpu transcoding:
ffmpeg -hwaccel cuda -hwaccel_output_format cuda -i 5ee1ac69-cdd6-4044-8bf5-08fc47db2cd9 -y -acodec libfdk_aac -vcodec h264_nvenc -rc vbr_hq -rc-lookahead 32 -cq 19 -threads 4 -f mp4 -movflags faststart -max_muxing_queue_size 1024 -map_metadata -1 -q:a 5 -vf scale_npp=w=-2:h=1080:interp_algo=super -preset slow -profile:v high -maxrate:v 2000000 -bufsize:v 4000000 -bf 4 -r 30 -g:v 60 -gpu 0
2/ mix CPU/GPU:

ffmpeg -hwaccel cuda -hwaccel_output_format cuda -i input.avi -y -acodec libfdk_aac -c:v libx264 -threads 4 -f mp4 -movflags faststart -max_muxing_queue_size 1024 -map_metadata -1 -q:a 5 -vf scale_npp=w=1920:h=1080:interp_algo=super,hwdownload,format=nv12 -preset veryfast -maxrate:v 522240 -bufsize:v 522240 -bf 16 -r 30 -g:v 60 -gpu 0 test-mix.mp4

Personal for me... best is to have mix... if I can get better quality using less bandwidth and have better disk space utilization I will always choose this option instend of faster transcoding but significantly increase bandwidth

Or maybe best is have to choose it by user... have some defaults?
on my tube.pol.social instance I have a lot webinaries, but also some dynamic videos.
Now one group will be uploading more than 100 materials all at least one hour long (that why I spent time to test hw accel ;) ).
This videos come from "Linux Autumn" event... so quality using h264_nvenc and low bitrate is very good. So for import time I will set this wrapper, but after I will switch to x264 and little gpu-offload

@piotr-sikora-v commented on GitHub (Feb 3, 2025): @frenzybiscuit @Chocobozzz I spent the last 24 hours analyzing transcoding with CUDA. Based on my analysis, there’s no way to match x264’s quality using h264_nvenc (Nvidia’s hardware encoder). The only option is to significantly increase the bitrate—by a lot. To get similar quality, you need about triple the bitrate, and to make it look identical, roughly four times. With a bit more work, I might get similar quality with double the bitrate. But also, speed is a lot better. On my setup it was 1.5x on CPU vs 13x GPU (3060 ti) Alternatively, you can use a mix of CPU and GPU. In that scenario, you do the transcoding on the CPU with x264, but for example, handle scaling on the GPU. Unfortunately, transferring frames and so on adds overhead, so you won’t really speed up the transcoding process. However, it will reduce CPU usage, allowing more simultaneous transcodes on one machine by offloading some tasks to the GPU. Conclusion: We have two options for GPU acceleration without losing quality: 1/ Significantly increase the file size/transfer rate, but speed up transcoding. 2/ Use only a partial offload to the GPU. examples: 1/ full gpu transcoding: `ffmpeg -hwaccel cuda -hwaccel_output_format cuda -i 5ee1ac69-cdd6-4044-8bf5-08fc47db2cd9 -y -acodec libfdk_aac -vcodec h264_nvenc -rc vbr_hq -rc-lookahead 32 -cq 19 -threads 4 -f mp4 -movflags faststart -max_muxing_queue_size 1024 -map_metadata -1 -q:a 5 -vf scale_npp=w=-2:h=1080:interp_algo=super -preset slow -profile:v high -maxrate:v 2000000 -bufsize:v 4000000 -bf 4 -r 30 -g:v 60 -gpu 0` 2/ mix CPU/GPU: `ffmpeg -hwaccel cuda -hwaccel_output_format cuda -i input.avi -y -acodec libfdk_aac -c:v libx264 -threads 4 -f mp4 -movflags faststart -max_muxing_queue_size 1024 -map_metadata -1 -q:a 5 -vf scale_npp=w=1920:h=1080:interp_algo=super,hwdownload,format=nv12 -preset veryfast -maxrate:v 522240 -bufsize:v 522240 -bf 16 -r 30 -g:v 60 -gpu 0 test-mix.mp4` Personal for me... best is to have mix... if I can get better quality using less bandwidth and have better disk space utilization I will always choose this option instend of faster transcoding but significantly increase bandwidth Or maybe best is have to choose it by user... have some defaults? on my tube.pol.social instance I have a lot webinaries, but also some dynamic videos. Now one group will be uploading more than 100 materials all at least one hour long (that why I spent time to test hw accel ;) ). This videos come from "Linux Autumn" event... so quality using h264_nvenc and low bitrate is very good. So for import time I will set this wrapper, but after I will switch to x264 and little gpu-offload
Author
Owner

@accessiblepixel commented on GitHub (Jun 5, 2025):

Hi, first of all thanks for all the input from everyone in the thread so far.

I've been trying today to get a remote runner working with the newer intel_qsv and/or intel-vaapi. (I have both 9th gen Intel HD630 hardware and 12th gen (alderlake) intel GPUs available to test. I've tried modifying some of the scripts, but I'm kind of not sure what I'm doing.

I know peertube itself has hardware encoding profiles that can be installed for intel gpu acceleration, but not the runners themselves. My instance will be in the clouds, but it's rather CPU bound for uploads, but I have a virtualisation stack at home that has plenty of untapped GPU transcoding resources and a fast enough connection to grab the video, and send back the transcoded results.

I can somewhat manually do a transcode on the commandline with downloading the file and using something like
ffmpeg -debug -hwaccel qsv -init_hw_device qsv=hw -i ~/7a725755-93ce-410c-8ee9-3a76d7383112-1080-fragmented.mp4 -vf hwupload=extra_hw_frames=64,format=qsv -c:v h264_qsv -b:v 5M -maxrate 5M ~/output.mp4

but I don't know how to translate the options that peertube-runner hands out, I tried MattyBoombalatty 's hijack method and tried replacing h264_nvenc with h264_qsv, and adding more options like -hwaccel qsv but I couldn't quite get it to work.

I also tried normen 's script too but now I'm quite lost.

I also tried enabling the plugin within peertube, but that's only for itself.

Any help would be greatly appreciated, and i've the hardware to test things if required :)

Thanks <3

@accessiblepixel commented on GitHub (Jun 5, 2025): Hi, first of all thanks for all the input from everyone in the thread so far. I've been trying today to get a remote runner working with the newer intel_qsv and/or intel-vaapi. (I have both 9th gen Intel HD630 hardware and 12th gen (alderlake) intel GPUs available to test. I've tried modifying some of the scripts, but I'm kind of not sure what I'm doing. I know peertube itself has hardware encoding profiles that can be installed for intel gpu acceleration, but not the runners themselves. My instance will be in the clouds, but it's rather CPU bound for uploads, but I have a virtualisation stack at home that has plenty of untapped GPU transcoding resources and a fast enough connection to grab the video, and send back the transcoded results. I can somewhat manually do a transcode on the commandline with downloading the file and using something like ``ffmpeg -debug -hwaccel qsv -init_hw_device qsv=hw -i ~/7a725755-93ce-410c-8ee9-3a76d7383112-1080-fragmented.mp4 -vf hwupload=extra_hw_frames=64,format=qsv -c:v h264_qsv -b:v 5M -maxrate 5M ~/output.mp4`` but I don't know how to translate the options that peertube-runner hands out, I tried [MattyBoombalatty](https://github.com/Chocobozzz/PeerTube/issues/6042#issuecomment-1843730794) 's hijack method and tried replacing h264_nvenc with h264_qsv, and adding more options like -hwaccel qsv but I couldn't quite get it to work. I also tried [normen](https://github.com/Chocobozzz/PeerTube/issues/6042#issuecomment-1837274564) 's script too but now I'm quite lost. I also tried enabling the plugin within peertube, but that's only for itself. Any help would be greatly appreciated, and i've the hardware to test things if required :) Thanks <3
Author
Owner

@bro2020 commented on GitHub (Jun 29, 2025):

I'll open a PR once I've integrated it within the admin web UI and once it's working with multiple vendors

What is the current status?

@bro2020 commented on GitHub (Jun 29, 2025): > I'll open a PR once I've integrated it within the admin web UI and once it's working with multiple vendors What is the current status?
Author
Owner

@emansom commented on GitHub (Jul 2, 2025):

I'll open a PR once I've integrated it within the admin web UI and once it's working with multiple vendors

What is the current status?

No longer have any need for PeerTube, someone else can pick it up. commits still there.

Codebase of PeerTube is a clusterfuck hell, I recommend anyone needing a reliable video streaming service to not bother.
Especially if high traffic is involved.

Reimplement something atop a more solid architecture like dotnet Orleans.

Single threaded callback hell is not going to scale, both in development as well as in production deployment.

Frontend juniors shouldn't do distributed (web)video platform architecture alone period, this whole project was doomed from the start.

@emansom commented on GitHub (Jul 2, 2025): > > I'll open a PR once I've integrated it within the admin web UI and once it's working with multiple vendors > > What is the current status? No longer have any need for PeerTube, someone else can pick it up. commits still there. Codebase of PeerTube is a clusterfuck hell, I recommend anyone needing a reliable video streaming service to not bother. Especially if high traffic is involved. Reimplement something atop a more solid architecture like dotnet Orleans. Single threaded callback hell is not going to scale, both in development as well as in production deployment. Frontend juniors shouldn't do distributed (web)video platform architecture alone period, this whole project was doomed from the start.
Author
Owner

@Chocobozzz commented on GitHub (Jul 2, 2025):

Would be happy to improve code architecture/paths if you have any suggestions ;)

Single threaded callback hell is not going to scale, both in development as well as in production deployment.

Don't hesitate to open issues if you find bottleneck. As far as I know, there aren't any at the moment already deployed PeerTube instances.

@Chocobozzz commented on GitHub (Jul 2, 2025): Would be happy to improve code architecture/paths if you have any suggestions ;) > Single threaded callback hell is not going to scale, both in development as well as in production deployment. Don't hesitate to open issues if you find bottleneck. As far as I know, there aren't any at the moment already deployed PeerTube instances.
Author
Owner

@bro2020 commented on GitHub (Jul 2, 2025):

@Chocobozzz Do you plan to implement encoding parameters for remote runners as standard?
That would be very appropriate and convenient.

@bro2020 commented on GitHub (Jul 2, 2025): @Chocobozzz Do you plan to implement encoding parameters for remote runners as standard? That would be very appropriate and convenient.
Author
Owner

@Chocobozzz commented on GitHub (Jul 2, 2025):

Framasoft's roadmap is already full until next year so no, sorry, we don't have an ETA.

@Chocobozzz commented on GitHub (Jul 2, 2025): Framasoft's roadmap is already full until next year so no, sorry, we don't have an ETA.
Author
Owner

@ROBERT-MCDOWELL commented on GitHub (Nov 16, 2025):

@Chocobozzz Do you plan to implement encoding parameters for remote runners as standard? That would be very appropriate and convenient.

you can create a ffmpeg wrapper and modify all parameters for now.

@ROBERT-MCDOWELL commented on GitHub (Nov 16, 2025): > [@Chocobozzz](https://github.com/Chocobozzz) Do you plan to implement encoding parameters for remote runners as standard? That would be very appropriate and convenient. you can create a ffmpeg wrapper and modify all parameters for now.
Author
Owner

@StanDog commented on GitHub (Jan 24, 2026):

I'm currently playing around with remote runners. PeerTube runs in a VM, while the remote runner on a separate machine with an Intel Arc A310. I just added a few entries for h264_qsv and it seems to work great with significantly faster video transcoding times than with software. I just changed the two functions getDefaultAvailableEncoders() and getDefaultEncodersToTry() in the peertube-runner.js:

function getDefaultAvailableEncoders() {
  return {
    vod: {
      h264_qsv: {
        default: defaultX264VODOptionsBuilder
      },
      libx264: {
        default: defaultX264VODOptionsBuilder
      },
      aac: {
        default: defaultAACOptionsBuilder
      },
      libfdk_aac: {
        default: defaultLibFDKAACVODOptionsBuilder
      }
    },
    live: {
      h264_qsv: {
        default: defaultX264LiveOptionsBuilder
      },
      libx264: {
        default: defaultX264LiveOptionsBuilder
      },
      aac: {
        default: defaultAACOptionsBuilder
      }
    }
  };
}
function getDefaultEncodersToTry() {
  return {
    vod: {
      video: ["h264_qsv", "libx264"],
      audio: ["libfdk_aac", "aac"]
    },
    live: {
      video: ["h264_qsv", "libx264"],
      audio: ["libfdk_aac", "aac"]
    }
  };
}

Not sure if this is the correct way to do it, though. But as long as it does the job with the newest ffmpeg version, I'm fine with this quick and dirty-fix.

@StanDog commented on GitHub (Jan 24, 2026): I'm currently playing around with remote runners. PeerTube runs in a VM, while the remote runner on a separate machine with an Intel Arc A310. I just added a few entries for h264_qsv and it seems to work great with significantly faster video transcoding times than with software. I just changed the two functions getDefaultAvailableEncoders() and getDefaultEncodersToTry() in the peertube-runner.js: ``` function getDefaultAvailableEncoders() { return { vod: { h264_qsv: { default: defaultX264VODOptionsBuilder }, libx264: { default: defaultX264VODOptionsBuilder }, aac: { default: defaultAACOptionsBuilder }, libfdk_aac: { default: defaultLibFDKAACVODOptionsBuilder } }, live: { h264_qsv: { default: defaultX264LiveOptionsBuilder }, libx264: { default: defaultX264LiveOptionsBuilder }, aac: { default: defaultAACOptionsBuilder } } }; } function getDefaultEncodersToTry() { return { vod: { video: ["h264_qsv", "libx264"], audio: ["libfdk_aac", "aac"] }, live: { video: ["h264_qsv", "libx264"], audio: ["libfdk_aac", "aac"] } }; } ``` Not sure if this is the correct way to do it, though. But as long as it does the job with the newest ffmpeg version, I'm fine with this quick and dirty-fix.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/PeerTube#5213
No description provided.