MPMoviePlayerController prepareToPlay not working with HTTP Live Streaming - objective-c

I'm trying to play an HTTP live streaming video using a MPMoviePlayerController object, inside a modal view controller. If I run the code like this, everything works fine. I get a MPMoviePlaybackStatePlaying notification, and the video plays.
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(moviePlayerPlaybackStateDidChange:) name:MPMoviePlayerPlaybackStateDidChangeNotification object:nil];
NSURL *url = [NSURL URLWithString:#"http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8"];
self.moviePlayerController = [[[MPMoviePlayerController alloc] initWithContentURL:url] autorelease];
self.moviePlayerController.view.frame = CGRectMake(0,0,320,416);
self.moviePlayerController.controlStyle = MPMovieControlStyleNone;
self.moviePlayerController.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.view addSubview:self.moviePlayerController.view];
self.moviePlayerController.fullscreen = NO;
[self.moviePlayerController play];
}
I would prefer to use the prepareToPlay method, so that I can show a loading indicator, and for a nicer experience. However, I don't seem to be able to get this working. No MPMoviePlayerPlaybackStateDidChangeNotification ever gets called, and the stream doesn't play. The activity indicator just sits there spinning forever.
I've confirmed that prepareToPlay does get called, but nothing else seems to happen after that. I've also confirmed that this code works fine with a local movie file. It just seems to be with HTTP Live Streaming which fails. Can anyone see what I'm doing wrong?
- (void)viewDidLoad {
[super viewDidLoad];
[self.activityIndicator startAnimating];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(moviePlayerPlaybackStateDidChange:) name:MPMoviePlayerPlaybackStateDidChangeNotification object:nil];
NSURL *url = [NSURL URLWithString:#"http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8"];
self.moviePlayerController = [[[MPMoviePlayerController alloc] initWithContentURL:url] autorelease];
[self registerForMovieNotifications];
}
- (void)registerForMovieNotifications {
//movie is ready to play notifications
if ([self.moviePlayerController respondsToSelector:#selector(loadState)]) {
//this is a 3.2+ device
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(moviePlayerLoadStateChanged:) name:MPMoviePlayerLoadStateDidChangeNotification object:nil];
self.moviePlayerController.movieSourceType = MPMovieSourceTypeStreaming;
[self.moviePlayerController prepareToPlay];
} else {
//pre-3.2 device
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(moviePreloadDidFinish:) name:MPMoviePlayerContentPreloadDidFinishNotification object:nil];
}
//movie has finished notification
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(moviePlayBackDidFinish:) name:MPMoviePlayerPlaybackDidFinishNotification object:nil];
}
- (void) moviePlayerPlaybackStateDidChange:(NSNotification*)notification {
NSLog(#"playbackDidChanged");
MPMoviePlayerController *moviePlayer = notification.object;
MPMoviePlaybackState playbackState = moviePlayer.playbackState;
if(playbackState == MPMoviePlaybackStateStopped) {
NSLog(#"MPMoviePlaybackStateStopped");
} else if(playbackState == MPMoviePlaybackStatePlaying) {
NSLog(#"MPMoviePlaybackStatePlaying");
} else if(playbackState == MPMoviePlaybackStatePaused) {
NSLog(#"MPMoviePlaybackStatePaused");
} else if(playbackState == MPMoviePlaybackStateInterrupted) {
NSLog(#"MPMoviePlaybackStateInterrupted");
} else if(playbackState == MPMoviePlaybackStateSeekingForward) {
NSLog(#"MPMoviePlaybackStateSeekingForward");
} else if(playbackState == MPMoviePlaybackStateSeekingBackward) {
NSLog(#"MPMoviePlaybackStateSeekingBackward");
}
}
//3.2+ devices
- (void)moviePlayerLoadStateChanged:(NSNotification*)notification {
NSLog(#"load state changed");
//unless state is unknown, start playback
if ([self.moviePlayerController loadState] != MPMovieLoadStateUnknown) {
[[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerLoadStateDidChangeNotification object:nil];
self.moviePlayerController.view.frame = CGRectMake(0,0,320,416);
self.moviePlayerController.controlStyle = MPMovieControlStyleNone;
self.moviePlayerController.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.view addSubview:self.moviePlayerController.view];
self.moviePlayerController.fullscreen = NO;
[self.moviePlayerController play];
}
}
//pre 3.2 devices
- (void) moviePreloadDidFinish:(NSNotification*)notification {
// Remove observer
[[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerContentPreloadDidFinishNotification object:nil];
[self.moviePlayerController play];
}

I don't know why, but I was able to solve this by moving the line self.moviePlayerController.controlStyle = MPMovieControlStyleNone; out of the moviePlayerLoadStateChanged: method, and into the viewDidLoad method.
Anyone have any ideas why this made a difference?

Related

AdMob interstitial memory leak? Sprite kit

I have problem with AdMob and sprite kit.
Everytime ad will show or load, it will increase memory usage a lot!
When EndGameScene open it will call "showAd", and when replay button is pressed "loadAd".
Ads works well.
When game starts memory usage is something like 50mb and few ads later it is at least 70-100mb!
So what i do wrong:
GameViewController.m
- (void)viewDidLoad{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(handleNotification:) name:#"showAd" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(handleNotification:) name:#"loadAd" object:nil];
self.interstitial = [self createAndLoadInterstitial];
self.interstitial = [[GADInterstitial alloc] initWithAdUnitID:#"ca-app-pub-<id>"];
GADRequest *request = [GADRequest request];
// Requests test ads on test devices.
request.testDevices = #[#"0000000"];
[self.interstitial loadRequest:request];
//etc
}
- (void)handleNotification:(NSNotification *)notification{
if ([notification.name isEqualToString:#"showAd"]) {
if (self.interstitial.isReady) {
[ self.interstitial presentFromRootViewController:self];
}
else {
}
}
if ([notification.name isEqualToString:#"loadAd"]) {
self.interstitial = [self createAndLoadInterstitial];
}
}
- (GADInterstitial *)createAndLoadInterstitial {
GADInterstitial *interstitial =
[[GADInterstitial alloc] initWithAdUnitID:#"ca-app-pub-<id>"];
interstitial.delegate = self;
[interstitial loadRequest:[GADRequest request]];
return interstitial;}
Thanks!
You are creating everytime a new GADInterstitial object, which starts a load request. I guess because it is waiting for an answer it will never be released from memory again.
A better way would be to store the GADInterstitial in a global property and just call a new loadRequest, if you need a new ad.

MPMoviePlayerController does not dismiss view when clicking done?

I use a MPMoviePlayerController to play a video from Internet.
player = [player initWithContentURL:[NSURL URLWithString:videoURL]];
player.view.frame = CGRectMake(0, 0, videoView.frame.size.width, videoView.frame.size.height - 20);
[player setControlStyle:MPMovieControlStyleEmbedded];
player.scalingMode = MPMovieScalingModeAspectFit;
[player prepareToPlay];
player.shouldAutoplay = NO;
[videoView addSubview:player.view];
I notified that after I clicked the full screen button (2-arrows-button), I was navigated to the full size video screen. I couldn't restore down the screen by touching the Done button. I even used NSNotification but can't resolve the problem. Here is the Notification code:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(movieEventFullscreenHandler:)
name:MPMoviePlayerWillEnterFullscreenNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(movieEventFullscreenHandler:)
name:MPMoviePlayerDidEnterFullscreenNotification
object:nil];
}
- (void)movieEventFullscreenHandler:(NSNotification*)notification {
[player setFullscreen:NO animated:NO];
[player setControlStyle:MPMovieControlStyleEmbedded];
}
How can I dismiss that video screen by touching the Done button? Thanks guys.
You can use the notification of MPMoviePlayerPlaybackDidFinishNotification to observe the done button.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(playObserver:)name:MPMoviePlayerPlaybackDidFinishNotification object:nil];
and then,make a judge of quitting.
- (void) playObserver:(NSNotification *)notification
{
MPMoviePlayerController* player = moviePlayerView.moviePlayer;
if (player == [notification object]) {
if (_invalidVideoCount > MOVIE_TRY_TIMES) {
[self dismissViewController];
}
_invalidVideoCount++;
int reason = [[[notification userInfo] objectForKey:MPMoviePlayerPlaybackDidFinishReasonUserInfoKey] intValue];
//Whether continuous playback
if (![SINGLETON_CALL(SystemInfoManager) boolValueForKey:UserContinuousPlayEnableKey]) {
[self playFinishWithForce:YES];
return;
}
switch (reason) {
case MPMovieFinishReasonUserExited:
[self playFinishWithForce:YES];
break;
case MPMovieFinishReasonPlaybackError:
[self playFinishWithForce:YES];
break;
case MPMovieFinishReasonPlaybackEnded:
movieTryTimes = 0;
[self playFinishWithForce:NO];
break;
default:
break;
}
}
}
and the last.
- (void)playFinishWithForce:(BOOL)force
{
FileInfoItem *item = ARRAY_OBJECT_AT_INDEX(_playlist, _currentIndex);
BOOL quit = force || !item;
if (quit) {
[self dismissViewController];
} else {
[self playMovieWithItem:item];
}
}
Also you can use the notification of MPMoviePlayerPlaybackStateDidChangeNotification to make any observe.something detail see MPMoviePlayerController.h or https://developer.apple.com/library/ios/documentation/MediaPlayer/Reference/MPMoviePlayerController_Class/Reference/Reference.html
I have found the problem. That's I laid [player stop] in the viewWillDisAppear so can't handle the notification. I fixed temporary by changing it to [player pause]. I appreciated any kind of your helps.

why isn't removeFromSuperview removing my movie subview? Xcode

I'm trying to get a movie that plays to dismiss on its own without having to hit the "Done" button. I think it's a recent iOS 6 problem since I'm following a tutorial exactly and when I insert NSLogs the NSNotification and removeFromSuperview are being recognized but the movie stays there once it has ended. Here's my code, please help:
- (IBAction)playMovie:(id)sender
{
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle]
pathForResource:#"RomneyFlipSequence1" 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:NO];
}
- (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];
}
}
#end
You entered the player into fullscreen mode.
[_moviePlayer setFullscreen:YES animated:NO];
Reading other solutions in SO it seems that when you press "Done" the player is taken out of fullscreen first, and then the notification is thrown. After reading this answer, adding
[_moviePlayer setFullscreen:NO animated:YES];
before your removeFromSuperview call will solve your problem.
If the above doesn't work, in addition you may try stoping the player first so the full code will be
-(void)removePlayer:(MPMoviePlayerController *)player{
NSLog(#"Playback Finished");
[[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerPlaybackDidFinishNotification object:_moviePlayer];
[[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerDidExitFullscreenNotification object:_moviePlayer];
[_moviePlayer stop]; // <-- May not be needed
if ([_moviePlayer respondsToSelector:#selector(setFullscreen:animated:)])
{
[_moviePlayer setFullscreen:NO animated:YES];
[_moviePlayer.view removeFromSuperview];
}
_moviePlayer=nil;
}
I use the same method for both notifications "Done" and "PlayBackFinished"
Hope this helps.
You had added _moviePlayer.view as a view and you are trying to remove player.view
i think this will do it :
- (void) moviePlayBackDidFinish:(NSNotification*)notification {
MPMoviePlayerController *player = [notification object];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:player];
if ([player
respondsToSelector:#selector(setFullscreen:animated:)])
{
[_moviePlayer.view removeFromSuperview];
}
}

memory leak during release of movieplayer

In one of my apps i want to play a video file from local.so iam using the below code for playing the file.
-(IBAction)playMovie{
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle]pathForResource:#"Myvideo" ofType:#"mov"]];
MPMoviePlayerController *moviePlayer=[[[MPMoviePlayerController alloc]initWithContentURL:url]autorelease];
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(moviePlayBackDidFinish:) name:MPMoviePlayerPlaybackDidFinishNotification object:moviePlayer];
moviePlayer.controlStyle = MPMovieControlStyleEmbedded;
moviePlayer.shouldAutoplay = YES;
[self.view addSubview:moviePlayer.view];
[moviePlayer setFullscreen:YES animated:YES];
//[moviePlayer release];
}
-(void) moviePlayBackDidFinish:(NSNotification*)notification {
MPMoviePlayerController *moviePlayer = [notification object];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:moviePlayer];
if ([moviePlayer
respondsToSelector:#selector(setFullscreen:animated:)])
{
[moviePlayer.view removeFromSuperview];
}
[moviePlayer release];
}
when i go to analyse or do profile for the above code there shows a warning potential leak happening at 2 places i.e,
[moviePlayer setFullscreen:YES animated:YES];
//[moviePlayer release];
one more is leak is at this part
{
[moviePlayer.view removeFromSuperview];
}
[moviePlayer release]
so how to avoid this memory leak.Even i tried giving autorelease the NSURL Line in the begining of the code,when i do autorelease leak wont happen but video wont play.so how to solve this issue can anyone help??
try this in moviePlayBackDidFinish method, may be it will help
if (videoPlayer) {
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification object:videoPlayer];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerLoadStateDidChangeNotification object:videoPlayer];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMovieMediaTypesAvailableNotification object:videoPlayer];
[videoPlayer pause];
videoPlayer.initialPlaybackTime = -1;
[videoPlayer stop];
[videoPlayer.view removeFromSuperview];
[videoPlayer release];
videoPlayer = nil;
}

MPMoviePlayerViewController exits after background

When my app goes to background and back, modal view closes. Why is this happend? I tried with pause on and off. I have ARC enabled, if it is a useful info.
MPMoviePlayerViewController * player = [[MPMoviePlayerViewController alloc] initWithContentURL:targetURL];
[player.moviePlayer prepareToPlay];
[self presentMoviePlayerViewControllerAnimated:player];
In case anyone else stumbles across this (as I did before I found my own solution), I was able to prevent MPMoviePlayerViewController from exiting when the app backgrounds by subclassing it and removing it as an observer of UIApplicationDidEnterBackgroundNotification:
- (id)initWithContentURL:(NSURL *)contentURL {
self = [super initWithContentURL:contentURL];
if (self){
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:nil];
}
return self;
}
You don't need to subclass MPMoviePlayerViewController - just do following after creating MPMoviePlayerViewController instance.
[[NSNotificationCenter defaultCenter] removeObserver:self.moviePlayerViewController name:UIApplicationDidEnterBackgroundNotification object:nil];
Here is full code that can help you
// Call this to start initialization and play movie
-(void)prepareMoviePlayer:(NSURL *)moviePath
{
moviePlayerViewController = [[MPMoviePlayerViewController alloc] initWithContentURL:moviePath];
if ([[moviePlayerViewController moviePlayer] respondsToSelector:#selector(loadState)])
{
[[moviePlayerViewController moviePlayer] setControlStyle:MPMovieControlStyleNone];
[[moviePlayerViewController moviePlayer] setFullscreen:YES];
[[moviePlayerViewController moviePlayer] prepareToPlay];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayerLoadStateDidChange:)
name:MPMoviePlayerLoadStateDidChangeNotification
object:nil];
}
}
- (void) addPlayer
{
[[[moviePlayerViewController moviePlayer] view] setFrame:self.view.bounds];
[[self view] addSubview:[[moviePlayerViewController moviePlayer] view]];
}
static NSTimeInterval t;
// Call this on applicationWillResignActive
-(void) pauseMovieInBackGround
{
[[moviePlayerViewController moviePlayer] pause];
t = [[moviePlayerViewController moviePlayer] currentPlaybackTime];
[moviePlayerViewController.view removeFromSuperview];
}
// Call this on applicationWillEnterForeground
-(void) resumeMovieInFrontGround
{
[self addPlayer];
[[moviePlayerViewController moviePlayer] stop];
[[moviePlayerViewController moviePlayer] setInitialPlaybackTime:t];
[[moviePlayerViewController moviePlayer] play];
}
-(void)moviePlayerLoadStateDidChange:(NSNotification *)notification
{
if([[moviePlayerViewController moviePlayer] loadState] != MPMovieLoadStateUnknown)
{
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerLoadStateDidChangeNotification
object:nil];
[self addPlayer];
[[moviePlayerViewController moviePlayer] play];
}
}
-(void)videoPlayBackDidFinish:(NSNotification*)notification
{
[self dismissMoviePlayerViewControllerAnimated];
}
I am coming across this issue.
I've tried ChrisH's answer, but it didn't work for me until I put removeObserver into viewDidLoad() instead of init().
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:nil];
}
Then it works. Enjoy it.