The simple JavaScript express() server and video client code samples below demonstrate the essential elements of HTTP Live Streaming (HLS) by a Raspberry Pi and Camera. The code was tested on the RPi Zero 2W test set shown in the accompanying figure.
The libcamera-vid and ffmpeg tools comprise the software pipeline for the video stream. The libcamera-vid output is incompatible with the HTML5 <video> element in the stream client; the ffmpeg tool formats the video stream for HTML5 compatibility.
Project Requirements
HW:
- Raspberry Pi with Video Camera installed
SW:
- Node
- NPM
- libcamera and tools
- ffmpeg
/** Nodejs Server Code
Streams Raspberry Pi Camera video
*/
const express = require('express');
const { spawn } = require('child_process');
const fs = require('fs');
/** @global */
const logger = require('morgan');
const path = require('path');
const app = express();
const port = 8554;
app.use(logger('dev'));
// Serve static files from public directory
app.use(express.static('public'));
// Route to start streaming
app.get('/start-stream', (req, res) => {
// Start the camera stream using libcamera-vid piped into FFmpeg for HLS conversion
const cameraStream = spawn('libcamera-vid', ['-t', '0', '-n', '--inline', '--listen', '-o', '-']);
console.log('Spawned cameraStream ...');
const ffmpeg = spawn('ffmpeg', [
'-i', '-',
'-c:v', 'copy',
'-f', 'hls',
'-preset', 'ultrafast',
'-tune', 'zerolatency',
'-g', '30',
'-hls_time', '2',
'-hls_list_size', '3',
'-hls_flags', 'delete_segments+append_list',
'-loglevel', 'error',
'./public/stream.m3u8'
]);
console.log('Spawned ffmpeg transcoder ...');
cameraStream.stdout.pipe(ffmpeg.stdin);
console.log('Setup cameraStream - ffmpeg pipe ...');
cameraStream.stderr.on('data', (data) => {
console.error(`libcamera-vid stderr: ${data}`);
});
ffmpeg.stderr.on('data', (data) => {
console.error(`ffmpeg stderr: ${data}`);
});
res.send('Streaming started');
});
// Start the Express server
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});
Camera Stream
Video Pipeline Attributes
libcamera-vid
- -t 0. Run indefinitely (ie, -t specifies the stream duration as N seconds; if N=0, the stream runs indefinitely)
- -n Run without the libcamera preview window (the preview would disrupt the video pipeline in this configuration)
- — inline Embeds the camera controls in the video stream
- — listen
- -o – Send the output video to stdout.
ffmpeg
- -i – Use stdin as input
- -c:v copy Copies the video stream (-c:v) without recoding the stream.
- -f hls Format the libcamera-vid H.264 video stream for HLS to the client
- -preset ultrafast
- -tune zerolatency
- -g 30 The ‘-g’ flag sets the number of pictures (frames) in a group
- -hls_time 2
- -hls_list_size 3
- -loglevel error
- ./public/stream.m3u8 Serve the stream to the static directory “.public” with name ‘stream.m3u8’