first commit
This commit is contained in:
@@ -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>:8000/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