Add M3U8 to RTMP streamer script
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Stream M3U8 (HLS) live stream to RTMP server using ffmpeg without re-encoding.
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
import signal
|
||||
import os
|
||||
import argparse
|
||||
|
||||
def stream_m3u_to_rtmp(m3u_url, rtmp_url, ffmpeg_path='ffmpeg'):
|
||||
"""
|
||||
Stream M3U8 playlist to RTMP server without re-encoding.
|
||||
|
||||
Args:
|
||||
m3u_url: URL or path to M3U8 playlist file
|
||||
rtmp_url: RTMP server URL (e.g., rtmp://server/live/stream_key)
|
||||
ffmpeg_path: Path to ffmpeg executable (default: 'ffmpeg')
|
||||
"""
|
||||
|
||||
# FFmpeg command for direct stream (no re-encoding)
|
||||
# -i: input M3U8 URL
|
||||
# -c copy: copy codecs without re-encoding
|
||||
# -f flv: output format FLV (required for RTMP)
|
||||
# -flvflags no_duration_filesize: avoid issues with FLV format
|
||||
# -re: read input at native frame rate (important for live streams)
|
||||
# -stream_loop -1: loop the stream indefinitely (for live streams, this might not be needed)
|
||||
|
||||
ffmpeg_cmd = [
|
||||
ffmpeg_path,
|
||||
'-i', m3u_url,
|
||||
'-c', 'copy', # Copy all streams without re-encoding
|
||||
'-f', 'flv', # RTMP requires FLV format
|
||||
'-flvflags', 'no_duration_filesize',
|
||||
'-re', # Read input at native frame rate
|
||||
rtmp_url
|
||||
]
|
||||
|
||||
print(f"Starting stream from: {m3u_url}")
|
||||
print(f"Streaming to: {rtmp_url}")
|
||||
print(f"FFmpeg command: {' '.join(ffmpeg_cmd)}")
|
||||
print("\nPress Ctrl+C to stop streaming...\n")
|
||||
|
||||
try:
|
||||
# Start ffmpeg process
|
||||
process = subprocess.Popen(
|
||||
ffmpeg_cmd,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
universal_newlines=True,
|
||||
bufsize=1
|
||||
)
|
||||
|
||||
# Print ffmpeg output in real-time
|
||||
def print_output(pipe):
|
||||
for line in iter(pipe.readline, ''):
|
||||
if line:
|
||||
print(line.strip())
|
||||
|
||||
# Monitor both stdout and stderr
|
||||
import threading
|
||||
stdout_thread = threading.Thread(target=print_output, args=(process.stdout,))
|
||||
stderr_thread = threading.Thread(target=print_output, args=(process.stderr,))
|
||||
|
||||
stdout_thread.daemon = True
|
||||
stderr_thread.daemon = True
|
||||
stdout_thread.start()
|
||||
stderr_thread.start()
|
||||
|
||||
# Wait for process to complete
|
||||
process.wait()
|
||||
|
||||
if process.returncode != 0:
|
||||
print(f"\nError: FFmpeg exited with code {process.returncode}")
|
||||
return False
|
||||
else:
|
||||
print("\nStream ended successfully")
|
||||
return True
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("\n\nStopping stream...")
|
||||
if process:
|
||||
process.terminate()
|
||||
try:
|
||||
process.wait(timeout=5)
|
||||
except subprocess.TimeoutExpired:
|
||||
process.kill()
|
||||
print("Stream stopped")
|
||||
return False
|
||||
except FileNotFoundError:
|
||||
print(f"Error: FFmpeg not found at '{ffmpeg_path}'")
|
||||
print("Please install FFmpeg or provide the correct path")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
return False
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Stream M3U8 (HLS) live stream to RTMP server without re-encoding'
|
||||
)
|
||||
parser.add_argument(
|
||||
'm3u_url',
|
||||
help='URL or path to M3U8 playlist file'
|
||||
)
|
||||
parser.add_argument(
|
||||
'rtmp_url',
|
||||
help='RTMP server URL (e.g., rtmp://server/live/stream_key)'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--ffmpeg',
|
||||
default='ffmpeg',
|
||||
help='Path to ffmpeg executable (default: ffmpeg)'
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
success = stream_m3u_to_rtmp(args.m3u_url, args.rtmp_url, args.ffmpeg)
|
||||
sys.exit(0 if success else 1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user