AVQueuePlayer失败(缓冲区欠载处理) [英] AVQueuePlayer frustrations (buffer underrun handling)

查看:213
本文介绍了AVQueuePlayer失败(缓冲区欠载处理)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在使用AVQueuePlayer时遇到了麻烦.很简单,我在使用playerItemWithURL:构建的AVPlayerItems数组上进行创建,并指向网络上服务器上的视频资产.

I am having a hell of a time with AVQueuePlayer. Very simply, I am making it on an array of AVPlayerItems built with playerItemWithURL: and pointing to video assets on a server out on the Net.

如果我尝试在刺激器中运行此东西,则它会播放第一个资产,然后开始播放第二个资产,然后死亡.有时它甚至无法通过第一笔资产.

If I try to run this thing in the stimulator (sic) it plays through the first asset, begins playing the second and just dies. Sometimes it doesn't even get through the first asset.

现在,我知道sim卡的行为与设备不同,因此我也在设备上尝试了同样的问题.

Now, I understand that the sim behaves differently than the device, so I tried it on the device as well, with the same problem.

当我在物品上记录各种状态变化时,我看到缓冲区用完了,而播放器死了.对于正在播放项目队列的结构,这对我来说似乎有点愚蠢……当然缓冲区可能不足,但是为什么它会死掉?

When I log the various status changes on the item, I see that the buffer runs out, and the player just dies. This seems a bit silly to me for a construct that is playing a queue of items... of course the buffer may underrun, but why would it just die?

我做错什么了吗?或者这是应该怎么做的?

Am I doing something wrong, or is this how it is supposed to behave?

通过观察loadedTimeRanges属性以及当它发生变化将PLAY发送给播放器时,我已经解决了这个问题.但这会导致停顿的播放,也很糟糕.

I have gotten around this problem by observing the loadedTimeRanges property and when it changes sending PLAY to the player. But this results in stuttering playback, which sucks too.

这是我的代码.有人可以告诉我如何在不完全播放的情况下执行此操作吗?

Here is my code. Can someone please tell me how to do this without the playback being complete crap?

- (void)viewDidLoad {
    [super viewDidLoad];

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handlePlayerItemReachedEnd:) name:AVPlayerItemDidPlayToEndTimeNotification object:self.queuePlayer];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handlePlayerStalled:) name:AVPlayerItemPlaybackStalledNotification object:self.queuePlayer];

    NSString *baseURL = @"http://www.aDomain.com/assets/";
    NSMutableArray *vidItemArray = [[NSMutableArray alloc] initWithCapacity:5];

    for (int i = 1; i <= 5; i++) {
        AVPlayerItem *vid = [AVPlayerItem playerItemWithURL:[NSURL URLWithString:[baseURL stringByAppendingFormat:@"%d.mov", i]]];
        [vid addObserver:self forKeyPath:@"status" options:0 context:nil];
        [vid addObserver:self forKeyPath:@"playbackBufferEmpty" options:0 context:nil];
        [vid addObserver:self forKeyPath:@"loadedTimeRanges" options:0 context:nil];
        [vidItemArray addObject:vid];
    }

    self.queuePlayer = [AVQueuePlayer queuePlayerWithItems:vidItemArray];
    [self.mPlaybackView setPlayer:self.queuePlayer];
}

- (void)handlePlayerItemReachedEnd:(NSNotification *)notification {
    NSLog(@"Clip #%d finished playing", [self.queuePlayer.items indexOfObject:self.queuePlayer.currentItem]);
}

- (void)handlePlayerStalled:(NSNotification *)notification {
    NSLog(@"CLIP STALLED...");
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if ([object isKindOfClass:[AVPlayerItem class]]) {
        AVPlayerItem *item = (AVPlayerItem *)object;

        if ([keyPath isEqualToString:@"status"]) {
            switch (item.status) {
                case AVPlayerItemStatusFailed:
                    NSLog(@"player item status failed");
                break;
                case AVPlayerItemStatusReadyToPlay:
                    NSLog(@"player item status is ready to play");
                [self.queuePlayer play];
                break;
                case AVPlayerItemStatusUnknown:
                    NSLog(@"player item status is unknown");
                break;
            }
        }
        else if ([keyPath isEqualToString:@"playbackBufferEmpty"]) {
            if (item.playbackBufferEmpty) {
                NSLog(@"player item playback buffer is empty");
            }
        }
        else if ([keyPath isEqualToString:@"loadedTimeRanges"]) {
            NSLog(@"Loaded time range = %@", item.loadedTimeRanges);
            self.queuePlayer play];
        }
    }
}

推荐答案

最初不应在AVQueuePlayer中添加许多AVPlayerItem,因为它们将根据框架的决定同时开始缓冲.

You should not add many AVPlayerItem to AVQueuePlayer initially because they will begin buffering at the same time, at discretion of the framework.

尝试加载一个文件,然后在KVO currentItem上更改下一个文件的队列,这可能会解决您的问题.我正在使用它来实现无缝播放.

Attempt to load one file and then on KVO currentItem changed queue the next one, it might solve your problem. I'm using this to achieve gapless playback.

这篇关于AVQueuePlayer失败(缓冲区欠载处理)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