0

I started a new project with a single view and added this code to the view controller:

- (void)viewDidLoad {
    [super viewDidLoad];

    NSURL *videoURL;
    videoURL = [NSURL URLWithString:@"https://s3.amazonaws.com/xxxxxx.mp4"];
    AVURLAsset *asset = [AVURLAsset URLAssetWithURL:videoURL options:nil];
    AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:asset];

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

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
                        change:(NSDictionary *)change context:(void *)context {

    if (context == @"AVPlayerStatus") {
        NSLog(@"AVPlayerStatus changed");

        if ([object isKindOfClass:[AVPlayerItem class]] && [keyPath isEqualToString:@"status"]) {
            NSLog(@"Ready to play");
        }
        else if (((AVPlayerItem *)object).status == AVPlayerStatusFailed) {
            NSLog(@"Failed to Ready");
        }
        else if (((AVPlayerItem *)object).status == AVPlayerStatusUnknown) {
            NSLog(@"Not known");
        }
    }
}

The output is:

2016-06-21 19:57:56.911 VideoTest[5740:1334235] AVPlayerStatus changed
2016-06-21 19:57:56.911 VideoTest[5740:1334235] Not known

Why doesn't the AVPlayerItem ever load? and how can I get it to load?

Cbas
  • 6,003
  • 11
  • 56
  • 87

1 Answers1

4

This is a remote asset (it's somewhere out there on the big wide Internet). It has no meaningful status until you try to play it; at that point, we begin loading the asset and exploring its nature. You have not tried to play it, so the status just sits there at Unknown.

Why doesn't the AVPlayerItem ever load? and how can I get it to load?

You can get the item to load by playing the asset.

Your code is flawed in three respects:

  • Your first condition never tests whether the status is ReadyToPlay;

  • You never try to play the asset.

  • You're using the context wrong.

I tested with your code, but edited like this, to fix all three of those things:

@interface ViewController ()
@property AVPlayer* player;
@end

@implementation ViewController

- (IBAction)doLoad:(id)sender {
    NSURL *videoURL;

    videoURL = [NSURL URLWithString:@"https://s3.amazonaws.com/lookvideos.mp4/t/05093dabec6c9448f7058a4a08f998155b03cc41.mp4"];
    AVURLAsset *asset = [AVURLAsset URLAssetWithURL:videoURL options:nil];
    AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:asset];

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


    self.player = [[AVPlayer alloc] initWithPlayerItem:playerItem];
    [self.player play];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
                        change:(NSDictionary *)change context:(void *)context {

    NSLog(@"AVPlayerStatus changed");

    if (((AVPlayerItem *)object).status == AVPlayerStatusReadyToPlay) {
        NSLog(@"Ready to play");
    }
    else if (((AVPlayerItem *)object).status == AVPlayerStatusFailed) {
        NSLog(@"Failed to Ready");
    }
    else if (((AVPlayerItem *)object).status == AVPlayerStatusUnknown) {
        NSLog(@"Not known");
    }
}

@end

At first I see "Not known" in the console, but as soon as I try to play the asset, it changes to "Ready to play".

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • ok but calling `[AVPlayer playerWithPlayerItem:playerItem]` blocks the main thread until the video starts playing. Is there any way to load the Item without trying to play it? – Cbas Jun 22 '16 at 03:45
  • "but calling [AVPlayer playerWithPlayerItem:playerItem] blocks the main thread until the video starts playing" That's just not true. I don't know what _you_ are doing — the code you showed makes no attempt to use an AVPlayer for anything — but the main thread absolutely does not block. Think about it. That would be against the entire nature of AV Foundation! The whole _point_ is that everything is asynchronous. – matt Jun 22 '16 at 04:00
  • take a glance at this: http://stackoverflow.com/questions/30363502/maintaining-good-scroll-performance-when-using-avplayer ... you may have never noticed, but if the video is in a scroll view its unacceptably laggy – Cbas Jun 22 '16 at 04:02
  • There is no scroll view in your question. I am not to blame if you don't ask the question properly. I answered the question you _did_ ask. To the extent that you divulged anything about your code, which was not very much, I answered. – matt Jun 22 '16 at 04:05
  • ok so you do have to start playing in order to load it.. thats disappointing, but helpful, thanks – Cbas Jun 22 '16 at 04:40
  • Follow [Apple's example](https://developer.apple.com/reference/avfoundation/avplayeritem?language=objc): you should handle the `change` dictionary instead of accessing directly the status of the player, otherwise by that time, the status could be something different than the one that actually triggered the observer. – Gobe Sep 15 '16 at 15:58