pipr is a universal shell tool for piping any video or livestream (YouTube, Twitch, Kick, Odysee, YouNow, etc – see yt-dlp’s supported sites) to an RTMP endpoint using yt-dlp and ffmpeg.
It prefers stream copy first for lowest latency/CPU, with an automatic fallback to re-encoding when copy isn’t possible.
- Supports any site supported by yt-dlp (YouTube, Twitch, Kick, Odysee, YouNow, and hundreds more)
- Auto-detects source domain and logs accordingly
- Extracts source via
yt-dlp(--get-url), with multi-URL handling (separate A/V) and mapping - Streams to RTMP with
ffmpeg - Copy-first strategy with automatic fallback to re-encoding
- Re-encoding controls: encoder, bitrate, preset, audio bitrate/rate, keyframe interval (seconds or frames), GOP, optional FPS alignment
- Input resilience: reconnect flags for HTTP(S) sources with conditional
http_persistentsupport (automatically detected) - Optional real-time pacing for VOD-to-RTMP streaming
- Optional HTTP header propagation from yt-dlp to ffmpeg
- Tunable buffering:
analyzedurationandprobesize(defaults preserved: 20M/100M) - Encoder-specific optimizations for libx264 and NVENC
- Improved rate control for more predictable RTMP output
- Robust logging with sanitizer: masks RTMP endpoints and reduces HTTP(S) URLs to
protocol://host/... - yt-dlp pass-through flags for cookies/headers/custom format selection
- Preflight validation: tool version logging and rtmps protocol checking
- Bash 3.2 compatibility (fallback for
mapfile/readarrayon older macOS)
yt-dlpffmpeg- Bash 3.2+ (works on Linux/macOS; includes a compatibility fallback for macOS’s default Bash 3.2)
- Optional:
jqif you use--propagate-headers
Examples (adjust to your platform):
- macOS (Homebrew):
brew install yt-dlp ffmpeg jq
- Debian/Ubuntu:
sudo apt-get update && sudo apt-get install -y yt-dlp ffmpeg jq
- Arch:
sudo pacman -S yt-dlp ffmpeg jq
- Clone or download this repo
- Make the script executable:
chmod +x pipr
- Run directly from the repo root or place it on your
$PATH(e.g.,/usr/local/bin)
# Basic usage (copy first, fallback to encode if needed):
pipr "https://www.youtube.com/watch?v=XXXXX" "rtmp://your-endpoint/live/stream_key"
# Verbose mode (shows ffmpeg progress in terminal; sanitized):
pipr -v "https://kick.com/<channelname>" "rtmp://your-endpoint/live/stream_key"
# Force re-encoding and tune video/audio:
pipr --force-encoding --encoder libx264 --bitrate 4500k --preset veryfast \
--audio-bitrate 160k --audio-rate 48k \
"https://www.twitch.tv/<channelname>" "rtmp://your-endpoint/live/stream_key"
# Set keyframe interval by seconds (common 2s) and align GOP via FPS:
pipr --force-encoding --encoder libx264 --bitrate 6000k --preset fast \
--keyframe-interval 2s --fps 60 \
"https://www.example.com/video" "rtmp://your-endpoint/live/stream_key"
# Stream a pre-recorded video with real-time pacing (VOD to RTMP):
pipr --realtime --force-encoding --encoder libx264 --bitrate 4500k \
"https://www.example.com/vod.mp4" "rtmp://your-endpoint/live/stream_key"
# Propagate yt-dlp HTTP headers to ffmpeg (requires jq):
pipr --propagate-headers --force-encoding --encoder libx264 --bitrate 4500k \
"https://www.example.com/video" "rtmp://your-endpoint/live/stream_key"
# Enable file logging with custom location:
pipr --log-file /tmp/my-stream.log \
"https://www.youtube.com/watch?v=XXXXX" "rtmp://your-endpoint/live/stream_key"
# Enable file logging with default location (pipr.log):
pipr --log-file \
"https://www.youtube.com/watch?v=XXXXX" "rtmp://your-endpoint/live/stream_key"
# Keep buffering defaults explicitly (values are tunable, defaults preserved):
pipr --analyzeduration 20M --probesize 100M \
"https://www.youtube.com/watch?v=XXXXX" "rtmp://your-endpoint/live/stream_key"
# yt-dlp: pass cookies file (repeatable --ytdlp-arg)
pipr --ytdlp-arg "--cookies cookies.txt" \
"https://www.example.com/live" "rtmp://your-endpoint/live/stream_key"
# yt-dlp: add custom headers (repeatable)
pipr --ytdlp-arg "--add-header" --ytdlp-arg "Authorization: Bearer <TOKEN>" \
"https://www.example.com/live" "rtmp://your-endpoint/live/stream_key"
# yt-dlp: override format selection
# Prefer H.264/AAC where possible for higher chance of copy-first success
pipr --ytdlp-format "bv*[vcodec*=avc1]+ba[acodec*=mp4a]/b[ext=mp4]" \
"https://www.example.com/v" "rtmp://your-endpoint/live/stream_key"-
General
-v: Verbose mode; shows ffmpeg progress and mirrors yt-dlp/ffmpeg output to terminal (and log if file logging is enabled).--force-encoding: Skip stream copy and start with re-encoding.--realtime: Apply real-time pacing (-re) to HTTP/HTTPS inputs for VOD-to-RTMP streaming.--propagate-headers: Fetch and forward yt-dlp HTTP headers to ffmpeg. Requiresjq. Ifjqis not available, a warning is logged and execution continues without header propagation.
-
Video encoding
--encoder <name>: Video encoder (default:libx264). Examples:libx264,h264_nvenc,hevc_videotoolbox.--bitrate <vbitrate>: Video bitrate (e.g.,4500k,5M). When specified, rate control is tuned withmaxrate = 1.07 * bitrateandbufsize = 2 * bitrate.--preset <preset>: Encoder preset (default:veryfast). Examples:veryfast,fast,medium.--gop <frames>: GOP size (keyframe interval in frames). Applies-g <frames>and-sc_threshold 0.--keyframe-interval <value>: Keyframe interval in seconds or frames; overrides--gop.- Examples:
2s,2.0s(seconds), or120(frames). - Seconds-based: applies
-force_key_frames "expr:gte(t,n_forced*seconds)"and-sc_threshold 0. - If
--fpsis also set, applies-g = round(seconds * fps)for targets that prefer matching GOP.
- Examples:
--fps <rate>: Optional helper for--keyframe-intervalin seconds to align-g. Example:--keyframe-interval 2s --fps 60->-g 120.
-
Audio encoding
--audio-bitrate <abitrate>: Audio bitrate (e.g.,128k,160k).--audio-rate <arate>: Audio sample rate (e.g.,44100,48k).
-
Buffering and probing
--analyzeduration <value>: ffmpeg analyzeduration (default:20M).--probesize <value>: ffmpeg probesize (default:100M).
-
Logging
--log-file [<path>]: Enable file logging. Optionally specify a log file path (default:pipr.logwhen enabled). File logging is OFF by default.--no-log-file: Explicitly disable file logging (default behavior). Terminal output still shows high-level pipr logs and (in-vmode) sanitized tool output.
-
yt-dlp pass-through
--ytdlp-format <fmt>: Override yt-dlp format selector (default:bestvideo*+bestaudio/best).--ytdlp-arg <arg>: Pass-through argument to yt-dlp. Repeatable.- Examples:
--ytdlp-arg "--cookies cookies.txt"--ytdlp-arg "--add-header" --ytdlp-arg "Authorization: Bearer <TOKEN>"
- Examples:
Notes on precedence
- Copy-first: Without
--force-encoding, the tool tries-c copyfirst. If copy fails, it re-encodes using your flags. - If both
--keyframe-intervaland--gopare provided,--keyframe-intervaltakes precedence.
To enhance resilience and compatibility for production streaming, pipr applies several defaults automatically:
-
Conditional HTTP flag support
- The
http_persistentflag is only applied when supported by your ffmpeg build (detected viaffmpeg -h protocol=http). This prevents “Option http_persistent not found” failures.
- The
-
Conditional throttling
- The
-reflag (real-time playback) is applied only to non-HTTP inputs (files, local streams) to throttle reading. For HTTP/HTTPS inputs,-reis not used by default.
- The
-
Network resilience for HTTP(S) inputs
-rw_timeout 15000000(15 seconds in microseconds) to prevent infinite stalls on network issues-http_persistent 0(when supported) to work better with flaky CDNs that don’t handle persistent connections well- Standard reconnect flags:
-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5 -thread_queue_size 1024before each input to reduce “Too many packets buffered” errors with HLS/DASH
-
Stream mapping defaults
- For single-input sources, pipr explicitly maps video and audio streams (
-map 0:v:0 -map 0:a:0?) with optional audio handling. - For multi-URL cases (separate video/audio), mapping is handled to maintain A/V sync where possible.
- For single-input sources, pipr explicitly maps video and audio streams (
-
RTMP/FLV compatibility defaults
- When re-encoding (either forced or as fallback), pipr automatically adds:
-pix_fmt yuv420pfor broad decoder compatibility-ac 2for stereo audio output- Tuned rate control when
--bitrateis set:-maxrate 1.07 * bitrateand-bufsize 2 * bitrate
- When re-encoding (either forced or as fallback), pipr automatically adds:
-
Encoder-specific optimizations
- libx264:
-profile:v high -tune zerolatencyby default. When GOP is set (via--gopor--keyframe-interval), also adds-x264-params scenecut=0. - NVENC (e.g.,
h264_nvenc,hevc_nvenc): adds-rc cbrand-forced-idr 1for consistent rate control and IDR enforcement.
- libx264:
-
Keyframe and framerate alignment
- When using
--keyframe-intervalwith seconds (e.g.,2s) AND--fpsis provided:- Output framerate is set with
-r <fps> - Constant framerate mode is enforced with
-vsync cfr - GOP size
-gis computed asround(seconds * fps)for predictable keyframe spacing - If
awkis not available and both seconds and fps are integers, shell arithmetic is used as fallback
- Output framerate is set with
- When using
-
Preflight validation
- At startup, pipr logs tool versions (
yt-dlp --versionandffmpeg -version). - If the RTMP endpoint uses
rtmps://, pipr verifies that ffmpeg supports the rtmps protocol before starting.
- At startup, pipr logs tool versions (
These defaults require no additional flags and do not change the existing CLI behavior.
- Bash 3.2 (macOS): pipr includes a fallback for
mapfile/readarrayso it works with the default macOS Bash 3.2 without requiring manual upgrades. - ffmpeg builds vary:
- If your build doesn’t support
http_persistent, pipr will detect and avoid using it. - rtmps requires an ffmpeg build with TLS/rtmps support; pipr preflights this and will exit with a clear error if unsupported.
- If your build doesn’t support
When streaming pre-recorded videos (VOD) to RTMP:
-
Codec compatibility: Stream copy (
-c copy) often fails for VOD content with VP9/Opus or other non-RTMP-compatible codecs. For better success with copy mode:- Use
--ytdlp-formatto prefer H.264/AAC formats:pipr --ytdlp-format "bv*[vcodec*=avc1]+ba[acodec*=mp4a]/b[ext=mp4]" ... - Or use
--force-encodingto re-encode to H.264/AAC:pipr --force-encoding --encoder libx264 --bitrate 4500k ...
- Use
-
Real-time pacing: By default, HTTP/HTTPS inputs are not throttled with
-reto minimize latency for live streams. When streaming VOD content, you may want to add--realtimeto pace the stream:pipr --realtime --force-encoding --encoder libx264 --bitrate 4500k \ "https://www.youtube.com/watch?v=XXXXX" "rtmp://your-endpoint/live/stream_key"Without
--realtime, pipr will push frames as fast as the network and encoder allow, which may cause buffering issues on some RTMP servers. -
Header propagation: Some CDNs require specific HTTP headers for VOD content. Use
--propagate-headers(requiresjq) to automatically forward yt-dlp-derived headers to ffmpeg:pipr --propagate-headers --force-encoding --encoder libx264 \ "https://www.example.com/video" "rtmp://your-endpoint/live/stream_key"
-
“Too many packets buffered”
- pipr adds
-thread_queue_size 1024before inputs; if you still see this, consider lowering input bitrate or network jitter, or forcing re-encode with a reasonable--bitrate.
- pipr adds
-
Copy mode fails or no video on RTMP
- Force encode:
--force-encoding --encoder libx264 --bitrate 4500k - Prefer H.264/AAC via yt-dlp:
--ytdlp-format "bv*[vcodec*=avc1]+ba[acodec*=mp4a]/b[ext=mp4]
- Force encode:
-
rtmps not supported
- Use an ffmpeg build with TLS/rtmps support or switch to
rtmp://. pipr checks support up-front and will explain the failure.
- Use an ffmpeg build with TLS/rtmps support or switch to
-
Keyframe interval requirements (e.g., some platforms require 2s)
- Use seconds-based keyframes plus fps alignment:
pipr --force-encoding --keyframe-interval 2s --fps 60 ...
- Use seconds-based keyframes plus fps alignment:
- File logging is OFF by default. Use
--log-fileto enable logging to a file. - Default (no
-v): pipr runs quietly with minimal output. High-level pipr log lines appear in terminal; ffmpeg shows errors only. - Verbose (
-v): ffmpeg progress stats are shown, andyt-dlp/ffmpegoutput is mirrored to terminal (and to file if--log-fileis used). - Sanitization:
piprmasks RTMP endpoints (e.g.,rtmp://server/app/***abcd) and reduces HTTP(S) URLs toprotocol://host/...in logged/echoed tool output. Review logs before sharing.
This project is free and open source. If you'd like to support pipr and tip the developer, you can donate via:
- Credit Card: tip.m60.live
- Crypto (Monero, Bitcoin, & more): xmrchat.com/m60
Thank you for supporting open source!