update rtmp-client

This commit is contained in:
2026-05-15 21:19:58 +03:30
parent cf04d41a4b
commit cc57ae65af
2 changed files with 171 additions and 172 deletions

View File

@@ -8,17 +8,7 @@ param(
[Parameter(Mandatory = $true)] [Parameter(Mandatory = $true)]
[string[]]$Files, [string[]]$Files,
[switch]$Loop, [switch]$Loop
[string]$Preset = "veryfast",
[string]$VideoBitrate = "2500k",
[string]$VideoBufsize = "5000k",
[string]$AudioBitrate = "128k",
[int]$KeyframeInterval = 60
) )
$ErrorActionPreference = "Stop" $ErrorActionPreference = "Stop"
@@ -34,71 +24,21 @@ function Write-Log {
Write-Host "[$time] $Message" Write-Host "[$time] $Message"
} }
function Test-Ffmpeg { function Test-FFmpeg {
try { try {
Get-Command ffmpeg -ErrorAction Stop | Out-Null Get-Command ffmpeg -ErrorAction Stop | Out-Null
} }
catch { catch {
Write-Error "ffmpeg is not installed or not in PATH." Write-Error "ffmpeg not found in PATH."
exit 1 exit 1
} }
} }
function Build-TargetUrl {
$base = $RtmpUrl.TrimEnd('/')
$key = $StreamKey.TrimStart('/')
return "$base/$key"
}
function Stream-File {
param(
[string]$File,
[string]$TargetUrl
)
Write-Log "Streaming file: $File"
$arguments = @(
"-hide_banner"
"-loglevel", "info"
"-re"
"-i", $File
"-map", "0:v:0"
"-map", "0:a?"
"-c:v", "libx264"
"-preset", $Preset
"-tune", "zerolatency"
"-pix_fmt", "yuv420p"
"-profile:v", "baseline"
"-level", "3.1"
"-b:v", $VideoBitrate
"-maxrate", $VideoBitrate
"-bufsize", $VideoBufsize
"-g", $KeyframeInterval
"-c:a", "aac"
"-b:a", $AudioBitrate
"-ar", "44100"
"-ac", "2"
"-f", "flv"
$TargetUrl
)
$process = Start-Process `
-FilePath "ffmpeg" `
-ArgumentList $arguments `
-NoNewWindow `
-PassThru `
-Wait
return $process.ExitCode
}
################################################## ##################################################
# Validation # Validation
################################################## ##################################################
Test-Ffmpeg Test-FFmpeg
foreach ($file in $Files) { foreach ($file in $Files) {
if (-not (Test-Path $file)) { if (-not (Test-Path $file)) {
@@ -108,31 +48,98 @@ foreach ($file in $Files) {
} }
################################################## ##################################################
# Main # Build playlist
################################################## ##################################################
$targetUrl = Build-TargetUrl $playlistFile = Join-Path $env:TEMP "ffmpeg_playlist.txt"
Write-Log "RTMP target: $targetUrl" if (Test-Path $playlistFile) {
Remove-Item $playlistFile -Force
}
foreach ($file in $Files) {
$fullPath = (Resolve-Path $file).Path.Replace("'", "''")
Add-Content -Path $playlistFile -Value "file '$fullPath'"
}
##################################################
# RTMP URL
##################################################
$targetUrl = "$($RtmpUrl.TrimEnd('/'))/$($StreamKey.TrimStart('/'))"
Write-Log "RTMP Target: $targetUrl"
Write-Log "Playlist: $playlistFile"
##################################################
# FFmpeg args
##################################################
$arguments = @(
"-hide_banner"
"-loglevel", "info"
# Real-time mode
"-re"
# Infinite loop playlist
"-stream_loop", "-1"
# Concat playlist
"-f", "concat"
"-safe", "0"
"-i", $playlistFile
# Video
"-c:v", "libx264"
"-preset", "veryfast"
"-tune", "zerolatency"
"-pix_fmt", "yuv420p"
"-profile:v", "baseline"
"-level", "3.1"
"-b:v", "2500k"
"-maxrate", "2500k"
"-bufsize", "5000k"
"-g", "60"
# Audio
"-c:a", "aac"
"-b:a", "128k"
"-ar", "44100"
"-ac", "2"
# Output
"-f", "flv"
$targetUrl
)
if (-not $Loop) {
# Remove infinite loop if user does not want looping
$arguments = $arguments | Where-Object { $_ -ne "-1" }
}
##################################################
# Run ffmpeg
##################################################
try { try {
do {
foreach ($file in $Files) {
$exitCode = Stream-File ` Write-Log "Starting stream..."
-File $file `
-TargetUrl $targetUrl
if ($exitCode -ne 0) { Start-Process `
Write-Log "ffmpeg exited with code $exitCode" -FilePath "ffmpeg" `
} -ArgumentList $arguments `
} -NoNewWindow `
-Wait
} while ($Loop)
} }
catch { finally {
Write-Log "Streaming interrupted."
if (Test-Path $playlistFile) {
Remove-Item $playlistFile -Force
}
} }
Write-Log "Finished." Write-Log "Finished."

View File

@@ -3,7 +3,7 @@
set -euo pipefail set -euo pipefail
######################################## ########################################
# Simple RTMP Streaming Client # RTMP Playlist Streamer (Single Session)
# Requires: ffmpeg # Requires: ffmpeg
######################################## ########################################
@@ -11,14 +11,14 @@ RTMP_URL=""
STREAM_KEY="" STREAM_KEY=""
LOOP=false LOOP=false
FILES=()
VIDEO_BITRATE="2500k" VIDEO_BITRATE="2500k"
VIDEO_BUFSIZE="5000k" VIDEO_BUFSIZE="5000k"
AUDIO_BITRATE="128k" AUDIO_BITRATE="128k"
PRESET="veryfast" PRESET="veryfast"
KEYFRAME_INTERVAL="60" KEYFRAME_INTERVAL="60"
FILES=()
######################################## ########################################
# Helpers # Helpers
######################################## ########################################
@@ -29,34 +29,15 @@ Usage:
$0 --rtmp-url URL --stream-key KEY --files file1.mp4 [file2.mp4 ...] $0 --rtmp-url URL --stream-key KEY --files file1.mp4 [file2.mp4 ...]
Options: Options:
--rtmp-url RTMP server URL --rtmp-url Example: rtmp://server/live
Example: rtmp://server/live
--stream-key Stream key --stream-key Stream key
--files One or more video files --files One or more video files
--loop Infinite playlist loop
--loop Loop playlist forever
--preset x264 preset
Default: veryfast
--video-bitrate Video bitrate
Default: 2500k
--video-bufsize Video buffer size
Default: 5000k
--audio-bitrate Audio bitrate
Default: 128k
--keyframe-interval GOP size
Default: 60
Example: Example:
$0 \ $0 \
--rtmp-url rtmp://live.example.com/app \ --rtmp-url rtmp://server/live \
--stream-key abc123 \ --stream-key mystream \
--files intro.mp4 movie.mp4 \ --files intro.mp4 movie.mp4 \
--loop --loop
EOF EOF
@@ -67,7 +48,9 @@ log() {
} }
cleanup() { cleanup() {
log "Stopping stream..." log "Cleaning up..."
[[ -f "$PLAYLIST_FILE" ]] && rm -f "$PLAYLIST_FILE"
if [[ -n "${FFMPEG_PID:-}" ]]; then if [[ -n "${FFMPEG_PID:-}" ]]; then
kill "$FFMPEG_PID" 2>/dev/null || true kill "$FFMPEG_PID" 2>/dev/null || true
@@ -106,31 +89,6 @@ while [[ $# -gt 0 ]]; do
shift shift
;; ;;
--preset)
PRESET="$2"
shift 2
;;
--video-bitrate)
VIDEO_BITRATE="$2"
shift 2
;;
--video-bufsize)
VIDEO_BUFSIZE="$2"
shift 2
;;
--audio-bitrate)
AUDIO_BITRATE="$2"
shift 2
;;
--keyframe-interval)
KEYFRAME_INTERVAL="$2"
shift 2
;;
-h|--help) -h|--help)
usage usage
exit 0 exit 0
@@ -182,54 +140,88 @@ done
trap cleanup SIGINT SIGTERM trap cleanup SIGINT SIGTERM
######################################## ########################################
# Main # Build playlist
########################################
PLAYLIST_FILE="$(mktemp)"
for file in "${FILES[@]}"; do
ABS_PATH="$(realpath "$file")"
# Escape single quotes
ESCAPED_PATH="${ABS_PATH//\'/\'\\\'\'}"
echo "file '$ESCAPED_PATH'" >> "$PLAYLIST_FILE"
done
########################################
# Build target URL
######################################## ########################################
TARGET_URL="${RTMP_URL%/}/${STREAM_KEY#/}" TARGET_URL="${RTMP_URL%/}/${STREAM_KEY#/}"
log "RTMP target: $TARGET_URL" log "RTMP Target: $TARGET_URL"
log "Playlist File: $PLAYLIST_FILE"
stream_file() { ########################################
local file="$1" # FFmpeg command
########################################
log "Streaming file: $file" FFMPEG_ARGS=(
-hide_banner
-loglevel info
ffmpeg \ # Real-time playback
-hide_banner \ -re
-loglevel info \
-re \
-i "$file" \
-map 0:v:0 \
-map 0:a? \
-c:v libx264 \
-preset "$PRESET" \
-tune zerolatency \
-pix_fmt yuv420p \
-profile:v baseline \
-level 3.1 \
-b:v "$VIDEO_BITRATE" \
-maxrate "$VIDEO_BITRATE" \
-bufsize "$VIDEO_BUFSIZE" \
-g "$KEYFRAME_INTERVAL" \
-c:a aac \
-b:a "$AUDIO_BITRATE" \
-ar 44100 \
-ac 2 \
-f flv \
"$TARGET_URL" &
FFMPEG_PID=$! # Concat playlist
wait "$FFMPEG_PID" -f concat
} -safe 0
-i "$PLAYLIST_FILE"
while true; do # Video
for file in "${FILES[@]}"; do -c:v libx264
stream_file "$file" -preset "$PRESET"
done -tune zerolatency
-pix_fmt yuv420p
-profile:v baseline
-level 3.1
-b:v "$VIDEO_BITRATE"
-maxrate "$VIDEO_BITRATE"
-bufsize "$VIDEO_BUFSIZE"
-g "$KEYFRAME_INTERVAL"
if [[ "$LOOP" != true ]]; then # Audio
break -c:a aac
fi -b:a "$AUDIO_BITRATE"
done -ar 44100
-ac 2
log "Finished." # Output
-f flv
"$TARGET_URL"
)
########################################
# Infinite loop
########################################
if [[ "$LOOP" == true ]]; then
FFMPEG_ARGS=(
-stream_loop -1
"${FFMPEG_ARGS[@]}"
)
fi
########################################
# Start streaming
########################################
log "Starting stream..."
ffmpeg "${FFMPEG_ARGS[@]}" &
FFMPEG_PID=$!
wait "$FFMPEG_PID"
cleanup