OC openvibe.community
Paste Bash

whip-printer-stream.sh (command line WHIP on raspi)

Created 49d ago · 11 views

Language
Bash
Lines
178
Characters
4574
Bash · teal-dock-83
#!/usr/bin/env bash
set -euo pipefail

CAM=/dev/video0
KEY_FILE=/opt/ai/conf/whip-key
START_DELAY=20
CHECK_URL=https://whip.hobostreamer.com/
BACKOFF=5
MAX_BACKOFF=300

choose_video_size() {
  if ! command -v v4l2-ctl >/dev/null 2>&1; then
    printf '%s\n' '640x480'
    return
  fi

  local size
  size=$(v4l2-ctl -d "$CAM" --list-formats-ext 2>/dev/null | awk '
    /Size: Discrete/ {
      sz = $3;
      split(sz, dims, "x");
      width = dims[1] + 0;
      height = dims[2] + 0;
      area = width * height;
      if (width <= 640 && height <= 480) {
        candidate = area "|" sz;
      } else {
        candidate = "";
      }
      next
    }
    /Interval: Discrete .*30(\.000)? fps/ && candidate {
      print candidate;
      candidate = "";
    }
  ' | sort -t'|' -k1,1nr | head -n 1 | cut -d'|' -f2)

  if [[ -z "$size" ]]; then
    printf '%s\n' '640x480'
  else
    printf '%s\n' "$size"
  fi
}

choose_video_bitrate() {
  case "$1" in
    1280x720) printf '%s\n' '1500k' ;;
    1024x576|960x720) printf '%s\n' '1200k' ;;
    640x480) printf '%s\n' '900k' ;;
    640x360) printf '%s\n' '900k' ;;
    *) printf '%s\n' '900k' ;;
  esac
}

choose_buffer_size() {
  case "$1" in
    1500k) printf '%s\n' '3000k' ;;
    1200k) printf '%s\n' '2400k' ;;
    900k) printf '%s\n' '1800k' ;;
    *) printf '%s\n' '1800k' ;;
  esac
}

choose_frame_rate() {
  case "$1" in
    1280x720) printf '%s\n' '15' ;;
    640x480) printf '%s\n' '20' ;;
    *) printf '%s\n' '30' ;;
  esac
}

choose_input_format() {
  local target="$1"
  if ! command -v v4l2-ctl >/dev/null 2>&1; then
    printf '%s\n' 'mjpeg'
    return
  fi

  local format
  format=$(v4l2-ctl -d "$CAM" --list-formats-ext 2>/dev/null | awk -v target="$target" '
    /^[[:space:]]*\[[0-9]+\]:/ {
      line = $0;
      gsub(/^[[:space:]]*\[[0-9]+\]:[[:space:]]*\x27/, "", line);
      gsub(/\x27.*$/, "", line);
      curfmt = line;
      next
    }
    /^[[:space:]]*Size: Discrete/ {
      if ($3 == target) {
        size_ok = 1;
      } else {
        size_ok = 0;
      }
      next
    }
    /^[[:space:]]*Interval: Discrete .*30(\.000)? fps/ && size_ok {
      if (curfmt == "YUYV") {
        print "yuyv422";
        exit
      }
      if (curfmt == "MJPG") {
        print "mjpeg";
        exit
      }
    }
  ')

  if [[ -z "$format" ]]; then
    printf '%s\n' 'mjpeg'
  else
    printf '%s\n' "$format"
  fi
}

check_connectivity() {
  if command -v curl >/dev/null 2>&1; then
    curl -fsS --connect-timeout 10 "$CHECK_URL" >/dev/null 2>&1 && return 0
  elif command -v ping >/dev/null 2>&1; then
    ping -c 1 -W 2 8.8.8.8 >/dev/null 2>&1 && return 0
  fi
  return 1
}

if [[ "$START_DELAY" -gt 0 ]]; then
  echo "$(date) startup delay: waiting $START_DELAY seconds for network"
  sleep "$START_DELAY"
fi

while true; do
  if [[ ! -c "$CAM" ]]; then
    echo "$(date) camera missing: $CAM"
    sleep 10
    continue
  fi

  if [[ ! -f "$KEY_FILE" ]]; then
    echo "$(date) key file missing: $KEY_FILE"
    sleep "$BACKOFF"
    BACKOFF=$(( BACKOFF * 2 ))
    if (( BACKOFF > MAX_BACKOFF )); then BACKOFF=$MAX_BACKOFF; fi
    continue
  fi

  STREAM_KEY="$(tr -d '\r\n ' < "$KEY_FILE")"
  URL="https://whip.hobostreamer.com/whip/50?key=$STREAM_KEY"

  if ! check_connectivity; then
    echo "$(date) network/HoboStreamer unreachable, waiting $BACKOFF seconds"
    sleep "$BACKOFF"
    BACKOFF=$(( BACKOFF * 2 ))
    if (( BACKOFF > MAX_BACKOFF )); then BACKOFF=$MAX_BACKOFF; fi
    continue
  fi
  VIDEO_SIZE="$(choose_video_size)"
  VIDEO_BITRATE="$(choose_video_bitrate "$VIDEO_SIZE")"
  VIDEO_BUFSIZE="$(choose_buffer_size "$VIDEO_BITRATE")"
  VIDEO_FPS="$(choose_frame_rate "$VIDEO_SIZE")"
  VIDEO_FORMAT="$(choose_input_format "$VIDEO_SIZE")"

  echo "$(date) using camera resolution $VIDEO_SIZE at $VIDEO_BITRATE (bufsize=$VIDEO_BUFSIZE) fps=$VIDEO_FPS format=$VIDEO_FORMAT"

  ffmpeg -hide_banner -loglevel info \
    -f v4l2 -input_format "$VIDEO_FORMAT" -video_size "$VIDEO_SIZE" -framerate "$VIDEO_FPS" -i "$CAM" \
    -f alsa -i default \
    -vf format=yuv420p \
    -c:v libx264 -preset ultrafast -tune zerolatency \
    -profile:v baseline -level 3.0 \
    -x264-params "keyint=30:min-keyint=30:scenecut=0:force-cfr=1:repeat-headers=1" \
    -b:v "$VIDEO_BITRATE" -maxrate "$VIDEO_BITRATE" -bufsize "$VIDEO_BUFSIZE" \
    -c:a libopus -b:a 64k -ar 48000 \
    -ts_buffer_size 20M \
    -f whip "$URL"

  echo "$(date) FFmpeg exited. retrying in $BACKOFF seconds."
  sleep "$BACKOFF"
  BACKOFF=$(( BACKOFF * 2 ))
  if (( BACKOFF > MAX_BACKOFF )); then BACKOFF=$MAX_BACKOFF; fi
done
← All pastes
Community pulse
More pastes Browse all →
TEXT twin birdies 27 views · 27d ago TEXT The Jeffrey Twins Grabbing 25 views · 27d ago TEXT Screenshot 14 views · 28d ago TEXT Screenshot 13 views · 28d ago TEXT Screenshot 15 views · 30d ago TEXT Guy belongs into Circus with that trick 12 views · 30d ago TEXT SDXL Sucks ass 12 views · 30d ago TEXT Screenshot 19 views · 31d ago TEXT Screenshot 15 views · 31d ago TEXT Korean Streamer 19 views · 31d ago TEXT Some beautiful Art 11 views · 31d ago TEXT Some kind of Demo account? 13 views · 32d ago TEXT Screenshot 8 views · 33d ago TEXT Screenshot 8 views · 33d ago TEXT Screenshot 13 views · 33d ago TEXT Screenshot 9 views · 33d ago