I am using the MPMoviePlayerController to play some streaming videos of type .m3u from a url. They video player launches perfectly and the video starts playing perfectly as well, but as soon as I press the Seek Forward or Next or beginSeekingForward button the video complete stops/freezes. After that I can click Done to dismiss the player or scrub the progress bar and it will come back to play to video. But the I can't click on the play/pause or at least seems not to do anything.
I have spent quite sometime looking around online for answer or at least a hint so I can tackle this issue in the right direction but not luck. So, I really hope someone could help with this. Btw, this only happens on iOS 8+, currently I am testing it in iOS 8.1.
This is how I create the player and load the video to it.
NSURL *videoURL = [NSURL URLWithString:self.video.flvurl];
self.moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL: videoURL];
self.moviePlayer.controlStyle = MPMovieControlStyleFullscreen;
self.moviePlayer.movieSourceType = MPMovieSourceTypeStreaming;
self.moviePlayer.shouldAutoplay = NO;
self.moviePlayer.fullscreen = YES;
self.moviePlayer.repeatMode = YES;
self.moviePlayer.view.backgroundColor = [UIColor blackColor];
self.moviePlayer.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.moviePlayer.view.frame = self.containerView.frame;
[self.view addSubview:self.moviePlayer.view];
[self.moviePlayer prepareToPlay];
[self.moviePlayer play];
I have tried using multiple different notifications to see if I can catch this within one of them, but not luck at all. I have tested all of these notifications so far.. I have added this to the self.moviePlayer and also the self.moviePlayer.view not luck in either of them.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(willResignActive:)
name:UIApplicationWillResignActiveNotification
object:self.moviePlayer.view];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(videoPlaybackDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:self.moviePlayer.view];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(videoStartedPlaying:)
name:MPMoviePlayerNowPlayingMovieDidChangeNotification
object:self.moviePlayer.view];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(videoLoadState:)
name:MPMoviePlayerLoadStateDidChangeNotification
object:self.moviePlayer.view];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(videoPlaybackState:)
name:MPMoviePlayerPlaybackStateDidChangeNotification
object:self.moviePlayer.view];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(videoPlaybackUserInfoKey:)
name:MPMoviePlayerPlaybackDidFinishReasonUserInfoKey
object:self.moviePlayer.view];
Well, if you need more relevant code please let me know. I really need some help with this.. Thanks in advance.
This code worked for me, but just to get rid of freezing. Sign up for the MPMoviePlayerLoadStateDidChangeNotification, like you did above. In the callback method, I simply set the movie players contentURL to the original URL I had initialized it with at the start, and set the movie player to play again.
The functionality of this is when you tap the NEXT or BACK buttons in fullscreen, the video simply starts playing again from the start. That may not be ideal since the user might not expect this, but at least it will stop it from freezing. I'm currently trying to find a better workaround.
- (void) videoLoadState:(NSNotification *)notification
{
MPMovieLoadState loadState = moviePlayer.loadState;
if(loadState == MPMovieLoadStateUnknown)
{
NSLog(#"Movie Load state is unknown");
moviePlayer.contentURL = currentlyPlayingVideoURL;
[moviePlayer prepareToPlay];
}
}
If you check the value of MPMoviePlaybackState in this method, it will always be MPMoviePlaybackStateStopped when NEXT or BACK are pressed, so I'm not sure how to handle it...
I am facing an issue with MPMoviePlayerController in iOS 7. I enter the fullscreen and then click (just a single tap) on seek forward button (>>|) , and the video playback ends and gives a black screen with a text "Loading" on the header.
I registered notification for "MPMoviePlayerPlaybackStateDidChangeNotification".
**[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayerPlaybackStateDidChange:)
name:MPMoviePlayerPlaybackStateDidChangeNotification
object:self.player];**
It does not get fired on a single click of seek forward button.
Also on registration of "MPMoviePlayerPlaybackDidFinishNotification"
**[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayerPlaybackDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:nil];**
I get "MPMovieFinishReasonPlaybackEnded" event fired on that single click of seek forward button.
Any one knows the reason why? Is this a bug in apple?
I need to either stop this behavior of showing a black screen on single click , or just disable single click of seek forward button so that nothing happens.
Any one knows how to achieve this?
I fixed this by removing the MPMoviePlayer object completely, setting it to nil, removing it from it's superview and re-adding it using the original video Url. Code below:
- (void)addPlayerForUrl:(NSURL *)url {
self.player = [[MPMoviePlayerController alloc] initWithContentURL:url];
self.player.view.frame = self.videoView.bounds;
self.player.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.player.controlStyle = MPMovieControlStyleDefault;
[self.videoView insertSubview:self.player.view atIndex:0];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayerLoadStateDidChangedNotification:)
name:MPMoviePlayerReadyForDisplayDidChangeNotification
object:self.player];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayerPlaybackStateDidChangeNotification:)
name:MPMoviePlayerPlaybackStateDidChangeNotification
object:self.player];
}
#pragma mark - Notifications
- (void)moviePlayerLoadStateDidChangedNotification:(NSNotification *)notification {
self.isVideoPreloaded = YES;
self.videoPlayButton.hidden = YES;
self.photoImageView.hidden = YES;
self.videoLoadingImageView.hidden = YES;
}
- (void)moviePlayerPlaybackStateDidChangeNotification:(NSNotification *)notification {
NSURL *url = self.player.contentURL;
switch (self.player.playbackState) {
case MPMoviePlaybackStateSeekingBackward:
case MPMoviePlaybackStateSeekingForward:
break;
case MPMoviePlaybackStatePlaying:
self.videoPlayButton.hidden = YES;
if (!self.isVideoPreloaded) {
self.videoLoadingImageView.hidden = NO;
[self.videoLoadingImageView startAnimating];
} else {
self.videoLoadingImageView.hidden = YES;
}
break;
case MPMoviePlaybackStatePaused:
case MPMoviePlaybackStateStopped:
self.videoPlayButton.hidden = NO;
self.videoLoadingImageView.hidden = YES;
[self.player endSeeking];
[self.player.view removeFromSuperview];
[self.player setFullscreen:NO];
self.player = nil;
[self addPlayerForUrl:url];
break;
default:
break;
}
}
Notice how I keep the NSURL, right before the switch statement in the moviePlayerPlaybackStateDidChangeNotification. That way, I can re-initialize and re-add the MPMoviePlayer object.
Btw, my mpmovieplayer is on a tableviewCell if you're wondering. Hope this helps and let me know if you have questions. Good luck!
MPMoviePlayerLoadStateDidChangeNotification will be called when you single tap on the fast-forward or rewind button. You should check the loadState and just give it the path to your video and prepareToPlay again.
- (void)moviePlayerLoadStateChanged:(NSNotification *)notification {
MPMoviePlayerController *moviePlayer = notification.object;
MPMovieLoadState loadState = moviePlayer.loadState;
if(loadState == MPMovieLoadStateUnknown) {
moviePlayer.contentURL = [NSURL fileURLWithPath:videoPath]
[moviePlayer prepareToPlay];
}
.....
}
The reason you're getting MPMovieFinishReasonPlaybackEnded is because playback reached the end of the video (sorry if this is obvious). So it seem's your seek forward actions are seeking all the way to the end of the video. You can check the playback state with MPMoviePlaybackStateSeekingForward.
A quick solution could be to create your own forward button that seek's ahead by a specified time (ie. 5 seconds). But perhaps this isn't the functionality you're looking for.
I have a MPMoviePlayerController setup:
self.moviePlayerController = [[MPMoviePlayerController alloc] init];
[self.moviePlayerController.view setFrame:frame];
// hide controls initially
[self.moviePlayerController setControlStyle:MPMovieControlStyleNone];
[self.view addSubview:self.moviePlayerController.view];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(loadStateChanged:) name:MPMoviePlayerLoadStateDidChangeNotification object:self.
moviePlayerController];
Then when the notification is fired:
-(void)loadStateChanged:(NSNotification*)notification {
if (self.moviePlayerController.controlStyle == MPMovieControlStyleNone) {
[self.moviePlayerController setControlStyle:MPMovieControlStyleDefault];
}
}
On initial playback this works great, controls are not shown when playback starts but tapping the view shows the controls.
However, when a movie is already playing and I start playback of another URL, I hide the controls, but they reappear after playback starts of the second movie:
[self.moviePlayerController setContentURL:videoURL];
[self.moviePlayerController setControlStyle:MPMovieControlStyleNone];
[self.moviePlayerController play];
The notification does fire again and it correctly has a controlStyle of MPMovieControlStyleNone which I then set to MPMovieControlStyleDefault.
Anybody have any experience with this, is there a way to make sure the controls stay hidden on a second playback, but are in fact visible when the user taps the movie view.
Thanks!
I have a weird problem for you all.
MPMoviePlayerController is playing the video fine, and the audio ONLY plays through headphones.
The real drag is that this only happens on some iPads and iPhones, even the SAME EXACT MODELS
running the SAME EXACT SYSTEM!
I've created a simple failing example here:
http://www.porcaro.org/MPMoviePlayerController/TestMovie.zip
I've seen it run fine and fail on iPhone 4S, iPhone 4 and iPad 2.
Here is the most relevant code. Thanks for any insight, I'm going to submit a bug to Apple as well:
(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
moviePath = [NSString stringWithFormat:#"%#/intro.m4v", [[NSBundle mainBundle] bundlePath]];
NSURL *movieURL = [NSURL fileURLWithPath:moviePath];
theMoviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:movieURL];
controlStyle = MPMovieControlStyleEmbedded;
movieView = [self view];
movieRect = [[self view] frame];
controlStyle = MPMovieControlStyleFullscreen;
theMoviePlayer.controlStyle = controlStyle;
theMoviePlayer.view.userInteractionEnabled = YES;
if (1) {
NSLog(#"Created theMoviePlayer: %#. Playing: %#", theMoviePlayer, moviePath);
}
[[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerPlaybackStateDidChangeNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(checkForEndOfMovie:)
name:MPMoviePlayerPlaybackStateDidChangeNotification
object:theMoviePlayer];
// this line doesn't fix the problem
//[theMoviePlayer prepareToPlay];
[[theMoviePlayer view] setFrame:movieRect];
[movieView addSubview: [theMoviePlayer view]];
[theMoviePlayer play];
}
This is an old question but maybe it'll help someone. I came across the same issue and found out it was happening when the phone is in silent mode only.
Solution is to set the player's useApplicationAudioSession property to false.
[theMoviePlayer setUseApplicationAudioSession:NO];
This problem was happen to me once playing video on iPad 2 using mpMoviePlayer. The video was playing perfectly but audio only comes when earphones connected.
Solution to solve the problem:
[theMoviePlayer setUseApplicationAudioSession:NO];
I use MPMoviePlayerController to play a local file in my Application Document folder which have I have downloaded for a server URL:
itemMoviePlayerController = [[MPMoviePlayerController alloc] initWithContentURL:fileURL];
[self.view addSubview:itemMoviePlayerController.view];
itemMoviePlayerController.fullscreen = YES;
itemMoviePlayerController.movieSourceType = MPMovieSourceTypeFile;
itemMoviePlayerController.initialPlaybackTime = -1.0;
[itemMoviePlayerController play];
When I play .mov file just after I downloaded it, It shows up a black empty screen & app UI is unusable.
But if play same local file next time, it plays fine.
I even verified playState & localState for MPMoviePlayerController they seems fine.
What could be reason for black empty screen?
You need to retain your instance of MPMoviePlayerController i.e. as a property or an instance variable. The reference to the movie player is lost if you do not retain it.
You could try to put [itemMoviePlayerController prepareToPlay];
before the [itemMoviePlayerController play];
The way preferred by Apple to display an only full screen video is to present a modal MPMoviePlayerViewController (as Hollance said).
To present it, you should use something like :
moviePlayerViewController = [[MPMoviePlayerViewController alloc] initWithContentURL:fileURL];
[self presentMoviePlayerViewControllerAnimated:moviePlayerViewController];
[itemMoviePlayerController play];
This is documented by Apple here
You can read there that you should keep a reference to your MPMoviePlayerViewController in order to dismiss it later with
[self dismissMoviePlayerViewControllerAnimated:moviePlayerViewController].
I fixed this by putting
#property (strong, nonatomic) MPMoviePlayerController *moviePlayer;
in my .h file, and calling self.moviePlayer in all my code and it worked!
You need to use MPMoviePlayerViewController instead. Notice the word "View" in there.
I hope this will help. I solved this problem in my project
-(void)startPlayingMovie
{
NSLog(#"startPlayingMovie");
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle]
pathForResource:#"Start_video" ofType:#"mov"]];
moviePlayer = [[MPMoviePlayerViewController alloc]
initWithContentURL:url];
moviePlayer.view.frame = CGRectMake(0, 0, self.view.bounds.size.height, self.view.bounds.size.width);
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayBackDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:moviePlayer.moviePlayer];
moviePlayer.moviePlayer.controlStyle = MPMovieControlStyleNone;
moviePlayer.moviePlayer.shouldAutoplay = YES;
[self presentMoviePlayerViewControllerAnimated:moviePlayer];
[moviePlayer.moviePlayer setFullscreen:YES animated:NO];
NSLog(#"endPlayingMovie");
}
Same thing happened to me. It turns out, I had tried to play the movie while the UIImagePicker wasn't dismissed yet.
In my UIImagePickerDelegate I had to first dismiss the UIImagePicker Popup and then open the ViewController managing the MPMediaPlayerController:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)infoDict
{
//the first thing to do: dismiss the media picker
if ([ipPop isPopoverVisible])
{
[ipPop dismissPopoverAnimated:ANIMATION_SETTING];
}
myMediaPlayerViewController * playerVC = [[myMediaPlayerViewController alloc] initWithMediaDict:infoDict];
[self.navigationController pushViewController:playerVC animated:ANIMATION_SETTING];
}
I had this same problem and it made me crazy. It would work on one view controller fine (audio and video), but not work on another (black screen with just audio). In the end, all I did was CHANGE THE ORDER of the calls: I simply waited until I was done configuring the movie player before adding it to the view. In other words, I called "addSubview" on the line just before the call to "play".
This is the code I'm using to play a file from URL:
MPMoviePlayerViewController *movieViewController = [[MPMoviePlayerViewController alloc] initWithContentURL:[NSURL URLWithString:contentUrl]];
movieViewController.moviePlayer.movieSourceType = MPMovieSourceTypeFile;
[self presentMoviePlayerViewControllerAnimated:movieViewController];
[movieViewController release];
It seems to work fine for me. Two notes:
Some simulators (like the current iOS 5.0) crash when playing a movie, but it works on a real device
If you leave out the movieSourceType part, a black screen is shown for about a second before the movie starts
I had the same problem, solved it changing the extension of the file being played from .mpg to .mp4. apparently MPMoviePlayerController expects a correct extension, though from the documentation it is not clear to me that this is a requirement:
http://developer.apple.com/library/ios/#documentation/mediaplayer/reference/MPMoviePlayerController_Class/Reference/Reference.html
Supported Formats This class plays any movie or audio file supported
in iOS. This includes both streamed content and fixed-length files.
For movie files, this typically means files with the extensions .mov,
.mp4, .mpv, and .3gp and using one of the following compression
standards:
This issue seems fixed after updating device iOS to 5.0.
Seems to iOS SDK issue for previous version
you must do like that with CGRectMake(0, 0, 0, 0) in the finished callback!
-(void)playMovieAtURL:(NSURL*)theURL
{
MPMoviePlayerController* theMovie=[[MPMoviePlayerController alloc] initWithContentURL:theURL];
theMovie.scalingMode=MPMovieScalingModeAspectFill;
theMovie.view.frame = CGRectMake(2, 246, 317, 70);
[self.view addSubview:theMovie.view];
// Register for the playback finished notification.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(myMovieFinishedCallback:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:theMovie];
// Movie playback is asynchronous, so this method returns immediately.
[theMovie play];
}
// When the movie is done,release the controller.
-(void)myMovieFinishedCallback:(NSNotification*)aNotification
{
MPMoviePlayerController* theMovie=[aNotification object];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:theMovie];
theMovie.view.frame = CGRectMake(0, 0, 0, 0);
// Release the movie instance created in playMovieAtURL
[theMovie release];
}
I was having a similar issue. After playback there comes an empty screen, which prevents me to play video again.
Well here is my work around. That way play button doesn't disappear.
[self.movieController stop];
[self.movieController prepareToPlay];
[self.movieController pause];
Also, If you are using http URLs, make sure you disable App Transport Security in your projects *.plist file. It will also cause a black screen.
Add the following code:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key><true/>
</dict>
Here:
[INSERT CODE ABOVE HERE]
</dict>
</plist>
----- BOTTOM OF PLIST FILE