Files
usda-vision/docs/VIDEO_STREAMING.md
Alireza Vaezi 07e8e52503 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.
2025-08-05 14:44:31 -04:00

18 KiB

🎬 Video Streaming Module

The USDA Vision Camera System now includes a modular video streaming system that provides YouTube-like video playback capabilities for your React web application.

🌟 Features

  • HTTP Range Request Support - Enables seeking and progressive download
  • Native MP4 Support - Direct streaming of MP4 files with automatic AVI conversion
  • 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

The video module follows clean architecture principles:

usda_vision_system/video/
├── domain/          # Business logic (pure Python)
├── infrastructure/  # External dependencies (OpenCV, FFmpeg)
├── application/     # Use cases and orchestration
├── presentation/    # HTTP controllers and API routes
└── integration.py   # Dependency injection and composition

🚀 API Endpoints

List Videos

GET /videos/

Query Parameters:

  • 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:

curl "http://localhost:8000/videos/?camera_name=camera1&include_metadata=true&limit=10"

Response:

{
  "videos": [
    {
      "file_id": "camera1_auto_blower_separator_20250804_143022.mp4",
      "camera_name": "camera1",
      "filename": "camera1_auto_blower_separator_20250804_143022.mp4",
      "file_size_bytes": 31457280,
      "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": false,
      "metadata": {
        "duration_seconds": 120.5,
        "width": 1920,
        "height": 1080,
        "fps": 30.0,
        "codec": "mp4v",
        "bitrate": 5000000,
        "aspect_ratio": 1.777
      }
    }
  ],
  "total_count": 1
}

Stream Video

GET /videos/{file_id}/stream

Headers:

  • Range: bytes=0-1023 (optional): Request specific byte range for seeking

Example Requests:

# 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:

  • 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

GET /videos/{file_id}

Example Request:

curl http://localhost:8000/videos/camera1_recording_20250804_143022.avi

Response includes complete metadata:

{
  "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
  }
}

Get Thumbnail

GET /videos/{file_id}/thumbnail?timestamp=5.0&width=320&height=240

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:

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

GET /videos/{file_id}/info

Example Request:

curl http://localhost:8000/videos/camera1_recording_20250804_143022.avi/info

Response: Technical streaming details

{
  "file_id": "camera1_recording_20250804_143022.avi",
  "file_size_bytes": 52428800,
  "content_type": "video/x-msvideo",
  "supports_range_requests": true,
  "chunk_size_bytes": 262144
}

Video Validation

POST /videos/{file_id}/validate

Example Request:

curl -X POST http://localhost:8000/videos/camera1_recording_20250804_143022.avi/validate

Response: Validation status

{
  "file_id": "camera1_recording_20250804_143022.avi",
  "is_valid": true
}

Cache Management

POST /videos/{file_id}/cache/invalidate

Example Request:

curl -X POST http://localhost:8000/videos/camera1_recording_20250804_143022.avi/cache/invalidate

Response: Cache invalidation status

{
  "file_id": "camera1_recording_20250804_143022.avi",
  "cache_invalidated": true
}

Admin: Cache Cleanup

POST /admin/videos/cache/cleanup?max_size_mb=100

Example Request:

curl -X POST "http://localhost:8000/admin/videos/cache/cleanup?max_size_mb=100"

Response: Cache cleanup results

{
  "cache_cleaned": true,
  "entries_removed": 15,
  "max_size_mb": 100
}

🌐 React Integration

Basic Video Player

function VideoPlayer({ fileId }) {
  return (
    <video controls width="100%">
      <source 
        src={`${API_BASE_URL}/videos/${fileId}/stream`} 
        type="video/mp4" 
      />
      Your browser does not support video playback.
    </video>
  );
}

Advanced Player with Thumbnail

function VideoPlayerWithThumbnail({ fileId }) {
  const [thumbnail, setThumbnail] = useState(null);
  
  useEffect(() => {
    fetch(`${API_BASE_URL}/videos/${fileId}/thumbnail`)
      .then(response => response.blob())
      .then(blob => setThumbnail(URL.createObjectURL(blob)));
  }, [fileId]);
  
  return (
    <video controls width="100%" poster={thumbnail}>
      <source 
        src={`${API_BASE_URL}/videos/${fileId}/stream`} 
        type="video/mp4" 
      />
    </video>
  );
}

Video List Component

function VideoList({ cameraName }) {
  const [videos, setVideos] = useState([]);
  
  useEffect(() => {
    const params = new URLSearchParams();
    if (cameraName) params.append('camera_name', cameraName);
    params.append('include_metadata', 'true');
    
    fetch(`${API_BASE_URL}/videos/?${params}`)
      .then(response => response.json())
      .then(data => setVideos(data.videos));
  }, [cameraName]);
  
  return (
    <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
      {videos.map(video => (
        <VideoCard key={video.file_id} video={video} />
      ))}
    </div>
  );
}

🔧 Configuration

The video module is automatically initialized when the API server starts. Configuration options:

# In your API server initialization
video_module = create_video_module(
    config=config,
    storage_manager=storage_manager,
    enable_caching=True,      # Enable streaming cache
    enable_conversion=True    # Enable format conversion
)

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

# 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

    # 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

    # 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

    # 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
  • Adaptive Chunking: Optimal chunk sizes based on file size
  • Range Requests: Only download needed portions
  • Format Conversion: Automatic conversion to web-compatible formats

🛠️ Service Management

Restart Service

sudo systemctl restart usda-vision-camera

Check Status

# Check video module status
curl http://localhost:8000/system/video-module

# Check available videos
curl http://localhost:8000/videos/

Logs

sudo journalctl -u usda-vision-camera -f

🧪 Testing

Run the video module tests:

cd /home/alireza/USDA-vision-cameras
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}
    curl http://localhost:8000/videos/camera1_recording_20250804_143022.avi
    
  2. Verify streaming info: GET /videos/{file_id}/info
    curl http://localhost:8000/videos/camera1_recording_20250804_143022.avi/info
    
  3. Test direct stream: GET /videos/{file_id}/stream
    curl -I http://localhost:8000/videos/camera1_recording_20250804_143022.avi/stream
    
  4. Validate video file: POST /videos/{file_id}/validate
    curl -X POST http://localhost:8000/videos/camera1_recording_20250804_143022.avi/validate
    

Performance Issues

  1. Check cache status: Clean up cache if needed
    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
    curl -X POST http://localhost:8000/videos/{file_id}/cache/invalidate
    

Format Issues

  • 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

# 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

# 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

# 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

# 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

# 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

# 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

  1. Restart the usda-vision-camera service to enable video streaming
  2. Test the endpoints using curl or your browser
  3. Integrate with your React app using the provided examples
  4. Monitor performance and adjust caching as needed

The video streaming system is now ready for production use! 🚀