查找与AVPlayerItem相关联的AVPlayer。

16

一个AVPlayerItem只能分配给一个AVPlayer。一旦将AVPlayerItem添加到AVPlayer中,将来尝试将其添加到另一个AVPlayer将导致应用程序崩溃(SIGABRT)。

因此,给定AVPlayerItem,您如何确定:

  1. 它当前关联的AVPlayer是哪个?以及
  2. 在过去的任何时间点是否曾将其插入到AVPlayer中?

以下代码可靠地演示了该问题:

AVPlayerItem *item = [AVPlayerItem playerItemWithURL:[NSURL URLWithString:@"http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8"]];
AVPlayer *firstPlayer = [[AVPlayer alloc] init];
[firstPlayer replaceCurrentItemWithPlayerItem:item];
AVPlayer *secondPlayer = [[AVPlayer alloc] init];
[secondPlayer replaceCurrentItemWithPlayerItem:item];

以下是错误信息:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'An AVPlayerItem cannot be associated with more than one instance of AVPlayer'

你曾经找到这个问题的答案了吗? - kpozin
3
哈,不是的。我们采用了不同的方法。当我们要将一个来路可疑的AVPlayerItem分配给AVPlayer时,我们会克隆该项并广播一条消息,说明我们正在用新项替换旧项。我们还使用关联对象将旧项指向新项。因此,如果我们获取到一个已经进行了此过程的旧AVPlayerItem,则可以沿着前向关联对象指针的链接列表找到最终的“真实”项。感谢苹果公司。 - jimbo
5个回答

8

有一种半合法的方法,可能在未来被破解。播放器项具有一个名为_player的私有方法(以及变量)。您可以像这样查询它(从技术上讲,不使用私有API,因此我认为它应该是AppStore安全的):

id player = [item valueForKey:@"_player"];

如何获取当前正在播放的 Webkit 声音的播放器?你可以发送私有 API 的 Git 链接吗? - Mickael Belhassen
@MickaelBelhassen:那是一个无关的问题。请在SO上提出一个新问题。 - DarkDust
如果您有任何想法,请访问以下链接:https://stackoverflow.com/questions/71912499/swift-getting-avplayer-from-webview - Mickael Belhassen
@DarkDust,我在编辑您的答案时加入下划线作为键名是否正确?我刚刚测试了一下,似乎只有在我的端口上使用下划线才有效。但我想再次确认一下。 - Albert Renshaw
1
@AlbertRenshaw:valueForKey:会查找带有下划线的实例变量,因此不需要添加前缀。但是添加前缀也不会有什么影响,我怀疑苹果的符号扫描在 _player 上不会触发应用商店提交,所以没问题。 - DarkDust

3

这里有一种优雅的解决方案,无需私钥和相关对象。创建一个自定义的播放器项:

class PlayerAwareItem {
    weak var player: AVPlayer?
}

设置一个播放器:

let item = PlayerAwareItem(asset: asset)
let player = AVPlayer(playerItem: item)
item.player = player

以后只要拥有该项目,就可以随时访问播放器(在本例中,我们希望在停顿后重新启动播放器):

@objc func handlePlayerItemDidStall(_ notification: Notification) {
    guard let playerItem = notification.object as? PlayerAwareItem,
        let player = playerItem.player else { return }
    player.play()
}

3

你尝试过另一种方式吗?试着访问由AVPlayer播放的项目内部的细节。

AVPlayer *firstPlayer = [[AVPlayer alloc]init];

在此之后,您可以访问firstPlayer.currentItem。这将使您可以访问firstPlayerAVPlayerItem

例如:

firstPlayer.currentItem.duration

这将为您提供该音轨的持续时间。


在我的情况下,我得到的是一个AVPlayerItem。这个项目可能已经与AVPlayer关联过了。我的目标是确定是否是这种情况。 - jimbo

0

根据Anil的回答,对于多个视频的循环播放:

for (NSObject * obj in cachedVideos){
    if ([obj isKindOfClass:[AVPlayerLayer class]]){
        AVPlayerLayer * layer = (AVPlayerLayer *)obj;
        if ([layer.player.currentItem isEqual:n.object]){
            [layer.player seekToTime:kCMTimeZero];
            [layer.player play];
            break;
        }
    }
}

0

您可以使用以下方式将 AVPlayerItemAVPlayer 关联:

static char playerKey;

objc_setAssociatedObject(item, &playerKey, player, OBJC_ASSOCIATION_RETAIN);

并使用以下代码获取它:

objc_getAssociatedObject(item, &playerKey);

刚看到你的评论@jimbojw。我也遇到了同样的错误,使用一个简单的关联对象并不能解决它。我会尝试广播通知的方法。 - vaughan
#import <objc/runtime.h> - Jonny

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