How do I dismiss subview in MPMoviePlayer? - mpmovieplayercontroller

I have a video that auto plays at launch. When the short clip is finished it shows a black screen. I would like to dismiss the subview to show an image or auto load another controller??
Below is my code:
(void)viewDidLoad
{
{
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle]
pathForResource:#"cover" ofType:#"mp4"]];
MPMoviePlayerController *player = [[MPMoviePlayerController alloc]
initWithContentURL:url];
player.movieSourceType = MPMovieSourceTypeFile;
[player setControlStyle:MPMovieControlStyleNone];
player.view.frame = CGRectMake(0, 0, 768, 960);
[self.view addSubview:player.view];
[player play];
player = nil;
}
Thanks for any help..i'm a rookie at this.

I figured out a lot of this a couple of weeks ago. Check out the notifications available. http://developer.apple.com/library/ios/#documentation/mediaplayer/reference/MPMoviePlayerController_Class/Reference/Reference.html
Add something like this to viewDidLoad:
// Remove the movie player view controller from the "playback did finish" notification observers
[[NSNotificationCenter defaultCenter] removeObserver:_moviePlayer
name:MPMoviePlayerPlaybackDidFinishNotification
object:_moviePlayer];
// Register this class as an observer instead
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(movieFinishedCallback:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:_moviePlayer];
Now you have a method where you can re-add the view, or a thumbnail, or whatever:
- (void)movieFinishedCallback:(NSNotification*)aNotification
{
// Obtain the reason why the movie playback finished
NSNumber *finishReason = [aNotification userInfo][MPMoviePlayerPlaybackDidFinishReasonUserInfoKey];
if ([finishReason intValue] == MPMovieFinishReasonPlaybackEnded) {
[self.view addSubview:self.moviePlayer.view];
}
(This code was adapted on the fly from my project, may need thinking to adapt!)
The MPMoviePlayerController has a lot of notifications that get fired when the movie is playing, is paused, is stopped, is finished, etc. You can add your code to those methods to get very good control of your presentation.
In my case, it took about a day of research and hacking (and maybe another half day of cleanup and tuning), but I managed to get a very nice play/pause transparent button, with a "play icon" image overlay when paused or stopped, all loading or unloading based on the player state. It's a simple custom player control that does exactly what I want. Totally doable, just start with one player state, get what you want, and move onto the next state.

Related

iOS8: What's going on with moving views during keyboard transitions?

After switching to iOS8, I'm getting weird behavior when I move views during a keyboard transition. Can anyone explain what's going on?
Here's a minimal example to demonstrate the problem. I have a simple view with a UITextField and a UIButton. The function nudgeUp moves the text field and the button up by 10 points. It is triggered either by the buttonPressed callback, or the keyboardWillShow callback.
When I tap the button, the code works as expected: buttonPressed calls nudgeUp and the button and text field jump up by 10 points.
When I tap the text field, keyboardWillShow calls nudgeUp, but the behaviour is very different. The button and text field immediately jump down by 10 points, and then slide back up to their original position as the keyboard shows itself.
Why is this happening? How can I regain control of animations during keyboard presentation in iOS8?
#import "ViewController.h"
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
}
- (void)keyboardWillShow:(NSNotification *)notification
{
// Called when the keyboard appears.
[self nudgeUp];
}
- (IBAction)buttonPressed:(id)sender {
[self nudgeUp];
}
- (void)nudgeUp
{
CGRect newTextFieldFrame = self.textField.frame;
newTextFieldFrame.origin.y -= 10;
self.textField.frame = newTextFieldFrame;
CGRect newButtonFrame = self.button.frame;
newButtonFrame.origin.y -= 10;
self.button.frame = newButtonFrame;
}
#end
It's AutoLayout. Something changed in iOS8 and you can't just change frame or center points anymore if you have AutoLayout enabled. You have to create an outlet(s) of your constraint (vertical space) and update it accordingly instead of changing frame position. Constraints are like any other ui control and can have an outlet. Constraint change can be animated.
Example:
[UIView animateWithDuration:[notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue] delay:0 options:[[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] integerValue] animations:^{
self.bottomSpaceConstraint.constant = adjustmentedValue;
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
}];
You should use UIKeyboardDidShowNotification (you're using will version) and everything will work as you expect:
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardDidShow:)
name:UIKeyboardDidShowNotification
object:nil];
}
- (void)keyboardDidShow:(NSNotification *)notification
{
// Called when the keyboard finished showing up
[self nudgeUp];
}
The explanation is that with UIKeyboardWillShowNotification you are changing the frames too early. After your changes the system will relayout everything to accomodate the keyboard and your changes won't have any effect.
Also, I recommend you to switch to autolayout and forget about frames.
Try using the UIKeyboardWillShowNotification userInfo to give you the frame of the keyboard. Then move the onscreen elements based on that.

