dragonflight/services/capture/Dockerfile

212 lines
11 KiB
Text
Raw Normal View History

# ── Stage 0: Extract Deltacast VideoMaster SDK ───────────────────────────
FROM debian:bookworm AS sdk-extractor
COPY services/capture/videomaster-linux.x64-6.34.1-dev.tar.gz /tmp/
RUN mkdir -p /sdk && tar -xzf /tmp/videomaster-linux.x64-6.34.1-dev.tar.gz -C /sdk
# ── Stage 1: Build deltacast-capture bridge binary ───────────────────────
FROM debian:bookworm AS bridge-builder
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential cmake ca-certificates \
&& rm -rf /var/lib/apt/lists/*
COPY --from=sdk-extractor /sdk /sdk
COPY services/capture/deltacast-bridge/ /bridge/
RUN rm -rf /bridge/build && cmake -S /bridge -B /bridge/build \
-DCMAKE_BUILD_TYPE=Release \
-DSDK_ROOT=/sdk \
&& cmake --build /bridge/build -j$(nproc)
feat(framecache): phase 4 — capture-manager reads from framecache - services/framecache/client/fc_pipe.c: new slot→stdout pipe adapter - Opens framecache slot as consumer (independent cursor per instance) - Streams raw UYVY422 frames to stdout continuously - SIGPIPE detection via write() return — exits cleanly on ffmpeg exit - SIGTERM/SIGINT clean stop from capture-manager - Periodic stats to stderr (every 300 frames) - Exit codes: 0=clean, 1=slot not found, 2=EPIPE - services/framecache/CMakeLists.txt: add fc_pipe target + install - services/framecache/Dockerfile: copy fc_pipe to runtime image - services/capture/Dockerfile: - New fc-pipe-builder stage (builds fc_pipe from framecache sources) - Copies fc_pipe binary to /usr/local/bin/fc_pipe in runtime image - services/capture/src/capture-manager.js: - _buildInputArgs: new framecache path for deltacast + sdi/blackmagic when FC_SLOT_ID env is set (injected by node-agent from bridge fmt JSON) - Spawns fc_pipe <slot_id> as child process - Uses pipe:0 as ffmpeg rawvideo input 0 - Audio FIFO (unchanged) as ffmpeg input 1 - Falls back to legacy FIFO path when FC_SLOT_ID unset - audioMap: covers blackmagic via framecache (input 1 for audio FIFO) - isInterlacedSource: covers blackmagic interlaced signals - hiresStdio: pipe stdin when bridgeProcess set (fc_pipe stdout→ffmpeg) - Non-growing spawn: pipes fc_pipe.stdout → ffmpeg.stdin - Growing orchestrator spawn: pipes fc_pipe.stdout → bash.stdin - sdiHlsDir: covers blackmagic source type - Session state stores _fcPipeProcess for clean stop - stop(): sends SIGTERM to fc_pipe after ffmpeg SIGINT
2026-06-03 11:32:40 -04:00
# ── Stage 1d: Build fc_pipe (framecache slot → stdout adapter) ──────────
# Spawned by capture-manager.js to pipe raw frames from a framecache slot
# into ffmpeg as a rawvideo pipe input. Statically linked against fc_client
# (no runtime dependency on the framecache container — just shm + semaphores).
FROM debian:bookworm AS fc-pipe-builder
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential cmake libmicrohttpd-dev \
&& rm -rf /var/lib/apt/lists/*
COPY services/framecache /fc-src
RUN rm -rf /fc-src/build && cmake -S /fc-src -B /fc-src/build \
feat(framecache): phase 4 — capture-manager reads from framecache - services/framecache/client/fc_pipe.c: new slot→stdout pipe adapter - Opens framecache slot as consumer (independent cursor per instance) - Streams raw UYVY422 frames to stdout continuously - SIGPIPE detection via write() return — exits cleanly on ffmpeg exit - SIGTERM/SIGINT clean stop from capture-manager - Periodic stats to stderr (every 300 frames) - Exit codes: 0=clean, 1=slot not found, 2=EPIPE - services/framecache/CMakeLists.txt: add fc_pipe target + install - services/framecache/Dockerfile: copy fc_pipe to runtime image - services/capture/Dockerfile: - New fc-pipe-builder stage (builds fc_pipe from framecache sources) - Copies fc_pipe binary to /usr/local/bin/fc_pipe in runtime image - services/capture/src/capture-manager.js: - _buildInputArgs: new framecache path for deltacast + sdi/blackmagic when FC_SLOT_ID env is set (injected by node-agent from bridge fmt JSON) - Spawns fc_pipe <slot_id> as child process - Uses pipe:0 as ffmpeg rawvideo input 0 - Audio FIFO (unchanged) as ffmpeg input 1 - Falls back to legacy FIFO path when FC_SLOT_ID unset - audioMap: covers blackmagic via framecache (input 1 for audio FIFO) - isInterlacedSource: covers blackmagic interlaced signals - hiresStdio: pipe stdin when bridgeProcess set (fc_pipe stdout→ffmpeg) - Non-growing spawn: pipes fc_pipe.stdout → ffmpeg.stdin - Growing orchestrator spawn: pipes fc_pipe.stdout → bash.stdin - sdiHlsDir: covers blackmagic source type - Session state stores _fcPipeProcess for clean stop - stop(): sends SIGTERM to fc_pipe after ffmpeg SIGINT
2026-06-03 11:32:40 -04:00
-DCMAKE_BUILD_TYPE=Release \
&& cmake --build /fc-src/build --target fc_pipe -j$(nproc)
feat(framecache): phase 3 — decklink-bridge writes to shm - services/capture/decklink-bridge/main.cpp: new C++ DeckLink bridge - IDeckLinkInputCallback (VideoInputFrameArrived) writes UYVY422 frames to framecache slot via fc_writer_write() - VideoInputFormatChanged reopens slot with new resolution/fps - bmdVideoInputEnableFormatDetection: auto-detects signal format - bmdFormat8BitYUV (UYVY422) — same pixel format as deltacast-bridge - Audio written from callback to named FIFO (same pattern as deltacast) - Silence thread keeps audio FIFO open between sessions - slot_id: decklink-<NODE_ID>-<device_idx> - Format JSON emitted on first frame (includes slot_id) - LEGACY_FIFO compile flag mirrors deltacast-bridge - --devices csv, --fc-url, --audio-pipe-dir, --signal-timeout args - services/capture/decklink-bridge/CMakeLists.txt: - Reuses fc_writer.c from deltacast-bridge (shared writer module) - Links rt + dl + pthread; DeckLink SDK via dlopen at runtime - LEGACY_FIFO option - services/capture/Dockerfile: - New decklink-bridge-builder stage (g++ + DeckLink SDK headers) - Copies decklink-bridge binary to /usr/local/bin/decklink-bridge - services/node-agent/index.js: - FC_URL + FC_NODE_ID constants (from env vars, passed to all bridges) - startDecklinkBridge(deviceIndices) / stopDecklinkBridge() functions mirror deltacast bridge lifecycle management - deltacast startDeltacastBridge: adds --fc-url arg + NODE_ID env - sidecar start: injects FC_URL into all sidecar envs; sets IpcMode=host for deltacast + blackmagic sidecars; starts decklink-bridge for sdi/ blackmagic source types; injects FC_SLOT_ID from fmt JSON - sidecar stop: stopDecklinkBridge() when last blackmagic sidecar stops
2026-06-03 11:25:25 -04:00
# ── Stage 1c: Build decklink-bridge binary ───────────────────────────────
FROM debian:bookworm AS decklink-bridge-builder
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential cmake ca-certificates g++ \
&& rm -rf /var/lib/apt/lists/*
# DeckLink SDK headers (for IDeckLinkInput etc.)
COPY services/capture/sdk/ /decklink-sdk/
# Shared fc_writer module from deltacast-bridge
COPY services/capture/deltacast-bridge/ /fc_writer/
# decklink-bridge source
COPY services/capture/decklink-bridge/ /decklink-bridge/
RUN rm -rf /decklink-bridge/build && cmake -S /decklink-bridge -B /decklink-bridge/build \
-DCMAKE_BUILD_TYPE=Release \
-DDECKLINK_SDK_DIR=/decklink-sdk \
-DDELTACAST_BRIDGE_DIR=/fc_writer \
&& cmake --build /decklink-bridge/build -j$(nproc)
feat(framecache): phase 3 — decklink-bridge writes to shm - services/capture/decklink-bridge/main.cpp: new C++ DeckLink bridge - IDeckLinkInputCallback (VideoInputFrameArrived) writes UYVY422 frames to framecache slot via fc_writer_write() - VideoInputFormatChanged reopens slot with new resolution/fps - bmdVideoInputEnableFormatDetection: auto-detects signal format - bmdFormat8BitYUV (UYVY422) — same pixel format as deltacast-bridge - Audio written from callback to named FIFO (same pattern as deltacast) - Silence thread keeps audio FIFO open between sessions - slot_id: decklink-<NODE_ID>-<device_idx> - Format JSON emitted on first frame (includes slot_id) - LEGACY_FIFO compile flag mirrors deltacast-bridge - --devices csv, --fc-url, --audio-pipe-dir, --signal-timeout args - services/capture/decklink-bridge/CMakeLists.txt: - Reuses fc_writer.c from deltacast-bridge (shared writer module) - Links rt + dl + pthread; DeckLink SDK via dlopen at runtime - LEGACY_FIFO option - services/capture/Dockerfile: - New decklink-bridge-builder stage (g++ + DeckLink SDK headers) - Copies decklink-bridge binary to /usr/local/bin/decklink-bridge - services/node-agent/index.js: - FC_URL + FC_NODE_ID constants (from env vars, passed to all bridges) - startDecklinkBridge(deviceIndices) / stopDecklinkBridge() functions mirror deltacast bridge lifecycle management - deltacast startDeltacastBridge: adds --fc-url arg + NODE_ID env - sidecar start: injects FC_URL into all sidecar envs; sets IpcMode=host for deltacast + blackmagic sidecars; starts decklink-bridge for sdi/ blackmagic source types; injects FC_SLOT_ID from fmt JSON - sidecar stop: stopDecklinkBridge() when last blackmagic sidecar stops
2026-06-03 11:25:25 -04:00
# ── Stage 2: 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
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential nasm yasm pkg-config git ca-certificates python3 \
libssl-dev libx264-dev libx265-dev libvpx-dev libopus-dev \
libmp3lame-dev libsrt-openssl-dev \
libzmq3-dev zlib1g-dev libstdc++-12-dev \
&& rm -rf /var/lib/apt/lists/*
# Copy in BMD DeckLink SDK headers and patch script
COPY services/capture/sdk/ /decklink-sdk/
COPY services/capture/patch_decklink.py /patch_decklink.py
COPY services/capture/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
RUN git clone --depth=1 --branch release/7.1 https://git.ffmpeg.org/ffmpeg.git /ffmpeg
# Patch FFmpeg DeckLink code for SDK 16.x API changes
RUN python3 /patch_decklink.py
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 \
--prefix=/usr/local \
--extra-cflags="-I/decklink-sdk -I/usr/local/include" \
--extra-ldflags="-L/usr/local/lib" \
--enable-gpl \
--enable-nonfree \
--enable-libx264 \
--enable-libx265 \
--enable-libvpx \
--enable-libopus \
--enable-libmp3lame \
--enable-libsrt \
--enable-libzmq \
--enable-decklink \
--enable-ffnvcodec \
--enable-nvenc \
--enable-cuvid \
--disable-doc \
--disable-debug \
--disable-ffplay \
&& make -j$(nproc) \
&& 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 1b: Build bmx (raw2bmx / bmxtranswrap) from source ─────────────────
# bmx (bmxlib + libMXF + libMXF++) is the reference GROWING OP1a MXF writer. It
# writes a fresh IndexTableSegment (with an updated IndexDuration) into a new
# body partition at a periodic interval, so the recorded duration is readable —
# and INCREASES — from the header+index alone while the file is still being
# written (no footer needed). This is what makes the master a TRUE Premiere
# growing file. ffmpeg's MXF muxer cannot do this (its real duration/index lands
# only in the footer at av_write_trailer, so duration probes N/A until close).
#
# Debian/Ubuntu have no `bmxlib-tools` package (verified absent in bookworm), so
# we build from the BBC source. liburiparser/uuid/lzma/zlib/expat are the build
# deps; the runtime needs only libexpat1 + liburiparser1 + libuuid1 (added in
# the runtime stage below). Pinned to the bbc/bmx default branch (v1.6.x).
FROM debian:bookworm AS bmx-builder
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential cmake git ca-certificates pkg-config \
liburiparser-dev uuid-dev liblzma-dev zlib1g-dev libexpat1-dev \
&& rm -rf /var/lib/apt/lists/*
# Pin to a release tag so the produced soname (libMXF.so.1.6 etc.) stays stable
# for the COPY in the runtime stage. v1.6 is the BBC bmx series verified here.
RUN git clone --recursive --branch v1.6 https://github.com/bbc/bmx.git /bmx \
|| git clone --recursive https://github.com/bbc/bmx.git /bmx
WORKDIR /bmx/build
RUN cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local .. \
&& make -j"$(nproc)" && make install && ldconfig
# Sanity-check: raw2bmx must run, otherwise the growing-MXF pipeline is broken.
RUN /usr/local/bin/raw2bmx -h >/dev/null 2>&1 && echo 'raw2bmx OK'
# ── Stage 2: Runtime image ───────────────────────────────────────────────────
2026-04-07 21:58:28 -04:00
FROM node:20-bookworm
feat(settings/growing): storage warning, SMB auth + CIFS mount, per-recorder growing Implements docs/superpowers/specs/2026-05-31-storage-settings-growing-smb-design.md. 1. Storage warning banner at the top of Settings → Storage (set-once / path-change-corrupts-data warning). 2. Growing-files SMB credentials + system CIFS mount (Approach A): - settings.js: new global keys growing_smb_mount / growing_smb_username / growing_smb_vers; growing_smb_password is write-only (GET returns only growing_smb_password_exists; growing_smb_password_clear:true removes it). - GrowingSettingsCard: SMB mount/username/password (masked, "saved" state) + CIFS version fields. - capture Dockerfile: add cifs-utils + util-linux. - capture-manager: on growing start, mount //host/share at /growing using a root-only credentials file (creds never on the command line); unmount on stop; mount failure falls back to S3 streaming so a recording is never lost. - recorders.js: pass GROWING_SMB_* env; don't host-bind /growing when a CIFS mount is configured (an empty mountpoint is required). 3. Per-recorder growing mode (global toggle removed): - Removed the global "capture writes to local SMB share first" checkbox; the growing card is now SMB-infrastructure-only. - recorders.js reads the per-recorder recorders.growing_enabled column (already present from migration 014) instead of the global setting; RECORDER_FIELDS += growing_enabled. - New-recorder modal: "Growing-files mode" toggle. - storage.js overview: "enabled" now means the SMB landing zone is configured (mount source set), surfaced as smb_mount; health strip labels updated. No DB migration required (recorders.growing_enabled exists; new settings are key/value rows). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 14:50:31 -04:00
# Runtime deps for compiled ffmpeg libs.
# cifs-utils provides mount.cifs so growing-files capture can mount the SMB
# landing-zone share inside the (privileged) container at start (Approach A).
# util-linux supplies mount/umount/mountpoint.
RUN apt-get update && apt-get install -y --no-install-recommends \
libx264-164 libx265-199 libvpx7 libopus0 libmp3lame0 \
libsrt1.5-openssl libzmq5 libstdc++6 libc++1 libc++abi1 \
feat(settings/growing): storage warning, SMB auth + CIFS mount, per-recorder growing Implements docs/superpowers/specs/2026-05-31-storage-settings-growing-smb-design.md. 1. Storage warning banner at the top of Settings → Storage (set-once / path-change-corrupts-data warning). 2. Growing-files SMB credentials + system CIFS mount (Approach A): - settings.js: new global keys growing_smb_mount / growing_smb_username / growing_smb_vers; growing_smb_password is write-only (GET returns only growing_smb_password_exists; growing_smb_password_clear:true removes it). - GrowingSettingsCard: SMB mount/username/password (masked, "saved" state) + CIFS version fields. - capture Dockerfile: add cifs-utils + util-linux. - capture-manager: on growing start, mount //host/share at /growing using a root-only credentials file (creds never on the command line); unmount on stop; mount failure falls back to S3 streaming so a recording is never lost. - recorders.js: pass GROWING_SMB_* env; don't host-bind /growing when a CIFS mount is configured (an empty mountpoint is required). 3. Per-recorder growing mode (global toggle removed): - Removed the global "capture writes to local SMB share first" checkbox; the growing card is now SMB-infrastructure-only. - recorders.js reads the per-recorder recorders.growing_enabled column (already present from migration 014) instead of the global setting; RECORDER_FIELDS += growing_enabled. - New-recorder modal: "Growing-files mode" toggle. - storage.js overview: "enabled" now means the SMB landing zone is configured (mount source set), surfaced as smb_mount; health strip labels updated. No DB migration required (recorders.growing_enabled exists; new settings are key/value rows). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 14:50:31 -04:00
cifs-utils util-linux \
libexpat1 liburiparser1 libuuid1 \
&& rm -rf /var/lib/apt/lists/*
# Copy compiled ffmpeg/ffprobe
COPY --from=ffmpeg-builder /usr/local/bin/ffmpeg /usr/local/bin/ffmpeg
COPY --from=ffmpeg-builder /usr/local/bin/ffprobe /usr/local/bin/ffprobe
COPY --from=ffmpeg-builder /usr/local/lib/ /usr/local/lib/
# DeckLink runtime .so
COPY services/capture/lib/libDeckLinkAPI.so /usr/lib/libDeckLinkAPI.so
COPY services/capture/lib/libDeckLinkPreviewAPI.so /usr/lib/libDeckLinkPreviewAPI.so
# bmx (raw2bmx / bmxtranswrap / mxf2raw) — the growing OP1a MXF writer used for
# the edit-while-record master. Copy the built binaries + shared libs; runtime
# deps (libexpat1/liburiparser1/libuuid1) were installed above.
COPY --from=bmx-builder /usr/local/bin/raw2bmx /usr/local/bin/raw2bmx
COPY --from=bmx-builder /usr/local/bin/bmxtranswrap /usr/local/bin/bmxtranswrap
COPY --from=bmx-builder /usr/local/bin/mxf2raw /usr/local/bin/mxf2raw
COPY --from=bmx-builder /usr/local/lib/libMXF.so.1.6 /usr/local/lib/
COPY --from=bmx-builder /usr/local/lib/libMXF++.so.1.6 /usr/local/lib/
COPY --from=bmx-builder /usr/local/lib/libbmx.so.1.6 /usr/local/lib/
RUN cd /usr/local/lib \
&& ln -sf libMXF.so.1.6 libMXF.so.1 && ln -sf libMXF.so.1 libMXF.so \
&& ln -sf libMXF++.so.1.6 libMXF++.so.1 && ln -sf libMXF++.so.1 libMXF++.so \
&& ln -sf libbmx.so.1.6 libbmx.so.1 && ln -sf libbmx.so.1 libbmx.so \
&& ldconfig
# Verify raw2bmx resolves its libs and runs in the final image.
RUN raw2bmx -h >/dev/null 2>&1 && echo 'raw2bmx runtime OK'
# Deltacast bridge binary + SDK runtime libs
COPY --from=bridge-builder /bridge/build/deltacast-capture /usr/local/bin/deltacast-capture
feat(framecache): phase 3 — decklink-bridge writes to shm - services/capture/decklink-bridge/main.cpp: new C++ DeckLink bridge - IDeckLinkInputCallback (VideoInputFrameArrived) writes UYVY422 frames to framecache slot via fc_writer_write() - VideoInputFormatChanged reopens slot with new resolution/fps - bmdVideoInputEnableFormatDetection: auto-detects signal format - bmdFormat8BitYUV (UYVY422) — same pixel format as deltacast-bridge - Audio written from callback to named FIFO (same pattern as deltacast) - Silence thread keeps audio FIFO open between sessions - slot_id: decklink-<NODE_ID>-<device_idx> - Format JSON emitted on first frame (includes slot_id) - LEGACY_FIFO compile flag mirrors deltacast-bridge - --devices csv, --fc-url, --audio-pipe-dir, --signal-timeout args - services/capture/decklink-bridge/CMakeLists.txt: - Reuses fc_writer.c from deltacast-bridge (shared writer module) - Links rt + dl + pthread; DeckLink SDK via dlopen at runtime - LEGACY_FIFO option - services/capture/Dockerfile: - New decklink-bridge-builder stage (g++ + DeckLink SDK headers) - Copies decklink-bridge binary to /usr/local/bin/decklink-bridge - services/node-agent/index.js: - FC_URL + FC_NODE_ID constants (from env vars, passed to all bridges) - startDecklinkBridge(deviceIndices) / stopDecklinkBridge() functions mirror deltacast bridge lifecycle management - deltacast startDeltacastBridge: adds --fc-url arg + NODE_ID env - sidecar start: injects FC_URL into all sidecar envs; sets IpcMode=host for deltacast + blackmagic sidecars; starts decklink-bridge for sdi/ blackmagic source types; injects FC_SLOT_ID from fmt JSON - sidecar stop: stopDecklinkBridge() when last blackmagic sidecar stops
2026-06-03 11:25:25 -04:00
# DeckLink bridge binary is disabled
# COPY --from=decklink-bridge-builder /decklink-bridge/build/decklink-bridge /usr/local/bin/decklink-bridge
feat(framecache): phase 4 — capture-manager reads from framecache - services/framecache/client/fc_pipe.c: new slot→stdout pipe adapter - Opens framecache slot as consumer (independent cursor per instance) - Streams raw UYVY422 frames to stdout continuously - SIGPIPE detection via write() return — exits cleanly on ffmpeg exit - SIGTERM/SIGINT clean stop from capture-manager - Periodic stats to stderr (every 300 frames) - Exit codes: 0=clean, 1=slot not found, 2=EPIPE - services/framecache/CMakeLists.txt: add fc_pipe target + install - services/framecache/Dockerfile: copy fc_pipe to runtime image - services/capture/Dockerfile: - New fc-pipe-builder stage (builds fc_pipe from framecache sources) - Copies fc_pipe binary to /usr/local/bin/fc_pipe in runtime image - services/capture/src/capture-manager.js: - _buildInputArgs: new framecache path for deltacast + sdi/blackmagic when FC_SLOT_ID env is set (injected by node-agent from bridge fmt JSON) - Spawns fc_pipe <slot_id> as child process - Uses pipe:0 as ffmpeg rawvideo input 0 - Audio FIFO (unchanged) as ffmpeg input 1 - Falls back to legacy FIFO path when FC_SLOT_ID unset - audioMap: covers blackmagic via framecache (input 1 for audio FIFO) - isInterlacedSource: covers blackmagic interlaced signals - hiresStdio: pipe stdin when bridgeProcess set (fc_pipe stdout→ffmpeg) - Non-growing spawn: pipes fc_pipe.stdout → ffmpeg.stdin - Growing orchestrator spawn: pipes fc_pipe.stdout → bash.stdin - sdiHlsDir: covers blackmagic source type - Session state stores _fcPipeProcess for clean stop - stop(): sends SIGTERM to fc_pipe after ffmpeg SIGINT
2026-06-03 11:32:40 -04:00
# fc_pipe — framecache slot → stdout, spawned by capture-manager.js
COPY --from=fc-pipe-builder /fc-src/build/fc_pipe /usr/local/bin/fc_pipe
COPY --from=sdk-extractor /sdk/lib/libvideomasterhd.so.6.34.1 /usr/local/lib/deltacast/
COPY --from=sdk-extractor /sdk/lib/libvideomasterhd_audio.so.6.34.1 /usr/local/lib/deltacast/
RUN ln -sf libvideomasterhd.so.6.34.1 /usr/local/lib/deltacast/libvideomasterhd.so.6 \
&& ln -sf libvideomasterhd.so.6.34.1 /usr/local/lib/deltacast/libvideomasterhd.so \
&& ln -sf libvideomasterhd_audio.so.6.34.1 /usr/local/lib/deltacast/libvideomasterhd_audio.so.6 \
&& ln -sf libvideomasterhd_audio.so.6.34.1 /usr/local/lib/deltacast/libvideomasterhd_audio.so \
&& ldconfig /usr/local/lib/deltacast \
&& 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
2026-04-07 21:58:28 -04:00
WORKDIR /app
COPY services/capture/package*.json ./
2026-04-07 21:58:28 -04:00
RUN npm install --omit=dev
COPY services/capture/. .
2026-04-07 21:58:28 -04:00
EXPOSE 3001
CMD ["node", "src/index.js"]