11

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.

yury.ku
  • 1,188
  • 1
  • 10
  • 19

3 Answers3

17

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.

yury.ku
  • 1,188
  • 1
  • 10
  • 19
  • 4
    Hi yury.ku, We have a same issue what you have posted. We created a sample app to test this. We add new player item once it is loaded in the didEndPlay: notification API. But still we are facing some UI freeze issue. Can you please provide more info on how did you solve this problem? – Naveen Sep 11 '13 at 08:10
  • 4
    This solution doesnt work me as well, there is still a narrow gap between audiotracks – SpaceDust__ Apr 07 '15 at 21:36
  • 3
    As per [AVFoundation Programming Guide](https://developer.apple.com/library/ios/documentation/AudioVideo/Conceptual/AVFoundationPG/Articles/02_Playback.html#//apple_ref/doc/uid/TP40010188-CH3-SW3):`Try to initialize an AVURLAsset using the URL, then load its tracks key. If the tracks load successfully, then you create a player item for the asset. `. So, you should use `NSArray *keys = [NSArray arrayWithObject:@"tracks"];` instead. – Anton Chikin Oct 13 '15 at 21:09
  • 1
    I can't tell a difference when I remove `dispatch_async(dispatch_get_main_queue(), ^ { ... });`. Can someone tell me why? – Gadget Blaster Feb 06 '16 at 21:56
  • 3
    This "works" but doesn't take into account the possibility that some assets may load faster than others and thus the order in which they are inserted is not guaranteed. How to maintain playback order? – Hyder Jun 12 '16 at 11:23
2

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)
}
Tom Lobato
  • 136
  • 2
  • 4
  • 5
    This "works" but doesn't take into account the possibility that some assets may load faster than others and thus the order in which they are inserted is not guaranteed. If playback order is not a concern this works great! – TimD Feb 05 '16 at 21:23
  • @user1171911 I have run into same problem. Can u suggest a solution to maintain playback order? Thanks in advance. – Hyder Jun 12 '16 at 11:26
-1

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