UIScrollView breaking when a new subview added

I'm fairly new to coding for the iOS platform and objective C in general. I'm writing a simple iPhone app utilizing storyboard that has a tall png file displayed via UIImageView embedded within a UIScrollView and a button next to it that will play a movie.
My issue is that when the movie finishes/exits and comes back to the original screen, the scrolling within the UIScrollView does not work. I have nailed down the "cause". It occurs when I add the MPMoviePlayerViewController object.view to the self.view subview. But I'm not sure how to rectify this issue. Here is my distilled code:
.h file
#interface StuffViewController : UIViewController
#property (strong,nonatomic) IBOutlet UIImageView *imageView;
#property (strong,nonatomic) IBOutlet UIScrollView *scrollView;
-(IBAction) playMovie;
-(void) moviePlayBackDidFinish:(NSNotification*)notification;
#end
.m file
-(void) viewDidLoad {
self.imageView.image = [UIImage imageNamed:#"image.png"];
}
-(void) viewDidAppear:(BOOL)animated {
self.scrollView.contentSize = self.imageView.image.size;
}
-(void) playMovie {
NSURL *movieURL = [NSURL fileURLWithPath:[[NSBundle mainBundle]
pathForResource:#"movieTitle" ofType:#"mp4"]];
MPMoviePlayerController *moviePlayer = [[MPMoviePlayerController alloc]
initWithContentURL:movieURL];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayBackDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:moviePlayer];
[moviePlayer setMovieSourceType:MPMovieSourceTypeFile];
[[self view] addSubview:moviePlayer.view]; //SCROLLING BREAKS HERE
[moviePlayer setFullscreen:YES];
[moviePlayer play];
}
-(void)moviePlayBackDidFinish: (NSNotification*)notification {
MPMoviePlayerController *movieDone = [notification object];
[[NSNotificationCenter defaultCenter] removeObserver:self];
[movieDone.view removeFromSuperview];
[movieDone setFullscreen:NO];
}
I have determined the culprit by commenting out sections, and like I said, the scrolling "locks" at the "[[self view] addSubview:moviePlayer.view];" line and doesn't recover until I navigate to a different view and then come back.
Any and all help on this would be greatly appreciated.
EDIT: I have discovered an interesting wrinkle that might help discover the underlying issue.
I have been using MPMoviePlayerController this whole time. However upon switching to MPMoviePlayerViewController some interesting things have been happening.
Here is the changed -(void)playMovie
-(void) playMovie {
self.scrollView.contentOffset = CGPointZero;
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle]
pathForResource:totalTitle ofType:#"mp4"]];
MPMoviePlayerViewController *playerController = [[MPMoviePlayerViewController alloc] initWithContentURL:url];
[self presentMoviePlayerViewControllerAnimated:playerController];
playerController.moviePlayer.movieSourceType = MPMovieSourceTypeFile;
[playerController.moviePlayer play];
playerController = nil;
}
What is interesting is that the UIScrollView will still work, HOWEVER, if it has been scrolled down at all it will no longer be able to scroll up from where it was when the movie started. I fixed this by adding self.scrollView.contentOffset = CGPointZero at the beginning of the playMovie to tell the scrollView to move to the top (so there would be nothing above it to have to scroll back to). I assume that adding some sort of if-statement to the code in viewDidAppear that would keep scrollView.contentSize from re-executing might fix the problem of not being able to scroll back up, however I like the 'cleanness' of it starting back at the top.
One last issue though. Using MPMoviePlayerViewController like this has caused a number of interesting errors to pop up in my debugger right when MPMoviePlayerViewController *playerController = [[MPMoviePlayerViewController alloc] initWithContentURL:url]; line is executed. They are as follows:
Oct 25 10:25:51 Compy.local AppName[14590] <Error>: CGContextSaveGState: invalid context 0x0
Oct 25 10:25:51 Compy.local AppName[14590] <Error>: CGContextClipToRect: invalid context 0x0
Oct 25 10:25:51 Compy.local AppName[14590] <Error>: CGContextTranslateCTM: invalid context 0x0
Oct 25 10:25:51 Compy.local AppName[14590] <Error>: CGContextDrawShading: invalid context 0x0
Oct 25 10:25:51 Compy.local AppName[14590] <Error>: CGContextRestoreGState: invalid context 0x0
It doesn't seem to break anything. I tend to be a perfectionist when it comes to errant error statements however. I've done some research on these errors, however I haven't found anything suitable that would lend a strong hand in this situation.
Thanks for all the help so far! Once again, I would appreciate any and all help on this as well.
Are you sure that everything gets removed from the superview? Also, you might try replacing
MPMoviePlayerController *movieDone = [notification object];
with
MPMoviePlayerController *movieDone = (MPMoviewPlayerController *)[notification object];
and also add
movieDone = nil;
To make sure that your MPMoviePlayerController is completely removed from the superView, try pressing a button on your view (created before adding the MPMoviePlayerController) after the video's finished playing and see if it fires. The navigation controller must present your MPMoviewPlayerController modally or make a push. If it is modally presented, try dismissing it when the the playback's finished.
The cause of the problem was the use of 'Autolayout' in Storyboard. I'm not 100% sure why it would cause it problem after playing a movie and not before. However I fixed it by either:
A: removing Autolayout
or
B: playing with the constraint functions until it ended up working. (Changing the height of the UIImageView to 0 and changing the Equals: Default to have the lowest priority possible.)
Try setting the SetUserInteractionEnabled of self and/or self.scrollview to YES in the moviePlayBackDidFinish method.
Also, check the size of the scroll view's ContentSize property, to check if the size is bigger than your actual screen size to see if that's causing the scroll view's functionality to break.

IOS 6 Issue with MPMoviePlayerController

Please check the below code:
(void) moviePlayerDidExitFullscreen:(NSNotification*)notification
{
MPMoviePlayerController *player = [notification object];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerDidExitFullscreenNotification
object:player];
[player setControlStyle:MPMovieControlStyleNone];
if (isPlaying)
{
[self stopCurrentMoviePlayer];
}
}
The issue is that this works perfectly in IOS 5, but not working in IOS 6 updates iPad3.
The movie player is not closing after the video is complete and I need to click done button every time to close the Movie Player.
Can anyone provide a solution for this issue?
Clicking done will call moviePlayerDidExitFullscreen
But if you let the movie finish normally moviePlaybackDidFinish is called but since IOS 6 it doesn't exit you from fullscreen mode. So the fix is to add player.fullscreen = FALSE; right before calling
[player.view removeFromSuperview];

