#react native expo does not play same sample video from FastAPI
50 messages · Page 1 of 1 (latest)
so that video with the link you gave doesnt work for you? is that correct? because it plays for me in both chrome and firefox
It works in browser. I downloaded it from Amazon s3 just to test. It works in browsers. It works on react native when on S3 but not from fastapi.
Same video
can you send the link to the video thats served from fastapi
It’s on top. You said you could play it in browser
This is original sample that plays
And this one does not play on my react native app
are there any errors? the video works and can be streamed in the browser, so theres no issues there with fastapi or railway
No errors except favicon error on browser
Both curls return 200
It must be sth in react
theres not too much i can help you with if theres no errors, at the very least its not an issue with your code or railway
it must be a client side issue
I think so. Meaning react.
But funny thing is only uri is different on react
I mean different for s3 or here
has anyone else experienced the same issues with react native? since this isnt an issue with your code or railway
I saw some posts on stack overflow saying same video would not play but no answers or solutions. I’ll keep looking
Like you said nothing to do w/o errors. Thanks again 🙂
no problem!
Here is something weirder.
It plays on Android simulator from FastAPI. It plays on both when url is changed to S3 ( same video )
I say blame apple
🙂 🙂 yeah 🙂 🙂
classic apple
I just read some place 'content-type': 'video/mp4', needs to be set for apple. I will look into this to see If I can do that from FastAPI but then I remembered the headers which I posted above. Both headers declare the type
indeed they do
It plays on safari but gives some kind of error. Failed to play the resource, plugin handled the load
now what the heck is that supposed to mean
They say needs to be streaming response in chunks of bytes. I'll see if there is a way to do that in fastapi
interesting
Something like this may be. If I find a solution, I'll write here so others can see. It is a weird problem
yeah that looks like it would do what you want, then you can use that route for the video folder instead of a static server that you currently use
Right. Thanks. It turns out tiangolo talks about this.
hmmm
Got it working at last 🙂 I have not deployed it yet since this time Android would not play the video if you can believe it 🙂 I lost a couple of hours debugging and remembered Android never played videos when tested locally :)))) It has to be on the server. Because Android thinks 127.0.0.1 or localhost is inside the phone :))) So I lost some hours for nothing 🙂 I knew this but just did not occur to me :))
Excellent example here:
https://github.com/tiangolo/fastapi/issues/1240
I adapted this code by angel-langdon towards the middle of the page. You'll see it
part 1
import os
from typing import BinaryIO
from fastapi import FastAPI, HTTPException, Request, status
from fastapi.responses import StreamingResponse
def send_bytes_range_requests(
file_obj: BinaryIO, start: int, end: int, chunk_size: int = 10_000
):
"""Send a file in chunks using Range Requests specification RFC7233
`start` and `end` parameters are inclusive due to specification
"""
with file_obj as f:
f.seek(start)
while (pos := f.tell()) <= end:
read_size = min(chunk_size, end + 1 - pos)
yield f.read(read_size)
def _get_range_header(range_header: str, file_size: int) -> tuple[int, int]:
def _invalid_range():
return HTTPException(
status.HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE,
detail=f"Invalid request range (Range:{range_header!r})",
)
try:
h = range_header.replace("bytes=", "").split("-")
start = int(h[0]) if h[0] != "" else 0
end = int(h[1]) if h[1] != "" else file_size - 1
except ValueError:
raise _invalid_range()
if start > end or start < 0 or end > file_size - 1:
raise _invalid_range()
return start, end
part 2:
def range_requests_response(
request: Request, file_path: str, content_type: str
):
"""Returns StreamingResponse using Range Requests of a given file"""
file_size = os.stat(file_path).st_size
range_header = request.headers.get("range")
headers = {
"content-type": content_type,
"accept-ranges": "bytes",
"content-encoding": "identity",
"content-length": str(file_size),
"access-control-expose-headers": (
"content-type, accept-ranges, content-length, "
"content-range, content-encoding"
),
}
start = 0
end = file_size - 1
status_code = status.HTTP_200_OK
if range_header is not None:
start, end = _get_range_header(range_header, file_size)
size = end - start + 1
headers["content-length"] = str(size)
headers["content-range"] = f"bytes {start}-{end}/{file_size}"
status_code = status.HTTP_206_PARTIAL_CONTENT
return StreamingResponse(
send_bytes_range_requests(open(file_path, mode="rb"), start, end),
headers=headers,
status_code=status_code,
)
app = FastAPI()
@app.get("/video")
def get_video(request: Request):
return range_requests_response(
request, file_path="path_to_my_video.mp4", content_type="video/mp4"
)
oh wow, that's a lot of code, at this point I would have setup an actual file server with caddy or something
🙂 yeah, true 🙂
well now I got myself thinking, will caddy do video streaming by default
well now so does fastapi
Well, this code that I posted uses some of the FastAPI libraries. Tiangolo comments on the github repo.
However, some of the streaming is handled by servers like S3 for instance. I wonder what happens then. Who decides what the chunk-size will be for instance. Oh well 🙂 It works I'm happy 🙂