Video On The iPhone Tutorial Part 2

Part 2
This tutorial continues on from the Video On The iPhone Tutorial Part 1, so we’ll just be adding code to that project, I suggest you do that tut first or just download the finished project files and continue on.

Alright so let’s add a spinning preloader that gives the user some feedback that the video is buffering. To do this we’re going to use a UIActivityIndicatorView, and set up a Notification to listen out for changes in the MPMovieLoadState, in particular the MPMovieLoadStatePlaythroughOK which, according to Apple’s docs, is TRUE when “Enough data has been buffered for playback to continue uninterrupted”. At this point we’re going to hide the UIActivityIndictorView, but not get rid of it as we may want to use it again later.

So here’s the iPhoneVideoTutViewController.h file:

#import <UIKit/UIKit.h>
#import <MediaPlayer/MediaPlayer.h>

@interface iPhoneVideoTutViewController : UIViewController {
   
    IBOutlet UIButton *playVideoButton;
    MPMoviePlayerController *moviePlayer;
    UIActivityIndicatorView *aiv;
}

@property (readwrite, retain) MPMoviePlayerController *moviePlayer;
@property (nonatomic, retain) IBOutlet UIButton *playVideoButton;

-(IBAction)playMovieButtonPressed:(id)sender;

@end

The only change here is the declaration of the UIActivityIndicatorView, we’re going to add this programmatically, as I find it easier to just place it on top of the video player this way.

Here’s the iPhoneVideoTutViewController.m file:

#import "iPhoneVideoTutViewController.h"

@implementation iPhoneVideoTutViewController

@synthesize moviePlayer, playVideoButton;

- (void)viewDidAppear:(BOOL)animated {
    NSLog(@"VIEW DID LOAD");
    // Register to receive a notification that the movie is now in memory and ready to play
	[[NSNotificationCenter defaultCenter] addObserver:self 
                                             selector:@selector(movieLoadStateDidChange:) 
                                                 name:MPMoviePlayerLoadStateDidChangeNotification 
                                               object:nil];

}

-(void)movieLoadStateDidChange:(id)sender{
    NSLog(@"STATE CHANGED");
    if(MPMovieLoadStatePlaythroughOK ) {
        NSLog(@"State is Playable OK");
        NSLog(@"Enough data has been buffered for playback to continue uninterrupted..");
        aiv.hidden = YES;
        [aiv stopAnimating];
    }
    
}


-(IBAction)playMovieButtonPressed:(id)sender{
    
    aiv = [[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]autorelease];
    aiv.frame = CGRectMake(0.0, 0.0, 40.0, 40.0);
    aiv.center = self.view.center;
    [self.view addSubview:aiv];
    [aiv startAnimating];
     
    NSURL *movieURL = [NSURL URLWithString:@"http://www.samkeeneinteractivedesign.com/videos/littleVid3.mp4"];
	self.moviePlayer = [[[MPMoviePlayerController alloc] initWithContentURL:movieURL]autorelease];
    self.moviePlayer.controlStyle = MPMovieControlStyleFullscreen;
    [self.moviePlayer.view setFrame:self.view.bounds];
    [self.view addSubview:self.moviePlayer.view];
    //insert the video player below the aiv
    [self.view insertSubview:self.moviePlayer.view belowSubview:aiv];
    [self.moviePlayer play];
}

- (void)dealloc
{
    [playVideoButton release];
    [moviePlayer release];
    [super dealloc];
}

@end

You’ll notice I’ve overwritten the UIViewController’s viewDidAppear method and added an NSNotification that will trigger the selector (method) movieLoadStateDidChange on any change received from the MPMoviePlayerLoadStateDidChangeNotification.
I’ve then set up that selector movieLoadStateDidChange, however we’re not looking for just any change, we’re specifically listening for MPMovieLoadStatePlaythroughOK == TRUE. This tells us enough video has buffered for the player to start playing without interuption
Inside the conditional operator, we hide the UIActivityIndicatorView and stop it from animating.
I’ve updated the playMovieButtonPressed method to instantiate the aiv, autorelease it, set it’s frame, center it add it to the view and start animating.
You’ll notice the only change I’ve made to the rest of the code in the playMovieButtonPressed method is to insert the moviePlayer view below the aiv, so the spinner isn’t obscured.
There are a lot of other changes in the video stream you can be notified of, I suggest you check out the Apple docs to see them all and download the project files here.

5 comments

  1. […] I come from a Flash background and something I’m use to doing a lot of in Flash is creating video walls (playing several videos at the same time). There are a lot of situations where you might want to do this, say having multiple video thumbnails playing, or a main video with another “talking head” video composited over the top, a video wall, and for all kinds of creative, arty and special effects. For a recent client project I had to do exactly this. Initially I thought this was going to be an easy job, just smash out a few MPMoviePlayers, feed them some video and job done. But it wasn’t to be that easy, there is no way of playing multiple videos at the same time using MPMediaFramework, I really wish there was, but there’s not. So to solve this problem we have to dig a bit deeper and use the AVFoundation Framework. It’s a lower level framework that’s used to develop Final Cut Pro and iMovie, but don’t let that scare you. In this tutorial I’m going to show you a quick and dirty way of getting multiple videos playing with the least amount of effort. I’ve included the working files at the end. This tut follows on from part 2 that can be found here […]

    Reply

  2. Greetings,
    I simply respect your thoughts and will tell my friends about it. It’s so good to find answers from such a nice website.
    Thanks.

    Reply

  3. Hello,
    Thank you very much for the great tutorial…I actually put the code for the UIActivityIndicator after adding the player to the view, and it worked perfectly. Your code actually adds it before adding the movie window, so it was getting obscured by the movie player.

    Reply

  4. Thank you i appreciate this example. I also have a question.
    I m trying to make a video loop and have some audio lag when it restart.

    self.mpc.repeatMode = MPMovieRepeatModeOne; // loop de video.

    Have some idea to correct this problem. Thx

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *