Issue with setting Movie Player frame - ios

In my ipad application I write a code to play a movie using MPMoviePlayerViewController . Here how I have achieve it.
NSURL *url = [NSURL fileURLWithPath:self.moviePlayingTempPath];
// Initialize the movie player view controller with a video URL string
self.playerVC = [[MPMoviePlayerViewController alloc] initWithContentURL:url];
// Remove the movie player view controller from the "playback did finish" notification observers
[[NSNotificationCenter defaultCenter] removeObserver:self.playerVC
name:MPMoviePlayerPlaybackDidFinishNotification
object:self.playerVC.moviePlayer];
// Register this class as an observer instead
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(movieFinishedCallback:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:self.playerVC.moviePlayer];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moveiPlayBackStateChanged:)
name:MPMoviePlayerPlaybackStateDidChangeNotification
object:self.playerVC.moviePlayer];
self.playerVC.view.frame = CGRectMake(0, 0, 600, 500);
[self.view addSubview:self.playerVC.view];
// Start playback
[self.playerVC.moviePlayer prepareToPlay];
[self.playerVC.moviePlayer play];
Issue is player always run in fullscreen mode. But I want to change the movie player frame size.
I tried following [self.playerVC.moviePlayer setFullscreen:NO];but no luck.
Here is the screen shot of my device. I use Xcode 4.6 and iOS 6 SDK.

I was able resolve this issue. There is a another view for movie player called MPMoviePlayerController.
Then I was able to change the frame of the movie. Here is the updated code.
NSURL *url = [NSURL fileURLWithPath:self.moviePlayingTempPath];
// Initialize the movie player view controller with a video URL string
self.playerVC = [[MPMoviePlayerController alloc] initWithContentURL:url];
// Remove the movie player view controller from the "playback did finish" notification observers
[[NSNotificationCenter defaultCenter] removeObserver:self.playerVC
name:MPMoviePlayerPlaybackDidFinishNotification
object:self.playerVC];
// Register this class as an observer instead
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(movieFinishedCallback:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:self.playerVC];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moveiPlayBackStateChanged:)
name:MPMoviePlayerPlaybackStateDidChangeNotification
object:self.playerVC];
[self.playerVC setControlStyle:MPMovieControlStyleDefault];
self.playerVC.view.frame = CGRectMake(0, 0, 600, 500);
[self.view addSubview:self.playerVC.view];
// Start playback
[self.playerVC prepareToPlay];
[self.playerVC play];

Related

MPMoviePlayerController stop/freezes video when beginSeekingForward is pressed only on iOS 8+

