Enhance media API transcoding and video streaming capabilities

- Added support for limiting concurrent transcoding operations in the media API to prevent resource exhaustion.
- Implemented functions to retrieve video duration and bitrate using ffprobe for improved streaming performance.
- Enhanced the generate_transcoded_stream function to handle HTTP range requests, allowing for more efficient video playback.
- Updated VideoModal component to disable fluid and responsive modes, ensuring proper container boundaries during video playback.
- Improved logging throughout the transcoding process for better error tracking and debugging.
This commit is contained in:
salirezav
2025-11-04 11:55:27 -05:00
parent de46753f15
commit 5070d9b2ca
15 changed files with 391 additions and 99 deletions

View File

@@ -162,3 +162,4 @@ if __name__ == "__main__":

View File

@@ -12,7 +12,7 @@ import paho.mqtt.client as mqtt
from ..core.config import Config, MQTTConfig
from ..core.state_manager import StateManager
from ..core.events import EventSystem, EventType, publish_machine_state_changed
from ..core.events import EventSystem, EventType
from .handlers import MQTTMessageHandler

View File

@@ -9,7 +9,7 @@ from typing import Dict, Optional
from datetime import datetime
from ..core.state_manager import StateManager, MachineState
from ..core.events import EventSystem, publish_machine_state_changed
from ..core.events import EventSystem, EventType
class MQTTMessageHandler:
@@ -47,7 +47,16 @@ class MQTTMessageHandler:
if state_changed:
self.logger.info(f"📡 MQTT: Machine {machine_name} state changed to: {normalized_payload}")
self.logger.info(f"📡 Publishing MACHINE_STATE_CHANGED event for {machine_name} -> {normalized_payload}")
publish_machine_state_changed(machine_name=machine_name, state=normalized_payload, source="mqtt_handler")
# Use the event_system instance passed to this handler, not the global one
self.event_system.publish(
EventType.MACHINE_STATE_CHANGED,
"mqtt_handler",
{
"machine_name": machine_name,
"state": normalized_payload,
"previous_state": None
}
)
self.logger.info(f"✅ Published MACHINE_STATE_CHANGED event for {machine_name} -> {normalized_payload}")
else:
self.logger.info(f"📡 Machine {machine_name} state unchanged (still {normalized_payload}) - no event published")

View File

@@ -103,7 +103,15 @@ class StandaloneAutoRecorder:
machine_name = camera_config.machine_topic
if machine_name:
mapping[machine_name] = camera_config.name
self.logger.info(f"Auto-recording enabled: {machine_name} -> {camera_config.name}")
self.logger.info(f"Auto-recording enabled: '{machine_name}' -> {camera_config.name}")
else:
self.logger.warning(f"⚠️ Camera {camera_config.name} has no machine_topic configured")
else:
if not camera_config.enabled:
self.logger.debug(f"Camera {camera_config.name} is disabled")
elif not camera_config.auto_start_recording_enabled:
self.logger.debug(f"Camera {camera_config.name} has auto-recording disabled")
self.logger.info(f"📋 Built machine-camera mapping with {len(mapping)} entries: {mapping}")
return mapping
def _setup_mqtt(self) -> bool:
@@ -197,7 +205,8 @@ class StandaloneAutoRecorder:
# Check if we have a camera for this machine
camera_name = self.machine_camera_map.get(machine_name)
if not camera_name:
self.logger.debug(f"No camera mapped to machine: {machine_name}")
self.logger.warning(f"❌ AUTO-RECORDER: No camera mapped to machine: '{machine_name}'")
self.logger.info(f"📋 Available machine-camera mappings: {self.machine_camera_map}")
return
self.logger.info(f"📡 MQTT: Machine {machine_name} ({camera_name}) -> {state}")
@@ -215,10 +224,12 @@ class StandaloneAutoRecorder:
def _start_recording(self, camera_name: str, machine_name: str):
"""Start recording for a camera"""
try:
self.logger.info(f"🎬 AUTO-RECORDER: Attempting to start recording for {camera_name} (machine: {machine_name})")
# Check if already recording
camera_info = self.state_manager.get_camera_status(camera_name) if self.state_manager else None
if camera_info and camera_info.is_recording:
self.logger.info(f"Camera {camera_name} is already recording, skipping")
self.logger.info(f"⚠️ Camera {camera_name} is already recording, skipping auto-start")
return
# Use camera_manager if available, otherwise use standalone recorder
@@ -227,8 +238,15 @@ class StandaloneAutoRecorder:
from ..core.timezone_utils import format_filename_timestamp
timestamp = format_filename_timestamp()
camera_config = self.config.get_camera_by_name(camera_name)
if not camera_config:
self.logger.error(f"❌ AUTO-RECORDER: No configuration found for camera {camera_name}")
return
video_format = camera_config.video_format if camera_config else "mp4"
filename = f"{camera_name}_auto_{machine_name}_{timestamp}.{video_format}"
self.logger.info(f"📹 AUTO-RECORDER: Starting recording with settings - Exposure: {camera_config.exposure_ms}ms, Gain: {camera_config.gain}, FPS: {camera_config.target_fps}")
# Use camera manager to start recording with camera's default settings
success = self.camera_manager.manual_start_recording(
@@ -240,10 +258,10 @@ class StandaloneAutoRecorder:
)
if success:
self.logger.info(f"Started auto-recording: {camera_name} -> {filename}")
self.logger.info(f"AUTO-RECORDER: Successfully started auto-recording: {camera_name} -> {filename}")
self.active_recordings[camera_name] = filename
else:
self.logger.error(f"❌ Failed to start auto-recording for camera {camera_name}")
self.logger.error(f" AUTO-RECORDER: Failed to start auto-recording for camera {camera_name} (manual_start_recording returned False)")
else:
# Standalone mode - use own recorder
recorder = self._get_camera_recorder(camera_name)