MPMoviePlayerViewController exits after background - objective-c

When my app goes to background and back, modal view closes. Why is this happend? I tried with pause on and off. I have ARC enabled, if it is a useful info.
MPMoviePlayerViewController * player = [[MPMoviePlayerViewController alloc] initWithContentURL:targetURL];
[player.moviePlayer prepareToPlay];
[self presentMoviePlayerViewControllerAnimated:player];

In case anyone else stumbles across this (as I did before I found my own solution), I was able to prevent MPMoviePlayerViewController from exiting when the app backgrounds by subclassing it and removing it as an observer of UIApplicationDidEnterBackgroundNotification:
- (id)initWithContentURL:(NSURL *)contentURL {
self = [super initWithContentURL:contentURL];
if (self){
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:nil];
}
return self;
}

You don't need to subclass MPMoviePlayerViewController - just do following after creating MPMoviePlayerViewController instance.
[[NSNotificationCenter defaultCenter] removeObserver:self.moviePlayerViewController name:UIApplicationDidEnterBackgroundNotification object:nil];

Here is full code that can help you
// Call this to start initialization and play movie
-(void)prepareMoviePlayer:(NSURL *)moviePath
{
moviePlayerViewController = [[MPMoviePlayerViewController alloc] initWithContentURL:moviePath];
if ([[moviePlayerViewController moviePlayer] respondsToSelector:#selector(loadState)])
{
[[moviePlayerViewController moviePlayer] setControlStyle:MPMovieControlStyleNone];
[[moviePlayerViewController moviePlayer] setFullscreen:YES];
[[moviePlayerViewController moviePlayer] prepareToPlay];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayerLoadStateDidChange:)
name:MPMoviePlayerLoadStateDidChangeNotification
object:nil];
}
}
- (void) addPlayer
{
[[[moviePlayerViewController moviePlayer] view] setFrame:self.view.bounds];
[[self view] addSubview:[[moviePlayerViewController moviePlayer] view]];
}
static NSTimeInterval t;
// Call this on applicationWillResignActive
-(void) pauseMovieInBackGround
{
[[moviePlayerViewController moviePlayer] pause];
t = [[moviePlayerViewController moviePlayer] currentPlaybackTime];
[moviePlayerViewController.view removeFromSuperview];
}
// Call this on applicationWillEnterForeground
-(void) resumeMovieInFrontGround
{
[self addPlayer];
[[moviePlayerViewController moviePlayer] stop];
[[moviePlayerViewController moviePlayer] setInitialPlaybackTime:t];
[[moviePlayerViewController moviePlayer] play];
}
-(void)moviePlayerLoadStateDidChange:(NSNotification *)notification
{
if([[moviePlayerViewController moviePlayer] loadState] != MPMovieLoadStateUnknown)
{
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerLoadStateDidChangeNotification
object:nil];
[self addPlayer];
[[moviePlayerViewController moviePlayer] play];
}
}
-(void)videoPlayBackDidFinish:(NSNotification*)notification
{
[self dismissMoviePlayerViewControllerAnimated];
}

I am coming across this issue.
I've tried ChrisH's answer, but it didn't work for me until I put removeObserver into viewDidLoad() instead of init().
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:nil];
}
Then it works. Enjoy it.

Related

why isn't removeFromSuperview removing my movie subview? Xcode

