Frontend: removed the forced MIME type from the Video.js sources object so it can correctly handle non-mp4 “regular” streams.

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
This commit is contained in:
salirezav
2026-03-18 15:04:06 -04:00
parent 78bfcf0261
commit 8a54a88729
2 changed files with 12 additions and 6 deletions

View File

@@ -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,

View File

@@ -52,7 +52,10 @@ export const VideoModal: React.FC<Props> = ({ 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.
}
]
})