Skip to content

Commit

Permalink
refactor: Streaming MP4 files in the browser using video html element…
Browse files Browse the repository at this point in the history
… instead of waiting for the entire file to download before playing
  • Loading branch information
kevin.zhang committed Apr 15, 2024
1 parent 0550e43 commit d13a3cf
Showing 1 changed file with 35 additions and 5 deletions.
40 changes: 35 additions & 5 deletions app/controllers/v1/video.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import shutil

from fastapi import Request, Depends, Path, BackgroundTasks, UploadFile
from fastapi.responses import FileResponse
from fastapi.responses import FileResponse, StreamingResponse
from fastapi.params import File
from loguru import logger

Expand Down Expand Up @@ -137,7 +137,37 @@ def upload_bgm_file(request: Request, file: UploadFile = File(...)):
async def stream_video(request: Request, file_path: str):
tasks_dir = utils.task_dir()
video_path = os.path.join(tasks_dir, file_path)
if os.path.isfile(video_path):
return FileResponse(video_path, media_type="video/mp4", filename=file_path)
else:
return {"message": "File not found."}
range_header = request.headers.get('Range')
video_size = os.path.getsize(video_path)
start, end = 0, video_size - 1

length = video_size
if range_header:
range_ = range_header.split('bytes=')[1]
start, end = [int(part) if part else None for part in range_.split('-')]
if start is None:
start = video_size - end
end = video_size - 1
if end is None:
end = video_size - 1
length = end - start + 1

def file_iterator(file_path, offset=0, bytes_to_read=None):
with open(file_path, 'rb') as f:
f.seek(offset, os.SEEK_SET)
remaining = bytes_to_read or video_size
while remaining > 0:
bytes_to_read = min(4096, remaining)
data = f.read(bytes_to_read)
if not data:
break
remaining -= len(data)
yield data

response = StreamingResponse(file_iterator(video_path, start, length), media_type='video/mp4')
response.headers['Content-Range'] = f'bytes {start}-{end}/{video_size}'
response.headers['Accept-Ranges'] = 'bytes'
response.headers['Content-Length'] = str(length)
response.status_code = 206 # Partial Content

return response

0 comments on commit d13a3cf

Please sign in to comment.