feat(capture): rebuild ffmpeg w/ nv-codec-headers + NVENC/CUVID for All-Intra HEVC

The custom FFmpeg 7.1 in this image previously had NO nvenc — only
prores_ks/dnxhd/libx264/libx265. The All-Intra HEVC ingest plan
(docs/design/2026-05-29-all-intra-hevc-ingest.md §4.1) needs
hevc_nvenc / h264_nvenc to offload the per-signal encode from CPU
to the L4, so we rebuild ffmpeg's configure stage with:

  --enable-ffnvcodec --enable-nvenc --enable-cuvid

nv-codec-headers (pinned n12.1.14.0) is cloned + installed before
configure so ffmpeg picks up the ffnvcodec pkg-config. Full CUDA
toolkit is omitted — only needed for GPU filters like yadif_cuda.

Adds a sanity-check RUN that fails the build if hevc_nvenc/h264_nvenc
don't appear in 'ffmpeg -encoders' so a broken NVENC build can't
silently ship. Creates /live and /growing as empty dirs since the
node-agent binds them at sidecar start.
This commit is contained in:
Zac Gaetano 2026-05-29 00:51:56 -04:00
parent 0f6c715a30
commit 68c8f47c8f

View file

@ -1,4 +1,10 @@
# ── Stage 1: Build FFmpeg with DeckLink support ───────────────────────────── # ── Stage 1: Build FFmpeg with DeckLink + NVENC (HEVC/H264) support ─────────
# All-Intra HEVC NVENC is the master codec for growing-file ingest (see
# docs/design/2026-05-29-all-intra-hevc-ingest.md). This stage gets the
# nv-codec-headers (header-only, no driver / no full CUDA toolkit needed)
# so ffmpeg's configure can light up hevc_nvenc / h264_nvenc / cuvid.
# At runtime, /dev/nvidia* + the host driver libs (via the NVIDIA Container
# Toolkit) supply the actual encoder.
FROM debian:bookworm AS ffmpeg-builder FROM debian:bookworm AS ffmpeg-builder
RUN apt-get update && apt-get install -y --no-install-recommends \ RUN apt-get update && apt-get install -y --no-install-recommends \
@ -13,6 +19,11 @@ COPY sdk/ /decklink-sdk/
COPY patch_decklink.py /patch_decklink.py COPY patch_decklink.py /patch_decklink.py
COPY decklink-sdk16.patch /decklink-sdk16.patch COPY decklink-sdk16.patch /decklink-sdk16.patch
# nv-codec-headers — just the ffnvcodec public headers + a pkg-config file.
# Pin to a tag known to work with FFmpeg 7.1 (n12.x series).
RUN git clone --depth=1 --branch n12.1.14.0 https://github.com/FFmpeg/nv-codec-headers.git /nv-codec-headers \
&& make -C /nv-codec-headers PREFIX=/usr/local install
# Pull FFmpeg 7.1 source # Pull FFmpeg 7.1 source
RUN git clone --depth=1 --branch release/7.1 https://git.ffmpeg.org/ffmpeg.git /ffmpeg RUN git clone --depth=1 --branch release/7.1 https://git.ffmpeg.org/ffmpeg.git /ffmpeg
@ -20,8 +31,16 @@ RUN git clone --depth=1 --branch release/7.1 https://git.ffmpeg.org/ffmpeg.git /
RUN python3 /patch_decklink.py RUN python3 /patch_decklink.py
WORKDIR /ffmpeg WORKDIR /ffmpeg
# NVENC adds: --enable-nvenc (encoder), --enable-cuvid (decoder), --enable-ffnvcodec.
# We deliberately do NOT enable --enable-cuda-nvcc / --enable-libnpp here — those
# require the full ~3GB CUDA toolkit and are only needed for GPU filters like
# yadif_cuda / scale_cuda. If §5's GPU deinterlace stretch goal goes ahead,
# rebuild this image off nvidia/cuda:12.x-devel and flip those flags on.
RUN ./configure \ RUN ./configure \
--prefix=/usr/local \ --prefix=/usr/local \
--pkg-config-flags="--static" \
--extra-cflags="-I/decklink-sdk -I/usr/local/include" \
--extra-ldflags="-L/usr/local/lib" \
--enable-gpl \ --enable-gpl \
--enable-nonfree \ --enable-nonfree \
--enable-libx264 \ --enable-libx264 \
@ -32,13 +51,20 @@ RUN ./configure \
--enable-libsrt \ --enable-libsrt \
--enable-libzmq \ --enable-libzmq \
--enable-decklink \ --enable-decklink \
--extra-cflags="-I/decklink-sdk" \ --enable-ffnvcodec \
--enable-nvenc \
--enable-cuvid \
--disable-doc \ --disable-doc \
--disable-debug \ --disable-debug \
--disable-ffplay \ --disable-ffplay \
&& make -j$(nproc) \ && make -j$(nproc) \
&& make install && make install
# Sanity-check: hevc_nvenc and h264_nvenc must be present in the encoder list,
# otherwise the resulting image is useless for the All-Intra HEVC pipeline.
RUN /usr/local/bin/ffmpeg -hide_banner -encoders 2>&1 | grep -E 'nvenc' \
|| (echo 'FATAL: nvenc encoders missing from ffmpeg build' && exit 1)
# ── Stage 2: Runtime image ─────────────────────────────────────────────────── # ── Stage 2: Runtime image ───────────────────────────────────────────────────
FROM node:20-bookworm FROM node:20-bookworm
@ -58,6 +84,11 @@ COPY lib/libDeckLinkAPI.so /usr/lib/libDeckLinkAPI.so
COPY lib/libDeckLinkPreviewAPI.so /usr/lib/libDeckLinkPreviewAPI.so COPY lib/libDeckLinkPreviewAPI.so /usr/lib/libDeckLinkPreviewAPI.so
RUN ldconfig RUN ldconfig
# Mount points the recorder lifecycle expects to exist.
# /live — HLS preview output (bound from host LIVE_DIR by node-agent)
# /growing — growing-file master output (bound from host /mnt/NVME/MAM/growing)
RUN mkdir -p /live /growing
WORKDIR /app WORKDIR /app
COPY package*.json ./ COPY package*.json ./
RUN npm install --omit=dev RUN npm install --omit=dev