avplayeritem 总是处于未知状态

Posted

技术标签:

【中文标题】avplayeritem 总是处于未知状态【英文标题】:avplayeritem always at unknown status 【发布时间】:2015-03-18 16:54:07 【问题描述】:

刚刚发现一个很奇怪的问题,

从本地存储加载 mp3 文件时,

avplayitem 一直处于未知状态,如果文件放在文件夹中,则无法播放。

方式一:

//AVAsset *asset = [[AVURLAsset alloc] initWithURL:_URL options:nil];
//AVPlayerItem *playerItem = [[AVPlayerItem alloc] initWithAsset:asset];

AVPlayerItem *playerItem = [[AVPlayerItem alloc] initWithURL:_URL];
//line 1
while (playerItem.status!=AVPlayerItemStatusReadyToPlay
       && playerItem.status!=AVPlayerItemStatusFailed) 
    NSLog(@"avplayer: %@ status: %d", playerItem, playerItem.status);
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
 
//line 2

NSLog(@"avplayer status: %d item: %@", playerItem.status, _URL);
NSArray *metadata = [playerItem.asset commonMetadata];

方式2:

AVAsset *asset = [[AVURLAsset alloc] initWithURL:_URL options:nil];
AVPlayerItem *playerItem = [[AVPlayerItem alloc] initWithAsset:asset];
/*
AVPlayerItem *playerItem = [[AVPlayerItem alloc] initWithURL:_URL];
//line 1
while (playerItem.status!=AVPlayerItemStatusReadyToPlay
       && playerItem.status!=AVPlayerItemStatusFailed) 
    NSLog(@"avplayer: %@ status: %d", playerItem, playerItem.status);
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
 
//line 2
 */
NSLog(@"avplayer status: %d item: %@", playerItem.status, _URL);
NSArray *metadata = [playerItem.asset commonMetadata];

输出:

2015-03-19 00:42:49.243 goodnightfm[6737:353911] avplayer: <AVPlayerItem: 0x7fdc3bbd5c00, asset = <AVURLAsset: 0x7fdc3bbd8a50, URL = file:///Users/galenzhao/Library/Developer/CoreSimulator/Devices/123A77A7-DC61-4795-8D9A-E71002E261DA/data/Containers/Data/Application/4CCEED79-1D5A-4D00-BC5E-FC52BD5393F9/Documents/CMStorage/70efdf2ec9b086079795c442636b55fb>> status: 0

但是如果 mp3 文件在 app bundle 中,即使状态仍然是未知的,way2 代码也能正常工作,

2015-03-19 00:45:35.977 goodnightfm[6783:355678] avplayer status: 0 item: file:///Users/galenzhao/Library/Developer/CoreSimulator/Devices/123A77A7-DC61-4795-8D9A-E71002E261DA/data/Containers/Bundle/Application/F2446C29-49F3-4B92-A7B0-7EFCC1A19274/goodnightfm.app/demo5.mp3

我确定app bundle&document中的文件是同一个,可以在任何其他软件中播放,

通过使用方式2,bundle文件和文档文件之间的唯一区别是,

如果mp3文件放在bundle中,这个函数可以返回元数据

NSArray *metadata = [playerItem.asset commonMetadata];

但使用文档 url 返回 nil

【问题讨论】:

您应该通过使用 KVO 观察 status 键路径来等待状态更改。 【参考方案1】:

首先,您需要向播放器项目添加观察者以适当地检查其状态:

[playerItem addObserver:self 
             forKeyPath:@"status"
                options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
                context:nil];

或者向 AVPlayer 对象添加观察者:

[player addObserver:self 
         forKeyPath:@"currentItem.status"
            options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
            context:nil];

然后像这样添加一个观察者方法:

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context 
    if ([object isKindOfClass:[AVPlayerItem class]] && [keyPath isEqualToString:@"status"]) 
        AVPlayerItem *playerItem = (AVPlayerItem *)object;
        NSLog(@"avplayer: %@ status: %d", playerItem, playerItem.status);
    
    else if ([object isKindOfClass:[AVPlayer class]] && [keyPath isEqualToString:@"currentItem.status"]) 
        AVPlayer *player = (AVPlayer *)object;
        NSLog(@"avplayer: %@ status: %d", player.currentItem, player.currentItem.status);
    

如果您仍然没有准备好播放器项目,请确保音频文件确实存在于 URL 指定的文档目录路径中。

【讨论】:

同时添加 player 和 playerItem 作为观察者有什么意义? playerItem 不应该足够吗? 无需注册观察者即可获得readyToPlay。没有投反对票,因为最后一句话实际上解决了我项目中的这个问题:它是一个录音机应用程序,在我使用它的url 属性之前我没有停止AVAudioRecorder @toraritte 你是对的,你在 iPad 上解决了我的问题。

以上是关于avplayeritem 总是处于未知状态的主要内容,如果未能解决你的问题,请参考以下文章

AVPlayerItem 不播放视频,即使其状态为 `readyToPlay` 并且 `isPlaybackLikelyToKeepUp` 为 true

生成者消费者模式,如何避免消费者一直处于饥饿状态

设置 AVPlayer AVPlayerItem 缓冲区大小?

打印机总是出现发生未知错误

AVQueuePlayer - 在缓存项目时保持活动状态

交换机光口总是DOWN状态