MPMoviePlayerController inside UITabBarController - iphone

Ok, so here's the thing. I have a UIViewController that contains a UITabBarController. That tab bar has a UIViewController for each tab button. Now, inside one of the tab buttons is an MPMoviePlayerController that is playing a stream from over the network. Playing the stream works just fine and you can see the video and hear the audio.
The problem is when you navigate to another tab. The audio still plays, which is good, but when you go back to the stream, the video is black. The audio is still playing, but the video needs to be playing too.
Has anyone run into this problem before?
I'm currently using iOS 4.0 to build against and an iPhone 3GS.
If more information is needed, just ask and I'll do my best to answer.
Thanks,
Robbie

Strange things might happen if the view isn't on-screen (I believe it's removed from the view hierarchy when you switch tabs).
Have you tried using MPMoviePlayer's view directly? (not MPMoviePlayerController)
Can you add and remove the view and keep the movie playing?
Does pausing and resuming help?
Could you pass the view around between view controllers, or maybe make it a direct subview of the window in viewWillDisappear and move it back in viewDidAppear? (I'm not sure if the view's been removed from the hierarchy in viewWillAppear/viewDidDisappear.)

The solution I'm going ahead with is entering fullscreen mode and exiting fullscreen mode very quickly. It may not be the best thing, but it's working.

This still happens on iOS 6. If I have two movie player (one on each tab), even if they are not playing, if I switch form the first to the seconds tab and return to the first, the movie player will be black.
My solution was as simple as calling prepareToPlay on -viewDidAppear::
- (void)viewDidAppear:(BOOL)animated;
{
[super viewDidAppear:animated];
[self.moviePlayer prepareToPlay];
}
I believe this will add the shared internal view of MPMoviePlayerController to the view hierarchy.

Related

Navigation from AppDelegate to a view controller don't disable the audio playing of previous view controller

i am a newbie in iOS programming. I am having a problem with navigation controller. My rootViewController is 'WelcomeViewController'. I navigate to 'AbcViewController' from the root view & when the 'AbcViewController' is loaded it plays an audio file. But when i receive an special message into my 'AppDelegate' class, i am pushing into XyzViewController from the AppDelegate class. But the problem is the audio playing of AbcViewController continues playing though the current view is showing the XyzViewController. But the player shouldn't play while the visible controller is XyzViewController. I think there is a problem with my navigation. How can i solve this problem?
As already stated by Robert, you need to stop audio in AbcViewController viewWillDisapper:
Hope that help.

Multiple AVPlayers with AVPlayerLayers disappears second time push viewcontroller

I have a viewcontroller with four (4) AVPlayers (with AVPlayerLayers like APPLE example).
If I pop this viewcontroller and the push a new instance of the same type. I'm not able to play video in one or two AVPlayers. No errors and code runs fine, AVPlayerLayers also says it has a superLayer.
And to the most strange thing if I push home button, coming back to springboard and the enter the app all video players like magic start playing. It's like it rerender the view tree or something.
Any hints or clues?
PS. I wait for assets to be ready using loadValuesAsynchronouslyForKeys.
We had a similar problem. Following answer lead to the solution:
AVplayer not showing in ScrollView after 2-3 times
You have to call: [AVPlayer replaceCurrentItemWithPlayerItem:nil]; when your viewcontroller gets unloaded. This might be tricky as you might have added an observer or used addBoundaryTimeObserverForTimes:queue:usingBlock:
Also you have to be careful when checking agaings superlayer: Better check against uiview.window when determing whether your view is still attached to the view hierarchy.
yours
phil

How can I make `-[MPMoviePlayerController backgroundView]` to show immediately?

