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!
Related
My app has to be work in Ios5 and later Versions. I am adding MPMoviePlayerViewController to mainWindow When clicking on a button.the Done button of moviePlayerController is not removing the moviePlayerController from window.
My code is
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle]
pathForResource:#"001 ATSW" ofType:#"m4v"]];
self.player = [[MPMoviePlayerViewController alloc]
initWithContentURL:url];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(videoPlayBackDidFinish:) name:MPMoviePlayerPlaybackDidFinishNotification object:nil];
[self.player.view setFrame:[UIScreen mainScreen].bounds];
[[[UIApplication sharedApplication] keyWindow] addSubview:self.player.view];
[[self.player moviePlayer] play];
}
-(void)videoPlayBackDidFinish:(NSNotification*)notification {
[[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerPlaybackDidFinishNotification object:nil];
[self.player.moviePlayer stop];
self.player = nil;
[self.player.view removeFromSuperview];
}
How to remove the moviePlayerController on clicking the Done Button.
Any help please.
As stated in the documentation:
To dismiss a modally presented movie player view controller, call the dismissMoviePlayerViewControllerAnimated method.
As with other preconfigured controllers by Apple (such as the mail compose controller or image picker controller), you are responsible to dismiss the controller.
What you'll probably need to do is to actually using the
presentMoviePlayerViewControllerAnimated:(MPMoviePlayerViewController *)playerVC
method to present the MPMoviewPlayerViewController, and not inserting the view directly. As MPMoviewPlayerViewController is trying to dismiss itself when pressing the done button. And from what I can see there's no good way to listen for that and do it like when the movie finishes.
It might depend on how your app is built, but with something like
[[[[UIApplication sharedApplication] keyWindow] rootViewController] presentMoviePlayerViewControllerAnimated:player];
You should be able to replace all of the code to insert a view maualy, and then just using
[[[[UIApplication sharedApplication] keyWindow] rootViewController] dismissMoviePlayerViewControllerAnimated];
I have an iPhone app which runs in portrait mode only. But I want to make mpmovieplayer to play video in landscape mode only.
How can I achieve that?
Here is the code.
NSString *path = [[NSBundle mainBundle] pathForResource:lblVideoName.text ofType:#"mp4" inDirectory:nil];
NSURL *url = [[NSURL alloc] initFileURLWithPath:path];
NSLog(#"URL== %#",url);
moviePlayer = [[MPMoviePlayerController alloc]
initWithContentURL:url];
moviePlayer.controlStyle = MPMovieControlStyleDefault;
moviePlayer.shouldAutoplay = YES;
[self.view addSubview:moviePlayer.view];
[moviePlayer setFullscreen:YES animated:YES];
You can present the movie in it's own view controller that's setup for landscape.
// in the VC where the user indicates he wants to see a movie...
- (void)startTheMovie {
// run a storyboard segue with a modal transition, or ...
MyMovieVC *movieVC = [[MyMovieVC alloc] initWithNibName:#"MyMovieVC" bundle:nil];
[self presentModalViewController:movieVC animated:YES];
}
// in MyMovieVC
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft) ||
(interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
// and the code that you wrote on view will appear
You can include a dismiss button in this interface, or, the youtube way is to have it dismiss itself. You can do that by subscribing to the finished notification:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayerFinished:)
name:MPMoviePlayerPlaybackDidFinishNotification object:nil];
then, on the finished message
- (void)moviePlayerFinished:(NSNotification*)notification {
[self dismissModalViewControllerAnimated:YES];
}
Note, if you're doing this in a tabbed interface, all the tabs - even the ones not visible - need to agree to let the interface turn landscape. This makes some sense but has caused me heartache in the past. I don't have a pretty solution to this. My approach has been a publicly accessible BOOL isLandscapeOK on my AppDelegate. This MovieVC would set it to YES, and the other tab VCs would answer portrait or landscape if isLandscapeOK==YES.
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.
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];
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.