Multi-stream video composition with mobile-friendly control interface.
MultiView combines multiple video streams into a single MPEG-TS output with a mobile-optimized web interface for layout control. Perfect for watching multiple sports streams, security cameras, or broadcasts simultaneously.
- π¬ 7 Layout Types - PiP, grids, split-screen, multi-PiP (up to 5 streams)
- π¨ Custom Layout Builder - Drag-and-drop editor for custom layouts
- π± Mobile-First UI - Touch-friendly React interface with iOS PWA support
- πΊ M3U Support - Auto-load channels from M3U playlists
- π Dynamic Audio Control - Select audio source + individual volume control per stream
- β‘ MPEG-TS Streaming - Low-latency output via FFmpeg (Plex/HDHomeRun compatible)
- π Auto-Reconnect - Handles stream failures gracefully
- π³ Docker Ready - Easy deployment with docker-compose
- Docker and docker-compose
- M3U playlist (URL or file)
- Optional Hardware Acceleration (auto-detected):
- NVIDIA GPU (RTX/GTX 1000+) with NVIDIA Container Toolkit
- Intel CPU with QuickSync (6th gen+)
- AMD GPU with VAAPI (RX 400+)
- Fallback: 4+ core CPU for software encoding (always available)
Recommended: Use pre-built image (single container)
# 1. (Optional) Install hardware acceleration support
# - NVIDIA: Install NVIDIA Container Toolkit - see GPU_SETUP.md
# - Intel/AMD: No additional setup needed!
# 2. Clone repository
git clone <repo-url>
cd MultiView
# 3. Configure M3U source (edit M3U_SOURCE in docker-compose.yml)
nano docker-compose.yml
# 4. Deploy with automated script (recommended)
./deploy.sh
# OR manually with docker-compose
docker-compose up -dAlternative: Build locally
If you prefer to build the image yourself:
# Edit docker-compose.yml and uncomment the "build:" section
# Comment out the "image:" line
# Then deploy
docker-compose up -d --buildThe deployment script will auto-detect your server IP and display access URLs.
Access:
- Frontend & API:
http://<server-ip>:9292(single port for both!) - Stream:
http://<server-ip>:9292/stream
Hardware encoder is automatically detected at startup - check logs to see which encoder was selected (NVIDIA/Intel/AMD/CPU).
Quick Deploy: Run ./deploy.sh for automated setup, or see DEPLOY.md for manual options.
Hardware Setup: See GPU_SETUP.md for NVIDIA/Intel/AMD configuration details.
βββββββββββββββ βββββββββββββββ ββββββββββββββββ
β Mobile βββββββΆβ Next.js βββββββΆβ FastAPI β
β Browser ββββββββ Frontend ββββββββ Backend β
βββββββββββββββ βββββββββββββββ ββββββββββββββββ
β
βΌ
ββββββββββββββββ
β FFmpeg β
β Compositor β
ββββββββββββββββ
β
βΌ
ββββββββββββββββ
β MPEG-TS β
β /stream β
ββββββββββββββββ
Stack:
- Frontend: Next.js 15, TypeScript, Tailwind CSS
- Backend: Python, FastAPI, FFmpeg 8.0
- Encoding: Universal hardware support (NVIDIA/Intel/AMD) with CPU fallback
- Streaming: MPEG-TS over HTTP (Plex/HDHomeRun compatible)
- Open frontend:
http://<server-ip>:9292(or on mobile) - Select layout type (e.g., 2x2 grid) or create custom layout
- Assign channels to each slot
- Choose audio source and adjust volumes
- Apply layout - streams start immediately
- Play stream in any player:
http://<server-ip>:9292/stream- Compatible with Plex, VLC, Dispatcharr, HDHomeRun clients
| Layout | Streams | Description |
|---|---|---|
| PiP | 2 | Picture-in-picture: 1 main + 1 inset |
| Split H | 2 | Horizontal split (side-by-side) |
| Split V | 2 | Vertical split (top/bottom) |
| Grid 2x2 | 4 | 4 equal streams in 2x2 grid |
| Multi-PiP 2 | 3 | 1 main + 2 small insets |
| Multi-PiP 3 | 4 | 1 main + 3 small insets |
| Multi-PiP 4 | 5 | 1 main + 4 small insets |
Plus: Custom layout builder with drag-and-drop editor for unlimited layout configurations!
A unified pre-built image is automatically published to GitHub Container Registry on every commit to main:
- Unified Image:
ghcr.io/kikootwo/multiview:latest
The image is built for linux/amd64 architecture and includes:
- Next.js frontend (static build)
- FastAPI backend
- FFmpeg with universal hardware encoder support (NVIDIA/Intel/AMD/CPU)
- Single port (9292) serves both frontend and API
latest- Latest commit on main branchv*- Semantic version releases (e.g.,v1.0.0,v1.0,v1)main- Main branch buildspr-*- Pull request builds (not pushed to registry)
Configure via docker-compose.yml or Docker -e flags:
M3U_SOURCE=http://127.0.0.1:9191/output/m3u?direct=true # M3U playlist URL
ENCODER_PREFERENCE=auto # Encoder: auto, nvidia, intel, amd, cpu
IDLE_TIMEOUT=300 # Standby after 5 min idle
PORT=9292 # Backend portHardware Encoding: Universal image supports all encoder types
auto(default) - Auto-detect best available: nvidia > intel > amd > cpunvidia- Force NVIDIA NVENC (requires NVIDIA GPU + Container Toolkit)intel- Force Intel QuickSync (requires Intel iGPU)amd- Force AMD VAAPI (requires AMD GPU)cpu- Force CPU encoding (libx264, always available)
Note: Frontend and backend are served from the same port (9292), simplifying deployment and networking.
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/channels |
List available channels from M3U |
POST |
/api/channels/refresh |
Reload M3U playlist |
POST |
/api/layout/set |
Apply layout configuration |
GET |
/api/layout/current |
Get current layout config |
POST |
/api/layout/swap-audio |
Swap audio source without restart |
POST |
/api/audio/volume |
Set volume for specific slot |
GET |
/api/audio/volumes |
Get all current volume levels |
GET |
/control/status |
Get system status |
GET |
/control/stop |
Stop streaming (standby) |
GET |
/stream |
MPEG-TS output stream |
Full API documentation in CLAUDE.md.
Backend:
pip install fastapi uvicorn[standard]
python3 -m uvicorn server:app --host 0.0.0.0 --port 9292Frontend:
cd frontend
npm install
npm run devMultiView/
βββ server.py # FastAPI backend + M3U parser
βββ Dockerfile # Backend container
βββ docker-compose.yml # Full stack deployment
βββ frontend/
β βββ app/ # Next.js pages
β βββ components/ # React components
β βββ lib/ # API client & utilities
β βββ types/ # TypeScript definitions
βββ DEPLOY.md # Deployment guide
βββ CLAUDE.md # Architecture documentation
Check which encoder is being used:
- View startup logs:
docker-compose logs multiview | grep "Encoder" - Check status endpoint:
curl http://<server-ip>:9292/control/status(seeencoderfield) - If not using desired encoder, check GPU_SETUP.md for configuration
Can't access frontend:
- Ensure you're accessing via server IP (not
localhost) from mobile - Verify firewall allows port 9292
- Test:
curl http://<server-ip>:9292/control/status - Check logs:
docker-compose logs multiview
No channels loading:
- Verify
M3U_SOURCEis accessible - Check logs:
docker-compose logs multiview - Test M3U URL in browser
Hardware encoding not working:
- Check startup logs for encoder detection results
- NVIDIA: Verify NVIDIA Container Toolkit is installed
- Intel/AMD: Verify
/dev/driexists:ls -la /dev/dri - Force CPU encoding if needed:
ENCODER_PREFERENCE=cpu
Mobile can't access:
- Ensure phone is on same network
- Use server's LAN IP (192.168.x.x), not 127.0.0.1
- Only port 9292 needs to be accessible (firewall rules)
- Test from mobile browser:
http://<server-ip>:9292
This is a personal project for household use. Feel free to fork and customize!
MIT License - See LICENSE file for details
Documentation:
- Deployment Guide - Docker setup & mobile access
- Docker Setup Guide - GitHub Container Registry & image publishing
- Architecture Guide - Technical details & design decisions