AVQueuePlayer无间隔和冻结播放

11

我使用 AVQueuePlayer 来播放从 URL 加载的电影序列。
我尝试通过数组初始化播放器实例,其中包含我需要播放的所有 AVPlayerItems

player = [[AVQueuePlayer queuePlayerWithItems:playerItemsArray]

但在这种情况下,AVQueuePlayer 在开始播放之前会加载每个AVPlayerItem的一部分。 这会导致令人沮丧的冻结,应用程序在几秒钟内无响应。

有可能只将第一个AVPLayerItem添加到播放器的队列中,观察其状态,并在第一个项目到达末尾后仅将第二个项目添加到队列中,但在这种情况下,在初始化和缓冲第二个AVPlayerItem时会产生两个项目之间的间隙。

是否有任何方法可以组织多个视频的无间隙播放而不会冻结?
我应该为此目的使用其他播放器吗?

预先感谢。

3个回答

17
解决方案已找到。
当在AVQueuePlayer队列中添加新的AVPlayerItem时,播放器会同步等待直到播放项的初始部分被缓冲。
因此,在这种情况下,播放项应该是异步缓冲的,然后才能添加到队列中。
可以使用[AVURLAsset loadValuesAsynchronouslyForKeys: completionHandler:]来完成。
例如:
AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:url options:nil];
NSArray *keys = [NSArray arrayWithObject:@"playable"];

[asset loadValuesAsynchronouslyForKeys:keys completionHandler:^()
{
    dispatch_async(dispatch_get_main_queue(), ^
    {
        AVPlayerItem *playerItem = [[[AVPlayerItem alloc] initWithAsset:asset] autorelease];         
        [player insertItem:playerItem afterItem:nil]; 
    });

}];

使用这个解决方案,AVQueuePlayer的队列可以填充项目,而不会出现任何间隙和冻结。

4
你好 yury.ku,我们遇到了你发布的相同问题。我们创建了一个示例应用程序来测试这个问题。我们在 didEndPlay: 通知 API 中添加新的播放器项目,但仍然遇到一些 UI 冻结的问题。请问您能否提供更多关于你是如何解决这个问题的信息? - Naveen
4
这个解决方案对我也不起作用,音轨之间仍然存在一个窄缝。 - SpaceDust__
3
根据AVFoundation编程指南:尝试使用URL初始化AVURLAsset,然后加载其track关键字。如果tracks成功加载,则为该资源创建一个player item。因此,您应该使用NSArray *keys = [NSArray arrayWithObject:@"tracks"]; - Anton Chikin
1
当我删除 dispatch_async(dispatch_get_main_queue(), ^ { ... }); 时,我感觉没有任何区别。有人能告诉我为什么吗? - Gadget Blaster
3
这种方法“可行”,但没有考虑到某些资源可能加载更快,因此插入的顺序不能保证。如何保持播放顺序? - Hyder

2

在Swift 2中,这里是工作的地方:

func load() {
     let player = AVQueuePlayer()
     for url in urls {
        makeItem(url)
    }
}

func makeItem(url: String) {
    let avAsset = AVURLAsset(URL: NSURL(string: url)!)

    avAsset.loadValuesAsynchronouslyForKeys(["playable", "tracks", "duration"], completionHandler: {
        dispatch_async(dispatch_get_main_queue(), {
            self.enqueue(avAsset: avAsset)
        })
    })
}

func enqueue(avAsset: AVURLAsset) {
    let item = AVPlayerItem(asset: avAsset)
    self.player.insertItem(item, afterItem: nil)
}

5
这个方法“能用”,但它没有考虑到某些资源可能加载得比其他资源快,因此插入的顺序并不能保证。如果播放顺序不是问题,则这种方法非常好用! - TimD
@user1171911 我也遇到了同样的问题。你能提供一个保持播放顺序的解决方案吗?先谢谢了。 - Hyder

-1

这是解决方案。

- (void)_makePlayer{
     _player = [[AVQueuePlayer alloc] initWithPlayerItem:[AVPlayerItem playerItemWithAsset:[SSMoviePreviewItemMaker generateAVMovieItem]]];
}

+ (AVAsset *)generateAVMovieItem{
    NSArray * array = [SSMovieFileManager getAllMovieResourceURL];
    AVMutableComposition *composition = [[AVMutableComposition alloc] init];
    for (int i = 0; i < array.count; i++) {
        AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:array[i] options:nil];
        [composition insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration)
                             ofAsset:asset
                              atTime:composition.duration error:nil];

    }
   return composition;
}

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