Properly displaying and dismissing fullscreen MPMoviePlayerController in iOS 3.2 (iPad)

jbrennan picture jbrennan · Jul 13, 2010 · Viewed 36.4k times · Source

I'm having lots of trouble displaying a fullscreen movie in my iPad app and then allowing the user to dismiss it with either the Done button or the "un-fullscreen" button on the player controls.

Initially I was using MPMoviePlayerViewController for the movie presentation, but I wasn't receiving the enter/exit fullscreen notifications from its MPMoviePlayerController object, so I switched to doing it myself.

I can make the movie appear fullscreen (although the transition is janky), but when either the "Done" or "un-fullscreen" buttons are pressed, no action is taken by the player. I've posted my code below:

- (void)startPlayingMovieWithURLString:(NSString *)movieURLString {
    // I get all of these callbacks **EXCEPT** the "willExitFullScreen:" callback.
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willEnterFullScreen:) name:MPMoviePlayerWillEnterFullscreenNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willExitFullScreen:) name:MPMoviePlayerWillExitFullscreenNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didFinishPlayback:) name:MPMoviePlayerPlaybackDidFinishNotification object:nil];

    [self.moviePlayerController setContentURL:someExistingURL];

        // "self" is a UIViewController subclass, and is presented as a "fullscreen" modal view controller from its parent
        // I'm setting the movie player's view's frame to take up the full rectangle of my view controller, but really I want the movie to be completely removed when the user presses "done" (that is, removed from the view hierarchy). Not sure when/where to do this.
    self.moviePlayerController.view.frame = self.view.frame;
    [self.view addSubview:self.moviePlayerController.view];
    [self.moviePlayerController setFullscreen:YES animated:YES];

}

And here is the code for my didFinish callback

- (void)didFinishPlayback:(NSNotification *)notification {
        // This ends up recursively telling the player that playback ended, thus calling this method, thus…well you get the picture.
        // What I'm trying to do here is just make the player go away and show my old UI again.
    [self.moviePlayerController setFullscreen:NO animated:YES];
}

So obviously I am doing something wrong but I've been up and down the documentation and I can't figure out how to make the movie just go away. I figured it would be more intuitive than this. What am I doing wrong?

Answer

Art Gillespie picture Art Gillespie · Jul 13, 2010

Here are how the events -> notifications work:

  • User presses 'Done' button

    • MPMoviePlayerWillExitFullscreenNotification
    • MPMoviePlayerDidExitFullscreenNotification
  • User presses 'Leave fullscreen' button on transport

    • MPMoviePlayerWillExitFullscreenNotification
    • MPMoviePlayerDidExitFullscreenNotification
    • Note that playback does not stop
  • Movie reaches end

    • MPMoviePlayerPlaybackDidFinishNotification with the MPMoviePlayerPlaybackDidFinishReasonUserInfoKey set to MPMovieFinishReasonPlaybackEnded
    • If you call setFullscreen:NO animated:YES on your MoviePlayerController instance from this notification, you'll then get the WillExit and DidExit notifications.
    • Note that you don't get the PlaybackDidFinish notification when the user presses the Done or Leave Fullscreen buttons.

So, typically, if you want to get rid of the MoviePlayer's view, you need to put [self.moviePlayerController.view removeFromSuperview] in the DidExitFullscreen notification handler. WillExitFullscreen is too soon.

Here's my code:

- (void)willEnterFullscreen:(NSNotification*)notification {
    NSLog(@"willEnterFullscreen");
}

- (void)enteredFullscreen:(NSNotification*)notification {
    NSLog(@"enteredFullscreen");
}

- (void)willExitFullscreen:(NSNotification*)notification {
    NSLog(@"willExitFullscreen");
}

- (void)exitedFullscreen:(NSNotification*)notification {
    NSLog(@"exitedFullscreen");
    [self.movieController.view removeFromSuperview];
    self.movieController = nil;
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void)playbackFinished:(NSNotification*)notification {
    NSNumber* reason = [[notification userInfo] objectForKey:MPMoviePlayerPlaybackDidFinishReasonUserInfoKey];
    switch ([reason intValue]) {
        case MPMovieFinishReasonPlaybackEnded:
            NSLog(@"playbackFinished. Reason: Playback Ended");         
                break;
        case MPMovieFinishReasonPlaybackError:
            NSLog(@"playbackFinished. Reason: Playback Error");
                break;
        case MPMovieFinishReasonUserExited:
            NSLog(@"playbackFinished. Reason: User Exited");
                break;
        default:
            break;
    }
    [self.movieController setFullscreen:NO animated:YES];
}

- (void)showMovie {
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willEnterFullscreen:) name:MPMoviePlayerWillEnterFullscreenNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willExitFullscreen:) name:MPMoviePlayerWillExitFullscreenNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(enteredFullscreen:) name:MPMoviePlayerDidEnterFullscreenNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(exitedFullscreen:) name:MPMoviePlayerDidExitFullscreenNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackFinished:) name:MPMoviePlayerPlaybackDidFinishNotification object:nil];

    NSURL* movieURL =  [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"tron" ofType:@"mov"]];
    self.movieController = [[MPMoviePlayerController alloc] initWithContentURL:movieURL];
    self.movieController.view.frame = self.view.frame;
    [self.view addSubview:movieController.view];
    [self.movieController setFullscreen:YES animated:YES];
    [self.movieController play];
}