Pause video upon applicationWillResignActive and Play upon applicationDidBecomeActive - iphone

Okay, my code plays a movie fullscreen with no controls for the user, (basically a cinematic). After the movie is done my NSNotification fires and loads a view.
However, when the user hits the home button during one of these movies, it pauses, but there is no way to get it to play again, since I took away the controls. I tried putting [playerController play] and [playerController shouldAutoplay] in my AppDelegate.m under applicationDidBecomeActive, but it's not defined there so it doesn't know what playerController is.
Can anyone help me properly pause and play this video if a user gets a text or hits the home button?
-(IBAction)playMovie:(id)sender {
NSString *movieUrl = [[NSBundle mainBundle] pathForResource:#"Initiate" ofType:#"m4v"]; playerController = [[MPMoviePlayerController alloc] initWithContentURL:[NSURL fileURLWithPath:movieUrl]];
[playerController.view setFrame: self.view.bounds];
[self.view addSubview:playerController.view];
playerController.controlStyle = MPMovieControlStyleNone;
[playerController shouldAutoplay];
[playerController play];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playbackFinished:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:playerController];
}
- (void)playbackFinished:(NSNotification*) notification {
playerController = [notification object];
[[NSNotificationCenter defaultCenter]
removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:playerController];
ViewController *viewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
viewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:viewController animated:YES];
EDIT:
Header
//ViewController.h
#interface ViewController : UIViewController {
MPMoviePlayerController *playerController;
}
Implementation
//ViewController.m
playerController = [[MPMoviePlayerController alloc] initWithContentURL:[NSURL fileURLWithPath:movieUrl]];
AppDelegate *sharedAppDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
sharedAppDelegate.pointer = playerController;

when implementing your player, send all necessary pointers to app delegate:
AppDelegate *sharedAppDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
sharedAppDelegate.yourPointer = yourPlayer;
use this methomd from appDelegate.m:
- (void)applicationWillResignActive:(UIApplication *)application
{
/*
Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
*/
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
/*
Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
*/
}

Related

MovieFinishedCallback notification not firing

