A lightweight HLS (HTTP Live Streaming) server that streams video files using FFmpeg concat demuxer.
- Stream multiple video files as a single continuous HLS stream
- Automatic concat file generation from file lists
- RESTful API for stream control
- Real-time HLS segment serving
- Multiple concurrent streams support
- Graceful shutdown handling
100% standalone - no installation needed!
✅ FFmpeg bundled inside ✅ GPU acceleration (NVIDIA/AMD/Intel) ✅ Auto-opens web player
- Download
hls-streamer-gui-windows.exefrom releases - Right-Click and run as administrator
Prerequisites:
- Node.js (v14 or higher)
- FFmpeg installed and available in PATH
Installation:
cd simple-hls-streamer
npm install
# Run CLI version:
npm start
# Or run GUI version (Windows/Linux/macOS):
npm run start:guiSee BUILD.md for instructions on building standalone executables for Windows, Linux, or macOS.
npm startThe server will start on http://localhost:3000
Create a stream with a list of video files:
curl -X POST http://localhost:3000/api/stream/start \
-H "Content-Type: application/json" \
-d '{
"streamId": "my-stream",
"files": [
"/absolute/path/to/video1.mp4",
"/absolute/path/to/video2.mp4",
"/absolute/path/to/video3.mp4"
]
}'Open in a video player that supports HLS (VLC, ffplay, web browser with hls.js):
http://localhost:3000/stream/my-stream/stream.m3u8
POST /api/stream/start
Start a new HLS stream from a list of files.
Request Body:
{
"streamId": "my-stream",
"files": [
"/path/to/video1.mp4",
"/path/to/video2.mp4"
],
"options": {
"segmentDuration": 6,
"videoBitrate": "1500k",
"audioBitrate": "128k",
"resolution": "1920x1080",
"fps": 30,
"preset": "veryfast"
}
}Response:
{
"success": true,
"stream": {
"streamId": "my-stream",
"m3u8Path": "/stream/my-stream/stream.m3u8",
"outputDir": "/path/to/output/my-stream"
},
"validation": {
"total": 2,
"existing": 2,
"missing": []
}
}POST /api/stream/stop
Stop an active stream.
Request Body:
{
"streamId": "my-stream"
}GET /api/streams
Get all active streams.
Response:
{
"count": 1,
"streams": [
{
"streamId": "my-stream",
"outputDir": "/path/to/output/my-stream",
"uptime": 45000
}
]
}POST /api/playlist/create
Create a concat file without starting a stream.
Request Body:
{
"playlistId": "my-playlist",
"files": [
"/path/to/video1.mp4",
"/path/to/video2.mp4"
]
}GET /api/playlists
List all concat files.
| Option | Default | Description |
|---|---|---|
segmentDuration |
6 |
Duration of each HLS segment in seconds |
videoBitrate |
"1500k" |
Video bitrate |
audioBitrate |
"128k" |
Audio bitrate |
resolution |
"1920x1080" |
Output resolution (width x height) |
fps |
30 |
Frames per second |
preset |
"veryfast" |
FFmpeg encoding preset (ultrafast, veryfast, fast, medium, slow) |
- Master Playlist:
GET /stream/:streamId/stream.m3u8 - Segments:
GET /stream/:streamId/stream_XXX.ts
# Start a stream
curl -X POST http://localhost:3000/api/stream/start \
-H "Content-Type: application/json" \
-d '{
"streamId": "test",
"files": ["/path/to/movie1.mp4", "/path/to/movie2.mp4"]
}'
# Check active streams
curl http://localhost:3000/api/streams
# Play with ffplay
ffplay http://localhost:3000/stream/test/stream.m3u8
# Stop the stream
curl -X POST http://localhost:3000/api/stream/stop \
-H "Content-Type: application/json" \
-d '{"streamId": "test"}'const axios = require('axios');
async function startStream() {
const response = await axios.post('http://localhost:3000/api/stream/start', {
streamId: 'my-channel',
files: [
'/path/to/episode1.mp4',
'/path/to/episode2.mp4',
'/path/to/episode3.mp4'
],
options: {
videoBitrate: '2500k',
resolution: '1920x1080'
}
});
console.log('Stream started:', response.data);
console.log('Watch at:', `http://localhost:3000${response.data.stream.m3u8Path}`);
}
startStream();simple-hls-streamer/
├── src/
│ ├── index.js # Main Express server
│ ├── ffmpeg.js # FFmpeg streaming logic
│ └── playlist.js # Concat file management
├── output/ # HLS output (segments and m3u8)
├── playlists/ # Concat files
├── package.json
└── README.md
- File List → You provide an array of video file paths
- Concat File → A
concat.txtfile is generated in FFmpeg format - FFmpeg → Streams files using
-f concatand outputs HLS segments - Express → Serves the
.m3u8playlist and.tssegments via HTTP - Client → Video player requests segments and plays the stream
- Check that FFmpeg is installed:
ffmpeg -version - Verify all file paths are absolute and exist
- Check server logs for FFmpeg errors
- Wait 5-10 seconds for initial segments to generate
- Check the
output/:streamId/directory for.tsfiles - Ensure FFmpeg has write permissions to output directory
- Increase
segmentDuration(e.g., 10 seconds) - Lower
videoBitratefor slower connections - Use a faster FFmpeg preset (e.g.,
ultrafast)
Run with auto-reload:
npm run devGNU General Public License v2.0 or later
This project uses FFmpeg with GPL components enabled, which requires the entire application to be licensed under GPL. See LICENSE file for details.