Can not detect MPMoviePlayerDidExitFullscreenNotification - objective-c

In my project, I used MPMoviePlayerController to stream video from an http url. It plays fullscreen. When the video is playing, if you tap on "Done" button the video stops and it disappears, but the problem is; if you pinch to close video screen the video screen disappears but it still plays, sound of video continues to play.
I tried to detect exit fullscreen notification and manually stop the video but it didn't work. My moviePlayerDidExitFullScreen method didn't called.
To control that if I am getting the notifications on the right way I tried to get another notification : MPMoviePlayerPlaybackStateDidChangeNotification, and it is working. It calls the method on video launching.
I searched many forums and Apple documentations but I couldn't find enough information.
Here is my code to open a fullscreen video and detect exit fullscreen :
- (void)openFullVideo
{
NSString* path = #"http://trtvizyon.mysys.com/test/leyla_ile_mecnun.mp4";
NSURL *fileURL = [NSURL URLWithString:path];
MPMoviePlayerController *player = [[MPMoviePlayerController alloc] initWithContentURL:fileURL];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(moviePlayerDidExitFullScreen:) name:MPMoviePlayerDidExitFullscreenNotification object:nil];
player.controlStyle = MPMovieControlStyleDefault;
player.movieSourceType = MPMovieSourceTypeStreaming;
[self.view addSubview:player.view];
[player setFullscreen:YES animated:YES];
[player play];
}
- (void) moviePlayerDidExitFullScreen:(id)sender {
NSLog(#"moviePlayerDidExitFullScreen");
}

OK, I played with your code for a while, and finally shot that little bug in the gut.
Your first problem is not retaining the player object (assuming you are using ARC, if not, then skip this). So, just make sure you retain it as an instance variable for example:
//Header File
#interface ViewController : UIViewController {
MPMoviePlayerController* _player;
}
// Implementation File
- (void)openFullVideo {
// ...
_player = player;
}
Now, if that just works, then great!! But I am getting a dreaded unsolved bug on apple's side:
An AVPlayerItem can occupy only one position in a player's queue at a time
To solve this issue, do it like so:
NSString* path = #"http://trtvizyon.mysys.com/test/leyla_ile_mecnun.mp4";
NSURL *fileURL = [NSURL URLWithString:path];
MPMoviePlayerController *player = [[MPMoviePlayerController alloc] init];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(moviePlayerDidExitFullScreen:) name:MPMoviePlayerDidExitFullscreenNotification object:nil];
player.controlStyle = MPMovieControlStyleDefault;
player.movieSourceType = MPMovieSourceTypeStreaming;
[self.view addSubview:player.view];
[player setContentURL:fileURL];
[player setInitialPlaybackTime:-1.f];
[player setFullscreen:YES animated:YES];
[player prepareToPlay];
[player play];
_player = player;
That should do it!
Some Other Friendly Advice:
Make sure you remove yourself from NSNotificationCenter before playing the movie again.
I would suggest adding something like if (_player != nil) to avoid recreating the object.

Related

Change AVPlayer Video MacOS Objective-C Cocoa