Currently my -[MPMoviePlayerController backgroundView] does not appear until movie loaded enough. So UIActivityIndicatorView which I placed on there does not appear immediately. This drives me crazy. The only solution have been found is placing duplicated indicator-view somewhere between background-view and -[MPMoviePlayerController view]. But this does not look regular, and definitely a view hierarchy hack which is not guaranteed to work properly. If the background-view shows immediately, all will work magically.
How can I make the background-view immediately before movie loaded?
Do not use the backgroundView but the view of the moviecontroller itself...
Following steps (assuming your MPMovieControllerPlayer instance is called moviePlayerController and your UIActivityIndicatorView instance is called activityIndicatorView)
Add your UIActivityIndicatorView on top of the MPMoviePlayerController view (e.g. [moviePlayerController.view addSubview:activityIndixatorView];)
Start animating the activity indicator
Register for MPMoviePlayerLoadStateDidChangeNotification
Within the handler of the above notification, watch out for moviePlayerController.loadState & MPMovieLoadStatePlayable == MPMovieLoadStatePlayable
If the above condition is matched, hide your activity indicator
I am not sure but Can a UIActivityIndicator be displayed over a MPMoviePlayerController in full screen mode? may help you a bit

Preventing view from unloading in iOS SDK?

I've built an app that uses a UITableView inside a UINavigationController, inside a UITabBarController. Every entry in the UITableView opens up a view that contains some basic text, buttons, but most importantly, an MPMoviePlayerController that plays audio when started. A user can click this MPMoviePlayerController and continue to browse around the rest of the app (different tabs, or moving back in the navcontroller, opening other views from the tableview) and continue to hear the audio.
I'd like the user to be able to return to the view with the active MPMoviePlayerController at any time. I understand how I would go about allowing the user to return to a certain view from any view, but I'm struggling with how to prevent that view from being reloaded when the user tries accessing the same view.
Is there any way I can save a view in memory? Or save the active MPMoviePlayerController as some type of global object, so that I can at least access that from anywhere?
I appreciate any and all help. Thanks!
I'd recommend you create a property for the MPMoviePlayerController in your app's UIApplicationDelegate (which you can then access from anywhere in the code with [UIApplication sharedApplication].delegate but you will need to cast to your UIApplicationDelegate subclass).
When you come to enter the screen which plays content, check whether your movie player property in the app delegate is nil, if it is create it, otherwise re-use it.
Don't forget to release the reference to your MPMoviePlayerController when the media stops playing, or when the media has already stopped and you get a memory warning or when your app shuts down.
The down side of this approach is it causes coupling between most of your view controllers and your app delegate. You could mitigate this with the use of a protocol however.
You should simply retain it. Like this [myView retain] and keep a pointer to it in where you need. When you want myView to appear, just add it as a subview to current visible view like[myController.view addSubview:myView].
Hope that will help, Good luck!
I've found that even adding a retain doesn't do the trick. I've actually found the best success with overriding the setView (since part of unloading the view involves calling setView:nil. I have a BOOL that gets set the FIRST time the VC loads and once thats set it will never allow setView to be called again.
- (void) setView: (UIView*) view{
NSLog(#"MainViewController: setView");
// this is our attempt to stop iOS from unloading our view.. when iOS tries to unload your view they call setView:nil.. so, no!
if(!viewDidAppear) [super setView:view];
}
A little bit of a hack, but you can override setView: in your subclass so that it never allows to set the view to nil:
-(void)setView:(UIView *)view
{
if (view == nil) return;
[super setView:view];
}

UIWebView/MPMoviePlayerController and the "Done" button

I am using the UIWebView to load both streaming audio and video. I have properly set up the UIWebView delegate and I am receiving webViewDidStartLoading and webViewFinishedLoading events perfectly. The webview launches a full screen window (likely a MPMoviePlayerController)
Apple's MoviePlayer example gets the array of Windows to determine which window the moviePlayerWindow is for adding custom drawing/getting at the GUI components. I believe this to be a bad practice/hack.
My expectation is that I should be able to figure out when that button was clicked by either a delegate method or an NSNotification. It may also be the case that I have to poke around subviews or controllers with isKindOf calls, but I don't think those are correct approaches.
Are my expectations incorrect, and if so, why?
What is the correct way to bind an action to that "Done" button?
There isn't an MPMoviePlayer instance method that covers this. You can use - (void) moviePlayBackDidFinish:(NSNotification*)notification to find out when the movie has finished. Or you could overlay the existing Done button with your own and have complete control that way.
You can also use MPMoviePlayerWillExitFullscreenNotification in order to conrol the action provided that youe MoviePlayer is in fulscreen mode.