What I have are 2 links to 2 versions of the same movie, one in lower definition the other in higher, both .mp4 format.
It plays the low-def just fine, but when I click the link for the HD version the movie player pops up like it should then dismisses itself back to the original view controller. If I click it again, it works, but the first try usually fails. Like something with threading is going on and succeeding or not. From what I've read it's an issue with ARC but I can't seem to get it right.
I want to use the MPMoviePlayerViewController because I like how it by default acts as a modal popup. I tried with a MPMoviePlayerController but you have to set the view then handle rotations it seems.
I'm not getting any crashes or any warnings in the log inside Xcode either.
Here's my code:
#interface VideoInfoViewController ()
#property (nonatomic, strong) MPMoviePlayerController *player;
#end
- (IBAction)playLowVideo:(id)sender {
[self playVideoFromURL:[NSURL URLWithString:_video.video_url_low]];
}
- (IBAction)playHDVideo:(id)sender {
[self playVideoFromURL:[NSURL URLWithString:_video.video_url_HD]];
}
- (void)playVideoFromURL:(NSURL *)url {
MPMoviePlayerViewController *playerViewController = [[MPMoviePlayerViewController alloc] initWithContentURL:url];
_player = playerViewController.moviePlayer;
_player.scalingMode = MPMovieScalingModeFill;
[_player prepareToPlay];
[self presentMoviePlayerViewControllerAnimated:playerViewController];
}
ETA:
found this tutorial: http://josebolanos.wordpress.com/2011/09/28/dismissing-mpmovieplayerviewcontroller-the-right-way/
- (void)playVideoFromURL:(NSURL *)url {
MPMoviePlayerViewController *player = [[MPMoviePlayerViewController alloc] initWithContentURL:url];
[self presentModalViewController:player animated:YES];
[player.moviePlayer prepareToPlay];
[player.moviePlayer play];
}
still doesn't work.
Related
I'm trying to get a basic movie to play in an iPhone app; however, I can't seem to get it to work. Here's my entire code:
#import <MediaPlayer/MediaPlayer.h>
#import "ViewController.h"
#implementation ViewController
- (IBAction)playMoviePressed:(id)sender
{
NSURL *url = [NSURL URLWithString:#"http://www.ebookfrenzy.com/ios_book/movie/movie.mov"];
MPMoviePlayerController *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];
[moviePlayer prepareToPlay];
[moviePlayer play];
}
#end
I have one button on screen that calls playMoviePressed when it is tapped. I know that this method is getting called. I have also tried this with .mov and .mp4 local files that I have dragged into xcode.
I got your code to play the video by adding a frame for it:
[moviePlayer.view setFrame:CGRectMake(0, 0, 320, 200)];
However the video was choppy but that could be my internet connection though. Seeing that you're using an IBAction, you're probably using Interface Builder or Storyboard so the only thing that I can think that's preventing it from playing is that you're missing the connection to the IBOutlet.
If you want a full screen mode, you can simply use MPMoviePlayerViewController and do something like:
MPMoviePlayerViewController* viewController = [[MPMoviePlayerViewController alloc] initWithContentURL:url];
[self presentMoviePlayerViewControllerAnimated:viewController];
I figured it out. My problem was really dumb. Because I am not maintaining a strong pointer to my MPMoviePlayerViewController, it gets deallocated as soon as the method ends. A simple #property in the interface solves this.
I have a problem using MPMoviePlayerViewController. I'm trying to initialize the movie on viewDidLoad and then play the movie on touchesBegan. But the movie initially starts playing and on touchesBegan it only shows the finished movie.
ViewController.h file
#interface ViewController : UIViewController{
MPMoviePlayerController *moviePlayer;
MPMoviePlayerViewController *mpviewController;
MPMovieControlStyle controlStyle;}
- (IBAction)touchesBegan:(id)sender;
#property (nonatomic) MPMovieControlStyle controlStyle;
#end
ViewController.m
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[self.view addSubview:mpviewController.view];
[moviePlayer play]; }
- (void)viewDidLoad
{
NSString *movpath = [[NSBundle mainBundle]
pathForResource:#"my_moviefile"
ofType:#"m4v"];
mpviewController =
[[MPMoviePlayerViewController alloc]
initWithContentURL:[NSURL fileURLWithPath:movpath]];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(movieFinishedCallback:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:mpviewController];
MPMoviePlayerController *mp = [mpviewController moviePlayer];
// [mp setMovieControlMode:MPMovieControlModeHidden];
// [mp.view setFrame:CGRectMake(0, 0, 250, 263)];
mp.controlStyle = MPMovieControlStyleNone;
[mp prepareToPlay];
[super viewDidLoad];
}
If I put all the code in touchesBeganit works as expected, but the movie still has to load, but I want to preload it and then do something again when it finished playing.
Any clues?
Regards
Consider putting your [super viewDidLoad] at the top of your viewDidLoad implementation. This often causes unpredictable problems.
Also, just try adding [mp pause] and mp.currentPlaybackTime = 0; at the end of viewDidLoad.
Make sure you set MPMoviePlayerController's property shouldAutoplay to NO when initializing the player.
From the Reference:
shouldAutoplay
A Boolean that indicates whether a movie should begin playback automatically.
#property (nonatomic) BOOL shouldAutoplay
Discussion
The default value of this property is YES. This property determines
whether the playback of network-based content begins automatically
when there is enough buffered data to ensure uninterrupted playback.
Availability
Available in iOS 3.2 and later.
Declared In
MPMoviePlayerController.h
I have a small UIView that displays a repeated movie. When the user taps a button another movie is loaded and displayed in the same UIView.
The problem is that there is a half second "flash" between the removing of the first movie and the displaying of the second. Is there any to remove this?
- (void) setUpMovie:(NSString*)title {
NSString *url = [[NSBundle mainBundle] pathForResource:title ofType:#"mp4"];
MPMoviePlayerController *player = [[MPMoviePlayerController alloc] initWithContentURL:[NSURL fileURLWithPath:url]];
[[player view] setFrame:self.movieView.bounds];
[self.movieView addSubview:player.view];
if ([title isEqualToString:#"Bo_idle_02"]) {
[player setRepeatMode:MPMovieRepeatModeOne];
} else {
[player setRepeatMode:MPMovieRepeatModeNone];
}
[player setControlStyle:MPMovieControlStyleNone];
[player play];
}
- (void) startDanceAnimation { [self setUpMovie:#"Bo_dance_02"]; return; }
I managed to get my movies changing without the white flash using the AVFoundation as suggested previously. sudo code below, hope it helps someone :)
Apples reference docs can be found here and I used them to get most of my information:
http://developer.apple.com/library/ios/#documentation/AudioVideo/Conceptual/AVFoundationPG/Articles/00_Introduction.html#//apple_ref/doc/uid/TP40010188-CH1-SW3
The first thing I did was to add the following class, called PlayerView (can't remember where I got it sorry) to my project. Its a subclass of UIView and its the view that the movie will be displayed in. Once you add it to your project open UI Builder, add a new view to an existing xib and change its class to PlayerView. Connect this using an IBOutlet. Again remember this is the view that will display the movie.
PlayerView.h
#import
#import
#import
#interface PlayerView : UIView {
AVPlayer *player;
}
#property (nonatomic,retain) AVPlayer *player;
#end
PlayerView.m
#import "PlayerView.h"
#implementation PlayerView
#synthesize player;
+ (Class)layerClass {
return [AVPlayerLayer class];
}
- (AVPlayer*)player {
return [(AVPlayerLayer *)[self layer] player];
}
- (void)setPlayer:(AVPlayer *)player {
[(AVPlayerLayer *)[self layer] setPlayer:player];
}
- (void) dealloc {
[super dealloc];
[player release];
}
#end
In the ViewContoller that displays the movies I have the following:
DisplayMovies.h
#import
#import
#class PlayerView;
#interface DisplayMovies : UIViewController {
IBOutlet AVPlayer *player;
AVPlayerItem *movieOneItem;
AVPlayerItem *movieTwoItem;
}
#property (nonatomic, retain) AVPlayer *player;
#property (retain) AVPlayerItem *movieOneItem;
#property (retain) AVPlayerItem *movieTwoItem;
DisplayMovies.m
#implementation DisplayMovies
#synthesize player, movieOneItem, movieTwoItem;
- (void)viewDidLoad {
// load the two movies
NSURL *movieOneItemURL = [[NSBundle mainBundle] URLForResource:#"movieOne" withExtension:#"mp4"];
AVURLAsset *movieOneItemAsset = [AVURLAsset URLAssetWithURL:movieOneItemURL options:nil];
self.movieOneItem = [AVPlayerItem playerItemWithAsset:movieOneItemAsset];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(movieOneItemDidReachEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:self.movieOneItem];
NSURL *movieTwoItemURL = [[NSBundle mainBundle] URLForResource:#"movieTwo" withExtension:#"mp4"];
AVURLAsset *movieTwoItemAsset = [AVURLAsset URLAssetWithURL:movieTwoItemURL options:nil];
self.movieTwoItem = [AVPlayerItem playerItemWithAsset:movieTwoItemAsset];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(movieTwoItemDidReachEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:self.movieTwoItem];
[self.player play];
}
- (void) movieOneItemDidReachEnd:(NSNotification*)notification {
// play movie two once movie one finishes
[self.player seekToTime:kCMTimeZero];
[self.player replaceCurrentItemWithPlayerItem:self.movieTwoItem];
[self.player play];
}
- (void) movieTwoItemDidReachEnd:(NSNotification*)notification {
// play movie one once movie two finishes
[self.player seekToTime:kCMTimeZero];
[self.player replaceCurrentItemWithPlayerItem:self.movieOneItem];
[self.player play];
}
The solution posted above didn't work for me. I was still getting short flashes between tracks. I was able to solve the problem by creating two views each with its own AVPlayer. I set them both playing and then switch between them by hiding the top view. This got rid of the flash, and I was able to animate a transition between the two tracks by hiding the top view by setting its alpha to 0.0 instead of using setHidden. Here is my code:
AVPlayerItem *theAsset = [self generatePlaylistAssetWithVideoOne]; //In my app this returns an AVPlayer Item
layerView1 = [[VideoLayerView alloc] initWithFrame:CGRectMake(-50, 0, 580, 320)]; //VideoLayerView is a subclass of UIView with the video layer stuff added in.
[layerView1 setPlayer:thePlayer];
[thePlayer play];
[self.view addSubview:layerView1];
AVPlayerItem *theAsset2 = [self generatePlaylistAssetWithVideoTwo];
[thePlayer2 setActionAtItemEnd:AVPlayerActionAtItemEndNone];
layerView2 = [[VideoLayerView alloc] initWithFrame:CGRectMake(-50, 0, 580, 320)];
[layerView2 setPlayer:thePlayer2];
[thePlayer2 play];
[self.view addSubview:layerView2];
Then to animate between the videos I used:
if (water) //Water is a BOOL set up earlier in the file
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
///DO STUFF
[layerView2 setAlpha:0];
[UIView commitAnimations];
water = NO;
}
else
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
///DO STUFF
[layerView2 setAlpha:1.0];
[UIView commitAnimations];
water = YES;
}
To change the videos, you just need to set the hidden view to start playing what you want and then do the switch after the flash.
I still have to come back to this project but I have received some more advice. I will be back working on this project in hopefully two weeks so I will let ye know which solution worked (fingers crossed) for me. In the mean time here's my options:
1.
You won't be able to use MPMoviePlayerController to switch the movie without a flash.
As an alternative, you can use AV Foundation. The AVPlayer -replaceCurrentItemWithPlayerItem: method will seamlessly transition from the old player item to the new one without flashes.
For more information about programming with AV Foundation, see the "AV Foundation Programming Guide" which you can find here:
http://developer.apple.com/library/ios/documentation/AudioVideo/Conceptual/AVFoundationPG/
2.
You can merge all your movies into a single (large) movie, then use the MPMediaPlayback currentPlaybackTime / endPlaybackTime properties to "select" and play the desired movie (within the large movie). If you use this technique you'll also need to make sure there's a key frame at the point in time where the new movie starts.
3.
Alternately, create a single MPMoviePlayerController object, use the -setContentURL: to set the new movie URL, and take advantage of the backgroundView property to make a more seamless transition. The backgroundView is automatically sized with the view property, but it will be hidden before the movie is preloaded. You can put a black view behind both movie views, and then make the backgroundView's backgroundColor = black, which should make it appear more seamless.
Hope this helps.
Find solution here http://joris.kluivers.nl/blog/2010/01/04/mpmovieplayercontroller-handle-with-care/ from iOS 6 you need to use [self.moviePlayer prepareToPlay]; and catch MPMoviePlayerReadyForDisplayDidChangeNotification to use [self.moviePlayer play];
I'm probably missing something really obvious.
I've included <MediaPlayer/MediaPlayer.h> and have this code:
NSURL *videoURL = [NSURL fileURLWithPath:pathToFile];
MPMoviePlayerViewController *mediaPlayer = [[MPMoviePlayerViewController alloc] initWithContentURL:videoURL];
[self presentMoviePlayerViewControllerAnimated:mediaPlayer];
mediaPlayer.view.backgroundColor = [UIColor blackColor];
[mediaPlayer release];
But the video won't play. I copied the code from another place where the video works perfectly.
pathToFile is correct becuase the variable is used in previous lines to move the video from the resources folder to the documents directory.
Any ideas why it might not be working?
Thanks
You can use following code except to presentMoviePlayerViewControllerAnimated
NSString *movieFile=[[NSBundle mainBundle] pathForResource:#"movie" ofType:#"m4v"];
moviePlayer= [[MPMoviePlayerController alloc] initWithContentURL:url];
moviePlayer.view.frame = self.view.frame;
[self.view addSubview:moviePlayer.view];
[moviePlayer setFullscreen:YES animated:YES];
this works fine for me.
I don't think presentMoviePlayerViewControllerAnimated retains its receiver, so it looks as though you're releasing your movie player too early. You could try making mediaPlayer a retained property:
#interface MyClass : SuperClass {
MVMoviePlayerViewController *mediaPlayer;
}
#property (nonatomic, retain) MVMoviePlayerViewController *mediaPlayer;
#end
#implementation MyClass
#synthesize mediaPlayer;
// rest of class implementation here...
#end
Then initialise as so:
self.mediaPlayer = [[[MPMoviePlayerViewController alloc]
initWithContentURL:videoURL] autorelease];
And release afterwards with:
self.mediaPlayer = nil;
(To write code that happens after the video has finished playing, check out the MPMoviePlayerPlaybackDidFinishNotification notification.)
Also bear in mind that presentMoviePlayerViewControllerAnimated first appeared in iOS 3.2, so this code won't work on earlier iOS versions. But I don't think that's the problem in this case.
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];
}