Skip to content

Instantly share code, notes, and snippets.

@rakeshopensource
Last active September 29, 2023 17:47
Show Gist options
  • Save rakeshopensource/1a21a0368e952353fd3b5b3f30344e4e to your computer and use it in GitHub Desktop.
Save rakeshopensource/1a21a0368e952353fd3b5b3f30344e4e to your computer and use it in GitHub Desktop.
This handles video streaming and transcoding using FFmpeg. It listens for incoming video streams, transcodes them into different resolutions (720p and 1080p), and generates an HLS (HTTP Live Streaming) playlist file (master.m3u8) that references the transcoded video segments.
import os
import subprocess
import threading
from fastapi import FastAPI
from starlette.responses import Response
from threading import Lock
app = FastAPI()
lock = Lock()
# Function to append content to the master.m3u8 playlist
def append_to_master_m3u8(content):
with lock:
if not os.path.exists("master.m3u8"):
with open("master.m3u8", "w") as f:
f.write("#EXTM3U\n")
f.write("#EXT-X-VERSION:3\n")
f.write("#EXT-X-TARGETDURATION:1\n")
f.write("#EXT-X-MEDIA-SEQUENCE:0\n")
f.write("#EXT-X-PLAYLIST-TYPE:VOD\n")
f.write("#EXT-X-ALLOW-CACHE:NO\n")
with open("master.m3u8", "a") as f:
f.write(content)
# Function to transcode the video stream
def transcode(stream_name, resolution, bitrate, scale):
cmd = [
"ffmpeg", "-i", f"rtmp://localhost/live/{stream_name}", "-vf", f"scale=-1:{scale},format=yuv422p",
"-c:v", "libx264", "-b:v", f"{bitrate}k", "-c:a", "aac", "-f", "hls", "-hls_time", "1",
f"-hls_segment_filename", f"{resolution}/output_%03d.ts", f"{resolution}/{resolution}.m3u8"
]
subprocess.run(cmd)
append_to_master_m3u8(f"#EXT-X-STREAM-INF:BANDWIDTH={bitrate}000,RESOLUTION={scale}\n{resolution}/{resolution}.m3u8\n")
# HTTP POST endpoint to handle incoming video streams
@app.post("/on_publish")
def on_publish(name: str):
stream_name = name
# Create directories and set permissions
for dir_name in ["720p", "1080p"]:
os.makedirs(dir_name, exist_ok=True)
os.chmod(dir_name, 0o755)
# Transcode in parallel for 720p and 1080p
threading.Thread(target=transcode, args=(stream_name, "720p", "2000", "720")).start()
threading.Thread(target=transcode, args=(stream_name, "1080p", "3000", "1080")).start()
return Response(content="OK", status_code=200)
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8080)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment