# RTSP to HLS Streaming in SvelteKit This guide walks you through setting up real-time RTSP stream conversion to HLS format in your SvelteKit application. ## What's Included - **Backend**: FFmpeg-based RTSP to HLS converter running on Node.js - **Frontend**: SvelteKit component with HLS.js video player - **API**: RESTful endpoints to control streams ## Prerequisites ### System Requirements - **Node.js**: 18 or higher - **FFmpeg**: Must be installed and in your PATH - **Package Manager**: npm or bun ### Install FFmpeg #### macOS ```bash brew install ffmpeg ``` #### Ubuntu/Debian ```bash sudo apt-get update sudo apt-get install ffmpeg ``` #### Windows (Chocolatey) ```bash choco install ffmpeg ``` #### Windows (Scoop) ```bash scoop install ffmpeg ``` #### Verify Installation ```bash ffmpeg -version ``` ## Installation ### 1. Install Dependencies ```bash npm install # or with bun bun install ``` This installs `hls.js` for browser-based HLS playback. ### 2. Project Structure The setup creates the following files: ``` src/ ├── lib/ │ ├── server/ │ │ └── streaming.ts # FFmpeg stream manager │ └── components/ │ └── RTSPVideoPlayer.svelte # Video player component ├── routes/ │ ├── +page.svelte # Home page │ └── api/ │ └── stream/ │ └── +server.ts # Stream API endpoints └── ... static/ └── hls/ # HLS playlists & segments (auto-created) ``` ### 3. Run Development Server ```bash npm run dev ``` Open `http://localhost:5173` in your browser. ## Usage ### Web Interface 1. **Stream ID**: Enter a unique identifier (e.g., "camera-1") 2. **RTSP URL**: Enter your camera's RTSP stream URL 3. **Start Stream**: Click to begin conversion and playback 4. **Stop Stream**: Click to terminate the stream ### Common RTSP URLs **Hikvision Cameras** ``` rtsp://admin:password@192.168.1.100:554/stream rtsp://admin:password@192.168.1.100:554/Streaming/Channels/101 ``` **Dahua Cameras** ``` rtsp://admin:password@192.168.1.100:554/live ``` **Generic IP Cameras** ``` rtsp://user:password@camera-ip:554/stream rtsp://camera-ip:554/stream1 ``` ## API Reference ### Start Stream **Request:** ```bash curl -X POST http://localhost:5173/api/stream \ -H "Content-Type: application/json" \ -d '{ "action": "start", "streamId": "camera-1", "rtspUrl": "rtsp://192.168.1.100:554/stream" }' ``` **Response:** ```json { "playlistUrl": "/hls/camera-1.m3u8" } ``` ### Stop Stream **Request:** ```bash curl -X POST http://localhost:5173/api/stream \ -H "Content-Type: application/json" \ -d '{ "action": "stop", "streamId": "camera-1" }' ``` **Response:** ```json { "success": true } ``` ### Get Stream Status **Request:** ```bash curl -X POST http://localhost:5173/api/stream \ -H "Content-Type: application/json" \ -d '{ "action": "status", "streamId": "camera-1" }' ``` **Response:** ```json { "streamId": "camera-1", "rtspUrl": "rtsp://192.168.1.100:554/stream", "startedAt": "2024-01-15T10:30:45.123Z", "isRunning": true, "playlistUrl": "/hls/camera-1.m3u8" } ``` ### List All Streams **Request:** ```bash curl -X POST http://localhost:5173/api/stream \ -H "Content-Type: application/json" \ -d '{"action": "list"}' ``` **Response:** ```json { "streams": [ { "streamId": "camera-1", "rtspUrl": "rtsp://192.168.1.100:554/stream", "startedAt": "2024-01-15T10:30:45.123Z", "isRunning": true, "playlistUrl": "/hls/camera-1.m3u8" } ] } ``` ## Configuration ### FFmpeg Parameters Edit `src/lib/server/streaming.ts` to adjust encoding parameters: ```typescript // Current defaults '-hls_time', '10', // Segment duration (seconds) '-hls_list_size', '3', // Number of segments to keep '-preset', 'fast', // Encoding speed '-b:a', '128k', // Audio bitrate ``` ### Low Latency Setup For real-time applications, modify the FFmpeg arguments: ```typescript '-hls_time', '2', // 2-second segments '-hls_list_size', '5', // Keep more segments '-preset', 'ultrafast', // Fastest encoding '-flags', '+low_delay', // Low-delay mode ``` ### High Quality Setup ```typescript '-crf', '23', // Quality (0-51, lower=better) '-b:v', '2500k', // Video bitrate '-c:a', 'aac', '-b:a', '192k', // Higher audio quality ``` ### GPU Acceleration (NVIDIA) ```typescript '-c:v', 'h264_nvenc', // NVIDIA encoder '-preset', 'fast', // fast, medium, slow ``` ## Troubleshooting ### "ffmpeg: command not found" FFmpeg is not installed or not in your system PATH. **Solution:** Reinstall FFmpeg and ensure it's in your PATH, then restart your terminal. ```bash # Verify FFmpeg is accessible which ffmpeg ffmpeg -version ``` ### Stream won't connect Check the following: 1. **RTSP URL is correct**: Test with VLC player first 2. **Network connectivity**: Ping the camera IP 3. **Firewall rules**: Ensure port 554 (default RTSP) is open 4. **Camera credentials**: Verify username/password in URL 5. **FFmpeg logs**: Check browser console and terminal output ### "Playlist not found" Error This usually means FFmpeg hasn't created the HLS segments yet. **Solution:** Increase the wait time in the component: ```typescript // In RTSPVideoPlayer.svelte, startStream function await new Promise((resolve) => setTimeout(resolve, 3000)); // Increase from 1000 to 3000 ``` ### Video won't play in Safari HLS.js may have issues with some configurations. **Solution:** Check that the HLS.js library is loaded: ```typescript // Verify HLS.js is available if (typeof window !== 'undefined' && !(window as any).HLS) { console.error('HLS.js not loaded'); } ``` ### High CPU Usage The FFmpeg process is using too many resources. **Solution:** Use a faster preset or reduce resolution: ```typescript // Use ultrafast preset '-preset', 'ultrafast', // Or reduce resolution '-vf', 'scale=1280:720', ``` ### High Latency / Buffering Segments are taking too long to generate or playback is laggy. **Solutions:** 1. Reduce segment duration to 2-5 seconds 2. Enable low-latency mode 3. Check network bandwidth 4. Reduce video resolution 5. Close other CPU-intensive applications ## Browser Support | Browser | HLS Support | Notes | |---------|-------------|-------| | Chrome | ✓ HLS.js | Full support via HLS.js library | | Firefox | ✓ HLS.js | Full support via HLS.js library | | Safari | ✓ Native | Native HLS support | | Edge | ✓ HLS.js | Chromium-based, full support | | Mobile Chrome | ✓ HLS.js | Full support | | Mobile Safari | ✓ Native | Native HLS support | | Opera | ✓ HLS.js | Full support | ## Security Best Practices ### 1. Environment Variables for Credentials Never hardcode camera credentials in your code. ```typescript // Load from environment const rtspUrl = `rtsp://${process.env.CAMERA_USER}:${process.env.CAMERA_PASS}@${process.env.CAMERA_IP}:554/stream`; ``` Create a `.env.local` file: ``` CAMERA_USER=admin CAMERA_PASS=password CAMERA_IP=192.168.1.100 ``` ### 2. Restrict API Access Implement authentication on the `/api/stream` endpoint: ```typescript // src/routes/api/stream/+server.ts export async function POST({ request, locals }) { // Check authentication if (!locals.user) { return json({ error: 'Unauthorized' }, { status: 401 }); } // Continue with stream logic } ``` ### 3. Network Security - Use HTTPS in production - Restrict camera access to internal network only - Use VPN for remote access - Implement IP whitelisting ### 4. Process Management FFmpeg runs with server privileges. Ensure: - Minimal file system access - Process limits to prevent DoS - Regular monitoring and logging ## Performance Optimization ### 1. Adaptive Bitrate Implement multiple quality levels: ```typescript // Start multiple streams at different resolutions const streams = [ { id: 'high', resolution: '1920:1080', bitrate: '5000k' }, { id: 'medium', resolution: '1280:720', bitrate: '2500k' }, { id: 'low', resolution: '640:360', bitrate: '1000k' } ]; ``` ### 2. Connection Pooling For multiple concurrent streams, optimize memory usage: ```typescript // Limit concurrent streams const MAX_STREAMS = 5; if (activeStreams.size >= MAX_STREAMS) { return { error: 'Too many concurrent streams' }; } ``` ### 3. Caching Cache HLS segments on a CDN for better performance. ### 4. Hardware Acceleration Use GPU encoding when available: - NVIDIA: `h264_nvenc` - Intel: `h264_qsv` - AMD: `h264_amf` ## Production Deployment ### Docker Create `Dockerfile`: ```dockerfile FROM node:18-slim RUN apt-get update && apt-get install -y ffmpeg && rm -rf /var/lib/apt/lists/* WORKDIR /app COPY package.json package-lock.json ./ RUN npm ci --only=production COPY . . RUN npm run build EXPOSE 3000 CMD ["node", "build/index.js"] ``` Build and run: ```bash docker build -t rtsp-hls-app . docker run -p 3000:3000 \ -e CAMERA_USER=admin \ -e CAMERA_PASS=password \ -e CAMERA_IP=192.168.1.100 \ rtsp-hls-app ``` ### Docker Compose ```yaml version: '3.8' services: app: build: . ports: - "3000:3000" environment: CAMERA_USER: admin CAMERA_PASS: password CAMERA_IP: 192.168.1.100 volumes: - ./static/hls:/app/static/hls restart: unless-stopped ``` ### Nginx Reverse Proxy ```nginx server { listen 443 ssl http2; server_name stream.example.com; ssl_certificate /etc/ssl/certs/cert.pem; ssl_certificate_key /etc/ssl/private/key.pem; location / { proxy_pass http://localhost:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; } location /hls/ { alias /app/static/hls/; expires 1h; add_header Cache-Control "public, max-age=3600"; } } ``` ## Advanced Topics ### Custom Video Filters Add effects or transformations: ```typescript '-vf', 'scale=1280:720,fps=30,format=yuv420p' ``` ### Audio Processing ```typescript '-af', 'aresample=44100' // Resample to 44.1kHz ``` ### Statistics and Monitoring Log stream statistics: ```typescript ffmpegProcess.stdout.on('data', (data) => { console.log(`Stream stats: ${data}`); }); ``` ### Multiple Bitrate HLS (Adaptive) Generate multiple quality versions: ```typescript // Create master playlist pointing to multiple variants const masterPlaylist = `#EXTM3U #EXT-X-STREAM-INF:BANDWIDTH=5000000 high.m3u8 #EXT-X-STREAM-INF:BANDWIDTH=2500000 medium.m3u8 #EXT-X-STREAM-INF:BANDWIDTH=1000000 low.m3u8`; ``` ## Support & Resources - [FFmpeg Documentation](https://ffmpeg.org/documentation.html) - [HLS.js Documentation](https://github.com/video-dev/hls.js/wiki) - [SvelteKit Documentation](https://kit.svelte.dev) - [ONVIF Protocol](https://www.onvif.org/) - For camera device discovery ## License MIT