yury.ku
yury.ku

Reputation: 1188

AVQueuePlayer playback without gap and freeze

I use AVQueuePlayer to play a sequence of movies which are loaded from URLs.
I tried to initialize player instance with array of all AVPlayerItems that I need to play.

player = [[AVQueuePlayer queuePlayerWithItems:playerItemsArray]

But in this case AVQueuePlayer loads some initial part of each AVPlayerItem before starting playback. It causes frustrating freeze and application doesn't respond for some seconds.

There is possibility to add only first AVPLayerItem to player's queue, observe its state and add second item in queue only when first will reach end, but in this case there will be a gap between playback of two items caused by initializing and buffering of second AVPlayerItem.

Is there any way to organize gapless playback of several videos without a freeze?
Should I use some other player for this purposes?

Thanks in advance.

Upvotes: 11

Views: 10881

Answers (3)

Tom Lobato
Tom Lobato

Reputation: 135

in Swift 2, working here:

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)
}

Upvotes: 2

Takahiro Ishihama
Takahiro Ishihama

Reputation: 49

Here is solution.

- (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;
}

Upvotes: -1

yury.ku
yury.ku

Reputation: 1188

The solution is found.

When adding new AVPlayerItem in queue of AVQueuePlayer player will synchronously wait till initial part of player item will be buffered.

So in this case player item should be buffered asynchronously and after that it can be added in the queue.
It can be done using [AVURLAsset loadValuesAsynchronouslyForKeys: completionHandler:]

For example:

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]; 
    });

}];

Using this solution queue of AVQueuePlayer can be populated with items without any gaps and freezes.

Upvotes: 17

Related Questions