I have encountered a problem with the MPMoviePlayerController in 3.1.2.
If I cancel the player while it is still loading, the player closes. However, the video starts playing a few moments later in the background. The only ways to stop it are to play another video or close the app. This seems to work fine in 3.2+.
Here's what I'm doing:
- (void)loadMoviePlayer
{
// Register to receive a notification when the movie has finished playing.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayBackDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:nil];
if ([NSClassFromString(#"MPMoviePlayerController") instancesRespondToSelector:#selector(view)])
{
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 30200
// running iOS 3.2 or better
MPMoviePlayerViewController *moviePlayer = [[MPMoviePlayerViewController alloc] initWithContentURL:[NSURL URLWithString:#"http://www.mysite.com/myvideo.m3u8"]];
[moviePlayer.view setBackgroundColor:[UIColor blackColor]];
[moviePlayer.moviePlayer setControlStyle:MPMovieControlStyleFullscreen];
// [moviePlayer.moviePlayer setControlStyle:MPMovieControlStyleNone];
[self presentMoviePlayerViewControllerAnimated:moviePlayer];
[moviePlayer.moviePlayer prepareToPlay];
[moviePlayer.moviePlayer play];
#endif
}
else
{
MPMoviePlayerController *mMPPlayer = [[MPMoviePlayerController alloc] initWithContentURL:[NSURL URLWithString:#"http://www.mysite.com/myvideo.m3u8"]];
mMPPlayer.scalingMode=MPMovieScalingModeFill;
mMPPlayer.backgroundColor=[UIColor blackColor];
[mMPPlayer play];
}
}
- (void) moviePlayBackDidFinish:(NSNotification*)notification
{
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackOpaque];
[[UIApplication sharedApplication] setStatusBarHidden:NO];
// Remove observer
[[NSNotificationCenter defaultCenter]
removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:nil];
[self dismissModalViewControllerAnimated:YES];
}
I added moviePlayBackDidFinish this morning. It gets called when I hit cancel, but dismissModalViewControllerAnimated doesn't seem to do anything. I also tried removeFromSuperView, but my player will not respond.
So, how can I make sure the player does not play after hitting "cancel"?
Thanks in advance.
You may have come across an old bug in MPMoviePlayerController. Back in the days, we actually had to play an almost empty (black, silence) M4V after playing proper content to be sure the player does not attempt to continue playback in the background when stopping at certain stages. That bug manifests in audible sound but no picture of the aborted/stopped video.
There are however a few more things worth trying when stopping (assuming your instance of MPMoviePlayerController is called moviePlayer);
set the current playback position to the complete movie duration moviePlayer.currentPlaybackTime = moviePlayer.duration;
send another stop within your notification handler [moviePlayer stop];
In my case, I found that setting the following line would eventually stop the movie player from playing:
moviePlayer.contentURL = nil;
(with moviePlayer your instance of MPMoviePlayerController).
Related
*I'm creating an iPhone app where we can watch videos...
I,ve been making my own controls so I want to implement the next, back buttons, I can show theme so for the UI everything is ok the problem is to restart the MoviePlayer with another content...
Any idea???
I could use the same configuration when the playback did finish, I mean... If the video ends playing to start playing another one...
I've tried to set contentUrl but it trows an exception:
2012-04-17 11:37:41.198 NexTest2[8218:11f03] *** Terminating app due to uncaught exception 'CALayerInvalidGeometry', reason: 'CALayer position contains NaN: [nan 11.5]'
viewController.m
- (void)viewDidLoad{
[super viewDidLoad];
fileURL = [NSURL URLWithString:urlString];
moviePlayerController = [[MPMoviePlayerController alloc] initWithContentURL:fileURL];
moviePlayerController.controlStyle = MPMovieControlStyleNone;
[moviePlayerController setShouldAutoplay:YES];
[self addObservers];
/* Inset the movie frame in the parent view frame. */
CGRect viewInsetRect = CGRectInset ([self.view bounds],0.0, 0.0 );
[[moviePlayerController view] setFrame: viewInsetRect ];
[self.view addSubview:moviePlayerController.view];
[self resizeControlViews];
}
then in resizeControlViews I have this, cause I'm using these two views like controls:
-(void)resizeControlViews{
CGRect barFrame = self.controlBarView.frame;
barFrame.origin.x = round((moviePlayerController.view.frame.size.width - barFrame.size.width) / 2.0);
barFrame.origin.y = round((moviePlayerController.view.frame.size.height - barFrame.size.height)/10.0);
self.controlBarView.frame = barFrame;
[moviePlayerController.view addSubview:controlBarView];
CGRect playFrame = self.controlPlaybackView.frame;
playFrame.origin.x = round((moviePlayerController.view.frame.size.width - playFrame.size.width) / 2.0);
playFrame.origin.y = round((moviePlayerController.view.frame.size.height - playFrame.size.height)/1.1);
self.controlPlaybackView.frame = playFrame;
[moviePlayerController.view addSubview:controlPlaybackView];
}
Here everything is working fine, in one of these views there is a slider who controls the seeking, and in the other one are the play, next and back buttons.
I think maybe the problem is whit the UI components of these views...
I've added these observers to control the playback:
//Add the observers to the player
-(void)addObservers{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(playbackStarted:) name:MPMoviePlayerPlaybackStateDidChangeNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(setDurationLabel:) name:MPMovieDurationAvailableNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(moviePlayBackDidFinish:) name:MPMoviePlayerPlaybackDidFinishNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyWindowChanged:) name:UIWindowDidBecomeKeyNotification object:nil];
}
so to handle when the player is playing I use the MPMoviePlayerPlaybackStateDidChangeNotification with this selector:
//called when the playback state changes of state
- (void)playbackStarted:(NSNotification*)notification {
MPMoviePlayerController *player = notification.object;
if (player.playbackState == MPMoviePlaybackStatePlaying) {
[self timerRunning];
}
}
and if the player is "playing" I monitor it with this method:
-(void)timerRunning{
self.currentTime.text = [self floatToStringTime:(moviePlayerController.currentPlaybackTime)];
self.timeBar.value = moviePlayerController.currentPlaybackTime / moviePlayerController.duration;
if (moviePlayerController.playbackState == MPMoviePlaybackStatePlaying) {
[self performSelector:#selector(timerRunning) withObject:nil afterDelay:0.5];
}
}
so Maybe here is the issue... but with a single video it works perfectly...
I've four where the mistake is... is while i'm monitoring in the line to set the value to the slider, but I really don't know why, I think it is cause when another video or stoping video it is still executed so the player has not duration or current playback what trows this exception... how could I to solve it... here is the mistake... maybe moving this code to another part...
self.timeBar.value = moviePlayerController.currentPlaybackTime / moviePlayerController.duration;
Check your UI related code. You most likely are not properly checking the player status before getting and using content related properties from it.
Well finally it works fine... the setCurrentContentUrl works fine, the problem was my code so I solved it... I just validate that duration was different to 0...
Now I have a player with full custom controls :) cool :)
-(void)timerRunning{
if (moviePlayerController.playbackState == MPMoviePlaybackStatePlaying) {
self.currentTime.text = [self floatToStringTime:(moviePlayerController.currentPlaybackTime)];
if (moviePlayerController.duration != 0) {
self.timeBar.value = moviePlayerController.currentPlaybackTime / moviePlayerController.duration;
}
[self performSelector:#selector(timerRunning) withObject:nil afterDelay:0.5];
}
}
Thank you anyways
I have an existing iPhone/iPad universal app that streamed video with the MPMoviePlayerController over wi-fi (mp4) and 3G Network (3gp). When iOS 4.3 was released our 4.3 devices can no longer play a 3gp video over 3G network. I tested a local 3gp file and that fails too, but works on a 3G phone running 4.2.x.
After debugging the view controller I see the MPMoviePlayerLoadStateDidChangeNotification notification is not being triggered when trying to play the 3gp file locally or streaming it via URL.
[APPDEL showStatusView: #"Please wait..."];
NSString * videoUrl = [[request.URL description] stringByReplacingOccurrencesOfString: #"idvideo:" withString: #"http:"];
DLog(#"Loading video %#", videoUrl);
_moviePlayer = [[IDMoviePlayerController alloc] initWithContentURL: [NSURL URLWithString: videoUrl]];
_moviePlayer.view.backgroundColor = [UIColor clearColor];
_moviePlayer.allowsAirPlay = YES;
_moviePlayer.scalingMode = MPMovieScalingModeAspectFit;
if ([_moviePlayer respondsToSelector:#selector(loadState)]) {
// May help to reduce latency
[_moviePlayer prepareToPlay];
// Register that the load state changed (movie is ready)
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayerLoadStateChanged:)
name:MPMoviePlayerLoadStateDidChangeNotification
object:_moviePlayer];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayerPreloadDidFinish:)
name:MPMoviePlayerContentPreloadDidFinishNotification
object:_moviePlayer];
//[NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:#selector(moviePlayerTimerUp:) userInfo:nil repeats:NO];
}
else {
// Register to receive a notification when the movie is in memory and ready to play.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePreloadDidFinish:)
name:MPMoviePlayerLoadStateDidChangeNotification
object:nil];
}
[[NSNotificationCenter defaultCenter] addObserver: self selector: #selector(onMovieDone:) name: MPMoviePlayerPlaybackDidFinishNotification object: nil];
if ([_moviePlayer respondsToSelector: #selector(view)]) {
[self.view addSubview: _moviePlayer.view];
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
_moviePlayer.controlStyle = MPMovieControlStyleEmbedded;
}
else {
_moviePlayer.controlStyle = MPMovieControlStyleFullscreen;
}
_moviePlayer.view.frame = _webView.frame;
}
[_moviePlayer play];
The first condition for the loadState is always hit. For the 3gp file the code will never reach the moviePlayerLoadStateChanged selector method which hides an indicator/status view and creates other fullscreen/orientation notifications. The indicator/status view will just remain up & spinning. Within debugger I can see the onMovieDone selector method gets triggered far sooner than the video would of really of finished.
Confused.
This my answer in regards with playing .3gp file with iPhone .....I have successfully played .3gp file with iphone sdk with using MpMoviePlayerController and my answer link is:
Link: https://stackoverflow.com/a/13088808/1092219
hope you will got help from my answer.........!! :))))))
I have following code that I use to play a selected portion of a movie clip. The movie plays okay. But the scrubber bar does not reflect the correct start stop time. Also, the forward and rewind buttons take the clip beyond the segment that was specified. Why is this and can we fix it?
TIA.
MPMoviePlayerViewController *mp =
[[MPMoviePlayerViewController alloc] initWithContentURL:[NSURL fileURLWithPath:movieFile] ];
[mp.moviePlayer setInitialPlaybackTime:21];
[mp.moviePlayer setEndPlaybackTime:48];
[self presentMoviePlayerViewControllerAnimated:mp];
[self shouldAutorotateToInterfaceOrientation:YES];
//NSLog(#"Movie Player Controller View = %#", mp.moviePlayer.view);
//NSLog(#"Movie Player Controller Parent View = %#", mp.parentViewController);
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayBackDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:[mp moviePlayer]];
[mp.moviePlayer play];
I have a class that plays a repeating background music loop with an AVAudioPlayer, and on specific occasion, plays a full-screen video with its own sound track using MPMoviePlayerController. In order to to have only one track at a time, I stop the background music before launching the video:
-(void)startVideo{
[backgroundMusic stop];
MPMoviePlayerViewController *mp = [[MPMoviePlayerViewController alloc] initWithContentURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"videofile" ofType:#"m4v"]]];
[self presentMoviePlayerViewControllerAnimated:mp];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(videoOver) name:MPMoviePlayerPlaybackDidFinishNotification object:nil];
[mp.moviePlayer play];
[mp release];
}
-(void)videoOver{
[[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerPlaybackDidFinishNotification object:nil];
if(![backgroundMusic play]){
NSLog(#"bad: can't resume bg music!");
[backgroundMusic release];
backgroundMusic = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"videofile" ofType:#"m4v"]] error:NULL];
backgroundMusic.delegate = self;
backgroundMusic.numberOfLoops = -1;
[backgroundMusic play];
}
}
The resumption worked fine without recreating the AVAudioPlayer object (i.e. the play method returned YES) on analogous code on os versions up to and including 3.2. But on iOS4, the play method always returns NO, and has to recreate the object. Why is that, and can I get to resume the background track properly (I have cases where the solution used above is unacceptable.)?
Figured this out. It turns out that in iOS 3.2 and above, when a video finishes playing, it goes into MPMoviePlaybackStatePaused state rather than MPMoviePlaybackStateStopped, and in order to make it release the hardware, you have to explicitly call the stop method on MPMoviePlayerController after it finishes playing before trying to resume AVAudioPlayer.
The code below is more or less taken from the example MPMoviePlayerController sample code. In an app I wrote last year, it used to play videos fullscreen without an issue. Since iOS 4.0, there's just audio in the background. It's like the movie player doesn't have a view or the view is behind my app. I can still interact with my app, even 'start' a new video (audio only).
It's like the movie player now needs a view, but I don't see any way of supplying this in the API or the sample code (which does seem to be a version or two behind.
I load my videos from a URL and if I type these into Safari, they play just fine.
Here's the relevant code fragments, for what it's worth:
- (void)playMovieUrl:(NSURL*)url
delegate:(id)delegate
callbackSelector:(SEL)selector
{
#try {
movieFinishedCallbackDelegate = delegate;
movieFinishedCallbackSelector = selector;
movieURL = url;
MPMoviePlayerController* theMovie=[[MPMoviePlayerController alloc] initWithContentURL:url];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(myMovieFinishedCallback:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:theMovie];
[theMovie play];
}
#catch (NSException * e) {
return;
}
}
// When the movie is done,release the controller.
-(void)myMovieFinishedCallback:(NSNotification*)aNotification
{
MPMoviePlayerController* theMovie=[aNotification object];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:theMovie];
[theMovie release];
[movieURL release];
[movieFinishedCallbackDelegate performSelector:movieFinishedCallbackSelector];
}
You probably need to present theMovie:
[self presentMoviePlayerViewControllerAnimated:theMovie];
And change to:
MPMoviePlayerViewController
in ios 3.2 letter use MPMoviePlayerViewController. it behave like a modelViewcontroller