Aaron Wojnowski
Aaron Wojnowski

Reputation: 6480

AVPlayer AVPlayerWaitingWhileEvaluatingBufferingRateReason slow loading for larger videos

I have an AVPlayer that is playing a moderately large video (~150mb). When loading the video initially, I find that the player remains idle for upwards of 10-15 seconds in the AVPlayerWaitingWhileEvaluatingBufferingRateReason state. My question is simple: how can I prevent AVPlayer from "evaluating the buffering rate reason" for this long and instead move to immediately playing the video?

I am using a custom resource loader (although this same behaviour is exhibited without using a custom resource loader). Here is the relevant code for creating the AVPlayer (all standard boilerplate):

AVURLAsset * const playerAsset = [[AVURLAsset alloc] initWithURL:videoURL options:nil];
[[playerAsset resourceLoader] setDelegate:self queue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)];

AVPlayerItem * const playerItem = [[AVPlayerItem alloc] initWithAsset:playerAsset];

AVPlayer * const player = [[AVPlayer alloc] initWithPlayerItem:playerItem];
[player play];
_player = player;

I then have a method for handling the data request, which I can use to get more information about what the AVPlayer is attempting to load:

-(void)handleDataRequest:(AVAssetResourceLoadingDataRequest *)dataRequest loadingRequest:(AVAssetResourceLoadingRequest *)loadingRequest {

    NSLog(@"handleDataRequest: %lld-%lld (%@)",[dataRequest requestedOffset],[dataRequest requestedOffset] + [dataRequest requestedLength],[[self player] reasonForWaitingToPlay]);

    NSMutableURLRequest * const request = ... // construct the request
    [request setValue:[NSString stringWithFormat:@"bytes=%lld-%lld",[dataRequest requestedOffset],[dataRequest requestedOffset] + [dataRequest requestedLength]] forHTTPHeaderField:@"Range"];

    NSURLSession * const downloadURLSession = ... // get the session
    NSURLSessionDataTask * const dataTask = [downloadURLSession dataTaskWithRequest:request];
    [dataTask resume];

}

Now, on to the issue. Suppose the video length is ~100mb, here's the result of that handleDataRequest log in the above method:

