Tuesday, June 30, 2015

Playing video using MediaPlayer Framework (Part II)

Customizing the Movie Display Size

In my previous post, we have embedded movie player in our application which played the movie in fullscreen mode. However, the great part about the MPMoviePlayerController enhancements in iOS 4 is that you can now specify a custom display size for playback within your own view controllers. To take advantage of this, modify the playMovie: method as follows:


[moviePlayerController.view setFrame:CGRectMake(30, 100, 250, 170)];

[self.view addSubview:moviePlayerController.view];
//moviePlayerController.fullscreen = YES;

[moviePlayerController play];


On first line we create a custom frame size for the movie playback with the CGRectMake function. The values I have entered were taken from Interface Builder and match the origin, height, and width of the custom UIButton we use to play the movie. Note that I also commented out the fullscreen command.
If you build and go with your project code now, you should see that clicking the button will now play the video within our custom view controller, right on top of the UIButton. This works well enough, but what if you want to move the button around a bit to find the right look? It’s a bit cumbersome to constantly copy the literal CGRect values all the time. Update the playMovie method to do this dynamically:


-(IBAction)playMovie:(id)sender
{
UIButton *playButton = (UIButton *) sender;

NSString *filepath = [[NSBundle mainBundle] pathForResource:@"sample-movie-clip" ofType:@"m4v"];
NSURL *fileURL = [NSURL fileURLWithPath:filepath];
MPMoviePlayerController *moviePlayerController = [[MPMoviePlayerController alloc] initWithContentURL:fileURL];

[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(moviePlaybackComplete:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:moviePlayerController];

[moviePlayerController.view setFrame:CGRectMake(playButton.frame.origin.x,
playButton.frame.origin.y,
playButton.frame.size.width,
playButton.frame.size.height)];

[self.view addSubview:moviePlayerController.view];
//moviePlayerController.fullscreen = YES;

[moviePlayerController play];
}


On third line, we typecast the “sender” parameter to a UIButton object as we know that is the kind of object that will be sending this message to our view controller. We then access this object directly to get the X and Y origin of the button as well as the button width and height. With the code above implemented, we are free to move the UIButton anywhere on the canvas and not have to worry about constantly updating our CGRectMake function call.

Rotating our Video

Our video player should support both landscape as well as portrait orientation. For this purpose just add this code in the controller:

// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return YES;
}


A word on Scaling Mode

When displaying video in a custom rectangle, you will sometimes need to modify the scalingMode property of the MPMoviePlayerController object. Setting this property will determine how the movie image adapts to fill the playback size you have defined. The available scaling mode settings are as follows:


* MPMovieScalingModeNone
* MPMovieScalingModeAspectFit
* MPMovieScalingModeAspectFill
* MPMovieScalingModeFill


Each of the above options functions as you might expect, with MPMovieScalingModeAspectFill and MPMovieScalingModeFill likely being the two most commonly used modifications. The default scaling mode is MPMovieScalingModeAspectFit.

To experiment with this property in our code, insert the following line just before the [moviePlayerController play] statement:

moviePlayerController.scalingMode = MPMovieScalingModeFill;


You will see that our video now fills all available space in the playback rectangle.

This provides you a fundamental ntroduction to using the MPMoviePlayerController class with the MediaPlayer framework. The MPMoviePlayerController class has additional options that we haven’t covered here, but I’ll leave the exploration of those as an exercise for the reader. With the foundation from this tutorial in place, you should be able to begin experimenting on your own!
Happy Coding!

Sunday, May 24, 2015

Playing video using MediaPlayer Framework (Part I)

This is a step-by-step overview of how to integrate the MediaPlayer framework and work with the MPMoviePlayerController class in iOS4.

Step 1: Add the MediaPlayer Framework
CTRL + Click (or right click) on the “Frameworks” folder in the “Groups & Files” pane in Xcode. Select Add > Existing Frameworks from the drop-down menu.



Select “MediaPlayer.framework” from the list of options presented, and click “Add.”



Step 2: Import the MediaPlayer Framework and Declare the playMovie Method

After adding the MediaPlayer framework into your project, you need to import it into the view controller responsible for playing the movie. Insert the following line at the top of .h file of your controller


#import
#import


Now we will declare an instance method will will be called to trigger movie playback.
Just above the @end statement in the header file, add this line
-(IBAction)playMovie:(id)sender;


Step 3: Implementing the playMovie method

Open the .m file of your view controller and add the following implementation of playMovie: method which we have declared earlier in our header file


- (IBAction)playMovie:(id)sender
{
NSString *filepath = [[NSBundle mainBundle] pathForResource:@"sample-movie-clip" ofType:@"m4v"];
NSURL *fileURL = [NSURL fileURLWithPath:filepath];
MPMoviePlayerController *moviePlayerController = [[MPMoviePlayerController alloc] initWithContentURL:fileURL];
[self.view addSubview:moviePlayerController.view];
moviePlayerController.fullscreen = YES;
[moviePlayerController play];
}


In the first line we create a NSString containing the file path to our movie file. Next line uses that file path to create NSURL to our local movie. Then we initialize the MPMoviePlayer with that file URL and adds it over the current view controller's view.

Now, open up viewController.xib file in Interface Builder and add a "Play" button. Connect it with our playMovie: method.

Step 4: Memory Management
In our playMovie: method, we explicitly allocated memory for the moviePlayerController object which is never being released. We cannot release this object in the method we allocated it in because our movie will still be playing at the time this method completes execution. It also isn’t safe to autorelease the object because we don’t know if our movie will still be playing the next time the autorelease pool is drained. Fortunately, the MPMoviePlayerController object is prebuilt to handle this scenario, and will dispatch a notification called MPMoviePlayerPlaybackDidFinishNotification to the NSNotificationCenter when playback completes. In order to receive this notification, we must register an “observer” to respond to that specific notification. To do so, modify our playMovie: method as follows:


NSString *filepath = [[NSBundle mainBundle] pathForResource:@"sample-movie-clip" ofType:@"m4v"];
NSURL *fileURL = [NSURL fileURLWithPath:filepath];
MPMoviePlayerController *moviePlayerController = [[MPMoviePlayerController alloc] initWithContentURL:fileURL];

[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(moviePlaybackComplete:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:moviePlayerController];

[self.view addSubview:moviePlayerController.view];
moviePlayerController.fullscreen = YES;
[moviePlayerController play];


We now need to create moviePlaybackComplete:, the selector we just registered. Add the following underneath the playMovie: method:


- (void)moviePlaybackComplete:(NSNotification *)notification
{
MPMoviePlayerController *moviePlayerController = [notification object];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:moviePlayerController];

[moviePlayerController.view removeFromSuperview];
[moviePlayerController release];
}


The object we set for "object" parameter is sent along with the notification later. In this method, first we are retrieving that object with the [notification object] statement and referencing it with a new MPMoviePlayerController pointer. Next, we again send a message to the NSNotificationCenter, this time removing the observer we registered in playMovie. On nect line we cleanup our custom view controller by removing the moviePlayerController view from our display, and then we finish out by releasing the memory we originally allocated in the playMovie method.

Congratulations! We now have a working movie player in our application. My next post will be dedicated to customization of the player.