For MacOS, not iOS. I am playing a video in an AVPlayerView in an XIB. Just experimenting with video playback. I would like to be able to choose a selection from the File Menu (For instance File / Videos / Video 1, Video2, Video3, etc) and change the currently playing video in the XIB when I select the menu item.
Currently I am using this to play a video:
- (void)windowDidChangeOcclusionState:(NSNotification *)notification
{
if (self.window.occlusionState & NSWindowOcclusionStateVisible)
{
loopPlayer = YES;
[_aspectView setAspectRatio:NSMakeSize(16, 9)];
NSBundle *mb = [NSBundle mainBundle];
NSURL *demoURL = [mb URLForResource:#"Video1" withExtension:#"mp4"];
player = [[AVPlayer alloc] initWithURL:demoURL];
self.playerView.player = player;
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:#selector(movieEndDetected:)
name:#"AVPlayerItemDidPlayToEndTimeNotification"
object:player.currentItem];
[player play];
}
else
{
[player pause];
[player seekToTime:kCMTimeZero];
}
}
and to loop the video playing:
- (void) movieEndDetected:(NSNotification *) note
{
if (loopPlayer) {
[player seekToTime:kCMTimeZero];
[player play];
}
}
But I would like to change the playing video in the XIB on the fly by choosing a menu button. Any ideas how this can be done? I have heard of AVPlayerQueue maybe working for this kind of thing, but I am very new and can't get it working on MacOS.
My solution was to use many avplayer views in xibs and when one was open from a menu item, close another.
- (void)Visual02Menu:(id)sender {
if (!visual02Window) {
visual02Window = [[Visual02 alloc] initWithWindowNibName:#"Visual02"]; }
[visual01Window close];
[visual02Window showWindow:self];

Movie player failed to play

I am trying to play video with this guide :http://www.techotopia.com/index.php/Video_Playback_from_within_an_iOS_7_Application
so i have :
//movieplayer initialization
NSURL *url = [NSURL URLWithString:
#"http://www.youtube.com/watch?v=CS-6gJkNAo4"];
self.moviePlayer = [[MPMoviePlayerController alloc]
initWithContentURL:url];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayBackDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:self.moviePlayer];
self.moviePlayer.controlStyle = MPMovieControlStyleDefault;
self.moviePlayer.shouldAutoplay = YES;
[self.movieView addSubview:self.moviePlayer.view];
[self.moviePlayer setFullscreen:YES animated:YES];
Where the player is loaded to some view .
I don't see nothing and i only get this error message :
_itemFailedToPlayToEnd: {
kind = 1;
new = 2;
old = 0;
}
MPMoviePlayerController can't play Youtube video. You have to paste direct link to file to play video in such way.

AVPlayer crashes after multiple playbacks-

I'm trying to create an app which plays videos from a file using AVFoundation. The videos are shown in a view accessed by tapping on a row in a parent tableview. The real app will have a video for each row, but at the moment I'm using just one for testing.
When run on the simulator the app is ok, but when run on the device (under ios 5.1) the video plays ok for about 5 times, then crashes unpredictably in a variety of ways.
Most commonly, the video view loads but the video itself doesn't play, but sometimes
I get an EXC_BAD_ACCESS on a coremedia.remote thread, complaining about objects being allocated with no autorelease pool in place. I've added an #autoreleasepool block wrapping the code launching the AVPlayer, but this doesn't seem to help.
I'm wondering whether what is happening is that GCD is creating multiple threads on the main queue to play the items, but they are not terminating.
So the key question is- how do I clear up the superfluous GCD threads the AVPlayer is running on
if the user hits the back button in the video view
As far as possible I've followed the example code provided in Apple's AVFoundation documentation here
I've added some logging and (as mentioned above) an #autoreleasepool block inside one of the GCD blocks- other than that I haven't changed the code.
The viewDidLoad method is as follows:
-(void)viewDidLoad{
[super viewDidLoad];
NSURL *fileURL = [[NSBundle mainBundle] URLForResource:#"TestLapCar2Vid" withExtension:#"m4v"];
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:fileURL options:nil];
NSString *tracksKey = #"tracks";
[asset loadValuesAsynchronouslyForKeys:[NSArray arrayWithObject:tracksKey] completionHandler:
^{
dispatch_async(dispatch_get_main_queue(),
^{
#autoreleasepool {
NSError *error = nil;
AVKeyValueStatus status = [asset statusOfValueForKey:tracksKey error:&error];
if(status == AVKeyValueStatusLoaded){
avPlayerItem = [AVPlayerItem playerItemWithAsset:asset];
[avPlayerItem addObserver:self forKeyPath:#"status"
options:0 context:&ItemStatusContext];
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(playerItemDidReachEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification object:avPlayerItem];
avPlayer = [AVPlayer playerWithPlayerItem:avPlayerItem];
[videoView setPlayer:avPlayer];
NSLog(#"Asset loaded");
[avPlayer play];
}
else{
NSLog(#"The asset's tracks were not loaded");
}
}
});
}];
}
The viewWillDisappear method is:
-(void)viewWillDisappear:(BOOL)animated{
NSLog(#"view will disappear called");
[super viewWillDisappear:animated];
dispatch_async(dispatch_get_main_queue(),
^{
[avPlayer pause];
[avPlayerItem removeObserver:self forKeyPath:#"status"];
[[NSNotificationCenter defaultCenter]removeObserver:self];
NSLog(#"Race timeline nav controller has %d sub controllers",self.navigationController.childViewControllers.count);
avPlayerItem = nil;
avPlayer = nil;
videoView = nil;
dataStore = nil;
pkReader = nil;
receivedData = nil;
revDial = nil;
speedDial = nil;
mapView = nil;
throttle = nil;
NSLog(#"releasing stuff");
});
}
I've been struggling with this for most of today- any help would be gratefully received
You should remove from superview first as it will reduce the retain count by 1 and ARC will take care of the release for your code.
like this
[videoView removeFromSuperview];
[self setVideoView:nil];
May be you leave your videoView retained in some place? Because if you do, your avPlayerItem and avPlayer stay alive and according to this topic you came up to iOS limitation for "render pipeline" with 4 videos staying in memory.
Remember that setting var to nil does not actually release underlying object. So your
videoView = nil;
can have zero effect.

MPMoviePlayer does not disappear on [moviePlayer.view removeFromSuperview] and [moviePlayer release]

I have a problem with MPMoviePlayerController.When I am watching a video, and hit the 'Done' button on the left top, the MoviePlayer does not disappear, even though the code seems to be called:
NSURL *url = [NSURL URLWithString:article.enclosureLink];
MPMoviePlayerController *moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:url];
// Set movie player layout
[moviePlayer setControlStyle:MPMovieControlStyleFullscreen];
[moviePlayer setFullscreen:YES];
// May help to reduce latency
[moviePlayer prepareToPlay];
// Register to receive a notification when the movie has finished playing.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayBackDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:moviePlayer];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(movieReadyToPlay:)
name:MPMoviePlayerLoadStateDidChangeNotification
object:moviePlayer];
And the selectors:
- (void) movieReadyToPlay:(NSNotification*)notification {
MPMoviePlayerController *moviePlayer = [notification object];
if(moviePlayer.loadState == MPMovieLoadStatePlayable){
[[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerLoadStateDidChangeNotification object:moviePlayer];
moviePlayer.controlStyle = MPMovieControlStyleFullscreen;
//moviePlayer.shouldAutoplay = YES;
[self.view addSubview:moviePlayer.view];
[moviePlayer setFullscreen:YES animated:YES];
[moviePlayer play];
}
}
- (void) moviePlayBackDidFinish:(NSNotification*)notification {
MPMoviePlayerController *moviePlayer = [notification object];
[[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerPlaybackDidFinishNotification object:moviePlayer];
[moviePlayer setFullscreen:NO animated:YES];
[moviePlayer.view removeFromSuperview];
[moviePlayer release];
NSLog(#"Finished movie!");
}
This looks to me a very straight forward code, but I must make a stupid mistake. The NSLog shows that the function is called, but the player stays where it is and there is no way of getting rid of it.
Also, the very fact that the player is still operational after the alleged release seems to indicate that there is something fundamental wrong, I just don't see what.
Is there anybody who has a suggestion?
[Update:]
Strangely in the iPhone Simulator it works fine!
[Update2:]
I tried and created a specific UIviewcontroller, even though it is not the way I want to do it as the animations are not nice. But what I learned is that I have the same problem. It seems to hav to do something with dismissing the player, but it starting again.
When I put [self.moviePlayer setFullscreen:YES animated:YES]; in viewDidApear, and click the 'Done' button in the player, the player, the video starts over again when I hit the Done button (the viewDidAppear is called again). So something is triggered, so it seems to me, to make the video start again.
If I put it viewDidLoad, then the system works, but the graphics are mixed and confused...
Any help is really, really appreciated as I spend two days on this now without making head or tail of it!
For me, I tried all of these:
[moviePlayer stop];
[moviePlayer setContentURL:nil];
[moviePlayer.view removeFromSuperview];
moviePlayer = nil;
And nothing worked. I figured out it had to due with my MPMoviePlayerController entering full screen. The fix?
[moviePlayer setFullscreen:NO animated:YES];
Adding
[moviePlayer stop]
before
[moviePlayer.view removeFromSuperview]
may work.
Update:
If this doesn't work then try setting controlstyle to MPMovieControlStyleNone before removing the subview.Most of the time the controlStyle causes such problems.

iPad videoPlayerDidFinishPlaying callback method not responding

I am facing a problem in ipad video incorporating. My code works fine I mean it plays the video, but once the video reaches to its end. The callback method is not called.
This method is called when play video button is pressed.
-(IBAction) playVideo : (id) sender
{
[self initPlayingVideo:#"toyVid.mp4"];
}
This method handles the playing of video.
-(void) initPlayingVideo: (NSString *) videoFile
{
NSString *moviePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:videoFile];
theMovie = [[MPMoviePlayerViewController alloc] initWithContentURL:[NSURL fileURLWithPath:moviePath]];
theMovie.moviePlayer.scalingMode = MPMovieScalingModeAspectFit;
theMovie.moviePlayer.controlStyle = MPMovieControlStyleFullscreen;
[self.view addSubview:theMovie.view];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(videoPlayerDidFinishPlaying
name:MPMoviePlayerPlaybackDidFinishNotification
object:theMovie];
videoPlayer = [theMovie moviePlayer];
[videoPlayer play];
}
This is the callback method.
-(void) videoPlayerDidFinishPlaying: (NSNotification*)aNotification
{
theMovie = [aNotification object];
[[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerPlaybackDidFinishNotification object:theMovie.moviePlayer];
[videoPlayer stop];
[theMovie.moviePlayer release];
[videoPlayer release];
[theMovie.view removeFromSuperview];
}
Where I am doing mistake? Please guide.
Regards
Ranjan
Did you miss the : and ) in your selector? I guess ) may be your typo otherwise you cannot compile your codes. Your selection takes one parameter. It should be:
selector:#selector(videoPlayerDidFinishPlaying:)
That will match to your instance method. I guess you don't have one without parameter.