handleDataRequest: 0-100000000 (AVPlayerWaitingWhileEvaluatingBufferingRateReason)
handleDataRequest: 3080192-100000000 (AVPlayerWaitingWhileEvaluatingBufferingRateReason)
handleDataRequest: 5570560-100000000 (AVPlayerWaitingWhileEvaluatingBufferingRateReason)
handleDataRequest: 7143424-100000000 (AVPlayerWaitingWhileEvaluatingBufferingRateReason)
handleDataRequest: 9699328-100000000 (AVPlayerWaitingWhileEvaluatingBufferingRateReason)
handleDataRequest: 12713984-100000000 (AVPlayerWaitingWhileEvaluatingBufferingRateReason)
handleDataRequest: 14811136-100000000 (AVPlayerWaitingWhileEvaluatingBufferingRateReason)
handleDataRequest: 17235968-100000000 (AVPlayerWaitingWhileEvaluatingBufferingRateReason)
handleDataRequest: 20054016-100000000 (AVPlayerWaitingWhileEvaluatingBufferingRateReason)
handleDataRequest: 22675456-100000000 (AVPlayerWaitingWhileEvaluatingBufferingRateReason)
handleDataRequest: 25427968-100000000 (AVPlayerWaitingWhileEvaluatingBufferingRateReason)
handleDataRequest: 28311552-100000000 (AVPlayerWaitingWhileEvaluatingBufferingRateReason)
handleDataRequest: 30932992-100000000 (AVPlayerWaitingWhileEvaluatingBufferingRateReason)
handleDataRequest: 32374784-100000000 (AVPlayerWaitingWhileEvaluatingBufferingRateReason)
handleDataRequest: 35192832-100000000 (AVPlayerWaitingWhileEvaluatingBufferingRateReason)
handleDataRequest: 37224448-100000000 (AVPlayerWaitingWhileEvaluatingBufferingRateReason)
handleDataRequest: 39780352-100000000 (AVPlayerWaitingWhileEvaluatingBufferingRateReason)
handleDataRequest: 41549824-100000000 (AVPlayerWaitingWhileEvaluatingBufferingRateReason)
handleDataRequest: 43778048-100000000 (AVPlayerWaitingWhileEvaluatingBufferingRateReason)
handleDataRequest: 46465024-100000000 (AVPlayerWaitingWhileEvaluatingBufferingRateReason)
handleDataRequest: 49414144-100000000 (AVPlayerWaitingWhileEvaluatingBufferingRateReason)
handleDataRequest: 52166656-100000000 (AVPlayerWaitingWhileEvaluatingBufferingRateReason)
handleDataRequest: 54984704-100000000 (AVPlayerWaitingWhileEvaluatingBufferingRateReason)
handleDataRequest: 57802752-100000000 (AVPlayerWaitingWhileEvaluatingBufferingRateReason)
handleDataRequest: 60293120-100000000 (AVPlayerWaitingWhileEvaluatingBufferingRateReason)
handleDataRequest: 62783488-100000000 (AVPlayerWaitingWhileEvaluatingBufferingRateReason)
handleDataRequest: 65732608-100000000 (AVPlayerWaitingWhileEvaluatingBufferingRateReason)
handleDataRequest: 68550656-100000000 (AVPlayerWaitingWhileEvaluatingBufferingRateReason)
handleDataRequest: 70975488-100000000 (AVPlayerWaitingWhileEvaluatingBufferingRateReason)
handleDataRequest: 73531392-100000000 (AVPlayerWaitingWhileEvaluatingBufferingRateReason)
handleDataRequest: 76480512-100000000 (AVPlayerWaitingWhileEvaluatingBufferingRateReason)
handleDataRequest: 79495168-100000000 (AVPlayerWaitingWhileEvaluatingBufferingRateReason)
handleDataRequest: 82313216-100000000 (AVPlayerWaitingWhileEvaluatingBufferingRateReason)
handleDataRequest: 83951616-100000000 (AVPlayerWaitingWhileEvaluatingBufferingRateReason)
handleDataRequest: 86573056-100000000 (AVPlayerWaitingWhileEvaluatingBufferingRateReason)
handleDataRequest: 88866816-100000000 (AVPlayerWaitingWhileEvaluatingBufferingRateReason)
handleDataRequest: 91422720-100000000 (AVPlayerWaitingWhileEvaluatingBufferingRateReason)
handleDataRequest: 92667904-100000000 (AVPlayerWaitingWhileEvaluatingBufferingRateReason)
handleDataRequest: 95289344-100000000 (AVPlayerWaitingWhileEvaluatingBufferingRateReason)
handleDataRequest: 98172928-100000000 (AVPlayerWaitingWhileEvaluatingBufferingRateReason)
handleDataRequest: 32768-5570560 (AVPlayerWaitingWhileEvaluatingBufferingRateReason)
handleDataRequest: 2032769-5570560 (AVPlayerWaitingToMinimizeStallsReason)
handleDataRequest: 4032770-5570560 (AVPlayerWaitingToMinimizeStallsReason)
handleDataRequest: 5668864-22675456 ((null))
handleDataRequest: 7668865-22675456 ((null))
handleDataRequest: 9668866-22675456 ((null))
handleDataRequest: 11668867-22675456 ((null))
handleDataRequest: 13668868-22675456 ((null))

As you can see, there's nearly 40 HTTP requests just to evaluate the buffering state reason. This takes a very long amount of time.

Here's what I've tried:

  1. Use AVPlayer's playImmediatelyAtRate: instead of play

I saw this suggestion online. I suppose the logic is that playing immediately would do just that, play immediately. This does not work as the player still takes the time (and the requests) to evaluate the buffering rate reason before playing.

  1. Set AVPlayer's automaticallyWaitsToMinimizeStalling to NO

Seems reasonable. We can tell the player not to wait to minimize stalling. Unfortunately, this fails as the player still makes the same requests to evaluate the buffering rate before playing (oddly enough, however, the reasonForWaitingToPlay is null while this is taking place).

  1. Call the loading request's finishLoading method to immediately accelerate the buffering rate evaluation

The logic here was that instead of firing actual HTTP requests while the AVPlayer was evaluating the buffering rate, I could immediately signal that loading was finished. The results of this varied. In some tests, the video would play immediately but only play for a couple of seconds whereas in other tests, the video failed to play at all and would time out.

In conclusion, is there any way to avoid this delay when playing larger videos? Is it truly necessary that the AVPlayer must evaluate the buffering rate prior to starting a video?

Upvotes: 4

Views: 764

Answers (1)

Aaron Wojnowski
Aaron Wojnowski

Reputation: 6480

Apple has confirmed that the issue is not the size of the video, but instead a malformed MP4 with too many moof+mdat atoms.

At this point in time, this has been determined to be working as intended. Although, I would like to see some way to avoid this initial buffering in the future, even if the MP4 is malformed.

Upvotes: 2

Related Questions