dịch chuyển documents
This commit is contained in:
@@ -0,0 +1,194 @@
|
||||
# IPCam Orange Pi Dashboard - FastAPI Backend Skeleton
|
||||
|
||||
## 1. Project Structure
|
||||
|
||||
```
|
||||
ipcam-dashboard/
|
||||
├── main.py
|
||||
├── mediamtx.py
|
||||
├── scheduler.py
|
||||
├── models.py
|
||||
├── config.py
|
||||
└── requirements.txt
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. requirements.txt
|
||||
|
||||
```
|
||||
fastapi
|
||||
uvicorn
|
||||
httpx
|
||||
pydantic
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. config.py
|
||||
|
||||
```python
|
||||
MEDIAMTX_API = "http://127.0.0.1:9997"
|
||||
|
||||
CAMERAS = ["cam1", "cam2", "cam3", "cam4"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. mediamtx.py (MediaMTX API wrapper)
|
||||
|
||||
```python
|
||||
import httpx
|
||||
from config import MEDIAMTX_API, CAMERAS
|
||||
|
||||
|
||||
async def set_recording(enabled: bool):
|
||||
payload = {
|
||||
"paths": {
|
||||
cam: {"record": enabled}
|
||||
for cam in CAMERAS
|
||||
}
|
||||
}
|
||||
|
||||
async with httpx.AsyncClient() as client:
|
||||
r = await client.post(
|
||||
f"{MEDIAMTX_API}/v3/config/paths/patch",
|
||||
json=payload,
|
||||
timeout=5
|
||||
)
|
||||
return r.json()
|
||||
|
||||
|
||||
async def get_paths():
|
||||
async with httpx.AsyncClient() as client:
|
||||
r = await client.get(f"{MEDIAMTX_API}/v3/paths/list")
|
||||
return r.json()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. scheduler.py
|
||||
|
||||
```python
|
||||
from datetime import datetime
|
||||
from mediamtx import set_recording
|
||||
|
||||
_last_state = None
|
||||
|
||||
|
||||
def is_record_time(now: datetime) -> bool:
|
||||
day = now.weekday() # 0=Mon
|
||||
hour = now.hour
|
||||
|
||||
# Weekend: always record
|
||||
if day in (5, 6):
|
||||
return True
|
||||
|
||||
# Weekdays: 18:00 → 08:00
|
||||
return hour >= 18 or hour < 8
|
||||
|
||||
|
||||
async def scheduler_loop():
|
||||
global _last_state
|
||||
|
||||
while True:
|
||||
now = datetime.now()
|
||||
should_record = is_record_time(now)
|
||||
|
||||
if _last_state != should_record:
|
||||
print(f"[Scheduler] Set recording = {should_record}")
|
||||
await set_recording(should_record)
|
||||
_last_state = should_record
|
||||
|
||||
import asyncio
|
||||
await asyncio.sleep(60)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. models.py
|
||||
|
||||
```python
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class RecordingToggle(BaseModel):
|
||||
enabled: bool
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. main.py
|
||||
|
||||
```python
|
||||
from fastapi import FastAPI
|
||||
import asyncio
|
||||
|
||||
from mediamtx import set_recording, get_paths
|
||||
from scheduler import scheduler_loop
|
||||
from models import RecordingToggle
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.on_event("startup")
|
||||
async def startup():
|
||||
asyncio.create_task(scheduler_loop())
|
||||
|
||||
|
||||
@app.get("/")
|
||||
async def root():
|
||||
return {"status": "ok"}
|
||||
|
||||
|
||||
@app.get("/paths")
|
||||
async def list_paths():
|
||||
return await get_paths()
|
||||
|
||||
|
||||
@app.post("/recording")
|
||||
async def toggle_recording(data: RecordingToggle):
|
||||
return await set_recording(data.enabled)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Run Server
|
||||
|
||||
```
|
||||
uvicorn main:app --host 0.0.0.0 --port 8008
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. API Endpoints
|
||||
|
||||
### Get stream status
|
||||
```
|
||||
GET /paths
|
||||
```
|
||||
|
||||
### Enable recording
|
||||
```
|
||||
POST /recording
|
||||
{
|
||||
"enabled": true
|
||||
}
|
||||
```
|
||||
|
||||
### Disable recording
|
||||
```
|
||||
POST /recording
|
||||
{
|
||||
"enabled": false
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. Next Steps
|
||||
|
||||
- Add recordings API (list files)
|
||||
- Serve video files (StaticFiles)
|
||||
- Add camera config management (DB or JSON)
|
||||
- Build frontend dashboard (WebRTC grid)
|
||||
@@ -0,0 +1,192 @@
|
||||
# IPCam Orange Pi Dashboard - Frontend UI Specification
|
||||
|
||||
## 1. Overview
|
||||
|
||||
This document describes the frontend UI/UX design for IPCam Orange Pi Dashboard.
|
||||
|
||||
The dashboard includes:
|
||||
- Live camera monitoring (WebRTC)
|
||||
- Playback system (recorded files)
|
||||
- System configuration (camera + schedule)
|
||||
|
||||
---
|
||||
|
||||
## 2. Layout Structure
|
||||
|
||||
```
|
||||
┌───────────────────────────────┐
|
||||
│ Header / Navigation │
|
||||
├───────────────┬───────────────┤
|
||||
│ Live View │ Playback │
|
||||
│ (WebRTC Grid) │ (Files list) │
|
||||
├───────────────┴───────────────┤
|
||||
│ Settings (modal / tab) │
|
||||
└───────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Live View (WebRTC Grid)
|
||||
|
||||
### Features
|
||||
- 4 camera grid (2x2)
|
||||
- Real-time streaming via WebRTC
|
||||
- Low latency
|
||||
- Auto reconnect
|
||||
|
||||
### Layout
|
||||
|
||||
```
|
||||
┌────────────┬────────────┐
|
||||
│ cam1 │ cam2 │
|
||||
│ [video] │ [video] │
|
||||
├────────────┼────────────┤
|
||||
│ cam3 │ cam4 │
|
||||
│ [video] │ [video] │
|
||||
└────────────┴────────────┘
|
||||
```
|
||||
|
||||
### Camera Tile Components
|
||||
- Video player (WebRTC)
|
||||
- Camera name
|
||||
- Status indicator (online/offline)
|
||||
- Buttons:
|
||||
- Fullscreen
|
||||
- Reload
|
||||
|
||||
### Behavior
|
||||
- Lazy load streams
|
||||
- Auto reconnect on failure
|
||||
- Click to fullscreen
|
||||
|
||||
---
|
||||
|
||||
## 4. Playback (Recordings)
|
||||
|
||||
### Layout
|
||||
|
||||
```
|
||||
┌───────────────┬──────────────────────┐
|
||||
│ Camera + Date │ File List + Player │
|
||||
└───────────────┴──────────────────────┘
|
||||
```
|
||||
|
||||
### Left Panel
|
||||
- Camera selector (dropdown)
|
||||
- Date picker
|
||||
|
||||
### Right Panel
|
||||
|
||||
#### File List
|
||||
```
|
||||
13:00:00 ▶️ ⬇️
|
||||
13:05:00 ▶️ ⬇️
|
||||
13:10:00 ▶️ ⬇️
|
||||
```
|
||||
|
||||
#### Video Player
|
||||
- HTML5 video player
|
||||
- Load selected file
|
||||
|
||||
### API Integration
|
||||
- GET /recordings?camera=cam1&date=YYYY-MM-DD
|
||||
- /videos/<camera>/<file>
|
||||
|
||||
### Behavior
|
||||
- Click ▶️ → play
|
||||
- Click ⬇️ → download
|
||||
- Auto load newest file
|
||||
|
||||
---
|
||||
|
||||
## 5. Settings
|
||||
|
||||
## 5.1 Camera Management
|
||||
|
||||
### UI
|
||||
|
||||
```
|
||||
Camera List:
|
||||
|
||||
[cam1] rtsp://...
|
||||
[cam2] rtsp://...
|
||||
|
||||
[ + Add Camera ]
|
||||
```
|
||||
|
||||
### Add Camera Form
|
||||
```
|
||||
Name: camX
|
||||
RTSP URL: rtsp://...
|
||||
|
||||
[ Save ]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5.2 Recording Schedule
|
||||
|
||||
### UI
|
||||
|
||||
```
|
||||
Recording Schedule
|
||||
|
||||
[ ] Enable scheduler
|
||||
|
||||
Weekdays:
|
||||
From: 18:00
|
||||
To: 08:00
|
||||
|
||||
Weekend:
|
||||
[x] Record all day
|
||||
```
|
||||
|
||||
### Logic
|
||||
- Controlled by backend scheduler
|
||||
- Uses MediaMTX API
|
||||
|
||||
---
|
||||
|
||||
## 6. Navigation
|
||||
|
||||
```
|
||||
[ Live ] [ Playback ] [ Settings ]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Tech Stack
|
||||
|
||||
- HTML / CSS / JS (or React)
|
||||
- WebRTC player
|
||||
- REST API integration
|
||||
|
||||
---
|
||||
|
||||
## 8. Constraints
|
||||
|
||||
- Requires H264 cameras (browser support)
|
||||
- Requires open ports:
|
||||
- 8889 (WebRTC HTTP)
|
||||
- 8189/UDP (ICE)
|
||||
|
||||
---
|
||||
|
||||
## 9. Future Enhancements
|
||||
|
||||
- Timeline playback
|
||||
- Multi-camera playback
|
||||
- Mobile UI
|
||||
- Authentication
|
||||
|
||||
---
|
||||
|
||||
## 10. Summary
|
||||
|
||||
Frontend responsibilities:
|
||||
- Render WebRTC streams
|
||||
- Display recordings
|
||||
- Control system configuration
|
||||
|
||||
This UI completes the full system:
|
||||
Camera → MediaMTX → Backend → Frontend
|
||||
@@ -0,0 +1,198 @@
|
||||
# IPCam Orange Pi Dashboard (Updated)
|
||||
|
||||
## 1. Overview
|
||||
IPCam Orange Pi Dashboard is a lightweight web-based surveillance system built on top of MediaMTX.
|
||||
|
||||
The system is designed for:
|
||||
- Orange Pi (low-resource hardware)
|
||||
- Multiple IP cameras (4–10 cams)
|
||||
- No AI processing (unlike Frigate)
|
||||
- Full control via MediaMTX Control API
|
||||
|
||||
---
|
||||
|
||||
## 2. Architecture
|
||||
|
||||
### Components
|
||||
- IP Cameras (RTSP - H264 recommended)
|
||||
- MediaMTX (stream proxy + recorder + API)
|
||||
- Dashboard Backend (scheduler + API)
|
||||
- Dashboard Frontend (live view + playback UI)
|
||||
|
||||
### Data Flow
|
||||
Camera → MediaMTX → WebRTC → Dashboard
|
||||
Camera → MediaMTX → Recording (fMP4) → Storage → Playback UI
|
||||
|
||||
---
|
||||
|
||||
## 3. Core Features
|
||||
|
||||
### 3.1 Live View
|
||||
- Grid layout (1 / 4 / 9 cameras)
|
||||
- WebRTC streaming (low latency)
|
||||
- Auto reconnect
|
||||
- Lazy loading streams
|
||||
|
||||
### 3.2 Playback
|
||||
- List recordings by:
|
||||
- Camera
|
||||
- Date
|
||||
- Play fMP4 files via HTML5 video
|
||||
- File-based playback (no timeline initially)
|
||||
|
||||
### 3.3 Camera Management
|
||||
- Add/remove camera (update MediaMTX config)
|
||||
- Reload MediaMTX if needed
|
||||
|
||||
### 3.4 Recording Schedule (IMPORTANT)
|
||||
- Configure recording time per system:
|
||||
- Weekdays: 18:00 → 08:00
|
||||
- Weekend: 24h
|
||||
- Implemented in Dashboard (NOT MediaMTX)
|
||||
|
||||
---
|
||||
|
||||
## 4. MediaMTX Integration
|
||||
|
||||
### 4.1 Endpoints
|
||||
- RTSP: rtsp://<server>:8554/<path>
|
||||
- WebRTC: http://<server>:8889
|
||||
- API: http://<server>:9997
|
||||
|
||||
---
|
||||
|
||||
### 4.2 Control API Usage
|
||||
|
||||
#### Enable API
|
||||
```
|
||||
api: true
|
||||
apiAddress: :9997
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4.3 Toggle Recording via API
|
||||
|
||||
#### Enable recording
|
||||
```
|
||||
POST /v3/config/paths/patch
|
||||
{
|
||||
"paths": {
|
||||
"cam1": { "record": true }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Disable recording
|
||||
```
|
||||
POST /v3/config/paths/patch
|
||||
{
|
||||
"paths": {
|
||||
"cam1": { "record": false }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4.4 Bulk Update
|
||||
```
|
||||
{
|
||||
"paths": {
|
||||
"cam1": { "record": true },
|
||||
"cam2": { "record": true },
|
||||
"cam3": { "record": true },
|
||||
"cam4": { "record": true }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Scheduler Design
|
||||
|
||||
### Logic
|
||||
- Dashboard backend controls recording
|
||||
- Runs every 60 seconds
|
||||
|
||||
### Example Logic
|
||||
```
|
||||
if weekend:
|
||||
record = true
|
||||
else:
|
||||
record = (hour >= 18 or hour < 8)
|
||||
```
|
||||
|
||||
### Implementation
|
||||
- setInterval / cron job in backend
|
||||
- Calls MediaMTX API
|
||||
|
||||
---
|
||||
|
||||
## 6. Storage
|
||||
|
||||
### Format
|
||||
- fMP4 segments
|
||||
|
||||
### Path
|
||||
```
|
||||
/recordings/<camera>/<timestamp>.fmp4
|
||||
```
|
||||
|
||||
### Notes
|
||||
- Files created per segment (e.g., 5 minutes)
|
||||
- Recording starts immediately when enabled
|
||||
|
||||
---
|
||||
|
||||
## 7. Technology Stack
|
||||
|
||||
### Backend
|
||||
- Node.js (Express) or Python (FastAPI)
|
||||
- Responsibilities:
|
||||
- Scheduler
|
||||
- MediaMTX API integration
|
||||
- Recording index API
|
||||
|
||||
### Frontend
|
||||
- HTML + JS (or React)
|
||||
- WebRTC player
|
||||
- Video playback UI
|
||||
|
||||
---
|
||||
|
||||
## 8. Performance Requirements
|
||||
|
||||
- 4–5 simultaneous streams
|
||||
- Minimal CPU usage (no transcoding)
|
||||
- Stable on Orange Pi
|
||||
|
||||
---
|
||||
|
||||
## 9. Constraints
|
||||
|
||||
- Browser requires H264 (NOT H265)
|
||||
- WebRTC requires UDP port (8189) open
|
||||
- Firewall must allow:
|
||||
- 8554 (RTSP)
|
||||
- 8889 (WebRTC HTTP)
|
||||
- 8189/UDP (ICE)
|
||||
|
||||
---
|
||||
|
||||
## 10. Future Enhancements
|
||||
|
||||
- Timeline playback (merge segments)
|
||||
- Multi-user authentication
|
||||
- Mobile UI
|
||||
- Event-based recording (optional)
|
||||
|
||||
---
|
||||
|
||||
## 11. Summary
|
||||
|
||||
- MediaMTX handles streaming + recording
|
||||
- Dashboard handles logic + scheduling
|
||||
- Recording is controlled via API (not config reload)
|
||||
|
||||
This architecture is optimized for simplicity, performance, and scalability on Orange Pi.
|
||||
@@ -0,0 +1,195 @@
|
||||
# IPCam Orange Pi Dashboard - Recording API & Video Serving
|
||||
|
||||
## 1. Overview
|
||||
|
||||
This module extends the backend to support:
|
||||
|
||||
- Listing recorded video files
|
||||
- Serving video files to frontend (playback)
|
||||
- Filtering by camera and date
|
||||
|
||||
This is REQUIRED for playback feature in dashboard.
|
||||
|
||||
---
|
||||
|
||||
## 2. Storage Structure (MediaMTX)
|
||||
|
||||
Assumed recording path:
|
||||
|
||||
```
|
||||
/recordings/<camera>/<timestamp>.fmp4
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
/recordings/cam1/2026-04-26_13-14-00-123456.fmp4
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Backend Responsibilities
|
||||
|
||||
Backend must:
|
||||
|
||||
1. Scan recording directory
|
||||
2. Parse metadata (camera, timestamp)
|
||||
3. Provide API for frontend
|
||||
4. Serve video files via HTTP
|
||||
|
||||
---
|
||||
|
||||
## 4. Add to requirements.txt
|
||||
|
||||
```
|
||||
python-multipart
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. recordings.py (new module)
|
||||
|
||||
```python
|
||||
import os
|
||||
from datetime import datetime
|
||||
|
||||
BASE_PATH = "/recordings"
|
||||
|
||||
|
||||
def parse_filename(filename: str):
|
||||
try:
|
||||
name = filename.replace(".fmp4", "")
|
||||
dt = datetime.strptime(name, "%Y-%m-%d_%H-%M-%S-%f")
|
||||
return dt
|
||||
except:
|
||||
return None
|
||||
|
||||
|
||||
def list_recordings(camera: str, date: str = None):
|
||||
cam_path = os.path.join(BASE_PATH, camera)
|
||||
|
||||
if not os.path.exists(cam_path):
|
||||
return []
|
||||
|
||||
results = []
|
||||
|
||||
for file in os.listdir(cam_path):
|
||||
if not file.endswith(".fmp4"):
|
||||
continue
|
||||
|
||||
dt = parse_filename(file)
|
||||
if not dt:
|
||||
continue
|
||||
|
||||
if date:
|
||||
if dt.strftime("%Y-%m-%d") != date:
|
||||
continue
|
||||
|
||||
results.append({
|
||||
"camera": camera,
|
||||
"filename": file,
|
||||
"timestamp": dt.isoformat(),
|
||||
"url": f"/videos/{camera}/{file}"
|
||||
})
|
||||
|
||||
# sort newest first
|
||||
results.sort(key=lambda x: x["timestamp"], reverse=True)
|
||||
|
||||
return results
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Update main.py
|
||||
|
||||
```python
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from recordings import list_recordings
|
||||
|
||||
# mount video folder
|
||||
app.mount("/videos", StaticFiles(directory="/recordings"), name="videos")
|
||||
|
||||
|
||||
@app.get("/recordings")
|
||||
async def get_recordings(camera: str, date: str = None):
|
||||
return list_recordings(camera, date)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. API Usage
|
||||
|
||||
### List recordings
|
||||
|
||||
```
|
||||
GET /recordings?camera=cam1
|
||||
```
|
||||
|
||||
### Filter by date
|
||||
|
||||
```
|
||||
GET /recordings?camera=cam1&date=2026-04-26
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Response Example
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"camera": "cam1",
|
||||
"filename": "2026-04-26_13-14-00-123456.fmp4",
|
||||
"timestamp": "2026-04-26T13:14:00",
|
||||
"url": "/videos/cam1/2026-04-26_13-14-00-123456.fmp4"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. Playback in Frontend
|
||||
|
||||
Use standard HTML:
|
||||
|
||||
```html
|
||||
<video controls width="600">
|
||||
<source src="http://<server>:8008/videos/cam1/file.fmp4">
|
||||
</video>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. Important Notes
|
||||
|
||||
### fMP4 compatibility
|
||||
- Modern browsers support fMP4
|
||||
- If issues → fallback to HLS later
|
||||
|
||||
### File size
|
||||
- Large files → consider pagination later
|
||||
|
||||
### Security (future)
|
||||
- Add auth before exposing /videos
|
||||
|
||||
---
|
||||
|
||||
## 11. Next Improvements
|
||||
|
||||
- Pagination (limit, offset)
|
||||
- Thumbnail generation
|
||||
- Timeline UI
|
||||
- Merge segments
|
||||
|
||||
---
|
||||
|
||||
## 12. Summary
|
||||
|
||||
This module completes playback pipeline:
|
||||
|
||||
MediaMTX → Disk → Backend API → Frontend Player
|
||||
|
||||
Without this layer:
|
||||
- You cannot build usable playback UI
|
||||
|
||||
This is a critical component of your system.
|
||||
Reference in New Issue
Block a user