546 lines
11 KiB
Markdown
546 lines
11 KiB
Markdown
# 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 |