如何判断 AVPlayerItem 是否正在播放。

4
我遇到了关于AVPlayerItemAVQueuePlayer的问题。目前我有很多1-2秒长的音乐文件,并使用队列播放器按顺序播放它们。
我想知道的是,当一个音乐文件刚开始播放时,而不是它播放结束时(通过AVPlayerItemDidPlayToEndTimeNotification),这是因为我想在加载和播放新文件时运行一个函数。
我的代码:
 for (NSUInteger i = 0; i < [matchedAddr count]; i++)
{
    NSString *firstVideoPath = [[NSBundle mainBundle] pathForResource:[matchedAddr objectAtIndex:i] ofType:@"wav"];
    //NSLog(@"file %@",firstVideoPath);
    avitem=[AVPlayerItem playerItemWithURL:[NSURL fileURLWithPath:firstVideoPath]];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(currentItemIs:)
                                                 name:AVPlayerItemDidPlayToEndTimeNotification
                                               object:avitem];

    [filelist addObject:avitem];
}
 player = [AVQueuePlayer queuePlayerWithItems:filelist];
[player play];


- (void)currentItemIs:(NSNotification *)notification
{
    NSString *asd=[seqArray objectAtIndex:currentColor];
    currentColor=currentColor+1;
    AVPlayerItem *p = [notification object];
    [p seekToTime:kCMTimeZero];

    if([asd isEqual:@"1"])
    {
        [UIView animateWithDuration:0.01 animations:^{
           one.alpha = 0;
        } completion:^(BOOL finished) {

            [UIView animateWithDuration:0.01 animations:^{
               one.alpha = 1;
            }];
        }];
    }
}

如您所见,currentItemIs 的 void 被调用,但它是在曲目播放完成后运行的。我希望它在曲目开始时被调用。

编辑: Winston 代码片段的更新版本:

NSString * const kStatusKey         = @"status";

        [avitem addObserver:self
                              forKeyPath:kStatusKey
                                 options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
                                 context:@"AVPlayerStatus"];
- (void)observeValueForKeyPath:(NSString *)path
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context {

    if (context == @"AVPlayerStatus") {

        AVPlayerStatus status = [[change objectForKey:NSKeyValueChangeNewKey] integerValue];
        switch (status) {
            case AVPlayerStatusUnknown: {

            }
                break;

            case AVPlayerStatusReadyToPlay: {
                // audio will begin to play now.
                NSLog(@"PLAU");
                [self playa];
            }
                break;
        }
    }
}
2个回答

5

首先,您需要将AVPlayerItem注册为一个观察器

[self.yourPlayerItem addObserver:self
                      forKeyPath:kStatus
                         options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
                         context:AVPlayerStatus];

然后在您的播放器键值观察者方法中,您需要检查AVPlayerStatusReadyToPlay状态,如下所示:

- (void)observeValueForKeyPath:(NSString *)path
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context {

     if (context == AVPlayerStatus) {

        AVPlayerStatus status = [[change objectForKey:NSKeyValueChangeNewKey] integerValue];
        switch (status) {
            case AVPlayerStatusUnknown: {

            }
            break;

            case AVPlayerStatusReadyToPlay: {
                // audio will begin to play now.
            }
            break;
   }
}

1
这很棒,除了远程文件之外,ReadyToPlay被触发和音频实际开始之间存在明显的间隔。 - Keab42
1
是的,我也注意到了。 - neowinston
这是否真的正确?readyToPlay 是否确实意味着 avplayeritem 正在 播放? - Jonny
是的,没错。当音频达到AVPlayerStatusReadyToPlay状态时,它将开始播放。 - neowinston
我认为有些地方需要更正,你将观察者添加到了 playerItem 上,并且将 AVPlayerStatus 定义为上下文并检查 AVPlayerStatus。而你应该检查 #keyPath(AVPlayer.currentItem.status)AVPlayerItem.Status 而不是 AVPlayerStatus,因为你的观察者是为项目而不是播放器添加的。 - Coder ACJHP
显示剩余4条评论

4

以下操作应该有效:

观察玩家的状态:

let playerItem: AVPlayerItem = AVPlayerItem(asset: videoPlusSubtitles, automaticallyLoadedAssetKeys: requiredAssetKeys)

playerItem.addObserver(self, forKeyPath: #keyPath(AVPlayerItem.status), options: [], context: nil)

player = AVPlayer(playerItem: playerItem)

响应状态变化:

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if keyPath == #keyPath(AVPlayerItem.status) {
        let status: AVPlayerItem.Status

        if let statusNumber = change?[.newKey] as? NSNumber {
            status = AVPlayerItem.Status(rawValue: statusNumber.intValue)!
        } else {
            status = .unknown
        }

        // Switch over status value
        switch status {
        case .readyToPlay:
            print("Player item is ready to play.")
            break
        case .failed:
            print("Player item failed. See error")
            break
        case .unknown:
            print("Player item is not yet ready")
            break
        @unknown default:
            fatalError()
        }
    }
}

只有一件事,在选项中:输入 [.new, .old] - miff

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