tags:

views:

406

answers:

3

I'm trying to play two videos using the MPMoviePlayerController class and allow the user to switch between the two videos by swiping their finger across the screen. Everything works great for the first movie. The overlay view correctly detects the swipe and starts the next movie playing.

Unfortunately things don't work so well with the second movie. I'm not sure what's happening, but the overlay view does not actually seem to be on top of the movie player and is certainly not responding to touch events. In fact, double tapping the screen while the second movie is playing zooms the movie in and out, so touches seem to be going to the MPMoviePlayerController.

I've tried a number of different approaches here, but none of them work. Here is the current version of the code:

- (void)allocateMoviePlayerForCurrentVideo
{
    // Create a movie player for the first video in the playlist
    NSURL *url = [videoURLs objectAtIndex:nowPlayingVideoIndex];
    moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:url];
    moviePlayer.scalingMode = MPMovieScalingModeAspectFill;
    moviePlayer.movieControlMode = MPMovieControlModeHidden;
    moviePlayer.backgroundColor = [UIColor blackColor];

    // Register for the movie preload complete notification
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(moviePreloadComplete:)
                                                 name:MPMoviePlayerContentPreloadDidFinishNotification
                                               object:nil];

    // Register for the playback did finish notification
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(movieDidFinishPlaying:)
                                             name:MPMoviePlayerPlaybackDidFinishNotification
                                             object:nil];
}

The code which handles the MPMoviePlayerContentPreloadDidFinishNotification starts the movie playing and adds the overlay view:

- (void)moviePreloadComplete:(NSNotification *)notification
{
    // Remove this object from observing the preload complete notification
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:MPMoviePlayerContentPreloadDidFinishNotification
                                                  object:nil];
    // Start playing the current movie
    [moviePlayer play];

    // Add the overlay view to the movie player
    UIWindow *moviePlayerWindow= [[[UIApplication sharedApplication] windows] objectAtIndex:1];
    overlayView = [[GGDMovieOverlayView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
    overlayView.backgroundColor = [UIColor clearColor];
    [moviePlayerWindow addSubview:overlayView];
    [moviePlayerWindow bringSubviewToFront:overlayView];

    // Register for swipe notifications from the overlay view
    [[NSNotificationCenter defaultCenter] addObserver:self
                                            selector:@selector(handleMoviePlayerSwipeNotification:)
                                                 name:GGDMoviePlayerSwipeNotification
                                               object:nil];
}

And finally, here's the routine which handles the swipe notification:

- (void)handleMoviePlayerSwipeNotification:(NSNotification *)notification
{
    // Stop the current movie player and release it
    [moviePlayer stop];
    [moviePlayer release];
    moviePlayer = nil;

    // Remove the overlay view from its superview
    [overlayView removeFromSuperview];

    // Advance to the next movie, treating the array of video URLs as a circular array
    if ( ++nowPlayingVideoIndex == [videoURLs count] ) {
        nowPlayingVideoIndex = 0;
    }
    [self allocateMoviePlayerForCurrentVideo];
}

I fear there's something obvious I'm missing, but this has been driving me crazy for a while now. I very much appreciate any help!

Thanks,
Adam

A: 

Fixed by using a NSTimer to add the overlay view after a delay to make sure the movie has started playing.

Thanks,
Adam

Adam Talcott
A: 

I just went through this myself and I can explain the issue and a slightly better workaround.

The problem with running the next movie in sequence is that the notification that you get when the movie has finished playing occurs before the current movie player window has been removed from the view. This is an issue because (as per the Apple example) the only way to get the movie player window is to grab the top window on the stack (or the key window). But if you try to use this technique immediately you'll get the old movie player window that is fading out, not the new one that is going to start. (As an aside - frankly, the Apple example is an illustration that there really isn't a proper way to get the movie window at all.. their example is terrible and is probably a race condition to begin with unless somehow the play method blocks until the window is actually on the stack).

Anyway, rather than an arbitrary delay, what I did is to tag the player window at the time that it is first created e.g.

UIWindow *moviePlayerWindow = [[UIApplication sharedApplication] keyWindow]; moviePlayerWindow.tag = MY_MOVIE_WINDOW_TAG; // this is just an int

and then in the moviePlaybackDidFinish method I call a waitForMovieWindowToExit method that looks for that tagged window. If it's still there then I use a timer to check again in 0.1 seconds. When it finally disappears I play the next sequence.

So, it's still a mess and still using a timer, but at least you are guaranteed to play the next movie within 0.1 second (or whatever) of the next possible time and it won't break if the system is a little slow, etc.

If anyone wants more code I can post it.

Pat Niemeyer
A: 

Can you please post the code I am also trying to do the same but i am not able to figure it out.

In advnce thank you very much.

Shiva.

shvia