why AVPlayer sends range

Hi,

I am writing my own HTTP web service server that supports iOS devices to view video files. On iOS I am using `AVPlayer` and on the server side it is simply `.mp4` files. But it seems like AVPlayer buffers for a long time (10+ seconds) before starting playing a video.


After a bit debugging, it seems that AVPlayer send weird range values in its HTTP request for the video, for example:


1st request headers send range 0-1: (this is OK)


X-Playback-Session-Id: B1F3B5AE-B49A-40B1-8F2E-A501E1BC24AF
Range: bytes=0-1
Accept: */*
User-Agent: AppleCoreMedia/1.0.0.17A860 (iPhone; U; CPU OS 13_1_2 like Mac OS X; en_us)
Accept-Language: en-us
Accept-Encoding: identity
Connection: keep-alive


2nd request headers send range 0-37724087, which is full length of the video.

This is weird, why doesn't AVPlayer take advantage of range header and ask for only a small range?


X-Playback-Session-Id: B1F3B5AE-B49A-40B1-8F2E-A501E1BC24AF
Range: bytes=0-37724087
Accept: */*
User-Agent: AppleCoreMedia/1.0.0.17A860 (iPhone; U; CPU OS 13_1_2 like Mac OS X; en_us)
Accept-Language: en-us
Accept-Encoding: identity
Connection: keep-alive


3rd request headers send range of 37683200-37724087, which is the last chunk of the video.

Again very weird, why does AVPlayer ask for the range that was already covered by the previous request?


X-Playback-Session-Id: B1F3B5AE-B49A-40B1-8F2E-A501E1BC24AF
Range: bytes=37683200-37724087
Accept: */*
User-Agent: AppleCoreMedia/1.0.0.17A860 (iPhone; U; CPU OS 13_1_2 like Mac OS X; en_us)
Accept-Language: en-us
Accept-Encoding: identity
Connection: keep-alive


Any ideas? Any comments or pointers are appreciated.

I know this was asked 2 years ago, but I have the same question. Any answers on that? That behaviour is especially bad when you proxy videos from an AWS S3 instance.

I can't figure it out, why is it handled this way?

Ok I’ve been solving this problem for a while for my own app so maybe my findings can help others. Note that this has nothing to do with playImmediately() or automaticallyWaitsToMinimizeStalling. Also note that AVPlayer is doing its best with what its parents taught it.

First, know that some mp4s and m4as are not made equal; some use different compression than others, that’s what AVPlayer checks for before playing.

One of these compression methods is variable bit rate. This is an issue for AVPlayer because while it can maybe know the average bitrate, it can’t calculate the duration of the file.

What I believe happens under the hood (based on my own server) is AVPlayer fetches a ridiculous and undefined amount of ranges in order to calculate the final duration. Sometimes it only then starts actually buffering the file. Notice that AVPlayer won’t play or properly buffer until duration > 0.

Sometimes (with a remote googlevideo url) it’s even wrong and says the duration is twice what it should be.

Yes, this is inefficient. Yes, there are ways to solve this that Apple doesn’t know about since the same url can be played immediately in Chrome, but take 10 seconds in Safari.

This is native and expected behaviour for Apple. AVPlayer IS handling a compression it’s not ready for, and DOES eventually succeed in playing it. Good job AVPlayer.

Using a different file format will solve this. I’ve yet to find a Swift library that buffers correctly, and has all the benefits of AVPlayer. You can do the conversion serverside at runtime, but if your server is also fetching remotely, I haven’t found a way to convert without also downloading the whole file.

why AVPlayer sends range
 
 
Q