I am using the MPMoviePlayerController to play some streaming videos of type .m3u from a url. They video player launches perfectly and the video starts playing perfectly as well, but as soon as I press the Seek Forward or Next or beginSeekingForward button the video complete stops/freezes. After that I can click Done to dismiss the player or scrub the progress bar and it will come back to play to video. But the I can't click on the play/pause or at least seems not to do anything.
I have spent quite sometime looking around online for answer or at least a hint so I can tackle this issue in the right direction but not luck. So, I really hope someone could help with this. Btw, this only happens on iOS 8+, currently I am testing it in iOS 8.1.
This is how I create the player and load the video to it.
NSURL *videoURL = [NSURL URLWithString:self.video.flvurl];
self.moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL: videoURL];
self.moviePlayer.controlStyle = MPMovieControlStyleFullscreen;
self.moviePlayer.movieSourceType = MPMovieSourceTypeStreaming;
self.moviePlayer.shouldAutoplay = NO;
self.moviePlayer.fullscreen = YES;
self.moviePlayer.repeatMode = YES;
self.moviePlayer.view.backgroundColor = [UIColor blackColor];
self.moviePlayer.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.moviePlayer.view.frame = self.containerView.frame;
[self.view addSubview:self.moviePlayer.view];
[self.moviePlayer prepareToPlay];
[self.moviePlayer play];
I have tried using multiple different notifications to see if I can catch this within one of them, but not luck at all. I have tested all of these notifications so far.. I have added this to the self.moviePlayer and also the self.moviePlayer.view not luck in either of them.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(willResignActive:)
name:UIApplicationWillResignActiveNotification
object:self.moviePlayer.view];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(videoPlaybackDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:self.moviePlayer.view];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(videoStartedPlaying:)
name:MPMoviePlayerNowPlayingMovieDidChangeNotification
object:self.moviePlayer.view];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(videoLoadState:)
name:MPMoviePlayerLoadStateDidChangeNotification
object:self.moviePlayer.view];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(videoPlaybackState:)
name:MPMoviePlayerPlaybackStateDidChangeNotification
object:self.moviePlayer.view];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(videoPlaybackUserInfoKey:)
name:MPMoviePlayerPlaybackDidFinishReasonUserInfoKey
object:self.moviePlayer.view];
Well, if you need more relevant code please let me know. I really need some help with this.. Thanks in advance.
This code worked for me, but just to get rid of freezing. Sign up for the MPMoviePlayerLoadStateDidChangeNotification, like you did above. In the callback method, I simply set the movie players contentURL to the original URL I had initialized it with at the start, and set the movie player to play again.
The functionality of this is when you tap the NEXT or BACK buttons in fullscreen, the video simply starts playing again from the start. That may not be ideal since the user might not expect this, but at least it will stop it from freezing. I'm currently trying to find a better workaround.
- (void) videoLoadState:(NSNotification *)notification
{
MPMovieLoadState loadState = moviePlayer.loadState;
if(loadState == MPMovieLoadStateUnknown)
{
NSLog(#"Movie Load state is unknown");
moviePlayer.contentURL = currentlyPlayingVideoURL;
[moviePlayer prepareToPlay];
}
}
If you check the value of MPMoviePlaybackState in this method, it will always be MPMoviePlaybackStateStopped when NEXT or BACK are pressed, so I'm not sure how to handle it...

How to detach AVPlayerLayer from AVPlayer to play video in background state?

I am trying to play video in background.I follow so many tutorial but i did not get appropriate results.For that i am using AVPlayer.I am able to play my video whenever application state is active.But i want to play music in background for that i need to detach AVPlayerLayer from AVPlayer,If you have any alternate solution so that i can play my video in background.Please help me.
This is my code:
ViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
[[AVAudioSession sharedInstance] setDelegate: self];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance] setActive: YES error: nil];
NSURL *url = [[NSBundle mainBundle] URLForResource:#"sample"
withExtension:#"m4v" subdirectory:nil];
avPlayerItem = [AVPlayerItem playerItemWithURL:url];
self.songPlayer = [AVPlayer playerWithPlayerItem:avPlayerItem];
self.avPlayerLayer = [AVPlayerLayer playerLayerWithPlayer: self.songPlayer];
self.avPlayerLayer.frame = self.view.layer.bounds;
UIView *newView = [[UIView alloc] initWithFrame:self.view.bounds];
[newView.layer addSublayer:avPlayerLayer];
[self.view addSubview:newView];
[self.songPlayer play];
}
AppDelegate.m
- (void)applicationWillResignActive:(UIApplication *)application
{
ViewController *vc=[[ViewController alloc]init];
vc.avPlayerLayer = [AVPlayerLayer playerLayerWithPlayer:nil];
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
ViewController *vc=[[ViewController alloc]init];
vc.avPlayerLayer = [AVPlayerLayer playerLayerWithPlayer:vc.songPlayer];
}
You are creating a new view controller in both your application delegate methods, with a new player etc.. That will not change a thing. You must use the player and layer you created in the view controller's viewDidLoad method, and modify that one later in the delegate methods. For this, your application delegate could store the main view controller in it's properties, or you could implement the NSNotifications for application delegate in your view controller class, like so: (could be added to the view controller's viewDidLoad method)
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(appDidBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(appWillResignActive:) name:UIApplicationWillResignActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(appDidEnterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(appWillEnterForeground:) name:UIApplicationWillEnterForegroundNotification object:nil];
To detach the player layer from the player, as it's said in the documentation, is slightly incorrect, at least confusing. In fact you have to detach the player from the player layer.
Add this code to the applicationDidEnterBackground (not applicationWillResignActive) method:
// Detach player from playerlayer to avoid pause while in background
if (self.playerLayer && self.player)
{
[self.playerLayer setPlayer: nil];
}
In your applicationWillEnterForeground, store a flag to remember that when the application becomes active, it is due to entering the foreground, and not one of the other numerous reasons for which applicationDidBecomeActive may be called:
self.enteringForeground = true;
And then, in your applicationDidBecomeActive: method,
if (self.enteringForeground)
{
// Re-attach player to playerlayer
if (self.playerLayer && self.player)
{
if (self.playerLayer.player != self.player)
[self.playerLayer setPlayer: self.player];
}
self.enteringForeground = false;
}
For this to work, you will need a new property in your application delegate .h file or view controller .h file, depending which implementation you chose:
#property (readwrite) BOOL enteringForeground;
Of course, you also need to add the entry UIBackgroundModes with value 'audio' to your application's info.plist file (or in the Info tab of your project, add the entry 'Required background modes' and then the value 'App plays audio or streams audio/video using AirPlay').
I hope this is helpful. I too struggled at first to implement background playback, and this method seems to work quite well.

MPMoviePlayer disappear when clicking on done button

I used MPMoviePlayerController to play video. Here is the code.
// Getting URL from path
NSURL *url = [NSURL fileURLWithPath:self.moviePlayingTempPath];
// Initialize the movie player view controller with a video URL string
self.playerVC = [[MPMoviePlayerController alloc] initWithContentURL:url];
// Remove the movie player view controller from the "playback did finish" notification observers
[[NSNotificationCenter defaultCenter] removeObserver:self.playerVC
name:MPMoviePlayerPlaybackDidFinishNotification
object:self.playerVC];
// Register this class as an observer instead
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(movieFinishedCallback:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:self.playerVC];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moveiPlayBackStateChanged:)
name:MPMoviePlayerPlaybackStateDidChangeNotification
object:self.playerVC];
[self.playerVC setControlStyle:MPMovieControlStyleEmbedded];
self.playerVC.view.frame = CGRectMake(0, 0, 1024, 648);
[self.view addSubview:self.playerVC.view];
// Start playback
[self.playerVC prepareToPlay];
[self.playerVC play];
It works fine in the embedded mode. I have very unusual behavior in full screen mode. When I go full screen and can play the video without any problem. Then I can click the done button and come to the embedded mode without problem.
Problem is occurring when go full screen and single click on forward or backward seeking buttons. Then player stop playing and show activity indicator with loading text. Then If i click the done button then the player disappears forever. I cant figure out exact problem to this. Actually i don't need forward and backward seeking buttons. Can we block seeking or how can i solve this problem.
I solve this by removing and adding the movie player to the view when user switch from full screen.
Here is the full code
-(void)continuePlayingFile{
NSURL *url = [NSURL fileURLWithPath:self.moviePlayingTempPath];
// Initialize the movie player view controller with a video URL string
self.playerVC = [[MPMoviePlayerController alloc] initWithContentURL:url];
// Remove the movie player view controller from the "playback did finish" notification observers
[[NSNotificationCenter defaultCenter] removeObserver:self.playerVC
name:MPMoviePlayerPlaybackDidFinishNotification
object:self.playerVC];
// Register this class as an observer instead
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(movieFinishedCallback:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:self.playerVC];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moveiPlayBackStateChanged:)
name:MPMoviePlayerPlaybackStateDidChangeNotification
object:self.playerVC];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(willEnterFullScreen:)
name:MPMoviePlayerWillEnterFullscreenNotification
object:self.playerVC];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(willExitFullScreen:)
name:MPMoviePlayerWillExitFullscreenNotification
object:self.playerVC];
[self.playerVC setControlStyle:MPMovieControlStyleEmbedded];
self.playerVC.movieSourceType = MPMovieSourceTypeFile;
self.playerVC.view.frame = CGRectMake(0, 0, 1024, 648);
[self.view addSubview:self.playerVC.view];
// Start playback
[self.playerVC prepareToPlay];
[self.playerVC play];
}
-(void)willExitFullScreen:(NSNotification *)note{
self.isMovieGoFullScreen = NO;
if(self.isUserClickNextButton){
//This is to handle user click on next/previous button and then click done button.
self.isUserClickNextButton=NO;
[self continuePlayingFile];
}
}
-(void)moveiPlayBackStateChanged:(NSNotification*)aNotification{
if(self.playerVC){
self.currentPlayerState = self.playerVC.playbackState;
if(self.currentPlayerState == MPMoviePlaybackStateStopped){
self.isUserClickNextButton =YES;
}
}
}
Please note that when adding the observer, the object parameter should be playerVC.moviePlayer and not the playerVC.
The moviePlayer (class MPMoviePlayerController) is the one sending the notification.
So change this:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(movieFinishedCallback:) name:MPMoviePlayerPlaybackDidFinishNotification object:videoPlayerVC];
to this:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(movieFinishedCallback:) name:MPMoviePlayerPlaybackDidFinishNotification object:videoPlayerVC.moviePlayer];

