AVPlayer AVPlayerWaitingWhileEvaluatingBufferingRateReason 大视频加载缓慢

4
我有一个AVPlayer在播放一个大小适中的视频(约150mb)。在最初加载视频时,我发现播放器在AVPlayerWaitingWhileEvaluatingBufferingRateReason状态下保持不活跃长达10-15秒。我的问题很简单:如何防止AVPlayer评估缓冲速率原因这么长时间,而是立即播放视频?
我正在使用自定义资源加载程序(尽管在没有使用自定义资源加载程序的情况下也会出现相同的行为)。以下是创建AVPlayer的相关代码(所有标准样板):
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;

我随后有一种处理数据请求的方法,可以使用它来获取更多关于AVPlayer正在尝试加载什么内容的信息:

-(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];

}

现在,我们来看一下问题。假设视频长度为 ~100mb,在上述方法中,handleDataRequest 日志的结果如下:

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))

如您所见,仅为评估缓冲状态原因,就有近40个HTTP请求。这需要很长时间。

这是我尝试过的:

  1. 使用AVPlayer的playImmediatelyAtRate:而不是play

我在网上看到了这个建议。我想逻辑是立即播放即可播放。但实际上,播放器仍然需要花费时间(和请求)来评估缓冲速率原因才能播放,因此它并不能起到作用。

  1. 将AVPlayer的automaticallyWaitsToMinimizeStalling设置为NO

看起来很合理。我们可以告诉播放器不要等待最小化停顿。不幸的是,这种方法失败了,因为播放器在播放之前仍会发出相同的请求来评估缓冲速率(奇怪的是,当这种情况发生时,reasonForWaitingToPlay为空)。

  1. 调用加载请求的finishLoading方法以立即加速缓冲速率评估

这里的逻辑是,在AVPlayer评估缓冲速率时,我可以立即发出加载完成的信号,而不是发送实际的HTTP请求。这样做的结果各不相同。在某些测试中,视频会立即播放,但仅播放几秒钟,而在其他测试中,视频无法播放并超时。

总之,在播放大型视频时有没有避免此延迟的方法?AVPlayer是否必须在开始视频之前评估缓冲速率?


1
更新:我使用了苹果TSI信用,工程师确认了我的发现,但我们还没有找到解决方法。看起来这是某些格式化视频的问题,而不一定是所有大型视频的问题。 - Aaron Wojnowski
preferredForwardBufferedDuration是AVPlayerItem类的一个属性,具体信息请参考https://developer.apple.com/documentation/avfoundation/avplayeritem/1643630-preferredforwardbufferduration。 - Dan M
@DanM 没有变化。无论将 preferredForwardBufferedDuration 设置为什么值,播放器仍然停留在 AVPlayerWaitingWhileEvaluatingBufferingRateReason 状态。 - Aaron Wojnowski
1个回答

2

苹果已经确认问题不在于视频大小,而在于损坏的 MP4 文件中有太多的 moof+mdat 原子。

目前已确定这是按预期工作的。尽管如此,我希望未来能找到一些方法来避免这种初始缓冲,即使 MP4 文件损坏。


你有没有尝试过一些解决方法,比如使用不同的x264参数重新编码视频? - undefined
重新编码视频是可行的。在我的情况下,这些视频来自第三方,所以如果不完全下载视频,重新编码是不可能的(这将违背流媒体的初衷)。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接