Reputation: 6480
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:
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.
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).
finishLoading
method to immediately accelerate the buffering rate evaluationThe 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
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