I'm trying to create an app that displays an info page once a video stops playing. I've looked at a similar question posted here and tried to implement it but it still doesn't work. I put an NSLog in the movieFinishedCallback method but that never came up so I'm guessing it doesn't even get called. Can someone help me figure it out?
Here's my implementation code...
-(IBAction)playvideo {
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle]
pathForResource:#"sample" ofType:#"mov"]];
MPMoviePlayerViewController *playercontroller = [[MPMoviePlayerViewController alloc]
initWithContentURL:url];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(movieFinishedCallback:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:playercontroller];
[self presentMoviePlayerViewControllerAnimated:playercontroller];
playercontroller.moviePlayer.movieSourceType = MPMovieSourceTypeFile;
[playercontroller.moviePlayer play];
playercontroller = nil;
}
- (void) movieFinishedCallback:(NSNotification*) notification {
NSLog (#"The video ended");
MPMoviePlayerController *player = [notification object];
[[NSNotificationCenter defaultCenter]
removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:player];
player = nil;
View2 *second =[[View2 alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:second animated:YES];
}
I think you're probably getting called back when movie is finished, but failing when presenting View2.
Is View2 a subclass of UIViewController? I can't see how you'll get a valid result by passing nil to initWithNibName:. I'd suggest an NSLog in movieFinishedCallback to prove you get there. Then NSLog(#"second = %#", second); My guess is that's nil.
The fix is to load a view controller for real, either using a valid nib or from your storyboard...
// #"MainStoryboard" should be the name of the storyboard containing your VC
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
// #"SomeViewController" has to be set on the attributes inspector of the VC
// in the storyboard
SomeViewController *newVC = [storyboard instantiateViewControllerWithIdentifier:#"SomeViewController"];
[self presentModalViewController:newVC animated:YES];
FINALLY made it work! I don't know if it has to do with the fact that MPMoviePlayerViewController doesn't respond to the NSNotificationCenter but I used MPMoviePlayerController instead to display my video, registered the notification for movieFinishedCallback and then used the movieFinishedCallback method to switch views. See this tutorial for video play http://www.techotopia.com/index.php/Video_Playback_from_within_an_iOS_5_iPhone_Application. Only thing is, now the video won't rotate to landscape!

Extremely weird behavior of navigationBar and MPMoviePlayerController. Bug in iOS or my error?

I have a MPMoviePlayerController object that plays a video fullscreen in either portrait or landscape. If I rotate orientation while the video is playing and do the rotation within a few seconds after the video starts playing and the video status bar is visible, when the video ends my navigation bar is perfect. But if I wait until the video status bar disappears a few seconds into the video playing and then rotate orientation, when the video ends my navigationBar is partially hidden behind the status bar, like pushed up.
Have you ever seen something like this?
I am able to recreate this bug easily. I created a new Single View App and simply added a button and a navigation bar. If I rotate orientation while video is playing, tap to enable fullscreen and the video status bar is still visible, when the video finishes, all is good. But, if I wait to rotate after the video status bar disappears, when I rotate and the video finishes, the navigationBar is under the status bar. See image:
iPhone Image
Here is the simple code I am using:
- (void) playMovie {
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource: #"movie" 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: YES];
- (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];
}
Here is where I am currently at with the suggestions given below. I must have something wrong because unfortunately I still have the same problem.
Here is the method onPlayerWillExitFullScreen
UIView *view = [[[UIApplication sharedApplication] delegate].window.subviews lastObject];
if (view) {
[view removeFromSuperview];
[[[UIApplication sharedApplication] delegate].window addSubview:view];
}
MPMoviePlayerController *player = [aNotification object];
[[NSNotificationCenter defaultCenter] removeObserver: self
name: MPMoviePlayerWillExitFullscreenNotification
object: player];
and here is my current playMovie method:
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource: #"movie" ofType: #"mov"]];
moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL: url];
[[NSNotificationCenter defaultCenter] addObserver: self
selector: #selector(moviePlayBackDidFinish:)
name: MPMoviePlayerPlaybackDidFinishNotification
object: moviePlayer];
[[NSNotificationCenter defaultCenter]addObserver: self
selector: #selector(onPlayerWillExitFullScreen:)
name: MPMoviePlayerWillExitFullscreenNotification
object: self.moviePlayer];
moviePlayer.controlStyle = MPMovieControlStyleDefault;
moviePlayer.shouldAutoplay = YES;
[self.view addSubview: moviePlayer.view];
[moviePlayer setFullscreen: YES animated: YES];
Ok, so I found this freaking same bug all over my app first in a UIWebView then in a MPMoviePlayerController, I solved this placing this code in my view controller.
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
[self.navigationController setNavigationBarHidden:YES animated:YES];
[self.navigationController setNavigationBarHidden:NO animated:YES];
}
Tricky bugs, tricky fixes.
If you listen for the MPMoviePlayerWillExitFullscreenNotification notification, you can force your main views to redraw properly as follows. The 'window' referenced is your application's main UIWindow object.
When MPMoviePlayerController switched to fullscreen, it actually creates a separate UIWindow instance to present the video. By catching the notification as it transitions back, this code will ensure the views you're switching back to correctly realign.
Admittedly, this is not an elegant solution, but it does work every time.
UIView *view = [window.subviews lastObject];
if (view) {
[view removeFromSuperview];
[window addSubview:view];
}
To listen for this notification, you'll need to do something like this, where self.playerController is your MPMoviePlayerController object.
Remember to stop listening for this notification once you release the player though!
// Determine the default notification centre
NSNotificationCenter *centre = [NSNotificationCenter defaultCenter];
// Listen for interesting movie player notifications
[centre addObserver: self
selector: #selector(onPlayerWillExitFullScreen:)
name: MPMoviePlayerWillExitFullscreenNotification
object: self.playerController];
- (void) moviePlayerWillExitFullScreen:(id)sender {
[[UIApplication sharedApplication]setStatusBarHidden:NO withAnimation:NO];
}
Guys try this... It works for me. I tried many other ways and only this one worked.

MPMoviePlayerViewController called from UITabBarController doesn't send notifications in IOS5

I had an app that worked fine in IOS4 but stopped displaying videos in IOS5. Previously I was using MPMoviePlayerController, so I switched to MPMoviePlayerViewController and now the videos display fine in IOS5.
But, now in IOS5, when the Done button is pressed the video stops playing in MPMoviePlayerViewController, but the MPMoviePlayerController no longer calls Notifications.
The hierarchy looks like:
AppDelegate -> UITabBarController -> UITableView -> UIViewController within which the MPMoviePlayerViewController is called. Inside the UIViewController the code looks like:
MPMoviePlayerViewController *tmpMoviePlayer = [[MPMoviePlayerViewController alloc] initWithContentURL:movieURL];
self.moviePlayer = tmpMoviePlayer;
[self presentMoviePlayerViewControllerAnimated:self.moviePlayer];
NSNotificationCenter *notificationCenter = [ NSNotificationCenter defaultCenter ];
[notificationCenter addObserver:self
selector:#selector(moviePlayerPlaybackDidFinish:)
name:MPMoviePlayerWillExitFullscreenNotification
object:[self.moviePlayer moviePlayer ]];
I've also tried the following notification names and none of them get triggered:
MPMoviePlayerPlaybackDidFinishNotification
MPMoviePlayerPlaybackStateDidChangeNotification
MPMoviePlayerPlaybackDidFinishReasonUserInfoKey
MPMoviePlayerNowPlayingMovieDidChangeNotification
MPMoviePlayerWillExitFullscreenNotification
MPMoviePlayerDidExitFullscreenNotification
I have seen a SO posting where the MPMoviePlayerViewController was called from within a UITabBarController and the view that called presentMoviePlayerViewControllerAnimated wasn't selected correctly, but I haven't been able to get any other view to work for calling presentMoviePlayerViewControllerAnimated.
Any ideas why the notifications are no longer called when the Done button of MPMoviePlayerViewController is pressed?
I did solve this but I can't remember what the fix actually was. But I can show the code that works now:
[ notificationCenter addObserver: self
selector:#selector(moviePlayerPlaybackDidFinish:)
name: MPMoviePlayerPlaybackDidFinishNotification
object: moviePlayer ];
self.moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:movieURL];
self.moviePlayer.shouldAutoplay = NO;
[self.moviePlayer setControlStyle:MPMovieControlStyleFullscreen];
[[self view] addSubview:[self.moviePlayer view]];
[self.moviePlayer setFullscreen:YES animated:YES];
[self.moviePlayer play];

