1
0
Fork 0

Replace ffmpeg-ndi with gst-plugin-ndi for ndi-feeder.

We can no longer reliably compile ffmpeg with the NDI reversal
patch. While gst-plugin-ndi isn't particularly well maintained
anymore either, it works for now and will probably become a
main-stay in my setup. The alternative is doing NDI via OBS and
that's just silly and not easily automatable.
main
Icedream 2025-04-20 16:19:43 +02:00
parent d2df62e51c
commit 57dbec3aac
Signed by: icedream
GPG Key ID: 468BBEEBB9EC6AEA
3 changed files with 125 additions and 45 deletions

View File

@ -205,6 +205,52 @@ RUN \
--mount=type=cache,target=/tmp/build/.cache \ --mount=type=cache,target=/tmp/build/.cache \
ulimit -n 1024 && makepkg -sr --noconfirm ulimit -n 1024 && makepkg -sr --noconfirm
###
# GST-PLUGIN-NDI-GIT
FROM base-devel-yay AS gst-plugin-ndi-git
WORKDIR /usr/src/gst-plugin-ndi-git
USER root
# COPY --from=ndi-sdk-embedded /usr/src/ndi-sdk-embedded/*.pkg.* /tmp/
COPY --from=ndi-sdk /usr/src/ndi-sdk/*.pkg.* /tmp/
RUN \
--mount=type=cache,target=/var/cache/pacman/pkg,sharing=locked \
--mount=type=cache,target=/tmp/build/.cache \
yay --noconfirm -U /tmp/*.pkg.* && rm /tmp/*.pkg.*
USER build
RUN git clone https://aur.archlinux.org/gst-plugin-ndi-git.git .
COPY patches/gst-plugin-ndi-git/*.patch /var/tmp
RUN set -e && for patch in /var/tmp/*.patch; do patch -Np1 -i "$patch"; done
RUN \
--mount=type=cache,target=/var/cache/pacman/pkg,sharing=locked \
--mount=type=cache,target=/tmp/build/.cache \
(\
. ./PKGBUILD &&\
if [ "${#depends[@]}" -eq 0 ]; then exit; fi &&\
packages=$(yay -T "${depends[@]}" 2>/dev/null|| true) &&\
if [ -z "$packages" ]; then exit; fi &&\
yay -S --noconfirm --asdeps --provides --needed $packages &&\
find ~/.cache/yay/ -mindepth 2 -maxdepth 2 -name \*.pkg.\* -exec mv {} . \;\
)
# RUN (. ./PKGBUILD && yay -S --noconfirm --asdeps --provides --needed $(yay -T "${optdepends[@]}") && (mv -v ~/.cache/yay/*/*.pkg.* . || true))
RUN \
--mount=type=cache,target=/var/cache/pacman/pkg,sharing=locked \
--mount=type=cache,target=/tmp/build/.cache \
(\
. ./PKGBUILD &&\
if [ "${#makedepends[@]}" -eq 0 ]; then exit; fi &&\
packages=$(yay -T "${makedepends[@]}" 2>/dev/null|| true) &&\
if [ -z "$packages" ]; then exit; fi &&\
yay -S --noconfirm --asdeps --provides --needed $packages \
)
RUN \
--mount=type=cache,target=/var/cache/pacman/pkg,sharing=locked \
--mount=type=cache,target=/tmp/build/.cache \
ulimit -n 1024 && makepkg -sr --noconfirm --nocheck
### ###
# FFMPEG-NDI # FFMPEG-NDI
@ -267,7 +313,7 @@ RUN chmod -v +x *.sh
FROM scratch as packages FROM scratch as packages
COPY --from=ndi-sdk /usr/src/ndi-sdk/*.pkg.* /packages/ COPY --from=ndi-sdk /usr/src/ndi-sdk/*.pkg.* /packages/
COPY --from=ffmpeg-ndi /usr/src/ffmpeg-ndi/*.pkg.* /packages/ COPY --from=gst-plugin-ndi-git /usr/src/gst-plugin-ndi-git/*.pkg.* /packages/
COPY --from=fakesilence /usr/local/bin/fakesilence /target/usr/local/bin/ COPY --from=fakesilence /usr/local/bin/fakesilence /target/usr/local/bin/
### ###
@ -284,7 +330,7 @@ USER root
#COPY --from=yay /usr/src/yay/*.pkg.* /tmp/ #COPY --from=yay /usr/src/yay/*.pkg.* /tmp/
COPY --from=ndi-sdk /usr/src/ndi-sdk/*.pkg.* /tmp/ COPY --from=ndi-sdk /usr/src/ndi-sdk/*.pkg.* /tmp/
COPY --from=ffmpeg-ndi /usr/src/ffmpeg-ndi/*.pkg.* /tmp/ COPY --from=gst-plugin-ndi-git /usr/src/gst-plugin-ndi-git/*.pkg.* /tmp/
RUN \ RUN \
--mount=type=cache,target=/var/cache/pacman/pkg,sharing=locked \ --mount=type=cache,target=/var/cache/pacman/pkg,sharing=locked \
--mount=type=cache,target=/tmp/build/.cache \ --mount=type=cache,target=/tmp/build/.cache \
@ -293,7 +339,7 @@ RUN \
RUN \ RUN \
--mount=type=cache,target=/var/cache/pacman/pkg,sharing=locked \ --mount=type=cache,target=/var/cache/pacman/pkg,sharing=locked \
--mount=type=cache,target=/tmp/build/.cache \ --mount=type=cache,target=/tmp/build/.cache \
rm -f /var/cache/pacman/pkg/cache.lck; pacman -S --noconfirm --needed sudo realtime-privileges rm -f /var/cache/pacman/pkg/cache.lck; pacman -S --noconfirm --needed sudo realtime-privileges gst-plugins-base gst-plugins-good
COPY --from=fakesilence /usr/local/bin/fakesilence /usr/local/bin/ COPY --from=fakesilence /usr/local/bin/fakesilence /usr/local/bin/

View File

@ -1,57 +1,58 @@
#!/bin/bash -e #!/bin/bash -e
target_url="${1:-icecast://source:source@127.0.0.1:61120/main}" #target_url="${1:-icecast://source:source@127.0.0.1:61120/main}"
ffmpeg_pids=() : "${TARGET_IP:=127.0.0.1}"
: "${TARGET_PORT:=61120}"
: "${TARGET_MOUNT:=/main}"
: "${TARGET_USERNAME:=source}"
: "${TARGET_PASSWORD:=source}"
: "${NDI_FEEDER_EXTRA_IP:=}"
call_ffmpeg() { gstreamer_pids=()
command ffmpeg -hide_banner "$@"
call_gstreamer() {
command gst-launch-1.0 "$@"
} }
daemon_ffmpeg() { daemon_gstreamer() {
call_ffmpeg "$@" & call_gstreamer "$@" &
ffmpeg_pids+=($!) gstreamer_pids+=($!)
} }
shutdown_ffmpeg() { shutdown_gstreamer() {
if is_ffmpeg_running; then if is_gstreamer_running; then
kill "$ffmpeg_pid" || true kill "$gstreamer_pid" || true
for t in $(seq 0 10); do for t in $(seq 0 10); do
if ! kill -0 "$ffmpeg_pid"; then if ! kill -0 "$gstreamer_pid"; then
break break
fi fi
sleep 1 sleep 1
done done
if kill -0 "$ffmpeg_pid"; then if kill -0 "$gstreamer_pid"; then
kill -9 "$ffmpeg_pid" || true kill -9 "$gstreamer_pid" || true
fi fi
fi fi
ffmpeg_pid= gstreamer_pid=
} }
is_ffmpeg_running() { is_gstreamer_running() {
[ -n "$ffmpeg_pid" ] && kill -0 "$ffmpeg_pid" [ -n "$gstreamer_pid" ] && kill -0 "$gstreamer_pid"
} }
on_exit() { on_exit() {
shutdown_ffmpeg shutdown_gstreamer
} }
trap on_exit EXIT trap on_exit EXIT
offline=0 offline=0
while true; do url_address=()
found_audio_source="" if [ -n "$NDI_FEEDER_EXTRA_IP" ]; then
url_address=("url-address=$NDI_FEEDER_EXTRA_IP:5961")
fi
while read -r line; do while true; do
declare -a "found_source=($(sed -e 's/"/\\"/g' -e "s/'/\"/g" -e 's/[][`~!@#$%^&*():;<>.,?/\|{}=+-]/\\&/g' <<<"$line"))" found_audio_source="$(grep --line-buffered -m 1 --color=none -Po 'ndi-name = \K.+\(ID.* Main Audio.*\)$' < <(gst-device-monitor-1.0 -f Source/Network:application/x-ndi))"
found_source[0]=$(sed -e 's/\\\([`~!@#$%^&*():;<>.,?/\|{}=+-]\)/\1/g' <<<"${found_source[0]}")
found_source[1]=$(sed -e 's/\\\([`~!@#$%^&*():;<>.,?/\|{}=+-]\)/\1/g' <<<"${found_source[1]}")
case "${found_source[0]}" in
*\(ID*\ Main\ Audio\))
found_audio_source="${found_source[0]}"
;;
esac
done < <(call_ffmpeg -loglevel info -extra_ips 192.168.188.21,192.168.188.76 -find_sources true -f libndi_newtek -i "dummy" 2>&1 | grep -Po "'(.+)'\s+'(.+)" | tee)
if [ -z "$found_audio_source" ]; then if [ -z "$found_audio_source" ]; then
offline=$((offline + 1)) offline=$((offline + 1))
@ -59,21 +60,16 @@ while true; do
offline=0 offline=0
fi fi
if ! is_ffmpeg_running && [ -n "$found_audio_source" ]; then if ! is_gstreamer_running && [ -n "$found_audio_source" ]; then
echo "starting ffmpeg with audio source: $found_audio_source" >&2 echo "starting gstreamer with audio source: $found_audio_source" >&2
call_ffmpeg -loglevel warning \ call_gstreamer ndisrc ndi-name="$found_audio_source" "${url_address[@]}" ! ndisrcdemux name=demux \
-analyzeduration 1 -f libndi_newtek -extra_ips 192.168.188.21 -i "$found_audio_source" \ demux.audio ! queue ! audioconvert ! audio/x-raw, channels=2, rate=48000, format=S16LE ! filesink location=/dev/stdout |
-map a -c:a pcm_s16le -ar 48000 -ac 2 -f s16le - |
fakesilence --samplerate 48000 --channels 2 --silence-threshold 125ms | fakesilence --samplerate 48000 --channels 2 --silence-threshold 125ms |
daemon_ffmpeg -loglevel warning \ daemon_gstreamer filesrc location=/dev/stdin ! rawaudioparse use-sink-caps=false format=pcm pcm-format=s16le sample-rate=48000 num-channels=2 ! queue ! audioconvert ! audioresample ! flacenc ! oggmux ! shout2send mount="$TARGET_MOUNT" port="$TARGET_PORT" username="$TARGET_USERNAME" password="$TARGET_PASSWORD" ip="$TARGET_IP"
-ar 48000 -channels 2 -f s16le -i - \ elif is_gstreamer_running && [ -z "$found_audio_source" ] && [ "$offline" -gt 0 ]; then
-map a -c:a flac -f ogg -content_type application/ogg "${target_url}" echo "shutting down gstreamer since no source has been found" >&2
shutdown_gstreamer # it won't shut down by itself unfortunately
# HACK - can't use the standard mpegts here, but liquidsoap will happily accept anything ffmpeg can parse (by default)… so let's just use nut here even though it feels super duper wrong
elif is_ffmpeg_running && [ -z "$found_audio_source" ] && [ "$offline" -gt 0 ]; then
echo "shutting down ffmpeg since no source has been found" >&2
shutdown_ffmpeg # it won't shut down by itself unfortunately
fi fi
sleep 1 sleep 1

View File

@ -0,0 +1,38 @@
From 4906403902c507ed70389f88ce4371b7055ac0b9 Mon Sep 17 00:00:00 2001
From: Carl Kittelberger <icedream@icedream.pw>
Date: Sun, 20 Apr 2025 00:15:30 +0200
Subject: [PATCH] Add gst-plugins-base-libs to depends
---
.SRCINFO | 1 +
PKGBUILD | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/.SRCINFO b/.SRCINFO
index 0aa79d5..b0ba5d4 100644
--- a/.SRCINFO
+++ b/.SRCINFO
@@ -10,6 +10,7 @@ pkgbase = gst-plugin-ndi-git
makedepends = git
makedepends = rust
depends = gstreamer
+ depends = gst-plugins-base-libs
depends = libndi
provides = gst-plugin-ndi
conflicts = gst-plugin-ndi
diff --git a/PKGBUILD b/PKGBUILD
index 3a0bfce..d2dee08 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -7,7 +7,7 @@ pkgdesc="GStreamer plugin for NDI"
arch=("x86_64")
url="https://github.com/teltek/gst-plugin-ndi"
license=('LGPL')
-depends=('gstreamer' 'libndi')
+depends=('gstreamer' 'gst-plugins-base-libs' 'libndi')
provides=("${pkgname%-git}")
conflicts=("${pkgname%-git}")
makedepends=('git' 'rust')
--
2.49.0