Skip to content

Instantly share code, notes, and snippets.

@Ghostbird
Last active April 25, 2024 02:46
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Ghostbird/0445ebe0d9f6d945c3978702ad455103 to your computer and use it in GitHub Desktop.
Save Ghostbird/0445ebe0d9f6d945c3978702ad455103 to your computer and use it in GitHub Desktop.
Build FFMPEG with NVIDIA hardware accelleration libraries on Debian 12. Includes non-free libnpp!
#!/bin/bash
# Automatically compile and install FFMPEG with NVIDIA hardware acceleration on Debian 12
# Includes cuvid, cuda, nvenc, nvdec, and non-free libnpp
# Based on:
# https://www.tal.org/tutorials/ffmpeg_nvidia_encode
# https://developer.nvidia.com/blog/nvidia-ffmpeg-transcoding-guide/
# Abort on error
set -e
suite=$(source /etc/os-release && echo $VERSION_CODENAME)*
# Install libavcodec-extra manually so the build-deps step doesn't pull the problematic libavcodec59
# libjs-bootstrap is a dependency of ffmpeg-doc
# devscripts contains the dch command
sudo apt-get install libavcodec-extra libjs-bootstrap devscripts
sudo apt-mark auto libavcodec-extra libjs-bootstrap devscripts
sudo apt-get build-dep ffmpeg -t $suite
sudo apt-get install nvidia-cuda-toolkit -t $suite
mkdir -p ffmpeg-deb/src
cd ffmpeg-deb
if [[ -d nv-codec-headers ]]
then
cd nv-codec-headers
git fetch --tags
else
git clone https://git.videolan.org/git/ffmpeg/nv-codec-headers.git
cd nv-codec-headers
fi
# Checkout latest release, intead of HEAD. The Debian driver in stable may not yet support the pre-release API.
git checkout $(git describe --tags $(git rev-list --tags --max-count=1))
make
sudo make install
cd ../src
rm -rf ./*
apt-get source ffmpeg -t $suite
cd ffmpeg-*
sed -i 's/--enable-sdl2/--enable-sdl2 --enable-cuda --enable-cuvid --enable-nvdec --enable-nvenc --enable-libnpp --enable-nonfree/' debian/rules
DEBEMAIL="root@local" DEBFULLNAME="script" dch --local "+nvidiasupport" "Compiled with support for nvidia hardware acceleration"
DEB_BUILD_OPTIONS="nocheck notest" dpkg-buildpackage -r -nc --jobs=auto --no-sign
cd ..
# Install all built packages, except the non-extra variants of libavfilter, libavcodec and libavformat
sudo dpkg -i $(ls *.deb | grep -Ev "(libavfilter|libavcodec|libavformat)[0-9]+_")
echo "Verification:"
ffmpeg -codecs 2> /dev/null | grep nvenc
@Ghostbird
Copy link
Author

It seems you misunderstand something about this script. It doesn't alter anything related to NVIDIA or CUDA. It only enables NVIDIA and CUDA options when building FFMPEG (and dependencies) from the official Debian sources. FFMPEG & co have support for these tools in the code, but Debian cannot distribute .deb packages built with these options enabled because of licensing issues.

So this doesn't put the nvidia driver anywhere, the only NVIDIA & CUDA related thing is that it installs the nvidia-cuda-toolkit, using apt, and it downloads the NVIDIA development headers for FFMPEG from https://git.videolan.org/git/ffmpeg/nv-codec-headers.git. These are additional tools used to bridge between FFMPEG & co and the NVIDIA driver. They absolutely should not change anything about your driver / cuda installation.

In this case you mention the nvidia patch. Keep in mind that using such a patch means that you're already using the NVIDIA driver from NVIDIA, not from Debian. Which means that in this case you already have set-up your Debian machine to use a non-Debian-standard NVIDIA driver set-up.

This script is made for the default set-up where you install nvidia-driver from Debian's repositories.

Your uninstall script is not correct. Purging nvidia* and cuda* will remove a lot of things unrelated to this script. Purging ffmpeg* will not remove a lot of things that were installed by this script.

To uninstall I'd suggest going into ffmpeg-deb/src and uninstall all the packages listed there using dpkg -r (some of them will not be installed).

Furthermore I would caution you to not run scripts you find on the internet without fully understanding:

  1. What they are intended for, and under which conditions.
  2. What actions they actually perform.

Point two is harder, and can be foregone if you trust the source. However it would have enabled you to know how to uninstall.
Point one is more important, because you would have understood that your set-up differs in some significant ways from what this script requires.

I recommend that you read the articles this script is based on (see comments at the start of the script). Those explain how to perform the process manually. This is just a slightly more advanced and automated version of what those articles do. When going through the steps manually you'll probably be able to figure out what you need to adapt to get it working on your set-up.

@danieliser
Copy link

danieliser commented Feb 8, 2023

@Ghostbird thanks for the resply.

It doesn't alter anything related to NVIDIA or CUDA

It installs nvidia-cuda-toolkit, which according to NVIDIA's own docs on the toolkit includes the NVIDIA drivers.

For convenience, the NVIDIA driver is installed as part of the CUDA Toolkit installation.

It also includes all of the compiled *.h files for the different codecs, which are not being properly symlinked or copied to a global path using this script.

Furthermore I would caution you to not run scripts you find on the internet without fully understanding:

Couldn't agree more, but having been working with linux for 2 decades and followed dozens of guides, including reading most of the NVIDIA docs I'm confident I understand what its supposed to be doing.

BUT, its not. on a clean Debian 11 install with drivers & cuda installed, it fails every time with missing H264_nvenc notices.

If it matters, hardware is AMD Epyc CPU, NVIDIA T600 (the one I want to use) & NVIDIA 3090 (disabled via VFIO locking for VM passthrough)

Only if I manually move the *.h files and installing the required NVIDIA Codec SDK does it work correctly, neither of which were mentioned.

https://developer.nvidia.com/nvidia-video-codec-sdk

Also none of the linked articles mention these points either, though I did find an obscure article from 2019 that mentioned them both and seemed to get the job done. This was the guide for reference: https://bradford.la/2016/GPU-FFMPEG-in-LXC/ though it also covers LXC setups it covered the mentioned requirements.

@Ghostbird
Copy link
Author

Thank you for your comments. I apologise if I came across as accusative. You clearly are far more experienced in these matters than I initially assumed.

I do not recall ever installing the NVIDIA Codec SDK on my machine. This script is based on my own manual following of the blogs I mentioned in my earlier commend.

Furthermore I don't think this quote from the NVIDIA docs applies:

For convenience, the NVIDIA driver is installed as part of the CUDA Toolkit installation.

apt doesn't list nvidia-driver as a dependency of nvidia-cuda-toolkit, only as a suggestion. Keep in mind that when we're talking vanilla Debian, what NVIDIA delivers in their installers doesn't apply. We're using the Debian package management and their installers, which can radically differ. In this case Debian's installer seems to have replaced the convenience installation of the driver with a mere suggestion which I think fits better with how Debian package management works.

Are you sure you're not running a hybrid of Debian + stuff installed from NVIDIA themselves?

It also includes all of the compiled *.h files for the different codecs, which are not being properly symlinked or copied to a global path using this script.

This part of the script is meant to do that:

if [[ -d nv-codec-headers ]]
then
  cd nv-codec-headers
  git fetch --tags
else
  git clone https://git.videolan.org/git/ffmpeg/nv-codec-headers.git
  cd nv-codec-headers
fi
# Checkout latest release, intead of HEAD. The Debian driver in stable may not yet support the pre-release API.
git checkout $(git describe --tags $(git rev-list --tags --max-count=1))
make
sudo make install

The last line should install the FFmpeg NVIDIA headers in Debian.

@tjvr
Copy link

tjvr commented Feb 11, 2023

Thank you for sharing this! I found it really helpful.

I had some problems getting the packages to install, and the verification check failed. I think the trick was to omit the -dev packages; it now seems to have worked. Thanks!

@Ghostbird
Copy link
Author

Ah, it might be that it builds some -dev packages that are not strictly needed, to run FFMPEG. Only if you want to compile something else with FFMPEG + NVENC support. Which in my original case I did (OBS studio).

@Ghostbird
Copy link
Author

Ghostbird commented Feb 18, 2023

I've recently built a similar script that built FFMPEG with BlackMagic Design DeckLink and VAAPI support, and noticed that if you have the non -extra variants of libavfilter and libavcodec installed before you run this type of script, it may fail in the dpkg step. Make sure you do not already have a system install of those two. All other packages are fine, since they will be replaced with just built packages with identical names, but in this case these are replaced with the -extra variants, and dpkg cannot handle such a replacement action.

Also I noticed that in some cases it might be useful to prepend yes | to the sudo dpkg line to auto-confirm some overrides related to the -extra packages.

@booski
Copy link

booski commented Aug 30, 2023

This script seems very helpful, but I'm running into a somewhat perplexing issue with getting the build-deps installed.

I'm on a machine running bullseye, and since stable isn't in my sources, I changed stable to bullseye at the top. However, apt doesn't think it's possible to resolve the dependencies. It seems that by specifying the release using the -t flag, something subtle changes in apt's dependency resolution:

root@test:~# apt-get build-dep ffmpeg -t bullseye
Reading package lists... Done
Selected version '7:4.3.5-0+deb11u1' (bullseye) for ffmpeg
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Some packages could not be installed. This may mean that you have
requested an impossible situation or if you are using the unstable
distribution that some required packages have not yet been created
or been moved out of Incoming.
The following information may help to resolve the situation:

The following packages have unmet dependencies:
 librsvg2-dev : Depends: librsvg2-2 (= 2.50.3+dfsg-1) but 2.50.3+dfsg-1+deb11u1 is to be installed
                Depends: librsvg2-common (= 2.50.3+dfsg-1) but 2.50.3+dfsg-1+deb11u1 is to be installed
 libssh-gcrypt-dev : Depends: libssh-gcrypt-4 (= 0.9.5-1+deb11u1) but 0.9.7-0+deb11u1 is to be installed
 libssl-dev : Depends: libssl1.1 (= 1.1.1n-0+deb11u4) but 1.1.1n-0+deb11u5 is to be installed
 libudev-dev : Depends: libudev1 (= 247.3-7+deb11u2) but 247.3-7+deb11u4 is to be installed
 libwebp-dev : Depends: libwebp6 (= 0.6.1-2.1) but 0.6.1-2.1+deb11u1 is to be installed
               Depends: libwebpmux3 (= 0.6.1-2.1) but 0.6.1-2.1+deb11u1 is to be installed
 libx11-dev : Depends: libx11-6 (= 2:1.7.2-1) but 2:1.7.2-1+deb11u1 is to be installed
E: Unable to correct problems, you have held broken packages.
root@test:~# apt-get build-dep ffmpeg
Reading package lists... Done
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following packages were automatically installed and are no longer required:
  linux-headers-5.10.0-23-amd64 linux-headers-5.10.0-23-common linux-image-5.10.0-23-amd64
Use 'apt autoremove' to remove them.
The following NEW packages will be installed:
  cleancss comerr-dev doxygen flite1-dev frei0r-plugins-dev gir1.2-freedesktop gir1.2-gdkpixbuf-2.0 gir1.2-glib-2.0
  [...]
0 upgraded, 256 newly installed, 0 to remove and 0 not upgraded.
Need to get 106 MB of archives.
After this operation, 438 MB of additional disk space will be used.
Do you want to continue? [Y/n] n
Abort.

It seems I can solve this easily by simply removing the -t flag and allowing apt to use the default sources, but since it looks like you went out of your way to specify the release this way I'm interested to know your reasoning behind doing it like this?

Edit: I solved the issue by using bullseye-security for the suite name, but I'm still interested in why the -t flag is used at all in the script.

@Ghostbird
Copy link
Author

Ghostbird commented Sep 1, 2023

@booski, the suite value is for situations where you might install packages from testing in some cases. I don't know why bullseye doesn't work. You can try suite=oldstable instead. Currently that refers to bullseye.

On my system I normally install packages from stable, but very rarely I need to install something from testing for a very specific reason. It's mainly an artefact from before Bookworm came out, and some packages in Bullseye could be pretty old. I did a running upgrade to Bookworm once it came out, so the configuration remained the same.

@booski
Copy link

booski commented Sep 1, 2023

Thanks for the clarification!

I'm not sure if the stable/oldstable names behave differently, but the solution to my problem was to specify bullseye-security as $suite. It seems apt can become confused when instructed to install from the "base" release when there are newer packages in -updates or -security (which are higher priority by default).

Thanks for sharing the script, it's a huge help!

@Ghostbird
Copy link
Author

Ah, apparently I never encountered that situation, but that could happen on my system too. I haven't yet found a way to exclude a specific release, which is the way that option is intended. Ideally I could add an option like -t !testing but that doesn't seem to exist.

@Ghostbird
Copy link
Author

Ghostbird commented Sep 2, 2023

If you're messing around with this anyway, could you give this a try?

# Load current OS info as shell variables
source /etc/os-release
# Set suite to current OS‌ by version number
suite=$VERSION_ID

That should use a suite value of 11 on your system. Maybe that will match all of bullseye, bullseye-security, bullseye-updates and bullseye-backports, but not testing.

@booski
Copy link

booski commented Sep 4, 2023

Interesting! I probably won't be poking at this for a few weeks but once we get into October I'll start working on getting a robust install of custom-compiled ffmpeg onto a production server. I'll give it a spin then.

@Ghostbird
Copy link
Author

Ghostbird commented Sep 6, 2023

I've update it with a mechanism that works for me, give it a try once you have the time.

I've used suite=$(source /etc/os-release && echo $VERSION_CODENAME)* which yields bookworm* on my system. This seems to work.

However suite=$(source /etc/os-release && echo $VERSION_ID)* which yields 12* works just as well.

I opted for the code name because it's clearer what it means. When you see (e.g. in a log) an apt command that includes a version number you won't instantly know whether it's a software version number or an OS version number. When you see a Debian code-name, it's obviously an OS version and not a software version.

@gitmybox
Copy link

The topic description mentioned Build FFMPEG with NVIDIA hardware accelleration libraries on Debian 11

Does the script support Debian 12 ?

Thanks.

@Ghostbird
Copy link
Author

Ghostbird commented Sep 14, 2023 via email

@gitmybox
Copy link

I managed to compile FFmpeg from the script without error in Debian 12 with ASUS RTX-4060 Ti 8GB Nvidia GPU Card.

Reference to Nvidia link Using FFmpeg with NVIDIA GPU Hardware Acceleration:- https://docs.nvidia.com/video-technologies/video-codec-sdk/11.1/ffmpeg-with-nvidia-gpu/index.html

I tried the Basic Testing first transcode command:-
ffmpeg -y -vsync 0 -hwaccel cuda -hwaccel_output_format cuda -i input.mp4 -c:a copy -c:v h264_nvenc -b:v 5M output.mp4

But I encountered the following errors:-

  1. -vsync is deprecated. Use -fps_mode
    Passing a number to -vsync is deprecated, use a string argument as described in the manual.

  2. No decoder surfaces left
    Error while decoding stream #0:0: Invalid data found when processing input

If I remove both flags -vsync & -hwaccel_output_format cuda , the errors disappear. I think these flags are there for a good reason.

Does anyone have experience on this issue to share some hints on how to solve it ?

Thanks in advance.

@Ghostbird
Copy link
Author

Ghostbird commented Sep 23, 2023 via email

@gitmybox
Copy link

gitmybox commented Sep 23, 2023

Thanks for the feedback.

I have another clarification that encoder av1_nvenc is not included:-
ffmpeg -hide_banner -encoders | grep nvenc
V....D h264_nvenc NVIDIA NVENC H.264 encoder (codec h264)
V....D hevc_nvenc NVIDIA NVENC hevc encoder (codec hevc)

Is it possible to compile this av1_nvenc into ffmpeg ?

According to Nvidia SDK v12 it is part of it:-
The NVENC plugin in FFMPEG supports the following codecs: h264_nvenc - H264 Encoder hevc_nvenc - HEVC Encoder av1_nvenc - AV1 Encoder The command lines in this document use h264_nvenc, and should be replaced by hevc_nvenc for HEVC encode and av1_nvenc for AV1 encode.

Thanks

@Ghostbird
Copy link
Author

I'd expect it to be included automatically, however I don't know for sure, and I can't test it. On my system it is not present after the compilation, simply because my hardware doesn't support it. You should check your hardware support here

@gitmybox
Copy link

I have verified that RTX-4060 Ti 8GB Nvidia GPU Card is listed to support AV1 in here.

If it is automatically complied to include encoder av1_nvenc, can I verify it in the log & what key word to look out for ?

Thanks

@Ghostbird
Copy link
Author

I see that the NVIDIA page on compiling FFMPEG lists a configuration flag --enable-cuda-nvcc. I have no idea whether it'll work, but you can try adding that to the sed line in the script. In the line that starts with sed -i, add --enable-cuda-nvcc after --enable-cuda and see whether that works. I'm not sure whether that's valid, but it's worth a quick try. If it isn't valid you'll probably get an error an you'll have to remove it again.

@Ghostbird
Copy link
Author

If it is automatically complied to include encoder av1_nvenc, can I verify it in the log & what key word to look out for ?

The script greps for nvenc at the end. If the encoder av1_nvenc is present, it would show up in the verification output at the end of the script. The fact that you haven't seen it already probably means it really isn't present.

@booski
Copy link

booski commented Oct 3, 2023

I've update it with a mechanism that works for me, give it a try once you have the time.

I've used suite=$(source /etc/os-release && echo $VERSION_CODENAME)* which yields bookworm* on my system. This seems to work.

However suite=$(source /etc/os-release && echo $VERSION_ID)* which yields 12* works just as well.

I opted for the code name because it's clearer what it means. When you see (e.g. in a log) an apt command that includes a version number you won't instantly know whether it's a software version number or an OS version number. When you see a Debian code-name, it's obviously an OS version and not a software version.

Testing this out, it doesn't seem to work at all on bullseye:

root@bullseye:~# apt-get build-dep ffmpeg -t bullseye
[...]
The following packages have unmet dependencies:
[...]
E: Unable to correct problems, you have held broken packages.

The other options do even worse (same result for 11 and 11*):

root@bullseye:~# apt-get build-dep ffmpeg -t bullseye*
Reading package lists... Done
E: Unable to find a source package for ffmpeg

On bookworm it works as long as the wildcard is specified:

root@bookworm:~# apt-get build-dep ffmpeg -t bookworm
[...]
The following packages have unmet dependencies:
[...]
E: Unable to correct problems, you have held broken packages.
root@bookworm:~# apt-get build-dep ffmpeg -t bookworm*
[...]
After this operation, 1,040 MB of additional disk space will be used.
Do you want to continue? [Y/n]
root@bookworm:~# apt-get build-dep ffmpeg -t 12
Reading package lists... Done
E: Unable to find a source package for ffmpeg
root@bookworm:~# apt-get build-dep ffmpeg -t 12*
[...]
After this operation, 1,040 MB of additional disk space will be used.
Do you want to continue? [Y/n]

So in short, I think the solution of using $VERSION_CODENAME* is the best for the clarity reasons you bring up.

While poking at this, I fixed some other issues I ran into, feel free to incorporate them if they seem useful to you:

  • I kept running into issues with the build-deps for ffmpeg automatically installing the problematic libavcodec59 package, so I added a line manually installing libavcodec-extra, which dpkg can replace without issue.
  • ffmpeg-doc gets built even though "nodoc" is specified. I don't mind getting the docs package, so I just made sure the dependencies for the package are in place (libjs-bootstrap) and removed the "nodoc" that doesn't seem to do anything.
  • I changed the parallelism level for dpkg-buildpackage to "auto" (from 4), it felt like a better choice considering the compilation time.
  • Once the packages were installed, apt immediately wanted to overwrite them with "newer" versions from the repo, so I added a version suffix (+nvidiasupport) to stop that happening.
  • Since the $suite logic doesn't work on bullseye, updated the top comment to refer to Debian 12.

Here's the diff covering all the above changes:

2c2
< # Automatically compile and install FFMPEG with NVIDIA hardware acceleration on Debian 11
---
> # Automatically compile and install FFMPEG with NVIDIA hardware acceleration on Debian 12
12a13,18
> # Install libavcodec-extra manually so the build-deps step doesn't pull the problematic libavcodec59
> # libjs-bootstrap is a dependency of ffmpeg-doc
> # devscripts contains the dch command
> sudo apt-get install libavcodec-extra libjs-bootstrap devscripts
> sudo apt-mark auto libavcodec-extra libjs-bootstrap devscripts
> 
31a38
> 
34c41,42
< DEB_BUILD_OPTIONS="nocheck nodoc notest" dpkg-buildpackage -r -nc -j4 --no-sign
---
> DEBEMAIL="root@local" DEBFULLNAME="script" dch --local "+nvidiasupport" "Compiled with support for nvidia hardware acceleration"
> DEB_BUILD_OPTIONS="nocheck notest" dpkg-buildpackage -r -nc --jobs=auto --no-sign
35a44
> 

I will probably set something up to automatically build the package again when there is a newer version in apt, I can share the result if that seems interesting to you.

/T

@Ghostbird
Copy link
Author

Ghostbird commented Oct 5, 2023

Odd that it didn't work on Bullseye. I've added your changes and it worked perfectly on my system. How the libavcodec59 problem happened, I don't know. The inverse grep in the subcommand that generates the package list for dpkg should have excluded it based on the regular expression.

I had no idea that I had left -j4 in there. --jobs=auto is of course much more desirable. I didn't know that option existed. I normally used -j$(nproc).

I have edited your message above. The word acceleration was somehow word-wrapped using a newline character, which broke the patch file.

UPDATE: Actually I didn't realise, but the new script broke some stuff on my system, but it was fixed after removing a lot of :i386 packages that I didn't need anyway.

@gitmybox
Copy link

I see that the NVIDIA page on compiling FFMPEG lists a configuration flag --enable-cuda-nvcc. I have no idea whether it'll work, but you can try adding that to the sed line in the script. In the line that starts with sed -i, add --enable-cuda-nvcc after --enable-cuda and see whether that works. I'm not sure whether that's valid, but it's worth a quick try. If it isn't valid you'll probably get an error an you'll have to remove it again.

I have tried by adding --enable-cuda-nvcc after --enable-cuda, the script stopped with error log shown below:-
. . . . . . .
nvcc -gencode arch=compute_60,code=sm_60 -O2 -std=c++11 -m64 -ptx -c -o /tmp/ffconf.jCphOBPP/test.o /tmp/ffconf.jCphOBPP/test.cu
ERROR: No supported gcc/g++ host compiler found, but clang-14 is available.
Use 'nvcc -ccbin clang-14' to use that instead.
ERROR: failed checking for nvcc.
make[1]: Leaving directory '/home/user233l/ffmpeg-deb/src/ffmpeg-5.1.3'
make[1]: *** [debian/rules:257: configure_standard] Error 1
make: *** [debian/rules:250: binary] Error 2
dpkg-buildpackage: error: debian/rules binary subprocess returned exit status 2

@Ghostbird
Copy link
Author

Interesting, I can't help you much with that, but you can look at NVIDIA/cuda-samples#46 as a starting point.

@falcie1337
Copy link

does this work on debian sid? i really need obs right now

@Ghostbird
Copy link
Author

Give it a try. You can run the first 43 lines of the script, and see whether it compiles, without changing your system too much.

@weskerty
Copy link

Thank you. It helped me.

@Ghostbird
Copy link
Author

Oddly, the added manual install of libavcodec-extra line suggested above today caused a problem and removing that package from the installation solved it.

The message was that libavcodec-extra59-XXX could not be installed because libavcodec-extra-59-XXX+nvidiasupport1 was already installed. (XXX is the same version identifier in both cases, but I forgot which one exactly it was).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment