Skip to content

Commit

Permalink
feat: Separate Linux static from hardware encoding (#48)
Browse files Browse the repository at this point in the history
Hardware acceleration for Linux is too wrapped up in dynamic libraries and drivers, so from now on, builds for Linux that support hardware encoding will be dynamic and will only run on Ubuntu.  For use in every other Linux distribution, fully static builds will be done with musl in Alpine Linux.

This also updates to the latest release, FFmpeg n7.1.
  • Loading branch information
joeyparrish authored Oct 11, 2024
1 parent b98a1da commit d0c07e8
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 26 deletions.
12 changes: 9 additions & 3 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ jobs:
matrix:
include: ${{ fromJSON(needs.matrix_config.outputs.MATRIX) }}

name: Build ${{ matrix.os_name }} ${{ matrix.target_arch }}
name: Build ${{ matrix.os_name }} ${{ matrix.target_arch }} ${{ matrix.container }}
runs-on: ${{ matrix.os }}
container:
image: ${{ matrix.container }}
Expand All @@ -125,7 +125,7 @@ jobs:
# actions.
# See https://github.com/actions/runner/issues/801#issuecomment-2394425757
- name: Patch native Alpine NodeJS into Runner environment
if: runner.os == 'Linux'
if: startsWith(matrix.container, 'alpine')
run: |
apk add nodejs
sed -i "s:^ID=alpine:ID=NotpineForGHA:" /etc/os-release
Expand All @@ -140,10 +140,16 @@ jobs:
shell: sh # No bash in Alpine by default

- name: Install Alpine Linux deps
if: runner.os == 'Linux'
if: startsWith(matrix.container, 'alpine')
run: apk add bash npm sudo
shell: sh # No bash in Alpine until after this command

- name: Install Ubuntu Linux deps
if: startsWith(matrix.container, 'ubuntu')
# Sudo is needed by the first build script, but isn't in the default
# container image for Ubuntu.
run: apt -y update && apt -y upgrade && apt -y install sudo

- uses: actions/checkout@v4
with:
path: repo-src
Expand Down
38 changes: 36 additions & 2 deletions build-matrix.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,29 @@
"comment1": "runners hosted by GitHub, always enabled",
"hosted": [
{
"comment": "Alpine container for static Linux binaries",
"os": "ubuntu-latest",
"container": "alpine:3.20",
"os_name": "linux",
"target_arch": "x64",
"exe_ext": ""
},
{
"comment": "Ubuntu 24.04 with hardware acceleration",
"os": "ubuntu-latest",
"container": "ubuntu:24.04",
"os_name": "linux",
"target_arch": "x64",
"exe_ext": "-ubuntu-24.04"
},
{
"comment": "Ubuntu 22.04 with hardware acceleration",
"os": "ubuntu-latest",
"container": "ubuntu:22.04",
"os_name": "linux",
"target_arch": "x64",
"exe_ext": "-ubuntu-22.04"
},
{
"comment": "Explicit macOS version 13 is required for explicit x64 CPU.",
"os": "macos-13",
Expand All @@ -16,7 +33,7 @@
"exe_ext": ""
},
{
"comment": "Latest macOS version 13 is arm64 CPU.",
"comment": "Latest macOS version is arm64 CPU.",
"os": "macos-latest",
"os_name": "osx",
"target_arch": "arm64",
Expand All @@ -33,11 +50,28 @@
"comment2": "runners hosted by the owner, enabled by the ENABLE_SELF_HOSTED variable being set on the repo",
"selfHosted": [
{
"comment": "Alpine container for static Linux binaries",
"os": "self-hosted-linux-arm64",
"container": "arm64v8/alpine:3.20",
"container": "alpine:3.20",
"os_name": "linux",
"target_arch": "arm64",
"exe_ext": ""
},
{
"comment": "Ubuntu 24.04 with hardware acceleration",
"os": "self-hosted-linux-arm64",
"container": "ubuntu:24.04",
"os_name": "linux",
"target_arch": "arm64",
"exe_ext": "-ubuntu-24.04"
},
{
"comment": "Ubuntu 22.04 with hardware acceleration",
"os": "self-hosted-linux-arm64",
"container": "ubuntu:22.04",
"os_name": "linux",
"target_arch": "arm64",
"exe_ext": "-ubuntu-22.04"
}
]
}
3 changes: 2 additions & 1 deletion build-scripts/00-packages.sh
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,13 @@ if [[ "$RUNNER_OS" == "Linux" ]]; then
sudo apt -y update
sudo apt -y upgrade
sudo apt -y install \
clang \
cmake \
curl \
g++ \
git \
libffmpeg-nvenc-dev \
libvdpau-dev \
libva-dev \
make \
nasm \
npm \
Expand Down
39 changes: 24 additions & 15 deletions build-scripts/90-ffmpeg.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,27 @@ cd ffmpeg

# Set some OS-specific environment variables and flags.
if [[ "$RUNNER_OS" == "Linux" ]]; then
export CFLAGS="-static"
export LDFLAGS="-static"
if ../repo-src/is-alpine.sh; then
# Truly static builds are only possible in musl-based Alpine Linux.
# Go for a completely static binary, but this prevents the use of hardware
# acceleration.
export CFLAGS="-static"
export LDFLAGS="-static"
else
# We can't build a truly static binary, so we might as well enable hardware
# acceleration, which uses dynamic libraries and will depend heavily on the
# OS distribution.
PLATFORM_CONFIGURE_FLAGS="--enable-vaapi --enable-nvenc"
# TODO: Is AMF an option for us in this context?

# Enable platform-specific hardware acceleration.
PLATFORM_CONFIGURE_FLAGS="--enable-vdpau"
# This version of ffmpeg will accept NVEnc 11.5.1.3+, but not Ubuntu
# 22.04's packaged version, 11.5.1.1. This patch makes it flexible enough
# to build with the older NVEnc version in Ubuntu Jammy.
# For code archaeologists, the commits that set the minimum beyond 11.5.1.1
# were https://github.com/ffmpeg/ffmpeg/commit/5c288a44 (released in n6.0)
# and https://github.com/ffmpeg/ffmpeg/commit/05f8b2ca (released in n6.1).
patch -p1 -i ../repo-src/ffmpeg-nvenc-jammy.patch
fi
elif [[ "$RUNNER_OS" == "macOS" ]]; then
export CFLAGS="-static"
# You can't do a _truly_ static build on macOS except the kernel.
Expand All @@ -36,11 +52,10 @@ elif [[ "$RUNNER_OS" == "macOS" ]]; then
# Enable platform-specific hardware acceleration.
PLATFORM_CONFIGURE_FLAGS="--enable-videotoolbox"

# Disable x86 ASM on macOS. It fails to build with an error about
# how macho64 format can't contain 32-bit assembly. I'm not sure
# how else to resolve this, and from my searches, it appears that
# others are not having this problem with ffmpeg. This is still a problem
# with n6.0.
# Disable x86 ASM on macOS. It fails to build with an error about "32-bit
# absolute addressing is not supported in 64-bit mode". I'm not sure how
# else to resolve this, and from my searches, it appears that others are not
# having this problem with ffmpeg. This is still a problem with n7.1
PLATFORM_CONFIGURE_FLAGS="$PLATFORM_CONFIGURE_FLAGS --disable-x86asm --disable-inline-asm"
elif [[ "$RUNNER_OS" == "Windows" ]]; then
# /usr/local/incude and /usr/local/lib are not in mingw's include
Expand All @@ -55,12 +70,6 @@ elif [[ "$RUNNER_OS" == "Windows" ]]; then
PLATFORM_CONFIGURE_FLAGS="--target-os=mingw64"
fi

# Install a patch from https://github.com/FFmpeg/FFmpeg/commit/effadce6 to
# resolve the binutils error "operand type mismatch for shr" on Windows,
# described in https://github.com/msys2/MINGW-packages/issues/17946
wget https://github.com/FFmpeg/FFmpeg/commit/effadce6.patch
patch -p1 -i effadce6.patch

if ! ./configure \
--pkg-config-flags="--static" \
--disable-ffplay \
Expand Down
14 changes: 10 additions & 4 deletions build-scripts/99-check-static.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,16 @@ set -x
cd ffmpeg

if [[ "$RUNNER_OS" == "Linux" ]]; then
# If ldd succeeds, then these are dynamic executables, so we fail
# this step if ldd succeeds. The output of ldd will still be logged.
ldd ffmpeg && exit 1
ldd ffprobe && exit 1
# We only check for static binaries on Alpine Linux. In other distributions,
# these are not possible due to the use of glibc. We allow glibc builds here
# because while tied to the distro, they at least give us the chance for
# hardware encoding.
if ../repo-src/is-alpine.sh; then
# If ldd succeeds, then these are dynamic executables, so we fail
# this step if ldd succeeds. The output of ldd will still be logged.
ldd ffmpeg && exit 1
ldd ffprobe && exit 1
fi
elif [[ "$RUNNER_OS" == "Windows" ]]; then
# These will still be dynamic executables.
# Capture the full list of DLL dependencies.
Expand Down
48 changes: 48 additions & 0 deletions ffmpeg-nvenc-jammy.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
FFmpeg n7.1 will accept NVEnc 11.5.1.3+, but not Ubuntu 22.04's packaged
version, 11.5.1.1. This patch makes it flexible enough to build with the older
NVEnc version in Ubuntu Jammy. For code archaeologists, the commits that set
the minimum beyond 11.5.1.1 were
https://github.com/ffmpeg/ffmpeg/commit/5c288a44 (released in n6.0) and
https://github.com/ffmpeg/ffmpeg/commit/05f8b2ca (released in n6.1).


diff --git a/configure b/configure
index d77a55b653..c28dcffbb0 100755
--- a/configure
+++ b/configure
@@ -6761,7 +6761,7 @@ if ! disabled ffnvcodec; then
ffnv_hdr_list="ffnvcodec/nvEncodeAPI.h ffnvcodec/dynlink_cuda.h ffnvcodec/dynlink_cuviddec.h ffnvcodec/dynlink_nvcuvid.h"
check_pkg_config ffnvcodec "ffnvcodec >= 12.1.14.0" "$ffnv_hdr_list" "" || \
check_pkg_config ffnvcodec "ffnvcodec >= 12.0.16.1 ffnvcodec < 12.1" "$ffnv_hdr_list" "" || \
- check_pkg_config ffnvcodec "ffnvcodec >= 11.1.5.3 ffnvcodec < 12.0" "$ffnv_hdr_list" "" || \
+ check_pkg_config ffnvcodec "ffnvcodec >= 11.1.5.1 ffnvcodec < 12.0" "$ffnv_hdr_list" "" || \
check_pkg_config ffnvcodec "ffnvcodec >= 11.0.10.3 ffnvcodec < 11.1" "$ffnv_hdr_list" "" || \
check_pkg_config ffnvcodec "ffnvcodec >= 8.1.24.15 ffnvcodec < 8.2" "$ffnv_hdr_list" ""
fi
@@ -7388,7 +7388,7 @@ int main(void) { return 0; }
EOF

if enabled nvenc; then
- check_type "ffnvcodec/nvEncodeAPI.h" "NV_ENC_PIC_PARAMS_AV1"
+ check_type "ffnvcodec/nvEncodeAPI.h" "NV_ENC_PIC_PARAMS_AV1" || add_cflags -DJAMMY
fi

if enabled_any nvdec cuvid; then
diff --git a/libavutil/hwcontext_cuda.c b/libavutil/hwcontext_cuda.c
index 3de3847399..0815360a46 100644
--- a/libavutil/hwcontext_cuda.c
+++ b/libavutil/hwcontext_cuda.c
@@ -363,11 +363,13 @@ static int cuda_context_init(AVHWDeviceContext *device_ctx, int flags) {
hwctx->internal->cuda_device));
if (ret < 0)
return ret;
+#ifndef JAMMY
} else if (flags & AV_CUDA_USE_CURRENT_CONTEXT) {
ret = CHECK_CU(cu->cuCtxGetCurrent(&hwctx->cuda_ctx));
if (ret < 0)
return ret;
av_log(device_ctx, AV_LOG_INFO, "Using current CUDA context.\n");
+#endif
} else {
ret = CHECK_CU(cu->cuCtxCreate(&hwctx->cuda_ctx, desired_flags,
hwctx->internal->cuda_device));
2 changes: 1 addition & 1 deletion versions.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
ffmpeg: n6.0
ffmpeg: n7.1
libvpx: v1.13.0
svt-av1: v1.7.0
x264: a8b68ebf
Expand Down

0 comments on commit d0c07e8

Please sign in to comment.