Release MPMoviePlayer when using a tabbarcontroller

I'm using a tabbarcontroller in which one of the views has an MPMoviePlayer. It works fine, except that if I change tab, the movie doesn't stop and keeps playing in the background. Then if I try to tab back to the movie tab, it crashes.
I think the only code I have to release the MPMoviePlayer is when it's finished playing, but I want it to be released when I change views instead. Then if I go back to the Movie tab, we start fresh.
In my .h file have set up as:
import < UIKit/UIKit.h>
import < MediaPlayer/MediaPlayer.h>
#interface SecondViewController : UIViewController {
MPMoviePlayerController *player;
}
#end
and in my .m file have:
- (void)viewDidLoad {
NSString *url = [[NSBundle mainBundle]
pathForResource:#"vid"
ofType:#"m4v"];
player = [[MPMoviePlayerController alloc]
initWithContentURL:[NSURL fileURLWithPath:url]];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(movieFinishedCallback:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:player];
//--called when the movie view and then add it to the View window--
player.view.frame = CGRectMake(10, 10, 300, 300);
[self.view addSubview:player.view];
//--play movie--
[player pause];
[super viewDidLoad];
}
//--called when the movie is done playing--
- (void) movieFinishedCallback:(NSNotification*) aNotification {
MPMoviePlayerController *moviePlayer = [aNotification object];
[[NSNotificationCenter defaultCenter]
removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:moviePlayer];
[moviePlayer.view removeFromSuperview];
[player release];
}
Any suggestions? Thank you :)
If you really want to release MPMoviePlayer at tab switch, then do it in viewWillDisappear or viewDidDisappear. Now it's left alive at background, as you described. When you come back to tab, you try to create it again.
Difficult to say what would be the exact reason for crash, there seems to be several possibilities. Next time write a "Why did this crash" question with a call stack.
Maybe you could think about just pause/resume, so you wouldn't need to reallocate new moviePlayer every time user changes tabs? Do alloc/release in viewDidLoad and viewDidUnload, but play/pause in viewWillAppear and viewWillDisappear.

Playing video in custom size screen - view in iPhone

Suppose user taps on a button and video begins to play. Now when video plays, it always in full screen mode.
Video should be played in a portrait mode (but normally video is played in landscape mode). How can I do this?
Just an update, the latest iPhone SDK 3.2+ will now allow the programmers to show the video in any desired size and Orientation, New MPMoviePlayerView is provided, which is a property of MPMoviePlayerController, this view will have the video, which you can add as a subview to your view.
#interface MPMoviePlayerController (extend)
-(void)setOrientation:(int)orientation animated:(BOOL)value;
#end
moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:movieUR];
[moviePlayer setOrientation:UIDeviceOrientationPortrait animated:NO];
if (moviePlayer)
{
[self.moviePlayer play];
}
This Solution will be rejected by Apple, as setOrientation for movie player is the Private API. You need to be careful, but it may work on Jailbroke iPhones.
From the documented docs i do not think this is possible using the built in media player
Try this out.
I found something new.
#interface MPMoviePlayerController (extend)
-(void)setOrientation:(int)orientation animated:(BOOL)value;
#end
moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:movieUR];
[moviePlayer setOrientation:UIDeviceOrientationPortrait animated:NO];
if (moviePlayer)
{
[self.moviePlayer play];
}
Here's what I did. Add NSNotification to notify you when preloading of the video finishes.
- (void)playVideoUrl:(NSString *)videoUrl {
NSURL *url = [NSURL URLWithString:videoUrl];
MPMoviePlayerController* theMovie=[[MPMoviePlayerController alloc]
initWithContentURL:url];
[[NSNotificationCenter defaultCenter] addObserver:self
//MPMoviePlayerContentPreloadDidFinishNotification
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(myMovieFinishedPreloading:)
name:MPMoviePlayerContentPreloadDidFinishNotification
object:theMovie];
// Movie playback is asynchronous, so this method returns immediately.
[theMovie play];
}
Callback selector:
-(void)myMovieFinishedPreloading:(NSNotification*)aNotification {
NSArray *windows = [[UIApplication sharedApplication] windows];
UIWindow *moviePlayerWindow = nil;
if ([windows count] > 1)
{
moviePlayerWindow = [[UIApplication sharedApplication] keyWindow];
}
CGAffineTransform transform = CGAffineTransformMakeScale(0.5, 0.5);
transform = CGAffineTransformRotate(transform, -90.0f*M_PI/180.0f);
[moviePlayerWindow setTransform:transform];
}