iPhone app : MPMoviePlayer: PlayVideo in Landscape mode only - iphone

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.

Related

How can I make a video display in Landscape mode on iOS 5?

I'm having a very strange problem. I want a video to appear in landscape mode, but I can't seem to make it work. Even if I can't make it always show Landscape, at least I want it to show ok, and I can't make that either!! Here is my code:
#import "SplashViewController.h"
#import "MainViewController.h"
#import "MediaPlayer/MediaPlayer.h"
#interface SplashViewController ()
#property (nonatomic, retain) NSTimer *timer;
#end
#implementation SplashViewController
#synthesize timer = _timer;
-(BOOL)shouldAutorotateToInterfaceOrientation:UIInterfaceOrientation)toInterfaceOrientation
{
return YES;
}
- (id)init
{
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
self = [self initWithNibName:#"SplashViewController_iPhone" bundle:nil];
} else {
self = [self initWithNibName:#"SplashViewController_iPad" bundle:nil];
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self.navigationController setNavigationBarHidden:YES];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewWillAppear:animated];
NSString *url = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"intro.mp4"];
playerViewController = [[MPMoviePlayerViewController alloc] initWithContentURL:[NSURL fileURLWithPath:url]];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(movieFinishedCallback:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:[playerViewController moviePlayer]];
[playerViewController shouldAutorotateToInterfaceOrientation: UIInterfaceOrientationLandscapeRight];
[self.view addSubview:playerViewController.view];
//play movie
MPMoviePlayerController *player = [playerViewController moviePlayer];
player.scalingMode = MPMovieScalingModeAspectFill;
[player play];
}
- (void) movieFinishedCallback:(NSNotification*) aNotification {
MPMoviePlayerController *player = [aNotification object];
[[NSNotificationCenter defaultCenter]
removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:player];
[player stop];
[player.view removeFromSuperview];
[self loadMainView];
}
- (void)loadMainView
{
MainViewController *mainVC = [[MainViewController alloc] init];
[self.navigationController pushViewController:mainVC animated:YES];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#end
And here comes the weirdness...
If I start the app with my iPad physically in Landscape Mode, the video shows like this (please not that the bar at the top is shorter than the widht! :O)
If I then rotate the iPad to Portrait, it looks like this:
But then, if I start the app with my iPad physically in Portrait Mode, the video shows like this:
And if I then rotate the iPad to Landscape, it looks like this:
Which is GREAT! This final image is what I would like the video to always look like.
Any ideas what I might be doing wrong???
Thanks!
EDIT 1
Ok, with #Tark answer I was able to fix the player display issue. Now it's showing fine no matter how I start the app. Thanks for that!! What is missing now is the always landscape mode.
I tried with the following methods:
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{
return (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft || toInterfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{
return UIInterfaceOrientationIsLandscape(toInterfaceOrientation);
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if (interfaceOrientation==UIInterfaceOrientationLandscapeRight)
return YES;
return NO;
}
I also tried inserting the row
Initial interface orientation = Landscape (right home button)
In the Info.plist
What I'm getting is that if I start the app in Landscape mode, if I rotate the iPad to Portrait, it stays in Landscape. GREAT!
But if I start the app in Portrait mode, the video shows in Portrait mode. Once I rotate it to Landscape, I can't rotate it back to Portrait, which is good, but I don't want it to start in Portrait!
EDIT 2
Ok, now this is even more weird. If I try it on an iPhone, it works great. No matter if I start the app in Landscape or Portrait, the video is shown always in Landscape.
But if I try it on an iPad, the problem in EDIT 1 arises... :S
Any ideas?
Thanks!
Have you tried setting the frame of the MPMoviePlayerViewControllers view when you add it as a subview?
...
playerViewController.view.frame = self.view.bounds;
[self.view addSubview:playerViewController.view];
...
To make the app only run in landscape mode, you should make sure that you have only selected the orientations you want in the app plist. In Xcode 4 there is a handy Supported Interface Orientations section in the target settings, make sure you only select landscape here. If you still have the issue, you have to make sure that you are disabling autorotation on all visible controllers in the view stack.
shouldAutorotateToInterfaceOrientation is deprecated as of iOS 6, Have you tried using supportedInterfaceOrientations?
If you are trying to support iOS 5 & 6 then I believe you need to use both:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return UIInterfaceOrientationIsLandscape(toInterfaceOrientation);
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscape;
}
I haven't tested this so take it for what it's worth.

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.

MPMoviePlayerController : orientation problem

finally I have to post my problem here. Yes it could be duplicate question here as I have referred many answers regarding to this question.But I could not find any fix. (Also didn't find any question regarding to tab-bar app specific so...) And I don't want to use MPMoviePlayerViewController
I have tab-bar application. In last tab's VC there is a button. On click event I want to start movie player. For that I am using MPMoviePlayerController. Its all fine when orientation is Portrait . But regarding to changes, now I have to play it in landscape mode only.
here is my code :
-(void)playMovie
{
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight];
[self.scrollView addSubview:moviePlayer.view];
[moviePlayer play];
[moviePlayer setFullscreen:TRUE];
}
-(void)btnPlayHandler:(id)sender
{
NSLog(#"btnPlayHandler");
NSURL * videoUrl = [NSURL URLWithString:[NSString stringWithFormat:#"%#",[dictResponse valueForKey:#"VideoPath"]]];
moviePlayer = [[MPMoviePlayerController alloc]initWithContentURL:videoUrl];
//[moviePlayer.view setFrame:CGRectMake(20, 40, 280, 222)];
moviePlayer.fullscreen = YES ;
moviePlayer.shouldAutoplay = NO ;
[self performSelector:#selector(playMovie) withObject:nil afterDelay:1];
}
- (void) movieWillExit:(NSNotification *)notification
{
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait];
}
- (void) movieExit:(NSNotification *)notification
{
[moviePlayer stop];
[moviePlayer.view removeFromSuperview];
moviePlayer = nil ;
[btnPlay setHidden:FALSE];
}
- (void)moviePreLoad:(NSNotification *)notification
{
NSLog(#"moviePreLoad");
}
- (void)moviePlaybackComplete:(NSNotification *)notification
{
NSLog(#"moviePlaybackComplete");
[btnPlay setHidden:FALSE];
}
Only device's orientation is changed not player's view ! How to accomplish this ??? Is it because the tab-bar application ?
You are making the window landscape, but as you have set the MPMoviePlayer view in scrollview, it is not rotating. try to rotate the scrollview according to your orientation.
See this link http://blog.sallarp.com/shouldautorotatetointerfaceorientation/. Hopefully it will solve your problem.

Flipping a Video Horizontally in Xcode

I have a video such that when I play it in full view and flip the simulator horizontally the video would not flip. How can I make the video flip according to the iPhone's accelerometer?
Here is the code for the video if it helps:
- (void)viewDidAppear:(BOOL)animated {
NSBundle *bundle=[NSBundle mainBundle];
NSString *moviePath = [bundle pathForResource:#"MainPageMovie" ofType:#"mp4"];
NSURL *movieURL=[[NSURL fileURLWithPath:moviePath] retain];
MPMoviePlayerController *theMovie = [[MPMoviePlayerController alloc] initWithContentURL:movieURL];
theMovie.scalingMode = MPMovieScalingModeAspectFill;
theMovie.view.frame = CGRectMake(115.0, 156.0, 200.0, 150.0);
[self.view addSubview:theMovie.view];
[theMovie play];
[super viewDidLoad];
self.view.backgroundColor = [UIColor viewFlipsideBackgroundColor];
}
Your MPMoviePlayerController view is added as a subview to another view controller's view. In that parent view controller, have you overridden shouldAutorotateToInterfaceOrientation method?
If you are just looking for landscape (horizontal) rotation, you can have your code as below:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Overriden to allow any orientation.
return ((interfaceOrientation == UIInterfaceOrientationLandscapeLeft) || (interfaceOrientation == UIInterfaceOrientationLandscapeRight));
}
In order to rotate specific subviews of the larger view controller view, (which in your situation would be the case with only rotating the video), you'd have to do CGAffineTransforms. This would allow you to resize a view, rotate it, etc. AFAIK, this is probably the best route to go for rotating a single view.
However, you may want to research more into MPMoviePlayerViewController. Take a look at this post, it seems to address your problem.