const express = require('express'); const cors = require('cors'); const { spawn } = require('child_process'); const dotenv = require('dotenv'); dotenv.config(); const app = express(); app.use(cors()); const port = process.env.PORT || 3000; const rtspUrl = process.env.RTSP_URL; app.get('/stream', (req, res) => { if (!rtspUrl) { return res.status(500).send('RTSP_URL not configured in .env'); } res.writeHead(200, { 'Content-Type': 'multipart/x-mixed-replace; boundary=ffserver', 'Cache-Control': 'no-cache', 'Connection': 'close', 'Pragma': 'no-cache' }); const ffmpegArgs = [ '-rtsp_transport', 'tcp', '-i', rtspUrl, '-f', 'mpjpeg', '-r', '15', // 15 fps is enough for motion detection '-q:v', '5', // Quality (2-31, lower is better) '-s', '1280x720', // Resize to 720p to save bandwidth and CPU '-' // Output to stdout ]; console.log('Starting ffmpeg with args:', ffmpegArgs.join(' ')); const ffmpeg = spawn('ffmpeg', ffmpegArgs); ffmpeg.stdout.on('data', (data) => { res.write(data); }); ffmpeg.stderr.on('data', (data) => { // Uncomment for debugging ffmpeg errors // console.error(`ffmpeg stderr: ${data.toString()}`); }); ffmpeg.on('close', (code) => { console.log(`ffmpeg process exited with code ${code}`); res.end(); }); req.on('close', () => { console.log('Client disconnected, killing ffmpeg process'); ffmpeg.kill('SIGKILL'); }); }); app.listen(port, () => { console.log(`Server listening on port ${port}`); console.log(`MJPEG Stream available at http://localhost:${port}/stream`); });