I am using a MPMoviePlayer to stream a video URL.
The video starts in a view's frame after the user taps on it. That works ok. As the video is embedded, the default control places a Zoom in button.
When the user presses the zoom in, the video goes fullscreen ok, without interrupting playback.
However, when the user presses again the zoom out button, i have three problems:
The video zooms to a corner of the screen and then disappears,
instead of returning to the original position.
The video disappears after going to the corner, and playback ends,
instead of continue playing the video.
The MPMoviePlayerDidExitFullscreenNotification never gets called,
only the MPMoviePlayerWillExitFullscreenNotification is called. I have tried sending nil and the mediaPlayerController to the notification center.
Also when pressing the Done button the video goes to the corner of the screen and disappears.
My player is created by doing:
moviePlayer=[[MPMoviePlayerController alloc] init];
moviePlayer.movieSourceType = MPMovieSourceTypeStreaming;
moviePlayer.scalingMode = MPMovieScalingModeAspectFit;
moviePlayer.shouldAutoplay=YES;
moviePlayer.controlStyle=MPMovieControlStyleEmbedded;
moviePlayer.view.hidden = YES;
Then when the user taps on the view this happens:
- (void) playVideo {
NSURL *url=[NSURL URLWithString: _news.videoUrl];
moviePlayer.contentURL = url;
moviePlayer.view.hidden = NO;
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(moviePlayBackDidFinish:) name:MPMoviePlayerPlaybackDidFinishNotification object:moviePlayer];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(moviePlayerWillExitFullScreen:) name:MPMoviePlayerWillExitFullscreenNotification object:moviePlayer];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(moviePlayerDidExitFullScreen:) name:MPMoviePlayerDidExitFullscreenNotification object:moviePlayer];
[moviePlayer play];
}
- (void) moviePlayerWillExitFullScreen:(NSNotification*)notification {
NSLog(#"WILL EXIT FULLSCREEN");
}
- (void) moviePlayerDidExitFullScreen:(NSNotification*)notification {
NSLog(#"EXITED FULLSCREEN"); //NOT CALLED
}
- (void) moviePlayBackDidFinish:(NSNotification*)notification {
NSLog(#"FINISHED PLAYIIING");
[[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerPlaybackDidFinishNotification object:moviePlayer];
moviePlayer.view.hidden = YES;
}
Well, on the meanwhile I will answer 3 of my 4 questions:
The video zooms to a corner of the screen and then disappears, instead of returning to the original position.
The video disappears after going to the corner, and playback ends, instead of continue playing the video.
Also when pressing the Done button the video goes to the corner of the screen and disappears.
The problem was that after exiting fullscreen mode the -viewWillAppearAnimated method is called. The layout was modified in that method and that's why the playback stopped and view was sent to corner.
Related
I want to play a video in seprate view controller, where I can Play/Pause or dismiss that view controller. In my case, I recorded the video in my app and calling this delegate method in order to save this video in assets, but I want to play it first before using the ALAssetsLibrary.
- (void)captureOutput:(AVCaptureFileOutput *)captureOutput
didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL
fromConnections:(NSArray *)connections
error:(NSError *)error
And the TEMO URL im getting is :
file:///private/var/mobile/Containers/Data/Application/EA6D31AC-6CC3-4BDF-B874-BC6F30BA5677/tmp/output.mov
How can I play this video in next view controller or in same view controller??
My try:
MPMoviePlayerController *player = [[MPMoviePlayerController alloc] initWithContentURL:outputFileURL];
player.view.frame = CGRectMake(184, 200, 400, 300);
[self.view addSubview:player.view];
[player play];
PS: This is showing a black screen area but not actually playing this video.
I had the same problem a few days ago. It ends up that I was calling play method to soon, before the video become ready to play. So, add this before call [player play]. This will notify whenever your video become read to play in MPMoviePlayerController.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(videoPlayBackDidFinish:) name:MPMoviePlayerPlaybackDidFinishNotification object:player];
Then setup the observer:
- (void)videoPlayBackDidFinish:(NSNotification *)notification {
[[NSNotificationCenter defaultCenter]removeObserver:self name:MPMoviePlayerPlaybackDidFinishNotification object:nil];
}
This worked for me.
Hope it helps.
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...
I am facing an issue with MPMoviePlayerController in iOS 7. I enter the fullscreen and then click (just a single tap) on seek forward button (>>|) , and the video playback ends and gives a black screen with a text "Loading" on the header.
I registered notification for "MPMoviePlayerPlaybackStateDidChangeNotification".
**[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayerPlaybackStateDidChange:)
name:MPMoviePlayerPlaybackStateDidChangeNotification
object:self.player];**
It does not get fired on a single click of seek forward button.
Also on registration of "MPMoviePlayerPlaybackDidFinishNotification"
**[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayerPlaybackDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:nil];**
I get "MPMovieFinishReasonPlaybackEnded" event fired on that single click of seek forward button.
Any one knows the reason why? Is this a bug in apple?
I need to either stop this behavior of showing a black screen on single click , or just disable single click of seek forward button so that nothing happens.
Any one knows how to achieve this?
I fixed this by removing the MPMoviePlayer object completely, setting it to nil, removing it from it's superview and re-adding it using the original video Url. Code below:
- (void)addPlayerForUrl:(NSURL *)url {
self.player = [[MPMoviePlayerController alloc] initWithContentURL:url];
self.player.view.frame = self.videoView.bounds;
self.player.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.player.controlStyle = MPMovieControlStyleDefault;
[self.videoView insertSubview:self.player.view atIndex:0];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayerLoadStateDidChangedNotification:)
name:MPMoviePlayerReadyForDisplayDidChangeNotification
object:self.player];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayerPlaybackStateDidChangeNotification:)
name:MPMoviePlayerPlaybackStateDidChangeNotification
object:self.player];
}
#pragma mark - Notifications
- (void)moviePlayerLoadStateDidChangedNotification:(NSNotification *)notification {
self.isVideoPreloaded = YES;
self.videoPlayButton.hidden = YES;
self.photoImageView.hidden = YES;
self.videoLoadingImageView.hidden = YES;
}
- (void)moviePlayerPlaybackStateDidChangeNotification:(NSNotification *)notification {
NSURL *url = self.player.contentURL;
switch (self.player.playbackState) {
case MPMoviePlaybackStateSeekingBackward:
case MPMoviePlaybackStateSeekingForward:
break;
case MPMoviePlaybackStatePlaying:
self.videoPlayButton.hidden = YES;
if (!self.isVideoPreloaded) {
self.videoLoadingImageView.hidden = NO;
[self.videoLoadingImageView startAnimating];
} else {
self.videoLoadingImageView.hidden = YES;
}
break;
case MPMoviePlaybackStatePaused:
case MPMoviePlaybackStateStopped:
self.videoPlayButton.hidden = NO;
self.videoLoadingImageView.hidden = YES;
[self.player endSeeking];
[self.player.view removeFromSuperview];
[self.player setFullscreen:NO];
self.player = nil;
[self addPlayerForUrl:url];
break;
default:
break;
}
}
Notice how I keep the NSURL, right before the switch statement in the moviePlayerPlaybackStateDidChangeNotification. That way, I can re-initialize and re-add the MPMoviePlayer object.
Btw, my mpmovieplayer is on a tableviewCell if you're wondering. Hope this helps and let me know if you have questions. Good luck!
MPMoviePlayerLoadStateDidChangeNotification will be called when you single tap on the fast-forward or rewind button. You should check the loadState and just give it the path to your video and prepareToPlay again.
- (void)moviePlayerLoadStateChanged:(NSNotification *)notification {
MPMoviePlayerController *moviePlayer = notification.object;
MPMovieLoadState loadState = moviePlayer.loadState;
if(loadState == MPMovieLoadStateUnknown) {
moviePlayer.contentURL = [NSURL fileURLWithPath:videoPath]
[moviePlayer prepareToPlay];
}
.....
}
The reason you're getting MPMovieFinishReasonPlaybackEnded is because playback reached the end of the video (sorry if this is obvious). So it seem's your seek forward actions are seeking all the way to the end of the video. You can check the playback state with MPMoviePlaybackStateSeekingForward.
A quick solution could be to create your own forward button that seek's ahead by a specified time (ie. 5 seconds). But perhaps this isn't the functionality you're looking for.
I have a MPMoviePlayerController setup:
self.moviePlayerController = [[MPMoviePlayerController alloc] init];
[self.moviePlayerController.view setFrame:frame];
// hide controls initially
[self.moviePlayerController setControlStyle:MPMovieControlStyleNone];
[self.view addSubview:self.moviePlayerController.view];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(loadStateChanged:) name:MPMoviePlayerLoadStateDidChangeNotification object:self.
moviePlayerController];
Then when the notification is fired:
-(void)loadStateChanged:(NSNotification*)notification {
if (self.moviePlayerController.controlStyle == MPMovieControlStyleNone) {
[self.moviePlayerController setControlStyle:MPMovieControlStyleDefault];
}
}
On initial playback this works great, controls are not shown when playback starts but tapping the view shows the controls.
However, when a movie is already playing and I start playback of another URL, I hide the controls, but they reappear after playback starts of the second movie:
[self.moviePlayerController setContentURL:videoURL];
[self.moviePlayerController setControlStyle:MPMovieControlStyleNone];
[self.moviePlayerController play];
The notification does fire again and it correctly has a controlStyle of MPMovieControlStyleNone which I then set to MPMovieControlStyleDefault.
Anybody have any experience with this, is there a way to make sure the controls stay hidden on a second playback, but are in fact visible when the user taps the movie view.
Thanks!
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];
}