I'm trying to get a movie that plays to dismiss on its own without having to hit the "Done" button. I think it's a recent iOS 6 problem since I'm following a tutorial exactly and when I insert NSLogs the NSNotification and removeFromSuperview are being recognized but the movie stays there once it has ended. Here's my code, please help:
- (IBAction)playMovie:(id)sender
{
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle]
pathForResource:#"RomneyFlipSequence1" ofType:#"mov"]];
_moviePlayer =
[[MPMoviePlayerController alloc]
initWithContentURL:url];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayBackDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:_moviePlayer];
_moviePlayer.controlStyle = MPMovieControlStyleDefault;
_moviePlayer.shouldAutoplay = YES;
[self.view addSubview:_moviePlayer.view];
[_moviePlayer setFullscreen:YES animated:NO];
}
- (void) moviePlayBackDidFinish:(NSNotification*)notification {
MPMoviePlayerController *player = [notification object];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:player];
if ([player
respondsToSelector:#selector(setFullscreen:animated:)])
{
[player.view removeFromSuperview];
}
}
#end
You entered the player into fullscreen mode.
[_moviePlayer setFullscreen:YES animated:NO];
Reading other solutions in SO it seems that when you press "Done" the player is taken out of fullscreen first, and then the notification is thrown. After reading this answer, adding
[_moviePlayer setFullscreen:NO animated:YES];
before your removeFromSuperview call will solve your problem.
If the above doesn't work, in addition you may try stoping the player first so the full code will be
-(void)removePlayer:(MPMoviePlayerController *)player{
NSLog(#"Playback Finished");
[[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerPlaybackDidFinishNotification object:_moviePlayer];
[[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerDidExitFullscreenNotification object:_moviePlayer];
[_moviePlayer stop]; // <-- May not be needed
if ([_moviePlayer respondsToSelector:#selector(setFullscreen:animated:)])
{
[_moviePlayer setFullscreen:NO animated:YES];
[_moviePlayer.view removeFromSuperview];
}
_moviePlayer=nil;
}
I use the same method for both notifications "Done" and "PlayBackFinished"
Hope this helps.
You had added _moviePlayer.view as a view and you are trying to remove player.view
i think this will do it :
- (void) moviePlayBackDidFinish:(NSNotification*)notification {
MPMoviePlayerController *player = [notification object];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:player];
if ([player
respondsToSelector:#selector(setFullscreen:animated:)])
{
[_moviePlayer.view removeFromSuperview];
}
}

memory leak during release of movieplayer

In one of my apps i want to play a video file from local.so iam using the below code for playing the file.
-(IBAction)playMovie{
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle]pathForResource:#"Myvideo" ofType:#"mov"]];
MPMoviePlayerController *moviePlayer=[[[MPMoviePlayerController alloc]initWithContentURL:url]autorelease];
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(moviePlayBackDidFinish:) name:MPMoviePlayerPlaybackDidFinishNotification object:moviePlayer];
moviePlayer.controlStyle = MPMovieControlStyleEmbedded;
moviePlayer.shouldAutoplay = YES;
[self.view addSubview:moviePlayer.view];
[moviePlayer setFullscreen:YES animated:YES];
//[moviePlayer release];
}
-(void) moviePlayBackDidFinish:(NSNotification*)notification {
MPMoviePlayerController *moviePlayer = [notification object];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:moviePlayer];
if ([moviePlayer
respondsToSelector:#selector(setFullscreen:animated:)])
{
[moviePlayer.view removeFromSuperview];
}
[moviePlayer release];
}
when i go to analyse or do profile for the above code there shows a warning potential leak happening at 2 places i.e,
[moviePlayer setFullscreen:YES animated:YES];
//[moviePlayer release];
one more is leak is at this part
{
[moviePlayer.view removeFromSuperview];
}
[moviePlayer release]
so how to avoid this memory leak.Even i tried giving autorelease the NSURL Line in the begining of the code,when i do autorelease leak wont happen but video wont play.so how to solve this issue can anyone help??
try this in moviePlayBackDidFinish method, may be it will help
if (videoPlayer) {
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification object:videoPlayer];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerLoadStateDidChangeNotification object:videoPlayer];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMovieMediaTypesAvailableNotification object:videoPlayer];
[videoPlayer pause];
videoPlayer.initialPlaybackTime = -1;
[videoPlayer stop];
[videoPlayer.view removeFromSuperview];
[videoPlayer release];
videoPlayer = nil;
}

MPMoviePlayerController gives endless loop on tapping 'Done'

I try to get a MPMoviePlayerController to work, but have a strange problem. When playing I click the done button and there seems an infinite look triggered:
2012-02-13 15:18:04.395 iDomsPortalDev[7376:12203] playbackFinished.
Reason: User Exited 2012-02-13 15:18:04.395 iDomsPortalDev[7376:12203]
playbackFinished. Reason: User Exited 2012-02-13 15:18:04.395
iDomsPortalDev[7376:12203] playbackFinished. Reason: User Exited
I use the following notifications on starting:
- (void) showMoviePlayer {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(willEnterFullscreen:) name:MPMoviePlayerWillEnterFullscreenNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(willExitFullscreen:) name:MPMoviePlayerWillExitFullscreenNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(enteredFullscreen:) name:MPMoviePlayerDidEnterFullscreenNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(exitedFullscreen:) name:MPMoviePlayerDidExitFullscreenNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(playbackFinished:) name:MPMoviePlayerPlaybackDidFinishNotification object:nil];
id appDelegate = (iDomsAppDelegate *)[[UIApplication sharedApplication] delegate];
//[[self navigationController] presentMoviePlayerViewControllerAnimated:[appDelegate movieController]];
[[appDelegate moviePlayer].view setFrame: self.view.bounds];
[self.view addSubview:[appDelegate moviePlayer].view];
[[appDelegate moviePlayer] setFullscreen:YES animated:YES];
}
and the following listeners:
#pragma mark - Movieplayer feedback
- (void)willEnterFullscreen:(NSNotification*)notification {
NSLog(#"willEnterFullscreen");
}
- (void)enteredFullscreen:(NSNotification*)notification {
NSLog(#"enteredFullscreen");
}
- (void)willExitFullscreen:(NSNotification*)notification {
NSLog(#"willExitFullscreen");
}
- (void)exitedFullscreen:(NSNotification*)notification {
NSLog(#"exitedFullscreen");
iDomsAppDelegate *appDelegate = (iDomsAppDelegate *)[[UIApplication sharedApplication] delegate];
[[appDelegate moviePlayer].view removeFromSuperview];
[[appDelegate moviePlayer] release];
[appDelegate setMovieController:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)playbackFinished:(NSNotification*)notification {
iDomsAppDelegate *appDelegate = (iDomsAppDelegate *)[[UIApplication sharedApplication] delegate];
NSNumber* reason = [[notification userInfo] objectForKey:MPMoviePlayerPlaybackDidFinishReasonUserInfoKey];
switch ([reason intValue]) {
case MPMovieFinishReasonPlaybackEnded:
NSLog(#"playbackFinished. Reason: Playback Ended");
break;
case MPMovieFinishReasonPlaybackError:
NSLog(#"playbackFinished. Reason: Playback Error");
break;
case MPMovieFinishReasonUserExited:
NSLog(#"playbackFinished. Reason: User Exited");
break;
default:
break;
}
[[appDelegate moviePlayer] setFullscreen:NO animated:YES];
}
Only the PlayBackFinished selector is called (infinite times), so there must be something stupid I do (running in the simulator with iOS5)
I found the problem, it seemed to have been setting the fullscreen option which caused it:
[[appDelegate moviePlayer] setFullscreen:YES animated:YES];

MPMoviePlayerController prepareToPlay not working with HTTP Live Streaming

I'm trying to play an HTTP live streaming video using a MPMoviePlayerController object, inside a modal view controller. If I run the code like this, everything works fine. I get a MPMoviePlaybackStatePlaying notification, and the video plays.
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(moviePlayerPlaybackStateDidChange:) name:MPMoviePlayerPlaybackStateDidChangeNotification object:nil];
NSURL *url = [NSURL URLWithString:#"http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8"];
self.moviePlayerController = [[[MPMoviePlayerController alloc] initWithContentURL:url] autorelease];
self.moviePlayerController.view.frame = CGRectMake(0,0,320,416);
self.moviePlayerController.controlStyle = MPMovieControlStyleNone;
self.moviePlayerController.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.view addSubview:self.moviePlayerController.view];
self.moviePlayerController.fullscreen = NO;
[self.moviePlayerController play];
}
I would prefer to use the prepareToPlay method, so that I can show a loading indicator, and for a nicer experience. However, I don't seem to be able to get this working. No MPMoviePlayerPlaybackStateDidChangeNotification ever gets called, and the stream doesn't play. The activity indicator just sits there spinning forever.
I've confirmed that prepareToPlay does get called, but nothing else seems to happen after that. I've also confirmed that this code works fine with a local movie file. It just seems to be with HTTP Live Streaming which fails. Can anyone see what I'm doing wrong?
- (void)viewDidLoad {
[super viewDidLoad];
[self.activityIndicator startAnimating];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(moviePlayerPlaybackStateDidChange:) name:MPMoviePlayerPlaybackStateDidChangeNotification object:nil];
NSURL *url = [NSURL URLWithString:#"http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8"];
self.moviePlayerController = [[[MPMoviePlayerController alloc] initWithContentURL:url] autorelease];
[self registerForMovieNotifications];
}
- (void)registerForMovieNotifications {
//movie is ready to play notifications
if ([self.moviePlayerController respondsToSelector:#selector(loadState)]) {
//this is a 3.2+ device
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(moviePlayerLoadStateChanged:) name:MPMoviePlayerLoadStateDidChangeNotification object:nil];
self.moviePlayerController.movieSourceType = MPMovieSourceTypeStreaming;
[self.moviePlayerController prepareToPlay];
} else {
//pre-3.2 device
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(moviePreloadDidFinish:) name:MPMoviePlayerContentPreloadDidFinishNotification object:nil];
}
//movie has finished notification
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(moviePlayBackDidFinish:) name:MPMoviePlayerPlaybackDidFinishNotification object:nil];
}
- (void) moviePlayerPlaybackStateDidChange:(NSNotification*)notification {
NSLog(#"playbackDidChanged");
MPMoviePlayerController *moviePlayer = notification.object;
MPMoviePlaybackState playbackState = moviePlayer.playbackState;
if(playbackState == MPMoviePlaybackStateStopped) {
NSLog(#"MPMoviePlaybackStateStopped");
} else if(playbackState == MPMoviePlaybackStatePlaying) {
NSLog(#"MPMoviePlaybackStatePlaying");
} else if(playbackState == MPMoviePlaybackStatePaused) {
NSLog(#"MPMoviePlaybackStatePaused");
} else if(playbackState == MPMoviePlaybackStateInterrupted) {
NSLog(#"MPMoviePlaybackStateInterrupted");
} else if(playbackState == MPMoviePlaybackStateSeekingForward) {
NSLog(#"MPMoviePlaybackStateSeekingForward");
} else if(playbackState == MPMoviePlaybackStateSeekingBackward) {
NSLog(#"MPMoviePlaybackStateSeekingBackward");
}
}
//3.2+ devices
- (void)moviePlayerLoadStateChanged:(NSNotification*)notification {
NSLog(#"load state changed");
//unless state is unknown, start playback
if ([self.moviePlayerController loadState] != MPMovieLoadStateUnknown) {
[[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerLoadStateDidChangeNotification object:nil];
self.moviePlayerController.view.frame = CGRectMake(0,0,320,416);
self.moviePlayerController.controlStyle = MPMovieControlStyleNone;
self.moviePlayerController.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.view addSubview:self.moviePlayerController.view];
self.moviePlayerController.fullscreen = NO;
[self.moviePlayerController play];
}
}
//pre 3.2 devices
- (void) moviePreloadDidFinish:(NSNotification*)notification {
// Remove observer
[[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerContentPreloadDidFinishNotification object:nil];
[self.moviePlayerController play];
}
I don't know why, but I was able to solve this by moving the line self.moviePlayerController.controlStyle = MPMovieControlStyleNone; out of the moviePlayerLoadStateChanged: method, and into the viewDidLoad method.
Anyone have any ideas why this made a difference?

How to play video in Objective-C - Causes Jerk when loads

I am developing an application which loads video while the application launches. I observe a huge jerk while the video plays and removes from screen.
My code is as follow:
VideoPlayer.m
-(id)initWithVideo: (CGRect)frame file:(NSString *)videoFile
{
if (self = [super initWithFrame:frame])
{
NSArray *file = [videoFile componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#"."]];
NSString *moviePath = [[NSBundle mainBundle] pathForResource:[file objectAtIndex:0] ofType:[file objectAtIndex:1]];
if (nil != moviePath)
{
if (nil != theMovie)
{
[theMovie.view removeFromSuperview];
}
theMovie = [[MPMoviePlayerViewController alloc] initWithContentURL:[NSURL fileURLWithPath:moviePath]];
theMovie.view.frame = self.bounds;
theMovie.moviePlayer.scalingMode = MPMovieScalingModeAspectFit;
theMovie.moviePlayer.controlStyle = MPMovieControlStyleNone;
theMovie.moviePlayer.movieSourceType = MPMovieSourceTypeFile;
theMovie.moviePlayer.fullscreen = NO;
[self addSubview:theMovie.view];
}
}
return self;
}
Please guide me where I am missing it.
-(void)prepareMoviePlayer:(NSURL *)moviePath {
self.moviePlayerViewController = [[MPMoviePlayerViewController alloc] initWithContentURL:moviePath];
if ([[self.moviePlayerViewController moviePlayer] respondsToSelector:#selector(loadState)]) {
[[self.moviePlayerViewController moviePlayer] setControlStyle:MPMovieControlStyleEmbedded];
[[self.moviePlayerViewController moviePlayer] setFullscreen:NO];
[[self.moviePlayerViewController moviePlayer] prepareToPlay];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayerLoadStateDidChange:)
name:MPMoviePlayerLoadStateDidChangeNotification
object:nil];
}
- (void)moviePlayerLoadStateDidChange:(NSNotification *)notification {
if ([[self.moviePlayerViewController moviePlayer] loadState] == MPMovieLoadStateStalled) {
NSLog(#"Movie Playback Stalled");
} else if([[self.moviePlayerViewController moviePlayer] loadState] != MPMovieLoadStateUnknown) {
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerLoadStateDidChangeNotification
object:nil];
[[[self.moviePlayerViewController moviePlayer] view] setFrame:self.view.bounds];
[[self view] addSubview:[[self.moviePlayerViewController moviePlayer] view]];
[[self.moviePlayerViewController moviePlayer] play];
}
}
The NSMoviePlayerViewController prepareToPlay method seems to be the key here. I also suggest adding other notifications to handle playback completion and playback stopping. Also some of this code is designed to work from a subview of the window.