init
This commit is contained in:
546
RTSP_STREAMING_SETUP.md
Normal file
546
RTSP_STREAMING_SETUP.md
Normal file
@@ -0,0 +1,546 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user