#rtsp
#hls
#node-js
#streaming
#ffmpeg
Streaming Live RTSP Camera Feeds in a Web Browser with Node.js and HLS
How I set up a media server to convert RTSP camera streams into HLS for playback in a React backoffice
• 5 min read min read
The Problem
IP cameras output RTSP streams. Browsers can't play RTSP natively. We needed to display live warehouse camera feeds inside a React backoffice.
The Solution: RTSP → FFmpeg → HLS → Browser
FFmpeg converts the RTSP stream into HLS (HTTP Live Streaming) segments that any browser can play.
const { spawn } = require('child_process');
const path = require('path');
function startStream(cameraId, rtspUrl) {
const outputDir = path.join(__dirname, 'streams', cameraId);
const ffmpeg = spawn('ffmpeg', [
'-i', rtspUrl,
'-c:v', 'libx264',
'-preset', 'ultrafast',
'-tune', 'zerolatency',
'-f', 'hls',
'-hls_time', '2',
'-hls_list_size', '3',
'-hls_flags', 'delete_segments',
path.join(outputDir, 'stream.m3u8')
]);
ffmpeg.stderr.on('data', (data) => {
console.log(`Camera ${cameraId}:`, data.toString());
});
return ffmpeg;
}
Playing HLS in React
import Hls from 'hls.js';
import { useEffect, useRef } from 'react';
export function CameraFeed({ cameraId }) {
const videoRef = useRef(null);
useEffect(() => {
const hls = new Hls();
hls.loadSource(`/streams/${cameraId}/stream.m3u8`);
hls.attachMedia(videoRef.current);
return () => hls.destroy();
}, [cameraId]);
return <video ref={videoRef} autoPlay muted />;
}
Key Settings for Low Latency
-preset ultrafast— reduces encoding time-tune zerolatency— removes buffering optimizations that add delay-hls_time 2— 2 second segments keep latency low-hls_list_size 3— only keep last 3 segments in playlist