obs-r2-uploader/streaming/STREAMING-SETUP.md

6.4 KiB
Raw Blame History

Live Streaming Setup Guide

This guide will help you set up hybrid live streaming with HLS + automatic VOD archiving to R2.

Architecture

OBS → RTMP → nginx-rtmp → HLS chunks → Real-time uploader → R2 → Cloudflare Worker → Viewers
                                                                         ↓
                                                                    VOD Archive

Quick Start

1. Start the Streaming Stack

cd streaming
./start-streaming.sh

This will:

  • Start nginx-rtmp server (Docker)
  • Start HLS chunk uploader to R2
  • Display connection info

2. Configure OBS

Settings → Stream

  1. Service: Custom
  2. Server: rtmp://localhost/live
  3. Stream Key: my-stream (or choose your own name like gaming, podcast, etc.)

Settings → Output

Recommended Settings for 1080p60:

  • Output Mode: Advanced
  • Encoder: x264 or Hardware (NVENC/AMD/QuickSync)
  • Rate Control: CBR
  • Bitrate: 6000 Kbps (adjust based on upload speed)
  • Keyframe Interval: 2 seconds
  • CPU Usage Preset: veryfast (or faster for lower-end CPUs)
  • Profile: high
  • Tune: zerolatency

For 720p60:

  • Bitrate: 4500 Kbps

For 1080p30:

  • Bitrate: 4500 Kbps

Settings → Video

  • Base Resolution: 1920x1080 (or your monitor resolution)
  • Output Resolution: 1920x1080 or 1280x720
  • FPS: 60 or 30

Settings → Advanced

  • Process Priority: High (optional, for smoother streaming)

3. Start Streaming

  1. Click "Start Streaming" in OBS
  2. Wait 5-10 seconds for HLS chunks to be created
  3. Access your stream at:
    • Local (testing): http://localhost:8081/hls/my-stream.m3u8
    • Public: https://videos.jeffemmett.com/live/my-stream/my-stream.m3u8

4. Watch Your Stream

In a browser:

  • Use the HLS.js player
  • Or use VLC: Media → Open Network Stream → Enter URL

Test Player HTML:

<!DOCTYPE html>
<html>
<head>
  <script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
</head>
<body>
  <video id="video" controls style="width: 100%; max-width: 1280px;"></video>
  <script>
    const video = document.getElementById('video');
    const src = 'https://videos.jeffemmett.com/live/my-stream/my-stream.m3u8';

    if (Hls.isSupported()) {
      const hls = new Hls();
      hls.loadSource(src);
      hls.attachMedia(video);
      hls.on(Hls.Events.MANIFEST_PARSED, () => {
        video.play();
      });
    } else if (video.canPlayType('application/vnd.apple.mpegurl')) {
      video.src = src;
    }
  </script>
</body>
</html>

5. Stop Streaming

  1. Click "Stop Streaming" in OBS
  2. (Optional) Stop the streaming stack:
    ./stop-streaming.sh
    

How It Works

Real-Time Streaming

  1. OBS sends RTMP stream to rtmp://localhost/live/my-stream
  2. nginx-rtmp receives the stream and segments it into HLS chunks:
    • Creates .m3u8 playlist (updated every 2 seconds)
    • Creates .ts video chunks (2-second segments)
  3. HLS Uploader watches the hls/ directory:
    • Detects new chunks as they're created
    • Immediately uploads to R2 at live/my-stream/
  4. Cloudflare Worker serves the chunks:
    • Viewers request .m3u8 playlist
    • Player loads .ts chunks as they become available
    • ~5-10 second latency end-to-end

Automatic VOD Archiving

  • All HLS chunks remain in R2 after stream ends
  • Can be concatenated into full VOD recording
  • Or left as is for HLS replay

Troubleshooting

Stream won't connect

  • Check if nginx-rtmp is running: docker ps | grep obs-streaming-server
  • Check nginx logs: docker logs obs-streaming-server
  • Verify RTMP URL: rtmp://localhost/live (not rtmp://localhost:1935/live)

Stream is choppy/buffering

  • Lower bitrate in OBS Output settings
  • Check CPU usage - try faster encoder preset
  • Check upload bandwidth - run speed test

Can't see stream on public URL

  • Wait 5-10 seconds after starting stream
  • Check HLS uploader logs: tail -f streaming/hls-uploader.log
  • Verify chunks are being uploaded to R2

High latency (>15 seconds)

  • Normal for HLS - typical latency is 6-15 seconds
  • Lower hls_fragment in nginx.conf to 1s (will increase bandwidth)
  • Consider WebRTC for sub-second latency (different setup)

Advanced Configuration

Multiple Quality Levels

Edit streaming/nginx/nginx.conf:

hls_variant _360p BANDWIDTH=800000;
hls_variant _720p BANDWIDTH=2800000;
hls_variant _1080p BANDWIDTH=5000000;

Change Stream Key

Use any stream key you want - it becomes the folder name in R2:

  • Stream key: my-stream → R2 path: live/my-stream/ (default)
  • Stream key: gaming → R2 path: live/gaming/
  • Stream key: podcast-ep-5 → R2 path: live/podcast-ep-5/

Custom Domain

If using a different domain, update in .env:

PUBLIC_DOMAIN=streams.yourdomain.com

Performance Notes

Bandwidth Usage

  • 720p60 @ 4500kbps: ~2.0 GB/hour
  • 1080p60 @ 6000kbps: ~2.7 GB/hour
  • 1080p30 @ 4500kbps: ~2.0 GB/hour

R2 Costs

  • Storage: $0.015/GB/month
  • Class A Operations (uploads): $4.50/million
  • Class B Operations (downloads): $0.36/million
  • Egress: Free to Cloudflare network

Example cost for 1 hour stream at 1080p60:

  • Storage: ~2.7GB × $0.015 = $0.04/month
  • Uploads: ~1800 chunks × $0.0000045 = $0.008
  • Total: ~$0.05 per hour streamed

Viewer Bandwidth

Viewers consume:

  • 720p: ~4.5 Mbps
  • 1080p: ~6 Mbps

File Structure

streaming/
├── docker-compose.yml          # nginx-rtmp container config
├── nginx/
│   └── nginx.conf             # nginx RTMP + HLS config
├── scripts/
│   ├── on_publish.sh          # Called when stream starts
│   └── on_publish_done.sh     # Called when stream ends
├── hls/                       # HLS output directory (auto-created)
│   ├── my-stream.m3u8         # Playlist
│   └── my-stream-*.ts         # Video chunks
├── start-streaming.sh         # Start everything
├── stop-streaming.sh          # Stop everything
└── STREAMING-SETUP.md         # This file

Next Steps

  • Create a custom player page
  • Set up stream notifications (when stream goes live)
  • Add stream recording/VOD conversion
  • Implement chat/comments
  • Add stream analytics

Support

For issues, check:

  1. Docker logs: docker logs obs-streaming-server
  2. HLS uploader logs: tail -f streaming/hls-uploader.log
  3. Nginx stats: http://localhost:8081/stat