feat(video): Implement MP4 format support across frontend and backend

- Updated VideoModal to display web compatibility status for video formats.
- Enhanced VideoPlayer to dynamically fetch video MIME types and handle MP4 streaming.
- Introduced video file utilities for better handling of video formats and MIME types.
- Modified CameraConfig interface to include new video recording settings (format, codec, quality).
- Created comprehensive documentation for MP4 format integration and frontend implementation.
- Ensured backward compatibility with existing AVI files while promoting MP4 as the preferred format.
- Added validation and error handling for video format configurations.
This commit is contained in:
Alireza Vaezi
2025-08-04 16:21:22 -04:00
parent 551e5dc2e3
commit 1aaac68edd
36 changed files with 1446 additions and 4578 deletions

View File

@@ -12,6 +12,7 @@ These settings can be changed while the camera is active:
- **Basic**: `exposure_ms`, `gain`, `target_fps`
- **Image Quality**: `sharpness`, `contrast`, `saturation`, `gamma`
- **Color**: `auto_white_balance`, `color_temperature_preset`
- **White Balance**: `wb_red_gain`, `wb_green_gain`, `wb_blue_gain`
- **Advanced**: `anti_flicker_enabled`, `light_frequency`
- **HDR**: `hdr_enabled`, `hdr_gain_mode`
@@ -19,8 +20,15 @@ These settings can be changed while the camera is active:
These settings require camera restart to take effect:
- **Noise Reduction**: `noise_filter_enabled`, `denoise_3d_enabled`
- **Video Recording**: `video_format`, `video_codec`, `video_quality`
- **System**: `machine_topic`, `storage_path`, `enabled`, `bit_depth`
### 🔒 **Read-Only Fields**
These fields are returned in the response but cannot be modified via the API:
- **System Info**: `name`, `machine_topic`, `storage_path`, `enabled`
- **Auto-Recording**: `auto_start_recording_enabled`, `auto_recording_max_retries`, `auto_recording_retry_delay_seconds`
## 🔌 API Endpoints
### 1. Get Camera Configuration
@@ -35,9 +43,18 @@ GET /cameras/{camera_name}/config
"machine_topic": "vibratory_conveyor",
"storage_path": "/storage/camera1",
"enabled": true,
"auto_start_recording_enabled": true,
"auto_recording_max_retries": 3,
"auto_recording_retry_delay_seconds": 2,
"exposure_ms": 1.0,
"gain": 3.5,
"target_fps": 0,
// Video Recording Settings (New in v2.1)
"video_format": "mp4",
"video_codec": "mp4v",
"video_quality": 95,
"sharpness": 120,
"contrast": 110,
"saturation": 100,
@@ -46,6 +63,9 @@ GET /cameras/{camera_name}/config
"denoise_3d_enabled": false,
"auto_white_balance": true,
"color_temperature_preset": 0,
"wb_red_gain": 1.0,
"wb_green_gain": 1.0,
"wb_blue_gain": 1.0,
"anti_flicker_enabled": true,
"light_frequency": 1,
"bit_depth": 8,
@@ -74,6 +94,9 @@ Content-Type: application/json
"denoise_3d_enabled": false,
"auto_white_balance": false,
"color_temperature_preset": 1,
"wb_red_gain": 1.2,
"wb_green_gain": 1.0,
"wb_blue_gain": 0.8,
"anti_flicker_enabled": true,
"light_frequency": 1,
"hdr_enabled": false,
@@ -86,7 +109,7 @@ Content-Type: application/json
{
"success": true,
"message": "Camera camera1 configuration updated",
"updated_settings": ["exposure_ms", "gain", "sharpness"]
"updated_settings": ["exposure_ms", "gain", "sharpness", "wb_red_gain"]
}
```
@@ -105,6 +128,21 @@ POST /cameras/{camera_name}/apply-config
## 📊 Setting Ranges and Descriptions
### System Settings
| Setting | Values | Default | Description |
|---------|--------|---------|-------------|
| `name` | string | - | Camera identifier (read-only) |
| `machine_topic` | string | - | MQTT topic for machine state (read-only) |
| `storage_path` | string | - | Video storage directory (read-only) |
| `enabled` | true/false | true | Camera enabled status (read-only) |
### Auto-Recording Settings
| Setting | Range | Default | Description |
|---------|-------|---------|-------------|
| `auto_start_recording_enabled` | true/false | true | Enable automatic recording on machine state changes (read-only) |
| `auto_recording_max_retries` | 1-10 | 3 | Maximum retry attempts for failed recordings (read-only) |
| `auto_recording_retry_delay_seconds` | 1-30 | 2 | Delay between retry attempts in seconds (read-only) |
### Basic Settings
| Setting | Range | Default | Description |
|---------|-------|---------|-------------|
@@ -126,6 +164,13 @@ POST /cameras/{camera_name}/apply-config
| `auto_white_balance` | true/false | true | Automatic white balance |
| `color_temperature_preset` | 0-10 | 0 | Color temperature preset (0=auto) |
### Manual White Balance RGB Gains
| Setting | Range | Default | Description |
|---------|-------|---------|-------------|
| `wb_red_gain` | 0.0 - 3.99 | 1.0 | Red channel gain for manual white balance |
| `wb_green_gain` | 0.0 - 3.99 | 1.0 | Green channel gain for manual white balance |
| `wb_blue_gain` | 0.0 - 3.99 | 1.0 | Blue channel gain for manual white balance |
### Advanced Settings
| Setting | Values | Default | Description |
|---------|--------|---------|-------------|
@@ -144,7 +189,7 @@ POST /cameras/{camera_name}/apply-config
### Example 1: Adjust Exposure and Gain
```bash
curl -X PUT http://vision:8000/cameras/camera1/config \
curl -X PUT http://localhost:8000/cameras/camera1/config \
-H "Content-Type: application/json" \
-d '{
"exposure_ms": 1.5,
@@ -154,7 +199,7 @@ curl -X PUT http://vision:8000/cameras/camera1/config \
### Example 2: Improve Image Quality
```bash
curl -X PUT http://vision:8000/cameras/camera1/config \
curl -X PUT http://localhost:8000/cameras/camera1/config \
-H "Content-Type: application/json" \
-d '{
"sharpness": 150,
@@ -165,7 +210,7 @@ curl -X PUT http://vision:8000/cameras/camera1/config \
### Example 3: Configure for Indoor Lighting
```bash
curl -X PUT http://vision:8000/cameras/camera1/config \
curl -X PUT http://localhost:8000/cameras/camera1/config \
-H "Content-Type: application/json" \
-d '{
"anti_flicker_enabled": true,
@@ -177,7 +222,7 @@ curl -X PUT http://vision:8000/cameras/camera1/config \
### Example 4: Enable HDR Mode
```bash
curl -X PUT http://vision:8000/cameras/camera1/config \
curl -X PUT http://localhost:8000/cameras/camera1/config \
-H "Content-Type: application/json" \
-d '{
"hdr_enabled": true,
@@ -191,7 +236,7 @@ curl -X PUT http://vision:8000/cameras/camera1/config \
```jsx
import React, { useState, useEffect } from 'react';
const CameraConfig = ({ cameraName, apiBaseUrl = 'http://vision:8000' }) => {
const CameraConfig = ({ cameraName, apiBaseUrl = 'http://localhost:8000' }) => {
const [config, setConfig] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
@@ -248,7 +293,21 @@ const CameraConfig = ({ cameraName, apiBaseUrl = 'http://vision:8000' }) => {
return (
<div className="camera-config">
<h3>Camera Configuration: {cameraName}</h3>
{/* System Information (Read-Only) */}
<div className="config-section">
<h4>System Information</h4>
<div className="info-grid">
<div><strong>Name:</strong> {config.name}</div>
<div><strong>Machine Topic:</strong> {config.machine_topic}</div>
<div><strong>Storage Path:</strong> {config.storage_path}</div>
<div><strong>Enabled:</strong> {config.enabled ? 'Yes' : 'No'}</div>
<div><strong>Auto Recording:</strong> {config.auto_start_recording_enabled ? 'Enabled' : 'Disabled'}</div>
<div><strong>Max Retries:</strong> {config.auto_recording_max_retries}</div>
<div><strong>Retry Delay:</strong> {config.auto_recording_retry_delay_seconds}s</div>
</div>
</div>
{/* Basic Settings */}
<div className="config-section">
<h4>Basic Settings</h4>
@@ -328,6 +387,47 @@ const CameraConfig = ({ cameraName, apiBaseUrl = 'http://vision:8000' }) => {
</div>
</div>
{/* White Balance RGB Gains */}
<div className="config-section">
<h4>White Balance RGB Gains</h4>
<div className="setting">
<label>Red Gain: {config.wb_red_gain}</label>
<input
type="range"
min="0"
max="3.99"
step="0.01"
value={config.wb_red_gain}
onChange={(e) => handleSliderChange('wb_red_gain', parseFloat(e.target.value))}
/>
</div>
<div className="setting">
<label>Green Gain: {config.wb_green_gain}</label>
<input
type="range"
min="0"
max="3.99"
step="0.01"
value={config.wb_green_gain}
onChange={(e) => handleSliderChange('wb_green_gain', parseFloat(e.target.value))}
/>
</div>
<div className="setting">
<label>Blue Gain: {config.wb_blue_gain}</label>
<input
type="range"
min="0"
max="3.99"
step="0.01"
value={config.wb_blue_gain}
onChange={(e) => handleSliderChange('wb_blue_gain', parseFloat(e.target.value))}
/>
</div>
</div>
{/* Advanced Settings */}
<div className="config-section">
<h4>Advanced Settings</h4>