How to set up your server for streaming videos with react-native-video?

2k views Asked by At

We are struggling to get our server set up to stream videos with react-native-video on Android. All the files to be streamed are in .MP4 format and vary in size from 50-100 MB. I am not able to provide the URL to reproduce or share any of the MP4 files. I have tried Android player and Exoplayer and I am not seeking the video as we speak.

For small videos there doesn't seem to be problem, as the server receives HTTP request with the following headers from the player:

{
    "name":"test.mp4",
    "User-Agent":"stagefright/1.2 (Linux;Android 10)",
    "Connection":"close",
    "X-Forwarded-Proto":"https",
    "X-Forwarded-For":**********,
    "Host":**********,
    "Accept-Encoding":"gzip",
    "ssl_session_id":**********,
}

And we serve the test.mp4 file. In this case everything works on the client side (video plays fine), even though we are getting the following error on server side as react-native-video is sending the same identical HTTP request again. Why is it sending multiple requests?

Failed to handle request.: java.io.IOException: Broken pipe
....
Failed to send error response: java.lang.IllegalStateException: UT010019: Response already commited

For both identical requests we return a response with the file content as body, 200 STATUS OK and the following headers:

{
    "Server": "nginx",
    "Date": <date>,
    "Content-Length": <length in bytes>,
    "Connection": "keep-alive",
    "Expires": 0,
    "Cache-Control": "no-cache, no-store, max-age=0, must-revalidate",
    "Pragma": "no-cache",
    "Content-Disposition": "attachment; filename="test.mp4",
}

What type of headers is react-native-video expecting?

The situation changes when files get larger (~100 MB). At some point react-native-video starts to send range requests. When? However the first request is without Range header parameter and identical to the one before. As usual we send the same response and produce same errors. However from there on the player starts to send repetitive range requests similar to the one described above, but with the Range header parameter like this:

{
    ...,
    "Range":"bytes=1752325-"
}

All the following requests follow the same pattern: bytes=<start-bytes>-, which means requesting bytes from some value to end. The value <start-bytes> increases with every new request (sometimes there are requests with the same value multiple times). Why is it requesting the same bytes over and over again and not requesting for specific ranges?

We have range requests supported on our server and thus responding with valid file data, 206 STATUS PARTIAL CONTENT and the same headers with the following addition (values are for example):

{
    ....,
    "Content-Range": "bytes 0-11546/115461173"
}

What type of response is react-native-video expecting?

With those range requests the server is also producing the errors described above and the video is getting freezed very often on the client side for minutes. After for some time the video starts to play fine and the errors are not being produced on the server side.

I have several questions marked with bold in the text that I am confused of. Also I could not find any documentation describing how the communication with the player works and what kind of requests is it sending and responses is it expecting.

Is there any documentation describing the protocol or could you hint anything I might be doing wrong here?

1

There are 1 answers

1
szatmary On

"mp4" does not tell the player very much about the file. The player needs information about the codecs, codec features, file layout, and a dozen or so other things. With mp4 this metadata may be at the beginning or end of the file. Its also possible the file you point to is not actually an mp4 so the player needs to check for that as well.

So how does the player get this information? Its starts to download the file. Once is has a few bytes the player may need to cancel the request because the data it needs was not at that location in the file. But there is no cancel mechanism in HTTP, so it just terminates the TCP session; hence java.io.IOException: Broken pipe. It may appear the player is downloading the same data multiple times, But its not because the request was canceled before the request was finished. As the player is scanning the file it can leap-frog over large blocks using the data it has learned so far seeking for the metadata needed.

To give the player the best chance of finding the metadata quickly, make sure it is art the start of the file. This is called "fast start". Searching google for "fast start mp4" will tell you how to do that.