Cbas Cbas - 5 months ago 189
iOS Question

AVPlayerItem never ready to play

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?

Answer

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".