处理AVPlayer卡顿问题

10

我正在尝试捕捉一个时刻,当AVPlayer无法继续播放因为没有更多的媒体可用(网络过慢、信号丢失等)。根据文档和不同的示例,我正在使用KVO来检测这一点:

item = [[AVPlayerItem alloc] initWithURL:audioURL];
player = [AVPlayer playerWithPlayerItem:item];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onItemNotification:) name:AVPlayerItemPlaybackStalledNotification object:item];
[item addObserver:self forKeyPath:@"playbackBufferEmpty" options:NSKeyValueObservingOptionNew context:nil];
[item addObserver:self forKeyPath:@"playbackLikelyToKeepUp" options:NSKeyValueObservingOptionNew context:nil];

...

- (void) onItemNotification:(NSNotification*)not
{
    NSLog(@"Item notification: %@", not.name);
}

...

- (void) observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context
{
    NSLog(@"Observe keyPath %@", keyPath);
}

我开始播放后把WiFi关掉,但是不幸的是没有收到'playbackBufferEmpty'或者'AVPlayerItemPlaybackStalledNotification'。只有在播放停止时,我才会收到一个AVPlayerItemTimeJumpedNotification通知,其他都没有了。 然而,至少有两次我收到了这些通知。但我不知道如何每次都在播放卡顿时获取它们。 我做错了什么吗?

2个回答

2

有两种情况会导致播放器无法进行:它无法启动或者缓存数据不足。我使用以下方法来处理这两种情况:

当您创建 AVPlayer 实例时:

[_player addObserver:self forKeyPath:@"rate" options:0 context:nil];
[_player.currentItem addObserver:self forKeyPath:@"status" options:0 context:nil];

这是处理程序:
-(void)observeValueForKeyPath:(NSString*)keyPath
                     ofObject:(id)object
                       change:(NSDictionary*)change
                      context:(void*)context {

    if ([keyPath isEqualToString:@"status"]) {
        if (_player.status == AVPlayerStatusFailed) {
            //Failed to start.
            //Description from the docs:
            //  Indicates that the player can no longer play AVPlayerItem instances because of an error. The error is described by
            //  the value of the player's error property.
        }
    } else if ([keyPath isEqualToString:@"rate"]) {
        if (_player.rate == 0 && //playback rate is 0
                CMTIME_COMPARE_INLINE(_player.currentItem.currentTime, >, kCMTimeZero) && //video has started
                CMTIME_COMPARE_INLINE(_player.currentItem.currentTime, <, _player.currentItem.duration) && //video hasn't reached the end
                _isPlaying) { //instance variable to track playback state
            //Video stalled. Possible connection loss or connection is too slow.
        }
    }
}

不要忘记在完成后删除观察者:
[_player.currentItem removeObserver:self forKeyPath:@"status"];
[_player removeObserver:self forKeyPath:@"rate"];

请查看我在这里的回答,了解我如何处理停滞的视频:AVPlayer stops playing and doesn't resume again


你怎么获取 '_isPlaying'? - Xiao Ming

2

首先尝试从您的路由器断开互联网连接,您将收到playbackBufferEmpty通知。为了处理网络切换,您需要实现Reachability


2
可达性和播放卡顿似乎是两回事。 - Xiao Ming

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