MPMoviePlayerController not playing URL from GDataFeedYouTubeVideo

I am using GDataFeedYouTubeVideo to populate a tableview with images and titles. This works. I want to play the video after the cell is selected. I am using the url from the feed to pass to the MPMoviePlayer and it looks like it loads because the screen goes black, the moviePlaybackDidFinish is called but does not play the video and goes back to displaying the tableview? An example url from the feed is:
https://www.youtube.com/v/o7QAMH3qRvU?version=3&f=user_uploads&app=youtube_gdata
This does work from a browser but not in the MPMoviePlayer? Please help me figure this one out. I would rather not have to write some hack routine to replace or remove the URLString returned by the feed. I am using ARC & Storyboards. The second time I select a cell I get:
An instance 0xce6a7b0 of class AVPlayerItem was deallocated while key value observers were still registered with it...
Yes I did try what was suggested in:
iOS 5 an instance of AVPlayerItem was deallocated
and this did not fix it.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
YouTubeVideo *item = [searchList objectAtIndex:indexPath.row];
if (item != nil) {
NSURL *url = [NSURL URLWithString:item.URLString];
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:YES];
}
}
- (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];
}
Tried this and it works if I format the url slightly:
https://github.com/hellozimi/HCYoutubeParser

MPMoviePlayerController keeps playing after view did unload?

I have a detail view, and when viewdidload in detailviewcontroller, MPMoviePlayerController allocs and plays an audio, but even if I navigate backto main table, audio is still being played.
How can I stop MPMovieplayercontroller when I navigate back to main table ? This is my MPMoviePlayerController code:
.h
MPMoviePlayerController *player;
.m
- (void)viewDidLoad
{
[super viewDidLoad];
//Get the Movie
NSURL *movieURL = [NSURL URLWithString:#"some link"];
player = [[MPMoviePlayerController alloc] initWithContentURL:movieURL];
//Place it in subview, else it won’t work
player.view.frame = CGRectMake(20, 20, 280, 25);
player.backgroundView.backgroundColor = [UIColor clearColor];
[self.view addSubview:player.view];
// Play the movie.
[player play];
}
I even added following code into viewdidunload method, but didn't work.
- (void)viewDidUnload {
[player stop];
player.initialPlaybackTime = -1;
[player release];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
What do you guys suggest ?
Thanks in advance,
I liked the user experience of viewDidDisappear better than viewWillDisappear. The animation starts and the movie stops after - the audio flows better for me this way.
-(void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[_moviePlayer stop];
}
I am having a similar issue. I am unable to use "viewDidDisappear" or "viewWillDisappear" because I have a "config" type view that can be opened while the content is playing, and it will trigger those two methods.
EDIT: Found that viewDidUnload and viewWillUnload are not getting called any more (I'm currently on an iOS 6+ device)...
From the documentation:
Availability: iOS (3.0 and later) Deprecated: Views are no longer
purged under low-memory conditions and so this method is never called.
I just created a simple function called unload, and inside the function, set any objects I needed to = nil (I'm using ARC). At the time that I make the call to remove the view, I call the unload function as well. Hope it helps someone.

Resources