What is the appropriate point to send the play message to a MPMoviePlayerController instance instantiated in a splitView detail View Controller?
My app is receiving the above console message (with a !) but not crashing...
The app is utilizing MPMoviePlayerController to play a movie from an asset URL
and the responsilble method is called as follows:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self startPlayingVideo:self];
}
It plays the video just fine but the console message is looming...
If I move the method call to viewWillAppear:animate:, the console message does not show up. The issue is now I can only hear audio and do not see the video.
For completeness, here is the called method...
- (void) startPlayingVideo:(id)sender
NSURL *movieURL = [NSURL URLWithString:self.movieURLString];
if (self.moviePlayer != nil){
[self stopPlayingVideo:nil];
}
self.moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:movieURL ];
if (self.moviePlayer != nil){
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(videoHasFinishedPlaying:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:self.moviePlayer];
self.moviePlayer.scalingMode = MPMovieScalingModeAspectFit;
[self.moviePlayer prepareToPlay];
[self.moviePlayer play];
[self.view addSubview:self.moviePlayer.view];
[self.moviePlayer setFullscreen:YES animated:YES];
} else {
NSLog(#"Failed to instantiate the movie player.");
}
}
My original issue stemmed from having the MoviePlayerController as an entirely different viewController (embedded in a detail navigation controller). I redesigned the parent view to include a moviePlayer child view. This solved the issue.
Related
Hi, I replaced MPMoviePlayerController with AVPlayerViewController since MPMoviePlayerController is deprecated.
I'm nearly there, but have one question. My movie start as a view within a view. When playing fullscreen I want it to jump back to NO fullscreen when finished playing. But I don't know how. Here is my code:
- (void)viewDidLoad {
// grab a local URL to our video
NSURL *videoURL = [[NSBundle mainBundle]URLForResource:#"movie" withExtension:#"m4v"];
// create an AVPlayer
AVPlayer *player = [AVPlayer playerWithURL:videoURL];
// create a player view controller
self.controller = [[AVPlayerViewController alloc]init];
controller.player = player;
[player play];
// show the view controller
[self addChildViewController:controller];
[self.view addSubview:controller.view];
controller.view.frame = CGRectMake(0,25, 750, 422);
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(itemDidFinishPlaying:) name:AVPlayerItemDidPlayToEndTimeNotification object:player];
}
With MPMoviePlayer it used to work with this code:
- (void) playerPlaybackDidFinish:(NSNotification*)notification{
// movie finished playing
[moviePlayerController setFullscreen:NO];
}
With what code do I need to replace it??
-(void)itemDidFinishPlaying:(NSNotification *) notification {
// Will be called when AVPlayer finishes playing playerItem
???????????}
Thanks, Meg
#iOS 10 and higher and Swift 4.2 this code are working.
Write this code in your player init methods
if #available(iOS 11.0, *) {
self.playerVC?.exitsFullScreenWhenPlaybackEnds = true
}
NotificationCenter.default.addObserver(self, selector: #selector(self.playerItemDidReachEnd(notification:)), name: .AVPlayerItemDidPlayToEndTime, object:self.playerVC?.player!.currentItem)
This is youy notification delegate
func playerItemDidReachEnd(note:NSNotification){
print("finished")
dismissViewControllerAnimated(true, completion: nil)
}
I want to show a small video (3 sec video) every time when user opens the application on iOS device.
(If the app is opened from memory then don't show video)
I am having my "dashboard" view as root view controller.
I searched all the links on SO and other sites, but none helps.
Sometimes my video is working but later application get crashed.
My dashboardview is from "Main.storyboard" but there are no controls on storyboard.
Only linking of navigation bar is done via storyboard.
Here is my code.
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
[self showVideo];
}
- (void)showVideo
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"video" ofType:#"mp4"];
NSURL *url = [NSURL fileURLWithPath:path];
NSLog(#"video path :- %#",url);
self.navigationController.navigationBar.hidden = YES;
self.videoController = [[MPMoviePlayerViewController alloc] initWithContentURL:url];
self.videoController.moviePlayer.controlStyle = MPMovieControlStyleNone;
//[self presentMoviePlayerViewControllerAnimated:videoController];
[self.navigationController pushViewController:self.videoController animated:NO];
[self.videoController.moviePlayer play];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayBackDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:self.videoController];
}
- (void) moviePlayBackDidFinish:(NSNotification*)_notification
{
self.navigationController.navigationBar.hidden = NO;
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:nil];
[self.videoController.view removeFromSuperview];
[self.videoController.moviePlayer stop];
self.videoController = nil;
[self.navigationController popViewControllerAnimated:NO];
//[self.view removeFromSuperview];
}
the nslog is printing video path correctly.
like
video path :- file:///Users/itshastra/Library/Developer/CoreSimulator/Devices/87C93694-66E8-4884-B087-10E1E4CBA4D1/data/Containers/Bundle/Application/DB6C89D4-EE6D-4830-B208-B4AA89FD8E59/Complaint.app/video.mp4
But App get crashed,
Neither it shows the video and then dashboard, not dashboard directly.
Can any one please guide me, what I am doing wrong.
Thanks in advance.
If by mistake I missed any link on SO, please provide that as well.
Thanks.
Try calling method like this,
- (void)viewDidLoad
{
[super viewDidLoad];
[self performSelector:#selector(showVideo) withObject:nil afterDelay:0.1f];
}
Please enable the option "Enable Zombie Objects" under following path:
Edit Scheme -> Diagnostics -> Enable Zombie Objects
and let me know the logs.
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 am working on a app in which I have a list of items where i want to click on a thumbnail and video must be played, My requirement is Only MPMovieViewController must rotate remaining screens must not rotate for this I am using below method in list to make it portrait every time. But if i am using it i am not able to rotate the MPMoviePlayerViewController.
- (NSUInteger)supportedInterfaceOrientations{
return (UIInterfaceOrientationMaskPortrait);
}
So i returned "UIInterfaceOrientationMaskAll" after returning i am able to Autorotate the MPMoviePlayerViewController But when i come back clicking on done Button or after video is done when video is in landscape mode then my previous is rotating but i dont want that behaviour i need the previous view in portrait, Below is code for implementing the MPMoviePlayerViewContoller.
NSString *filepath = [[NSBundle mainBundle] pathForResource:[exeDict objectForKey:#"longVideoName"] ofType:#"mp4"];
NSURL *fileURL = [NSURL fileURLWithPath:filepath];
moviePlayerController = [[MPMoviePlayerViewController alloc] initWithContentURL:fileURL];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlaybackComplete:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:moviePlayerController.moviePlayer];
[moviePlayerController.view setFrame:CGRectMake(0, 0, 320, 480)];
moviePlayerController.moviePlayer.controlStyle = MPMovieControlStyleFullscreen;
moviePlayerController.view.userInteractionEnabled =YES;
[moviePlayerController shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationMaskAll];
// AppDelegate* myDelegate = (((AppDelegate*) [UIApplication sharedApplication].delegate));
// [myDelegate.window addSubview:moviePlayerController.view];
MainViewController* mainViewController = (MainViewController*)self.mainViewDelegate;
[mainViewController presentMoviePlayerViewControllerAnimated:moviePlayerController];
[moviePlayerController.moviePlayer play];
Please let me know how to get it.
you will have have to put code in viewwillappear() method so that your list appears in portrait mode
- (BOOL)shouldAutorotate
{
return NO;
}
Implemented above code in mainViewController??
I have an app for iOS 4.0-5.1 that uses HTTP Live Streaming to play videos. I have a simple setup with a button in a view that starts playing the stream when it is tapped. This works fine in iOS 5 but the button needs to be tapped twice before the stream begins playing in iOS 4. Does anybody know why this is happening and how to make the video play on the first tap of the button?
Here is what I'm doing:
.h
#import <UIKit/UIKit.h>
#import <MediaPlayer/MediaPlayer.h>
#interface ViewController : UIViewController{
MPMoviePlayerController *moviePlayer;
}
#property (nonatomic, strong) MPMoviePlayerController *moviePlayer;
-(IBAction)playApple:(id)sender;
#end
.m
-(IBAction)playApple:(id)sender{
if(self.moviePlayer){
self.moviePlayer = nil;
}
//Use Apple's sample stream
NSURL *mediaURL = [NSURL URLWithString:#"http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8"];
self.moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:mediaURL];
//Begin observing the moviePlayer's load state.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayerLoadStateChanged:)
name:MPMoviePlayerLoadStateDidChangeNotification
object:self.moviePlayer];
[self.moviePlayer setMovieSourceType:MPMovieSourceTypeStreaming];
[self.moviePlayer setShouldAutoplay:NO];//Stop it from autoplaying
[self.moviePlayer prepareToPlay];//Start preparing the video
}
#pragma mark Notification Center
- (void)moviePlayerLoadStateChanged:(NSNotification *)notification{
NSLog(#"State changed to: %d\n", moviePlayer.loadState);
if(self.moviePlayer.loadState == MPMovieLoadStatePlayable){
//if load state is ready to play
[self.view addSubview:[self.moviePlayer view]];
[self.moviePlayer setFullscreen:YES];
[self.moviePlayer play];//play the video
}
}
I can see some possible issues - just try it out and let us know if any or all of this did the trick.
1. loadstate masking
The loadstate should not be directly compared but masked before comparing as it might contain a mixture of multiple states.
MPMovieLoadState
Constants describing the network load state of the movie player.
enum {
MPMovieLoadStateUnknown = 0,
MPMovieLoadStatePlayable = 1 << 0,
MPMovieLoadStatePlaythroughOK = 1 << 1,
MPMovieLoadStateStalled = 1 << 2,
};
typedef NSInteger MPMovieLoadState;
So instead of directly comparing it, as you are, mask it to be on the safe side.
2. view setup
Why not setting up the player view right before starting the playback. I have never seen it the way you do it (not that I was positively sure that this is the problem - still, seems odd to me). Additionally, even though the player will not actually use the view you are assigning (fullscreen mode does it a bit differently), you may want to enhance the view-setup with assigning a proper frame.
All of the above rolled into this new version of your code...
-(IBAction)playApple:(id)sender
{
if(self.moviePlayer)
{
self.moviePlayer = nil;
}
//Use Apple's sample stream
NSURL *mediaURL = [NSURL URLWithString:#"http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8"];
self.moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:mediaURL];
//Begin observing the moviePlayer's load state.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayerLoadStateChanged:)
name:MPMoviePlayerLoadStateDidChangeNotification
object:self.moviePlayer];
self.moviePlayer.view.frame = self.view.bounds;
[self.view addSubview:[self.moviePlayer view]];
[self.moviePlayer setFullscreen:YES];
[self.moviePlayer setMovieSourceType:MPMovieSourceTypeStreaming];
[self.moviePlayer setShouldAutoplay:NO]; //Stop it from autoplaying
[self.moviePlayer prepareToPlay]; //Start preparing the video
}
- (void)moviePlayerLoadStateChanged:(NSNotification *)notification
{
NSLog(#"State changed to: %d\n", moviePlayer.loadState);
if((self.moviePlayer.loadState & MPMovieLoadStatePlayable) == MPMovieLoadStatePlayable)
{
//if load state is ready to play
[self.moviePlayer play];//play the video
}
}