MoviePlayer in iOS 4
June 24th, 2010 by Tommy Leung
In the quest to make Propaganda Lander run under iPhone SDK 4.0 and eventually utilize Game Center, I’ve run across some problems/solutions with multitasking. The most recent problem was with MPMoviePlayer. Propaganda Lander plays a movie on each planet plus a nice little video after you’ve beaten the game so movie playing had to work.
SDK 4.0 changes how the MPMoviePlayer works. I think it is now much better than it was before. You have more control over it. It will also, by default, mix with other audio as well. Right now, Propaganda Lander will kill your iPod if a movie plays. We didn’t particularly like that but, there was no choice in the matter. There is now! The iOS 4 version of Propaganda Lander will have this feature.
So, Apple has created an MPMoviePlayerViewController that you can use as a view to control the movie. MPMoviePlayerController still exists but is slightly different. In the past, creating an MPMoviePlayerController would just take over the device and play the movie. You now need to add your MPMoviePlayerController’s view to a UIView or UIWindow.
The MPMoviePlayerViewController will auto rotate if the device’s orientation changes. This was not ideal for Propaganda Lander as it only plays in one orientation: OrientationLandscapeRight. In order to get around that, we had to use the UIView from the MPMoviePlayerController and transform it accordingly.
Here is some code straight out of Propaganda Lander for movie player in iOS 4
You’ll need this for the degrees to radians conversion
#define degreesToRadian(x) (M_PI * (x) / 180.0)
This is the actual code:
MPMoviePlayerController * theMovie; theMovie = [[MPMoviePlayerController alloc] initWithContentURL: movieURL]; UIView * movieView = [theMovie view]; [movieView setFrame: CGRectMake(0, 0, 480, 320)]; CGAffineTransform landscapeTransform; landscapeTransform = CGAffineTransformMakeRotation(degreesToRadian(90)); landscapeTransform = CGAffineTransformTranslate(landscapeTransform, 80, 80); [movieView setTransform: landscapeTransform]; theMovie.scalingMode = MPMovieScalingModeAspectFit; theMovie.fullscreen = TRUE; theMovie.controlStyle = MPMovieControlStyleNone; theMovie.shouldAutoplay = TRUE; [[[UIApplication sharedApplication] keyWindow] addSubview: movieView];
If you would like to use the MPMoviePlayerViewController that has all the auto rotation features, it would look like this:
MPMoviePlayerViewController * movieView; movieView = [[MPMoviePlayerViewController alloc] initWithContentURL: movieURL]; MPMoviePlayerController * theMovie = [movieView moviePlayer]; theMovie.scalingMode = MPMovieScalingModeAspectFit; theMovie.fullscreen = TRUE; theMovie.controlStyle = MPMovieControlStyleNone; theMovie.shouldAutoplay = TRUE; [[[UIApplication sharedApplication] keyWindow] addSubview: movieView.view]
When you the movie is done playing, you will want to remove it. You can do so by using the NSNotificationCenter to get a callback when the movie is done.
[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(movieFinishedCallback:) name: MPMoviePlayerPlaybackDidFinishNotification object: theMovie];
When the movie is finished, it will call the movieFinishedCallback method which would look something like this:
- (void)movieFinishedCallback: (NSNotification*) notification;
{
[[NSNotificationCenter defaultCenter] removeObserver: self
name:MPMoviePlayerPlaybackDidFinishNotification
object: [notification object]];
MPMoviePlayerController * theMovie = [notification object];
[theMovie.view removeFromSuperview];
[theMovie release];
}
This ONLY works in iOS 4 devices. If you also need to target iPhone OS 3.0 or 2.0, you will need to check for the OS and then have the former MPMoviePlayer code as well. Since Propaganda Lander still targets iPhone OS 3.0, we made this function to check for the OS.
std::string getOS()
{
UIDevice * device = [UIDevice currentDevice];
NSString * os = [device systemVersion];
if([os isEqualToString:@"4.0"])
return "4.0";
if([os isEqualToString:@"3.0"])
return "3.0";
if([os isEqualToString:@"3.1"])
return "3.1";
if([os isEqualToString:@"3.2"])
return "3.2";
if([os isEqualToString:@"3.1.2"])
return "3.1.2";
if([os isEqualToString:@"3.1.3"])
return "3.1.3";
return "";
}
And for a much more robust way of determining iOS version that can be compared as numbers:
float getOSf()
{
UIDevice * device = [UIDevice currentDevice];
NSString * os = [device systemVersion];
float osAsFloat = [os floatValue];
return osAsFloat;
}
There’s some C++ and Objective-C in there as you can see. I actually wanted to return numbers but, strings will do for now. You can just as well return NSString’s exclusively if you’d like. As you can also see, we don’t care about OS’s below 3.0. OS 3.2 is the iPad OS and should have no effect for iPhone development but, I left it in there anyway. I believe 3.2 uses the same MPMoviePlayer code as iOS 4.0.
So if your movie player suddenly stops working in iOS 4.0, this is why and this is how to fix it.
| Tweet |
Tags: 4.0, code, ios, ios 4, iphone, mpmovieplayer, mpmovieplayercontroller, mpmovieplayerviewcontroller


