From 8a54a887294608ac8a0fff308124f3e74af8c487 Mon Sep 17 00:00:00 2001 From: salirezav Date: Wed, 18 Mar 2026 15:04:06 -0400 Subject: [PATCH] =?UTF-8?q?Frontend:=20removed=20the=20forced=20MIME=20typ?= =?UTF-8?q?e=20from=20the=20Video.js=20sources=20object=20so=20it=20can=20?= =?UTF-8?q?correctly=20handle=20non-mp4=20=E2=80=9Cregular=E2=80=9D=20stre?= =?UTF-8?q?ams.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit File: video-remote/src/components/VideoModal.tsx Backend: updated /videos/{file_id}/stream-transcoded so that when a Range request is present, it computes an approximate duration_sec from the requested byte length and bitrate, and passes that to ffmpeg (so the response length aligns with Content-Length). File: media-api/main.py --- media-api/main.py | 13 ++++++++----- video-remote/src/components/VideoModal.tsx | 5 ++++- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/media-api/main.py b/media-api/main.py index c971f37..9b6274b 100644 --- a/media-api/main.py +++ b/media-api/main.py @@ -746,18 +746,21 @@ def stream_transcoded(request: Request, file_id: str, start_time: float = 0.0): time_start_sec = (byte_start / estimated_total_bytes) * video_duration time_start_sec = max(0.0, min(time_start_sec, video_duration - 0.5)) - # For seeking, don't limit duration - stream to end - # The browser will handle buffering - duration_sec = None # None means stream to end - # Update headers for range response # For seeking, we typically don't know the exact end, so estimate actual_byte_end = min(byte_end or estimated_total_bytes - 1, estimated_total_bytes - 1) headers["Content-Range"] = f"bytes {byte_start}-{actual_byte_end}/{estimated_total_bytes}" headers["Content-Length"] = str(actual_byte_end - byte_start + 1) + + # Honor the requested range: approximate duration based on bitrate so the + # transcoded response length matches the declared Content-Length. + requested_bytes = actual_byte_end - byte_start + 1 + duration_sec = requested_bytes * 8 / transcoded_bitrate if transcoded_bitrate else None + if duration_sec is not None: + # Clamp to remaining duration. + duration_sec = max(0.0, min(duration_sec, video_duration - time_start_sec)) # Stream from the calculated time position using FFmpeg's -ss flag - # Duration is None, so it will stream to the end return StreamingResponse( generate_transcoded_stream(p, time_start_sec, duration_sec), media_type=content_type, diff --git a/video-remote/src/components/VideoModal.tsx b/video-remote/src/components/VideoModal.tsx index 9cc652a..d7545b0 100644 --- a/video-remote/src/components/VideoModal.tsx +++ b/video-remote/src/components/VideoModal.tsx @@ -52,7 +52,10 @@ export const VideoModal: React.FC = ({ fileId, onClose }) => { sources: [ { src: src, - type: 'video/mp4' + // Do not hardcode the MIME type: the "regular" endpoint may serve + // non-mp4 containers (avi/mkv/etc), and forcing mp4 can trigger + // MEDIA_ERR_SRC_NOT_SUPPORTED in Video.js/browser. + // Let Video.js/browser sniff based on the actual response. } ] })