MPMoviePlayerController Works in Simulator, But Not On Device

I have a MPMoviePlayerController that streams video. The problem is that the video and audio work fine in the simulator, but on the device, the view just turns black and no audio or video comes out. Here is my code:
- (IBAction)playVideoPress:(id)sender
{
MPMoviePlayerController *player = [[MPMoviePlayerController alloc] initWithContentURL:mediaURL];
_mpPlayer3 = player;
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(moviePlayerDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:nil];
_mpPlayer3.controlStyle = MPMovieControlStyleDefault;
[_playerView3 addSubview: _mpPlayer3.view];
[_mpPlayer3.view setFrame:_playerView3.bounds];
[_mpPlayer3 play];
}
Then the notification when the video finishes is:
- (void)moviePlayerDidFinish:(NSNotification*)notification {
[[NSNotificationCenter defaultCenter]
removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:nil];
NSLog(#"Did Finish Notification");
[_mpPlayer3 stop];
_mpPlayer3 = nil;
}
This works fine in the simulator, but just shows a black screen in the view I want to display the video in. Another weird thing that happens is that when I do run it in the simulator, I get a bunch of errors such as:
Error loading /System/Library/Extensions/AudioIPCDriver.kext/Contents/Resources/AudioIPCPlugIn.bundle/Contents/MacOS/AudioIPCPlugIn: dlopen(/System/Library/Extensions/AudioIPCDriver.kext/Contents/Resources/AudioIPCPlugIn.bundle/Contents/MacOS/AudioIPCPlugIn, 262): Symbol not found: ___CFObjCIsCollectable
I don't know if that has anything to do with the simulator playing the video and the device not, but I thought that I would mention it here.

iOS Using MPMoviePlayerViewController in Fullscreen (iPad)

I have a single view app with 5 buttons and when one of the buttons is pressed, the player slides up over the original view and begins playing the video in fullscreen (as it should).
All works great with the exception of when pressing the Fullscreen/Minimize icon (the two diagonal arrows pointing to each other next to the play back controls). When pressing this, the original view with the five buttons slides up over the video player. The problem is the video is still playing underneath the original view. I would really like to eliminate the Fullscreen/Minimize icon but from I can tell, that does not seem possible. So... I am thinking, I might be able to use an observer to listen to when the Fullscreen/Minimize icon is pressed and I can do what I need to. I just can not find anything solid on how to do this. Any help/direction would be greatly appreciated.
Here is my current code...
-(IBAction)playvideo {
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"Megamind" ofType:#"mov"]];
MPMoviePlayerViewController * playerController = [[MPMoviePlayerViewController alloc] initWithContentURL:url];
[self presentMoviePlayerViewControllerAnimated:(MPMoviePlayerViewController *)playerController];
playerController.moviePlayer.movieSourceType = MPMovieSourceTypeFile;
[playerController.moviePlayer play];
[playerController release];
playerController=nil;
}
- (void)moviePlayerWillExitFullscreen:(NSNotification *)theNotification {
MPMoviePlayerController *playerController = [theNotification object];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayerWillExitFullscreen:)
name:MPMoviePlayerWillExitFullscreenNotification
object:nil];
[playerController stop];
[self dismissMoviePlayerViewControllerAnimated];
}
This line is causing you that behaviour.
[self presentMoviePlayerViewControllerAnimated:(MPMoviePlayerViewController *)playerController];
It is pretty much similar to your regular presentModalViewController method.
It presents the Movieplayer and its view controller Modally. So the default settings here are
movieplayer.controlStyle = MPMovieControlStyleFullScreen
which are set up by default.
So when you press those diagonal arrows, it exits that mode, and gives a notification for that. But you have to setup an observer first to listen to that notifcation as you did for movie finished.
You did
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(movieFinishedPlayback:) name:MPMoviePlayerPlaybackDidFinishNotification object:nil];
This adds a notification to observe for movie completion notifications.
For exiting full screen mode add one more observer that is this..
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(movieExitFullScreen:) name:MPMoviePlayerDidExitFullscreenNotification object:nil];
And you should be good to go after adding the -(void) movieExitFullScreen:(NSNotification *) selector for the same. Hope it helps. :)
Put this line just after the init of your MPMoviePlayer :
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayerWillExitFullscreen:)
name:MPMoviePlayerWillExitFullscreenNotification
object:nil];
I think you're adding the observer in the method where you want to be REMOVING it.
You want this
MPMoviePlayerController *playerController = [theNotification object];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayerWillExitFullscreen:)
name:MPMoviePlayerWillExitFullscreenNotification
object:nil];
in the playVideo()
and THIS
[[NSNotificationCenter defaultCenter] removeObserver:self
name:name:MPMoviePlayerWillExitFullscreenNotificationn
object:nil];
in the moviePlayerWillExitFullscreen method.
I did find a solution and my lack of knowledge put me in a situation where I do not fully understand why it works this way. My apologies for not having a thorough reasoning. In my original code... the MPMoviePlayerWillExitFullscreenNotification was not answering to taps. This is true for MPMoviePlayerDidExitFullscreenNotification as well. What was answering was MPMoviePlayerPlaybackDidFinishNotification. Here is teh working code in knowing that the MPMoviePlayerPlaybackDidFinishNotification was working and also applied to the Fullscreen/Embed presses.
-(IBAction)playvideo {
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"Megamind" ofType:#"mov"]];
MPMoviePlayerViewController * playerController = [[MPMoviePlayerViewController alloc] initWithContentURL:url];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(movieFinishedPlayback:) name:MPMoviePlayerPlaybackDidFinishNotification object:nil];
[self presentMoviePlayerViewControllerAnimated:(MPMoviePlayerViewController *)playerController];
playerController.moviePlayer.movieSourceType = MPMovieSourceTypeFile;
[playerController.moviePlayer play];
[playerController release];
playerController=nil;
NSLog(#"playvideo");
}
- (void)movieFinishedPlayback:(NSNotification*)notification {
MPMoviePlayerController *playerController = [notification object];
[playerController pause];
[self dismissMoviePlayerViewControllerAnimated];
}

Resources