Using the Movie Player
The Media Player framework provides access to the built-in media playback capabilities of the iPhone. Everything you typically see when playing video or audio-the scrubber control, fast forward/rewind, play, pause-all of these features come "for free" within the classes provided by the Media Player.
In this exercise, we'll use the MPMoviePlayerController class. There are only three methods between us and movie-playback bliss:
- initWithContentURL: Provided with an NSURL object, this method initializes the movie player and prepares it for playback.
- play: Begins playing the selected movie file.
- setFullscreen:animated: Sets the movie playback to fullscreen.
Because the movie controller itself implements controls for controlling playback, we don't need to implement additional features ourselves. If we wanted to, however, there are many other methods, including stop, that we could call on to control playback.
These are only a few of the dozens of methods and properties available for the movie player. You can get pointers to additional resources in the "Further Exploration" section at the end of this article.
Adding the Media Player Framework
To use the MPMoviePlayerController class (and the MPMusicPlayerController we'll be implementing a bit later), we must first add the Media Player framework to the project. To do this, right-click the Frameworks folder icon in Xcode, and choose Add, Existing Frameworks. Select MediaPlayer.framework in the list that appears, and then click Add.
Typically, you also need to add a corresponding import line in your header file (#import <MediaPlayer/MediaPlayer.h>), but because we already added this during the application setup, you should be good to go!
Adding Media Files
As you might have noticed earlier when we listed the methods we would be using, initializing an instance of MPMoviePlayerController is performed by passing in an NSURL object. This means that if you pass in a URL for a media file hosted on a web server, as long as it is a supported format, it will work!
What Are the Supported Formats?
Officially, Apple supports the following codecs: H.264 Baseline Profile 3, MPEG-4 Part 2 video in .mov, .m4v, .mpv, or .mp4 containers. On the audio side, AAC-LC, and MP3 formats are supported.
This is the complete list of audio formats supported by the iPhone:
AAC (16 to 320Kbps) AIFF AAC Protected (MP4 from iTunes Store) MP3 (16 to 320Kbps) MP3 VBR Audible (formats 2-4) Apple Lossless WAV
For this example, however, we've chosen to include a local media file so that we can easily test the functionality. Locate the movie.m4v file included in the MediaPlayground project folder, and drag it into your Xcode resources group so that we can access it directly in the application. Be sure to choose to copy the file to the project, when prompted.
Implementing Movie Playback
For movie playback in the MediaPlayground application to work, we need to implement the playMedia: method. This is invoked by the Play Movie button we built in to the interface earlier. Let's add the method, and then walk through how it works. Add the code from Listing 18.2 to the MediaPlaygroundViewController.m file.
LISTING-2
1: -(IBAction)playMedia:(id)sender { 2: NSString *movieFile; 3: MPMoviePlayerController *moviePlayer; 4: 5: movieFile = [[NSBundle mainBundle] 6: pathForResource:@"movie" ofType:@"m4v"]; 7: moviePlayer = [[MPMoviePlayerController alloc] 8: initWithContentURL: [NSURL fileURLWithPath: movieFile]]; 9: 10: [moviePlayer.view setFrame:CGRectMake(145.0, 20.0, 155.0 , 100.0)]; 11: [self.view addSubview:moviePlayer.view ]; 12: 13: 14: [[NSNotificationCenter defaultCenter] addObserver:self 15: selector:@selector(playMediaFinished:) 16: name:MPMoviePlayerPlaybackDidFinishNotification 17: object:moviePlayer]; 18: 19: [moviePlayer play]; 20: 21: if ([toggleFullscreen isOn]) { 22: [moviePlayer setFullscreen:YES animated:YES]; 23: } 24: 25: }
Things start off simple enough. Line 2 declares a string movieFile that will hold the path to the movie file we added in the previous step. Next, in line 3, we declare the moviePlayer, a reference to an instance of MPMoviePlayerController. Next, lines 5-6 grab and store the path of the movie.m4v file in the movieFile variable.
Lines 7-8 allocate and initialize the moviePlayer itself using an NSURL instance that contains the path from movieFile. Believe it or not, this is most of the "heavy lifting" of the movie playback method! After we've completed this line, we could (if we wanted) immediately call the play method on the moviePlayer object and see the movie play! We've chosen to add an additional feature instead.
Lines 10-11 set the frame dimensions of the movie player that we want to embed in the view, and then adds the moviePlayer view to the main application view. If this seems familiar, it's because it's the same technique we used to add a field to an alert.
Playback is started using the play method in line 19.
Finally, lines 21-23 check to see whether the toggle switch (toggleFullscreen) is turned "on" using the UISwitch instance method isOn. If the switch is on, we use the method setFullscreen:animated to expand the movie to fill the iPhone's screen. If the switch is off, we do nothing, and the movie plays back within the confines of the frame we defined.
Notice anything missing? We've conveniently skipped over lines 14-17. These lines add a notification for the movie player that will help us identify when the movie has stopped playing. Because this is the first time you've worked with a notification, we'll address it separately.
Receiving a Notification
There is a teensy-weensy problem with implementing the MPMoviePlayerController as we've done here. If we attempt to release the movie player after the play line, the application will crash. If we attempt to autorelease the player, the same thing happens! So, how in the world can we get rid of the player?
The key is that we need to wait until the movie is no longer playing. To do that, we use the NSNotificationCenter class to register an "observer" that will watch for a specific notification message from the mediaPlayer object, and then call a method of our choosing when it receives the notification.
The MPMoviePlayerController sends the MPMoviePlayerPlaybackDidFinish Notification when it has finished playing a piece of media. In lines 16-19 we register that notification for our mediaPlayer object and ask the notification center to invoke the playMediaFinished: method when it receives the notification. Put simply, when the movie player is finished playing the movie (or the user stops playback), the playMediaFinished: method is called.
Implementing the playMediaFinished: method allows us to clean up when we're done with the movie player!
Handling Cleanup
To clean up after the movie playback has finished, we need to release the mediaPlayer object. Add the playMediaFinished: method to the MPMoviePlayerController.m file, as shown in Listing-3.
LISTING-3
1: -(void)playMediaFinished:(NSNotification*)theNotification 2: { 3: MPMoviePlayerController *moviePlayer=[theNotification object]; 4: 5: [[NSNotificationCenter defaultCenter] removeObserver:self 6: name:MPMoviePlayerPlaybackDidFinishNotification 7: object:moviePlayer]; 8: 9: [moviePlayer.view removeFromSuperview]; 10: [moviePlayer release]; 11: }
Three things need to happen in this method. First, in line 3, we assign the local moviePlayer variable to the object that is passed in from the notification. This is the same object that we were using when we initiated the play method in playMedia; it just arrived in this method by way of a notification, so we need to call the object method on the notification to access it again.
In lines 5-7, we tell the notification center that it can stop looking for the MPMoviePlayerPlaybackDidFinishNotification notification. Because we're going to be releasing the movie player object, there's no point in keeping it around. Line 9 removes the embedded movie player view from the main application view.
Finally, in line 9, we can release the movie player!
Movie playback is now available in the application. Choose Build and Run in Xcode, press the Play Movie button, and sit back and enjoy the show!