Add comprehensive video streaming module and AI agent integration guide
- Introduced a new video streaming module with endpoints for listing, streaming, and managing video files. - Added detailed API documentation for video streaming, including features like HTTP range requests, thumbnail generation, and caching. - Created a new AI Agent Video Integration Guide with step-by-step instructions for integrating with the video streaming API. - Implemented a video reindexing script to update video statuses from "unknown" to "completed". - Enhanced error handling and logging throughout the video streaming and reindexing processes.
This commit is contained in:
@@ -9,6 +9,8 @@ The USDA Vision Camera System now includes a modular video streaming system that
|
||||
- **Intelligent Caching** - Optimized streaming performance
|
||||
- **Thumbnail Generation** - Extract preview images from videos
|
||||
- **Modular Architecture** - Clean separation of concerns
|
||||
- **No Authentication Required** - Open access for internal network use
|
||||
- **CORS Enabled** - Ready for web browser integration
|
||||
|
||||
## 🏗️ Architecture
|
||||
|
||||
@@ -30,11 +32,16 @@ usda_vision_system/video/
|
||||
GET /videos/
|
||||
```
|
||||
**Query Parameters:**
|
||||
- `camera_name` - Filter by camera
|
||||
- `start_date` - Filter by date range
|
||||
- `end_date` - Filter by date range
|
||||
- `limit` - Maximum results (default: 50)
|
||||
- `include_metadata` - Include video metadata
|
||||
- `camera_name` (optional): Filter by camera name
|
||||
- `start_date` (optional): Filter videos created after this date (ISO format: 2025-08-04T14:30:22)
|
||||
- `end_date` (optional): Filter videos created before this date (ISO format: 2025-08-04T14:30:22)
|
||||
- `limit` (optional): Maximum results (default: 50, max: 1000)
|
||||
- `include_metadata` (optional): Include video metadata (default: false)
|
||||
|
||||
**Example Request:**
|
||||
```bash
|
||||
curl "http://localhost:8000/videos/?camera_name=camera1&include_metadata=true&limit=10"
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
@@ -48,8 +55,20 @@ GET /videos/
|
||||
"format": "mp4",
|
||||
"status": "completed",
|
||||
"created_at": "2025-08-04T14:30:22",
|
||||
"start_time": "2025-08-04T14:30:22",
|
||||
"end_time": "2025-08-04T14:32:22",
|
||||
"machine_trigger": "blower_separator",
|
||||
"is_streamable": true,
|
||||
"needs_conversion": true
|
||||
"needs_conversion": false,
|
||||
"metadata": {
|
||||
"duration_seconds": 120.5,
|
||||
"width": 1920,
|
||||
"height": 1080,
|
||||
"fps": 30.0,
|
||||
"codec": "mp4v",
|
||||
"bitrate": 5000000,
|
||||
"aspect_ratio": 1.777
|
||||
}
|
||||
}
|
||||
],
|
||||
"total_count": 1
|
||||
@@ -61,28 +80,63 @@ GET /videos/
|
||||
GET /videos/{file_id}/stream
|
||||
```
|
||||
**Headers:**
|
||||
- `Range: bytes=0-1023` - Request specific byte range
|
||||
- `Range: bytes=0-1023` (optional): Request specific byte range for seeking
|
||||
|
||||
**Example Requests:**
|
||||
```bash
|
||||
# Stream entire video
|
||||
curl http://localhost:8000/videos/camera1_recording_20250804_143022.avi/stream
|
||||
|
||||
# Stream specific byte range (for seeking)
|
||||
curl -H "Range: bytes=0-1023" \
|
||||
http://localhost:8000/videos/camera1_recording_20250804_143022.avi/stream
|
||||
```
|
||||
|
||||
**Response Headers:**
|
||||
- `Accept-Ranges: bytes`
|
||||
- `Content-Length: {size}`
|
||||
- `Content-Range: bytes {start}-{end}/{total}` (for range requests)
|
||||
- `Cache-Control: public, max-age=3600`
|
||||
- `Content-Type: video/mp4` or `video/x-msvideo`
|
||||
|
||||
**Features:**
|
||||
- Supports HTTP range requests for seeking
|
||||
- Returns 206 Partial Content for range requests
|
||||
- Automatic format conversion for web compatibility
|
||||
- Intelligent caching for performance
|
||||
- ✅ **HTTP Range Requests**: Enables video seeking and progressive download
|
||||
- ✅ **Partial Content**: Returns 206 status for range requests
|
||||
- ✅ **Format Conversion**: Automatic AVI to MP4 conversion for web compatibility
|
||||
- ✅ **Intelligent Caching**: Byte-range caching for optimal performance
|
||||
- ✅ **CORS Enabled**: Ready for web browser integration
|
||||
|
||||
### Get Video Info
|
||||
```http
|
||||
GET /videos/{file_id}
|
||||
```
|
||||
**Response includes metadata:**
|
||||
**Example Request:**
|
||||
```bash
|
||||
curl http://localhost:8000/videos/camera1_recording_20250804_143022.avi
|
||||
```
|
||||
|
||||
**Response includes complete metadata:**
|
||||
```json
|
||||
{
|
||||
"file_id": "camera1_recording_20250804_143022.avi",
|
||||
"camera_name": "camera1",
|
||||
"filename": "camera1_recording_20250804_143022.avi",
|
||||
"file_size_bytes": 52428800,
|
||||
"format": "avi",
|
||||
"status": "completed",
|
||||
"created_at": "2025-08-04T14:30:22",
|
||||
"start_time": "2025-08-04T14:30:22",
|
||||
"end_time": "2025-08-04T14:32:22",
|
||||
"machine_trigger": "vibratory_conveyor",
|
||||
"is_streamable": true,
|
||||
"needs_conversion": true,
|
||||
"metadata": {
|
||||
"duration_seconds": 120.5,
|
||||
"width": 1920,
|
||||
"height": 1080,
|
||||
"fps": 30.0,
|
||||
"codec": "XVID",
|
||||
"bitrate": 5000000,
|
||||
"aspect_ratio": 1.777
|
||||
}
|
||||
}
|
||||
@@ -92,13 +146,31 @@ GET /videos/{file_id}
|
||||
```http
|
||||
GET /videos/{file_id}/thumbnail?timestamp=5.0&width=320&height=240
|
||||
```
|
||||
Returns JPEG thumbnail image.
|
||||
**Query Parameters:**
|
||||
- `timestamp` (optional): Time position in seconds to extract thumbnail from (default: 1.0)
|
||||
- `width` (optional): Thumbnail width in pixels (default: 320)
|
||||
- `height` (optional): Thumbnail height in pixels (default: 240)
|
||||
|
||||
**Example Request:**
|
||||
```bash
|
||||
curl "http://localhost:8000/videos/camera1_recording_20250804_143022.avi/thumbnail?timestamp=5.0&width=320&height=240" \
|
||||
--output thumbnail.jpg
|
||||
```
|
||||
|
||||
**Response**: JPEG image data with caching headers
|
||||
- `Content-Type: image/jpeg`
|
||||
- `Cache-Control: public, max-age=3600`
|
||||
|
||||
### Streaming Info
|
||||
```http
|
||||
GET /videos/{file_id}/info
|
||||
```
|
||||
Returns technical streaming details:
|
||||
**Example Request:**
|
||||
```bash
|
||||
curl http://localhost:8000/videos/camera1_recording_20250804_143022.avi/info
|
||||
```
|
||||
|
||||
**Response**: Technical streaming details
|
||||
```json
|
||||
{
|
||||
"file_id": "camera1_recording_20250804_143022.avi",
|
||||
@@ -109,6 +181,58 @@ Returns technical streaming details:
|
||||
}
|
||||
```
|
||||
|
||||
### Video Validation
|
||||
```http
|
||||
POST /videos/{file_id}/validate
|
||||
```
|
||||
**Example Request:**
|
||||
```bash
|
||||
curl -X POST http://localhost:8000/videos/camera1_recording_20250804_143022.avi/validate
|
||||
```
|
||||
|
||||
**Response**: Validation status
|
||||
```json
|
||||
{
|
||||
"file_id": "camera1_recording_20250804_143022.avi",
|
||||
"is_valid": true
|
||||
}
|
||||
```
|
||||
|
||||
### Cache Management
|
||||
```http
|
||||
POST /videos/{file_id}/cache/invalidate
|
||||
```
|
||||
**Example Request:**
|
||||
```bash
|
||||
curl -X POST http://localhost:8000/videos/camera1_recording_20250804_143022.avi/cache/invalidate
|
||||
```
|
||||
|
||||
**Response**: Cache invalidation status
|
||||
```json
|
||||
{
|
||||
"file_id": "camera1_recording_20250804_143022.avi",
|
||||
"cache_invalidated": true
|
||||
}
|
||||
```
|
||||
|
||||
### Admin: Cache Cleanup
|
||||
```http
|
||||
POST /admin/videos/cache/cleanup?max_size_mb=100
|
||||
```
|
||||
**Example Request:**
|
||||
```bash
|
||||
curl -X POST "http://localhost:8000/admin/videos/cache/cleanup?max_size_mb=100"
|
||||
```
|
||||
|
||||
**Response**: Cache cleanup results
|
||||
```json
|
||||
{
|
||||
"cache_cleaned": true,
|
||||
"entries_removed": 15,
|
||||
"max_size_mb": 100
|
||||
}
|
||||
```
|
||||
|
||||
## 🌐 React Integration
|
||||
|
||||
### Basic Video Player
|
||||
@@ -187,6 +311,101 @@ video_module = create_video_module(
|
||||
)
|
||||
```
|
||||
|
||||
### Configuration Parameters
|
||||
- **`enable_caching`**: Enable/disable intelligent byte-range caching (default: True)
|
||||
- **`cache_size_mb`**: Maximum cache size in MB (default: 100)
|
||||
- **`cache_max_age_minutes`**: Cache entry expiration time (default: 30)
|
||||
- **`enable_conversion`**: Enable/disable automatic AVI to MP4 conversion (default: True)
|
||||
- **`conversion_quality`**: Video conversion quality: "low", "medium", "high" (default: "medium")
|
||||
|
||||
### System Requirements
|
||||
- **OpenCV**: Required for thumbnail generation and metadata extraction
|
||||
- **FFmpeg**: Optional, for video format conversion (graceful fallback if not available)
|
||||
- **Storage**: Sufficient disk space for video files and cache
|
||||
- **Memory**: Recommended 2GB+ RAM for caching and video processing
|
||||
|
||||
## 🔐 Authentication & Security
|
||||
|
||||
### Current Security Model
|
||||
**⚠️ IMPORTANT: No authentication is currently implemented.**
|
||||
|
||||
- **Open Access**: All video streaming endpoints are publicly accessible
|
||||
- **CORS Policy**: Currently set to allow all origins (`allow_origins=["*"]`)
|
||||
- **Network Security**: Designed for internal network use only
|
||||
- **No API Keys**: No authentication tokens or API keys required
|
||||
- **No Rate Limiting**: No request rate limiting currently implemented
|
||||
|
||||
### Security Considerations for Production
|
||||
|
||||
#### For Internal Network Deployment
|
||||
```bash
|
||||
# Current configuration is suitable for:
|
||||
# - Internal corporate networks
|
||||
# - Isolated network segments
|
||||
# - Development and testing environments
|
||||
```
|
||||
|
||||
#### For External Access (Recommendations)
|
||||
If you need to expose the video streaming API externally, consider implementing:
|
||||
|
||||
1. **Authentication Layer**
|
||||
```python
|
||||
# Example: Add JWT authentication
|
||||
from fastapi import Depends, HTTPException
|
||||
from fastapi.security import HTTPBearer
|
||||
|
||||
security = HTTPBearer()
|
||||
|
||||
async def verify_token(token: str = Depends(security)):
|
||||
# Implement token verification logic
|
||||
pass
|
||||
```
|
||||
|
||||
2. **CORS Configuration**
|
||||
```python
|
||||
# Restrict CORS to specific domains
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["https://yourdomain.com"],
|
||||
allow_credentials=True,
|
||||
allow_methods=["GET", "POST"],
|
||||
allow_headers=["*"]
|
||||
)
|
||||
```
|
||||
|
||||
3. **Rate Limiting**
|
||||
```python
|
||||
# Example: Add rate limiting
|
||||
from slowapi import Limiter
|
||||
|
||||
limiter = Limiter(key_func=get_remote_address)
|
||||
|
||||
@app.get("/videos/")
|
||||
@limiter.limit("10/minute")
|
||||
async def list_videos():
|
||||
pass
|
||||
```
|
||||
|
||||
4. **Network Security**
|
||||
- Use HTTPS/TLS for encrypted communication
|
||||
- Implement firewall rules to restrict access
|
||||
- Consider VPN access for remote users
|
||||
- Use reverse proxy (nginx) for additional security
|
||||
|
||||
### Access Control Summary
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Current Access Model │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ Authentication: ❌ None │
|
||||
│ Authorization: ❌ None │
|
||||
│ CORS: ✅ Enabled (all origins) │
|
||||
│ Rate Limiting: ❌ None │
|
||||
│ HTTPS: ⚠️ Depends on deployment │
|
||||
│ Network Security: ⚠️ Firewall/VPN recommended │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## 📊 Performance
|
||||
|
||||
- **Caching**: Intelligent byte-range caching reduces disk I/O
|
||||
@@ -226,18 +445,136 @@ PYTHONPATH=/home/alireza/USDA-vision-cameras python tests/test_video_module.py
|
||||
## 🔍 Troubleshooting
|
||||
|
||||
### Video Not Playing
|
||||
1. Check if file exists: `GET /videos/{file_id}`
|
||||
2. Verify streaming info: `GET /videos/{file_id}/info`
|
||||
3. Test direct stream: `GET /videos/{file_id}/stream`
|
||||
1. **Check if file exists**: `GET /videos/{file_id}`
|
||||
```bash
|
||||
curl http://localhost:8000/videos/camera1_recording_20250804_143022.avi
|
||||
```
|
||||
2. **Verify streaming info**: `GET /videos/{file_id}/info`
|
||||
```bash
|
||||
curl http://localhost:8000/videos/camera1_recording_20250804_143022.avi/info
|
||||
```
|
||||
3. **Test direct stream**: `GET /videos/{file_id}/stream`
|
||||
```bash
|
||||
curl -I http://localhost:8000/videos/camera1_recording_20250804_143022.avi/stream
|
||||
```
|
||||
4. **Validate video file**: `POST /videos/{file_id}/validate`
|
||||
```bash
|
||||
curl -X POST http://localhost:8000/videos/camera1_recording_20250804_143022.avi/validate
|
||||
```
|
||||
|
||||
### Performance Issues
|
||||
1. Check cache status: `GET /admin/videos/cache/cleanup`
|
||||
2. Monitor system resources
|
||||
3. Adjust cache size in configuration
|
||||
1. **Check cache status**: Clean up cache if needed
|
||||
```bash
|
||||
curl -X POST "http://localhost:8000/admin/videos/cache/cleanup?max_size_mb=100"
|
||||
```
|
||||
2. **Monitor system resources**: Check CPU, memory, and disk usage
|
||||
3. **Adjust cache size**: Modify configuration parameters
|
||||
4. **Invalidate specific cache**: For updated files
|
||||
```bash
|
||||
curl -X POST http://localhost:8000/videos/{file_id}/cache/invalidate
|
||||
```
|
||||
|
||||
### Format Issues
|
||||
- AVI files are automatically converted to MP4 for web compatibility
|
||||
- Conversion requires FFmpeg (optional, graceful fallback)
|
||||
- **AVI files**: Automatically converted to MP4 for web compatibility
|
||||
- **Conversion requires FFmpeg**: Optional dependency with graceful fallback
|
||||
- **Supported formats**: AVI (with conversion), MP4 (native), WebM (native)
|
||||
|
||||
### Common HTTP Status Codes
|
||||
- **200**: Success - Video streamed successfully
|
||||
- **206**: Partial Content - Range request successful
|
||||
- **404**: Not Found - Video file doesn't exist or isn't streamable
|
||||
- **416**: Range Not Satisfiable - Invalid range request
|
||||
- **500**: Internal Server Error - Failed to read video data or generate thumbnail
|
||||
|
||||
### Browser Compatibility
|
||||
- **Chrome/Chromium**: Full support for MP4 and range requests
|
||||
- **Firefox**: Full support for MP4 and range requests
|
||||
- **Safari**: Full support for MP4 and range requests
|
||||
- **Edge**: Full support for MP4 and range requests
|
||||
- **Mobile browsers**: Generally good support for MP4 streaming
|
||||
|
||||
### Error Scenarios and Solutions
|
||||
|
||||
#### Video File Issues
|
||||
```bash
|
||||
# Problem: Video not found (404)
|
||||
curl http://localhost:8000/videos/nonexistent_video.mp4
|
||||
# Response: {"detail": "Video nonexistent_video.mp4 not found"}
|
||||
# Solution: Verify file_id exists using list endpoint
|
||||
|
||||
# Problem: Video not streamable
|
||||
curl http://localhost:8000/videos/corrupted_video.avi/stream
|
||||
# Response: {"detail": "Video corrupted_video.avi not found or not streamable"}
|
||||
# Solution: Use validation endpoint to check file integrity
|
||||
```
|
||||
|
||||
#### Range Request Issues
|
||||
```bash
|
||||
# Problem: Invalid range request (416)
|
||||
curl -H "Range: bytes=999999999-" http://localhost:8000/videos/small_video.mp4/stream
|
||||
# Response: {"detail": "Invalid range request: Range exceeds file size"}
|
||||
# Solution: Check file size first using /info endpoint
|
||||
|
||||
# Problem: Malformed range header
|
||||
curl -H "Range: invalid-range" http://localhost:8000/videos/video.mp4/stream
|
||||
# Response: {"detail": "Invalid range request: Malformed range header"}
|
||||
# Solution: Use proper range format: "bytes=start-end"
|
||||
```
|
||||
|
||||
#### Thumbnail Generation Issues
|
||||
```bash
|
||||
# Problem: Thumbnail generation failed (404)
|
||||
curl http://localhost:8000/videos/audio_only.mp4/thumbnail
|
||||
# Response: {"detail": "Could not generate thumbnail for audio_only.mp4"}
|
||||
# Solution: Verify video has visual content and is not audio-only
|
||||
|
||||
# Problem: Invalid timestamp
|
||||
curl "http://localhost:8000/videos/short_video.mp4/thumbnail?timestamp=999"
|
||||
# Response: Returns thumbnail from last available frame
|
||||
# Solution: Check video duration first using metadata
|
||||
```
|
||||
|
||||
#### System Resource Issues
|
||||
```bash
|
||||
# Problem: Cache full or system overloaded (500)
|
||||
curl http://localhost:8000/videos/large_video.mp4/stream
|
||||
# Response: {"detail": "Failed to read video data"}
|
||||
# Solution: Clean cache or wait for system resources
|
||||
curl -X POST "http://localhost:8000/admin/videos/cache/cleanup?max_size_mb=50"
|
||||
```
|
||||
|
||||
### Debugging Workflow
|
||||
```bash
|
||||
# Step 1: Check system health
|
||||
curl http://localhost:8000/health
|
||||
|
||||
# Step 2: Verify video exists and get info
|
||||
curl http://localhost:8000/videos/your_video_id
|
||||
|
||||
# Step 3: Check streaming capabilities
|
||||
curl http://localhost:8000/videos/your_video_id/info
|
||||
|
||||
# Step 4: Validate video file
|
||||
curl -X POST http://localhost:8000/videos/your_video_id/validate
|
||||
|
||||
# Step 5: Test basic streaming
|
||||
curl -I http://localhost:8000/videos/your_video_id/stream
|
||||
|
||||
# Step 6: Test range request
|
||||
curl -I -H "Range: bytes=0-1023" http://localhost:8000/videos/your_video_id/stream
|
||||
```
|
||||
|
||||
### Performance Monitoring
|
||||
```bash
|
||||
# Monitor cache usage
|
||||
curl -X POST "http://localhost:8000/admin/videos/cache/cleanup?max_size_mb=100"
|
||||
|
||||
# Check system resources
|
||||
curl http://localhost:8000/system/status
|
||||
|
||||
# Monitor video module status
|
||||
curl http://localhost:8000/videos/ | jq '.total_count'
|
||||
```
|
||||
|
||||
## 🎯 Next Steps
|
||||
|
||||
|
||||
Reference in New Issue
Block a user