Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple MPMoviePlayerController instances

Tags:

I'm trying to put two MPMoviePlayerController on a UIView like this

    for (int i = 0; i < 2; i++) {     UIView* v = [[UIView alloc] initWithFrame: CGRectMake(0.0f, 300.0f * i, self.view.width, 300.0f)];     [self.view addSubview: v];      NSURL* url = [NSURL URLWithString: [urls objectAtIndex: i]];     MPMoviePlayerController* movieController = [[MPMoviePlayerController alloc] initWithContentURL: url];     movieController.movieSourceType = MPMovieSourceTypeFile;     movieController.shouldAutoplay = NO;     movieController.view.frame = v.bounds;     [self.view addSubview: movieController.view]; } 

But only one view at a time is shown. I know Apple's documentation says

Note: Although you may create multiple MPMoviePlayerController objects and present their views in your interface, only one movie player at a time may play its movie.

but shouldn't the view show all two players at a time? Also only one instance sends MPMoviePlayerLoadStateDidChangeNotification notifications...

like image 647
Kostia Dombrovsky Avatar asked Dec 06 '10 15:12

Kostia Dombrovsky


2 Answers

You can play multiple videos on the screen by using the AVFoundation framework: AV Foundation Programming Guide

The downside is, that it is not as easy to use as the MPMoviePlayerController, and you shoul create a UIView subclass which contains the AVFoundation classes. This way you can create the necessary controls for it, control the video playback, animate the view (for example animate the transition to fullscreen).

Here it is how I used it:

// Create an AVURLAsset with an NSURL containing the path to the video AVURLAsset *asset = [AVURLAsset URLAssetWithURL:url options:nil];  // Create an AVPlayerItem using the asset AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:asset];  // Create the AVPlayer using the playeritem AVPlayer *player = [AVPlayer playerWithPlayerItem:playerItem];  // Create an AVPlayerLayer using the player AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:player];  // Add it to your view's sublayers [self.layer addSublayer:playerLayer];  // You can play/pause using the AVPlayer object [player play]; [player pause];  // You can seek to a specified time [player seekToTime:kCMTimeZero];  // It is also useful to use the AVPlayerItem's notifications and Key-Value  // Observing on the AVPlayer's status and the AVPlayerLayer's readForDisplay property // (to know when the video is ready to be played, if for example you want to cover the  // black rectangle with an image until the video is ready to be played) [[NSNotificationCenter defaultCenter] addObserver:self                                          selector:@selector(playerItemDidReachEnd:)                                              name:AVPlayerItemDidPlayToEndTimeNotification                                             object:[player currentItem]];      [player addObserver:self forKeyPath:@"currentItem.status"                      options:0                      context:nil];      [playerLayer addObserver:self forKeyPath:@"readyForDisplay"                      options:0                      context:nil]; 

You can resize the AVPlayerLayer as you like, even while the video is playing.

If you want to use animations while resizing or repositioning your AVPlayerLayer, you have to alter it's default animations, otherwise you'll see that the player layer's video is not resized in sync with its rect. (Thanks to @djromero for his answer regarding the AVPlayerLayer animation)

Here is a small example for how to alter its default animation. The setup for this example is that the AVPlayerLayer is in a UIView subclass that acts as its container:

// UIView animation to animate the view [UIView animateWithDuration:0.5 animations:^(){     // CATransaction to alter the AVPlayerLayer's animation     [CATransaction begin];     // Set the CATransaction's duration to the value used for the UIView animation     [CATransaction setValue:[NSNumber numberWithFloat:0.5]                       forKey:kCATransactionAnimationDuration];     // Set the CATransaction's timing function to linear (which corresponds to the      // default animation curve for the UIView: UIViewAnimationCurveLinear)     [CATransaction setAnimationTimingFunction:[CAMediaTimingFunction                               functionWithName:kCAMediaTimingFunctionLinear]];          self.frame = CGRectMake(50.0, 50.0, 200.0, 100.0);         playerLayer.frame = CGRectMake(0.0, 0.0, 200.0, 100.0);      [CATransaction commit];  }]; 
like image 55
Alpár Avatar answered Sep 17 '22 17:09

Alpár


You won't be able to do this. Internally MPMoviePlayerController seems to use the same view to trade between instances depending on whatever instance is playing. Your only option is to develop your own video player using AVFoundation in order to get multiple instances, or use HTML and UIWebViews. See: http://developer.apple.com/library/ios/#documentation/AudioVideo/Conceptual/AVFoundationPG/Articles/00_Introduction.html#//apple_ref/doc/uid/TP40010188

like image 28
gdavis Avatar answered Sep 17 '22 17:09

gdavis