June 27th, 2010 at 7:36 pm
Hi,
The code you mention “that has all the auto rotation” really doesn’t work for having it auto rotate to landscape.
Maybe I’m missing something?
June 27th, 2010 at 11:29 pm
hmmm, have you overrode shouldAutorotateToInterfaceOrientation in the UIView that you attached the MPMoviePlayerViewController to support other rotations?
according to the docs, MPMoviePlayerViewController will auto respond to Portrait, LandscapeLeft/Right by default.
Default UIView’s only support Portrait unless you specify otherwise by overriding shouldAutorotateToInterfaceOrientation
June 28th, 2010 at 12:05 pm
You Saved my day.
Thanks a lot
June 30th, 2010 at 1:49 pm
I am having trouble with the MPMoviePlayer notifications… i can’t seem to register for them and I can’t remove the movie once it’s subview has been added… do you know how to register for notifications other that the following?
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(logoFinishedPlaying:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:movieView];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(logoFinishedPlaying:) name:MPMoviePlayerDidExitFullscreenNotification
object:movieView];
June 30th, 2010 at 2:01 pm
that looks right to me altho, I tend to pass in the movie itself and not the view and I remove the view with:
[theMovie.view removeFromSuperview]
I’m using the same notification as you have there.
July 2nd, 2010 at 7:19 am
Cheers Tommy ..!!!
Great Post and Great Help.
Your code works nice. I have been through a lot of forums, but no one had such a code.
Keep up the Good Work.
July 6th, 2010 at 1:48 pm
[...] here’s the code. I’m going to give credit where credit is due. I took this from here, but I modified it very slightly to work nicely with Cocos2D. I’m going to add more to this [...]
July 20th, 2010 at 8:14 pm
Awesome post and I too am trying to get the [theMovie.view removeFromSuperview]; working when the movie stops. I can’t seem to get it to work correctly. Would you be so kind as to post an example? I have the code Rudy has posted, but I cannot seem to get the notification to trigger.
Again, thanks for all the help
July 21st, 2010 at 11:49 am
I put up the code that we use for detecting when the movie is finished playing. It’s in the original post under the previous MPMoviePlayer code. Hopefully that helps!
July 21st, 2010 at 11:55 am
I actually did a quick re-read of Rudy’s code and the issue is that movieView is being passed into the notification instead of the theMovie itself. I think, at least. That’s the difference between the two.
July 22nd, 2010 at 5:07 am
in order to check if your application is running on iOS4, you can also check that your component has capability to respond to an iOS4 method… For example:
if ([MPMoviePlayerController instancesRespondToSelector:@selector(view)]) {
…
}
August 5th, 2010 at 9:31 am
thanks
can you share with us the project & source code for the player?
August 6th, 2010 at 11:54 am
well, I can’t share the project and source code for Propaganda Lander and that’s where the movieplayer code resides. I did reuse this code again for the iPad and it worked great. Sometimes, it doesn’t like some versions of it’s supported formats.
this is the source code for the movieplayer and there’s nothing particularly special that you need in the project file other than the MediaPlayer framework.
August 30th, 2010 at 1:15 pm
Thanks for the code examples! I noticed a small issue when I tried the code that uses MPMoviePlayerViewController. (Your auto-rotate example.) When you addSubview on the last line, you should reference moveView.vew instead of just movieView. When I made this change, the compiler didn’t complain and everything worked.
August 30th, 2010 at 6:01 pm
haha, sorry, good catch. movieView was a ViewController and not a UIView in that example.
thanks!
September 21st, 2010 at 7:41 pm
You should use Default Apple constants to test the OS version. This will secure better compatibility with future iOSs. This is an example how to test on runtime by iOS 3.2 or later:
if ( kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iPhoneOS_3_2 ) {
// iOS 3.2 or later code here.
} else {
// older than iOS 3.2 here.
}
April 13th, 2011 at 12:54 pm
Tommy, U are awesome, have been struggling on this for a long time,,,, u are just awesome !!