good progress
This commit is contained in:
@@ -5,11 +5,16 @@
|
||||
#
|
||||
# Requires: sudo for kmsgrab, PulseAudio for audio capture
|
||||
# Audio is non-blocking (monitor source = passive tap)
|
||||
#
|
||||
# Auto-restarts on stall: a watchdog checks ffmpeg's frame counter
|
||||
# and kills/restarts if video freezes (DRM/VAAPI contention from
|
||||
# other apps using the GPU, e.g. video calls).
|
||||
|
||||
set -uo pipefail
|
||||
|
||||
RECEIVER_IP="${1:-mcrndeb}"
|
||||
PORT="${2:-4444}"
|
||||
STALL_TIMEOUT=10 # seconds with no frame progress before restart
|
||||
|
||||
# Let root access the user's PulseAudio session
|
||||
REAL_UID="${SUDO_UID:-$(id -u)}"
|
||||
@@ -24,34 +29,84 @@ echo "Monitor source: $MONITOR"
|
||||
echo "Webcam mic: ${WEBCAM_MIC:-not found}"
|
||||
echo "Streaming to: ${RECEIVER_IP}:${PORT}"
|
||||
|
||||
if [ -n "$WEBCAM_MIC" ]; then
|
||||
echo "Webcam mic found, mixing desktop + mic"
|
||||
# Two pulse inputs: desktop monitor + webcam mic, mixed into one audio stream
|
||||
exec ffmpeg \
|
||||
-init_hw_device drm=drm:/dev/dri/card0 \
|
||||
-init_hw_device vaapi=va@drm \
|
||||
-device /dev/dri/card0 -f kmsgrab -framerate 30 -i - \
|
||||
-f pulse -i "$MONITOR" \
|
||||
-f pulse -i "$WEBCAM_MIC" \
|
||||
-filter_complex "[1:a][2:a]amix=inputs=2:duration=longest[aout]" \
|
||||
-map 0:v -map "[aout]" \
|
||||
-vf 'hwmap=derive_device=vaapi,scale_vaapi=w=1920:h=1080:format=nv12,fps=30' \
|
||||
-c:v h264_vaapi -qp 20 -g 30 -keyint_min 30 -bf 0 \
|
||||
-c:a aac -b:a 128k \
|
||||
-flush_packets 1 -fflags nobuffer -muxdelay 0 -muxpreload 0 \
|
||||
-f mpegts "tcp://${RECEIVER_IP}:${PORT}" \
|
||||
-hide_banner
|
||||
else
|
||||
echo "No webcam mic, desktop audio only"
|
||||
exec ffmpeg \
|
||||
-init_hw_device drm=drm:/dev/dri/card0 \
|
||||
-init_hw_device vaapi=va@drm \
|
||||
-device /dev/dri/card0 -f kmsgrab -framerate 30 -i - \
|
||||
-f pulse -i "$MONITOR" \
|
||||
-vf 'hwmap=derive_device=vaapi,scale_vaapi=w=1920:h=1080:format=nv12,fps=30' \
|
||||
-c:v h264_vaapi -qp 20 -g 30 -keyint_min 30 -bf 0 \
|
||||
-c:a aac -b:a 128k \
|
||||
-flush_packets 1 -fflags nobuffer -muxdelay 0 -muxpreload 0 \
|
||||
-f mpegts "tcp://${RECEIVER_IP}:${PORT}" \
|
||||
-hide_banner
|
||||
fi
|
||||
# Raise fd limit for long sessions (DMA-BUF fds from kmsgrab)
|
||||
ulimit -n 65536
|
||||
|
||||
PROGRESS_FILE=$(mktemp)
|
||||
trap 'rm -f "$PROGRESS_FILE"' EXIT
|
||||
|
||||
start_ffmpeg() {
|
||||
local args=(
|
||||
ffmpeg
|
||||
-init_hw_device drm=drm:/dev/dri/card0
|
||||
-init_hw_device vaapi=va@drm
|
||||
-thread_queue_size 64 -device /dev/dri/card0 -f kmsgrab -framerate 30 -i -
|
||||
-thread_queue_size 1024 -f pulse -i "$MONITOR"
|
||||
)
|
||||
|
||||
if [ -n "$WEBCAM_MIC" ]; then
|
||||
args+=(-thread_queue_size 1024 -f pulse -i "$WEBCAM_MIC")
|
||||
args+=(-filter_complex "[1:a][2:a]amix=inputs=2:duration=longest[aout]")
|
||||
args+=(-map 0:v -map "[aout]")
|
||||
fi
|
||||
|
||||
args+=(
|
||||
-vf 'hwmap=derive_device=vaapi,scale_vaapi=w=1920:h=1080:format=nv12,fps=30'
|
||||
-c:v h264_vaapi -qp 20 -g 30 -keyint_min 30 -bf 0
|
||||
-c:a aac -b:a 128k
|
||||
-max_muxing_queue_size 64
|
||||
-flush_packets 1 -fflags nobuffer -muxdelay 0 -muxpreload 0
|
||||
-f mpegts "tcp://${RECEIVER_IP}:${PORT}"
|
||||
-hide_banner -progress "$PROGRESS_FILE"
|
||||
)
|
||||
|
||||
"${args[@]}" &
|
||||
echo $!
|
||||
}
|
||||
|
||||
get_frame_count() {
|
||||
# -progress file writes key=value pairs; frame= is the video frame counter
|
||||
grep -oP '^frame=\K[0-9]+' "$PROGRESS_FILE" 2>/dev/null | tail -1
|
||||
}
|
||||
|
||||
while true; do
|
||||
echo "--- Starting sender $(date) ---"
|
||||
> "$PROGRESS_FILE" # reset
|
||||
|
||||
FFPID=$(start_ffmpeg)
|
||||
echo "ffmpeg started: pid=$FFPID"
|
||||
|
||||
last_frame=0
|
||||
stall_since=$SECONDS
|
||||
|
||||
while kill -0 "$FFPID" 2>/dev/null; do
|
||||
sleep 2
|
||||
|
||||
cur_frame=$(get_frame_count)
|
||||
cur_frame=${cur_frame:-0}
|
||||
|
||||
if (( cur_frame > last_frame )); then
|
||||
last_frame=$cur_frame
|
||||
stall_since=$SECONDS
|
||||
fi
|
||||
|
||||
if (( SECONDS - stall_since > STALL_TIMEOUT )); then
|
||||
echo "Video stalled at frame $last_frame for ${STALL_TIMEOUT}s — killing ffmpeg"
|
||||
kill "$FFPID" 2>/dev/null
|
||||
wait "$FFPID" 2>/dev/null
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if ! kill -0 "$FFPID" 2>/dev/null; then
|
||||
wait "$FFPID" 2>/dev/null
|
||||
rc=$?
|
||||
if (( rc == 0 )); then
|
||||
echo "ffmpeg exited cleanly"
|
||||
break
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Restarting in 2s..."
|
||||
sleep 2
|
||||
done
|
||||
|
||||
Reference in New Issue
Block a user