5

Any idea why I can get my AVPlayerViewController class to playback content, but can't get it to display playback controls? The player loads content as expected, but that's it.

In my MediaPlayerViewController.m class, I have:

#pragma mark - Player
- (void)setupPlayer{

    // Sample URLs to use either a local file or streaming URL
    NSURL *url = [[NSBundle mainBundle] URLForResource:@"Besan" withExtension:@"mp4"];
    //url = [NSURL URLWithString:@"http://www.youtube.com/watch?v=qcI2_v7Vj2U"];

    // Create an instance of the AVPlayer object
    self.player = [AVPlayer playerWithURL:url];


    // Keep an eye on the status of our player
    [self.player addObserver:self forKeyPath:@"status" options:0 context:nil];
}

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

    if (object == self.player && [keyPath isEqualToString:@"status"]) {
        if (self.player.status == AVPlayerStatusFailed){
            NSLog(@"AVPlayer setup failed");
        } else if (self.player.status == AVPlayerStatusReadyToPlay) {
            NSLog(@"AVPlayer is ready to play");
            [self.player play];
        }
    }
}
R Brennan
  • 715
  • 1
  • 6
  • 13
  • I'm having this issue as well. Turns out when you remove the observeValueForKeyPath method, the controls appear. Looking for some kind of workaround now... – Aaron Vegh Dec 09 '14 at 17:56

3 Answers3

13

It's not a framework bug, but related to the way key-value observing works. By implementing

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

in your ViewController you are overriding the implementation of AVPlayerViewController. The solution is to add a context, when registering the observer:

static NSString* const AVPlayerStatusObservationContext = @"AVPlayerStatusObservationContext";

then register your observer like this

[self.player addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionPrior context:(__bridge void *)(AVPlayerStatusObservationContext)];

and do the following in observeValueForKeyPath

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

    if (context == (__bridge void *)(AVPlayerStatusObservationContext))
    {
        NSLog(@"Change Object %@, Value %@",object,change);
    } else {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}
holtmann
  • 6,043
  • 32
  • 44
  • The documentation states "Do not subclass AVPlayerViewController. Overriding this class’s methods is unsupported and results in undefined behavior.". I guess this issue is one reason they don't want us to do that :) – fluidsonic Dec 18 '15 at 00:13
4

As I pointed out in my comment to the question, the controls disappear when you implement - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context in the AVPlayerViewController. It can be an empty implementation; the player controls won't appear. This has to be a framework bug, and I'm shocked (shocked!) that Apple didn't catch this.

My solution is to implement the observer in a different class. I created a VideoObserver class inherited from NSObject, and set it up like so:

@implementation VideoObserver

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if ([keyPath isEqualToString:@"status"]) {
        NSLog(@"Change: %@", change);
    }
}
@end

In the AVPlayerViewController, I setup the observer as a property and then use it to start observing:

self.observer = [VideoObserver new];

NSURL * videoURL = [NSURL URLWithString:@"http://www.quirksmode.org/html5/videos/big_buck_bunny.mp4"];
self.videoPlayer = [AVPlayer playerWithURL:videoURL];

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

I've posted my demo project on Github.

Aaron Vegh
  • 5,217
  • 7
  • 48
  • 75
1

Perhaps funny, but make sure that the controls aren't actually hiding beneath a TabBar. Haven't found the solution to that yet, but that small thing has given me some grief and took a little time to realize--yet the controls were actually still there.

matthewsheets
  • 4,535
  • 2
  • 15
  • 11