Playing video in iOS

This week I had the interesting challenge of having to play a video in an iPad app. I basically needed to explore having a full-screen video play in the background while still allowing the user to interact with other controls rendered on top of the video.

You have 2 options for playing video in iOS – MPMoviePlayerController and AVPlayer. MPMoviePlayerController uses the AVPlayer behind the scenes so it’s an easier way of showing a video to the user and letting them interact with it while with AVPlayer you get more custom control.

Playing video with MPMoviePlayerController

For testing the MPMoviePlayerController I simply added a video file to my XCode project, just as you would do with a regular image file. According to the documentation the supported video formats are .mov, .mp4, .mpv, and .3gp – I used an .mp4 file.

To get started, I created the player inside my viewDidAppear and point it to my video file. (As far as I can tell it doesn’t always work if you set the frame inside your viewDidLoad method – I’m guessing it’s because the frame isn’t properly loaded) Make sure you set the player as a property inside your implementation.

NSString *filepath = [[NSBundle mainBundle] pathForResource:@"vid" ofType:@"mp4"];
NSURL *fileURL = [NSURL fileURLWithPath:filepath];
self.moviePlayerController = [[MPMoviePlayerController alloc] initWithContentURL:fileURL];

Now we need to give the player a frame and add it as a subview.

[self.moviePlayerController.view setFrame: CGRectMake(0, 0, 1024, 768)];
[self.view addSubview:self.moviePlayerController.view];

And now you simply play the video.

[self.moviePlayerController play];

To minimize playback delay, you can call the prepareToPlay method which will tell the player to start loading the file from disk.

I also needed to know when the video was finished. The MPMoviePlayerController uses the NSNotificationCenter to send notifications about events such as the video being ready to play or the video ending.

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

Here is the full code example:

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    NSString *filepath = [[NSBundle mainBundle] pathForResource:@"vid" ofType:@"mp4"];
    NSURL *fileURL = [NSURL fileURLWithPath:filepath];
    self.moviePlayerController = [[MPMoviePlayerController alloc] initWithContentURL:fileURL];
    [[NSNotificationCenter defaultCenter] addObserver:self 
                                             selector:@selector(introMovieFinished:)
                                                 name:MPMoviePlayerPlaybackDidFinishNotification
                                               object:self.moviePlayerController];
    
    // Hide the video controls from the user
    [self.moviePlayerController setControlStyle:MPMovieControlStyleNone];
    
    [self.moviePlayerController prepareToPlay];
    [self.moviePlayerController.view setFrame: CGRectMake(0, 0, 1024, 768)];
    [self.view addSubview:self.moviePlayerController.view];
    
    [self.moviePlayerController play];
}

- (void)introMovieFinished:(NSNotification *)notification
{
    NSLog(@"Video ended!");
}

Playing video with AVPlayer

If you need more fine-grained control over your video or you need to play multiple videos at once, you can use the AVPlayer.

Once again, I create the player inside my viewDidLoad and point it to my video file. Again, make sure you set the AVPlayer as a property.

NSString *filepath = [[NSBundle mainBundle] pathForResource:@"vid" ofType:@"mp4"];
NSURL *fileURL = [NSURL fileURLWithPath:filepath];
self.avPlayer = [AVPlayer playerWithURL:fileURL];

Now you need to create an AVPlayerLayer with your player and then add the layer to your current view.

AVPlayerLayer *layer = [AVPlayerLayer playerLayerWithPlayer:self.avPlayer];
self.avPlayer.actionAtItemEnd = AVPlayerActionAtItemEndNone;
        
layer.frame = CGRectMake(0, 0, 1024, 768);
[self.view.layer addSublayer: layer];

And now you simply play the video.

[self.avPlayer play];

The AVPlayer also uses NSNotificationCenter to send notifications about changes in the video’s state, so subscribing to those events follow the same pattern as with the MPMoviePlayerController.

Here is the full code example:

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    NSString *filepath = [[NSBundle mainBundle] pathForResource:@"vid" ofType:@"mp4"];
    NSURL *fileURL = [NSURL fileURLWithPath:filepath];
    self.avPlayer = [AVPlayer playerWithURL:fileURL];
    
    AVPlayerLayer *layer = [AVPlayerLayer playerLayerWithPlayer:self.avPlayer];
    self.avPlayer.actionAtItemEnd = AVPlayerActionAtItemEndNone;
    layer.frame = CGRectMake(0, 0, 1024, 768);
    [self.view.layer addSublayer: layer];
    
    [self.avPlayer play];
}

The AVPlayer also supports very fine-grained control in terms of synchronizing playback with external sources and jumping to a specified time within the video.

As far as I can tell the MPMoviePlayerController is supposed to be the easier version to implement while the AVPlayer offers more fine-grained control. Happy coding.

Tags: iOS, Objective-C

  1. AK says:

    Great example but your example for MPMoviePlayerController does not work for me. You’ve commented on that possibility though.

    Thanks

  2. Louis Yip says:

    Nice tutorial, but would you please tell me what is the coding for jumping to a specified time within the video

  3. Have a look at the apple docs for AVPlayer – https://developer.apple.com/library/mac/#documentation/AVFoundation/Reference/AVPlayer_Class/Reference/Reference.html. You want to use the seekToTime method. Just be aware that you might want to use the overload that specifies the tolerance – if you use a very high tolerance you might see a slight delay as the player buffers the video.

  4. Nino Bennett says:

    Hi, thanks very much for this tut ! I have followed it ot the T and i get the video to play, the question is, can I instanciate it to the storyboard view so I can put buttons over the video through the storyboard ? Thanks in advance !

  5. Hi Nico

    I haven’t tried to do that, but I would guess you could probably add an empty view to the storyboard and then add the buttons on top of that view. Then simply add the AVPlayer to this empty view’s layer instead of the parent view. So assuming you’ve created a view in the storyboard called videoContainer and made an outlet to in your viewcontroller, you would do [self.viewContainer.layer addSublayer:layer] instead of [self.view.layer addSublayer:layer]. That should do it!

  6. Nino Bennett says:

    Thanks Jaco for you answer, It really helped ! Now I have a different issue which has nothing to do with this but was wondering if you might know anyways. When the player starts playing within the subview with mpplayercontroller, there is a short black flash when the player loads. Is there anyway to preload the videos ?

    thanks again !!!

  7. You can try the prepareToPlay method…

  8. shakeer says:

    Hello,

    Can any one help me in playing a video using Avplayer. My requirement is, create a movie from images using CoreAnimation framework and then play it using Avplayer. I am able to play it after creating a movie. Is there any way where I can preview video using avplayer before actually creating a movie file. Thanks in advance.

  9. divya says:

    adding layer to view in fullsreen mode of mpmovieplayer controller….while entry into full sreen… i need to one view in it layer….for adding text in CAlayer…..

  10. Robert DeSaeger says:

    I wish that when someone does a tutorial, that they upload the xCode project for download.
    Very few people do that. Thank

  11. Alex says:

    This is exactly what I need.. think you could elaborate your tutorial just a bit.. pleeeease.. :)

  12. Paul says:

    Hi nice article, just to remind you and others that you also need to remove the view from the Notification Center as well

  13. Syed says:

    i played a video using AVPlayer, and i paused it using player.pause now if i want to resume it, what should i do?

  14. Hi Jaco,

    Thanks for writing this up. Could you post the final project code on GitHub? Setting the player as a property is tripping me up, and Xcode is throwing errors left and right, so I want to figure out what I’m doing wrong.

    Thanks!

  15. Hi Julian,

    Unfortunately I don’t have that code anymore, sorry.

    Jaco