The movie plays just fine but there is a quick black flash right before it plays. Is this a quirk resulting from setting the controlstyle to MPMovieControlStyleNone?
NSString *url = [[NSBundle mainBundle] pathForResource:#"00" ofType:#"mov"];
MPMoviePlayerController *player = [[MPMoviePlayerController alloc]
initWithContentURL:[NSURL fileURLWithPath:url]];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(movieFinishedCallback:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:player];
//---play video in implicit size---
player.view.frame = CGRectMake(80, 64, 163, 246);
[self.view addSubview:player.view];
// Hide video controls
player.controlStyle = MPMovieControlStyleNone;
//---play movie---
[player play];
I just had this problem and fixed it by adding an observer to the default NSNotificationCenter to find out when the movie was completely ready to play, and THEN adding the view as a subview to my main view.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(checkMovieStatus:) name:MPMoviePlayerLoadStateDidChangeNotification object:nil];
...
if(moviePlayer.loadState & (MPMovieLoadStatePlayable | MPMovieLoadStatePlaythroughOK))
{
[pageShown.view addSubview:moviePlayer.view];
[moviePlayer play];
}
In IOS 6 mpmoviewplayer added a new property :readyForDisplay
this is what I'm playing around with and so far so good:
create mpmovieplayer ,add to stage, hide it.
add notification for play state on the movieController
wait for the displayState to Change and once its ready show the video controller:
- (void)moviePlayerPlayState:(NSNotification *)noti {
if (noti.object == self.movieController) {
MPMoviePlaybackState reason = self.movieController.playbackState;
if (reason==MPMoviePlaybackStatePlaying) {
[[NSNotificationCenter defaultCenter] removeObserver:self name: MPMoviePlayerPlaybackStateDidChangeNotification object:nil];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
while (self.movieController.view.hidden)
{
NSLog(#"not ready");
if (self.movieController.readyForDisplay) {
dispatch_async(dispatch_get_main_queue(), ^(void) {
NSLog(#"show");
self.movieController.view.hidden=NO;
});
}
usleep(50);
}
});
}
}
}
When the play state changes to MPMoviePlaybackStatePlaying we start checking for the readyDisplayState to change.
Evidently there is a flash of black in the movie rect until enough movie loads so it can start playback. Here is my workaround:
Create a UIImageView and put the MPMoviePlayerController in it. That way you can set the alpha to 0.
As soon as you call [player play]; to play the video, set up a .5 second timer.
When the time is done, change the alpha to 1.
This will make the player invisible for 1/2 second (which hides the black flash).
Create video without addSubview and play instructions:
NSString *filepath = [[NSBundle mainBundle] pathForResource:#"video" ofType:#"mp4"];
NSURL *fileURL = [NSURL fileURLWithPath:filepath];
MPMoviePlayerController *moviePlayerController = [[MPMoviePlayerController alloc] initWithContentURL:fileURL];
[moviePlayerController.view setFrame:CGRectMake(80, 64, 163, 246)];
moviePlayerController.controlStyle = MPMovieControlStyleNone;
Prepare video to play and add notification:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(checkMovieStatus:) name:MPMoviePlayerLoadStateDidChangeNotification object:nil];
[moviePlayerController prepareToPlay];
Create function checkMovieStatus with addSubview and play instructions:
- (void)checkMovieStatus:(NSNotification *)notification {
if(moviePlayerController.loadState & (MPMovieLoadStatePlayable | MPMovieLoadStatePlaythroughOK)) {
[self.view addSubview:moviePlayerController.view];
[moviePlayerController play];
}
}
Or simply change the color of the view, that is what your actually seeing...
player.view.backgroundColor = [UIColor colorWithRed:1 green:1 blue:1 alpha:0];
I believe the black flash may be related to the movieSourceType property of MPMoviePlayerController.
If you don't set it, it defaults to MPMovieSourceTypeUnknown which causes the UI to be delayed until the file is loaded.
Try adding this line:
player.movieSourceType = MPMovieSourceTypeFile;
Right after initializing player.
To avoid the black flash, use a MPMoviePlayerViewController instead of a MPMoviePlayerController. I think that this class creates the background on view display, rather than on video load (like MPMoviePlayerController does).
Before adding the moviePlayerViewController.moviePlayer.view to your display view, you have to add a white subview (or a subview appropriate for your content) to the backgroundView, like this:
[moviePlayerViewController.moviePlayer.view setFrame:[displayView bounds]];
UIView *movieBackgroundView = [[UIView alloc] initWithFrame:[displayView bounds]];
movieBackgroundView.backgroundColor = [UIColor whiteColor];
[moviePlayerViewController.moviePlayer.backgroundView addSubview:movieBackgroundView];
[movieBackgroundView release];
Fond solution here http://joris.kluivers.nl/blog/2010/01/04/mpmovieplayercontroller-handle-with-care/
from iOS 6
you need to use [self.moviePlayer prepareToPlay]; and catch MPMoviePlayerReadyForDisplayDidChangeNotification to use [self.moviePlayer play];
Related
I am having a problem with rotate youtube video. I added the following code to my app. And it works for iOS 7. However, it doesn't for iOS8.
In my view controller, I used the following code:
if(IS_OS_6_OR_LATER){
// I use the following notification for iOS 7
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(youTubeStarted:) latername:#"UIMoviePlayerControllerDidEnterFullscreenNotification" object:nil];//Notification
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(youTubeFinished:) name:#"UIMoviePlayerControllerWillExitFullscreenNotification" object:nil];//Notification
}
if (IS_OS_8_OR_LATER) {
// I use the following notification for iOS 8
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(youTubeStarted:) name:UIWindowDidBecomeVisibleNotification object:self.view.window];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(youTubeFinished:) name:UIWindowDidBecomeHiddenNotification object:self.view.window];
}
-(void) youTubeStarted:(NSNotification*) notif {
//Handle event
AppDelegate* appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
appDelegate.fullScreenVideoIsPlaying = YES;
NSLog(#"start fullscreen");
}
-(void) youTubeFinished:(NSNotification*) notif {
AppDelegate* appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];//Notification
appDelegate.fullScreenVideoIsPlaying = NO;//Notification
NSLog(#"exit fullscreen");//Notification
}
-(BOOL) shouldAutorotate {
//Handle rotate
NSLog(#"AutoState");
return NO;
}
-(NSUInteger)supportedInterfaceOrientations{
//Handle rotate
NSLog(#"AutoState 1");
return UIInterfaceOrientationMaskPortrait;//Notification
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
//Handle rotate
NSLog(#"AutoState 2");
return UIInterfaceOrientationPortrait;//Notification
}
In iOS 7, when video is played in Landscape mode, I press Done button, I see log 'AutoState 1' is shown however I don't see this log when running with iOS 8. Can you help me resolve this on iOS 8? Thank you very much
Instead of limiting the entire app to Portrait and then trying to make the video player allow landscape, you should instead allow landscape all over your app and then limit your invididual view controllers (or the root view controller) to only allow Portrait mode, like this:
In the target settings, allow landscape for your app:
In your view controller(s), add this to limit it to portrait orientation:
-(NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskPortrait;
}
I have a music button in the main UI of iOS and I want the button function as stop music button and at the same time can play the music again. My problem is I can only stop the music but can't play it again. Here is my iOS code in xcode4. How can I define one button for both play and stop music button? I have assigned one button for both stopMusic and playMusic but it doesn't work.
- (IBAction)stopMusic{
self.playBgMusic.enabled = YES;
[self.player stop];
}
- (IBAction)playMusic{
self.playBgMusic.enabled = YES;
[self.player play];
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"music" ofType:#"mp3"];
self.player=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
player.delegate = self;
[player play];
player.numberOfLoops = -1;
[super viewDidLoad];
}
Rather than have a single button try to send two different messages (stopMusic, playMusic), have it send toggleMusic every time. The toggleMusic method can then stop or play the music based on the current state of the player.
- (IBAction)toggleMusic{
if ([self.player isPlaying] == YES) {
[self.player stop];
} else {
[self.player play];
}
self.playBgMusic.enabled = YES;
}
I have a small UIView that I hide/show in to show a message to the user. The message itself is in a UITextView that I add to the small UIView that gets shown.
The sliding-in and sliding-out works fine - but the prior messages are not cleared. I have spent enough time to fix the problem - but to no avail. Can someone lend me their eyes!!
Here is how the UITextField is created programatically:
#interface MessageVC : UIViewController {
UITextView *messageTV;
}
#property (nonatomic, retain) UITextView *messageTV;
- (id)init;
- (void)showMsg:(NSString *)title;
#end
and
- (id)init {
if (self = [super init]) {
self.view = [[[UIView alloc] initWithFrame:CGRectMake(0, 380, 320, 100)] autorelease];
[self.view setBackgroundColor:[UIColor blackColor]];
}
return self;
}
- (void)showMsg:(NSString *)title {
[self setMessageTV : [[UITextView alloc] initWithFrame:CGRectMake(5, 5, 315, 90 )]];
[[self messageTV] setBackgroundColor : [UIColor greenColor]];
[[self messageTV] setTextColor : [UIColor whiteColor]];
[[self messageTV] setText:#""]; <<<<<<<< - does not clear the text
[[self messageTV] setText : title];
[self.view addSubview : [self messageTV]];
[self.view setHidden:NO];
}
- (void) hideMessage {
[self.view setHidden:YES]
}
I'll go out on a limb and ask why you're using a UITextView. I honestly have never needed to use a UITextView. Try changing it to a UILabel and see if the problem is specific to the UITextView. If you absolutely need a UITextView, let me know in a comment, but I have a suspicion that a UILabel is what you're after.
It appears that you are adding it as a subview every time. So you're actually creating multiple UITextViews and adding them on top of each other. You would either need to removeFromSuperview or just set the text of the instance variable.
Take these two lines out of showMsg and put them in viewDidLoad:
[self setMessageTV : [[UITextView alloc] initWithFrame:CGRectMake(5, 5, 315, 90 )]];
[self.view addSubview : [self messageTV]];
I have tried hiding a segmented controller just like a button or label can be hidden in XCode. It's intended to be hidden/shown when touching a parent segmented controller above. This Code would work with Buttons or Labels:
mySegmContr.hidden = YES;
But it just won't work for segmented controllers. Can you help me out?
I figured out that you can use a simple UIView in which you put the things you want to hide. The UIView can then be hidden with
myView.hidden = YES;
still I found no way to hide a segmented control directly.
If you create a property for the segment controller you can do more stuff with it like changing it's location, resizing it and want you want hiding it.
In your .h file do this
UISegmentedControl *mySegment;
#property (nonatomic, retain) UISegmentedControl *mySegment;
-(void) createMySegment;
In your .m file do this
#synthesize mySegment;
- (void) createMySegment {
if ([self mySegment] == nil) {
NSArray *buttons = [NSArray arrayWithObjects:#"One", #"Two", #"Three", nil];
UISegmentedControl *segName = [[UISegmentedControl alloc] buttons];
[self setMySegment:segName];
[segName release];
segName.frame = CGRectMake(110, 62, 120, 25);
segName.segmentedControlStyle = UISegmentedControlStyleBar;
segName.momentary = NO;
segName.selectedSegmentIndex = 0;
[segName addTarget:self
action:#selector(pickMethod:)
forControlEvents:UIControlEventValueChanged];
[self.view addSubview:segName];
}
}
NOTE: With "setMySegment" above make sure you use a capital first letter which is M in "mySegment".
Then when you want to hide it use this. Don't for get to dealloc mySegment.
[[self mySegment] setHidden:YES];
Does somebody know why this code is crashing somewhere in the release pool (after 'eject' is called)?
I saw in AVPlayer class reference that the 'currentItem' property is NOT declared as 'retain' http://developer.apple.com/library/ios/documentation/AVFoundation/Reference/AVPlayer_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40009530-CH1-SW21
Is it a bug in the AVPlayer class or should I retain it somewhere else?
Thanks!
- (void) viewDidLoad {
NSURL *url = [NSURL URLWithString:#"http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8"];
playerItem = [[AVPlayerItem alloc] initWithURL:url];
player = [[AVPlayer alloc] initWithPlayerItem:playerItem];
}
- (IBAction) eject {
[player release];
[playerItem release];
}
I typically use this to setup a player:
if (!self.player) {
player = [[AVPlayer alloc] init];
}
[self.player replaceCurrentItemWithPlayerItem:[AVPlayerItem playerItemWithURL:videoURL]];
I believe that AVPlayer retains AVPlayerItem in initWithPlayerItem: function, so you are possibly leaking memory with your AVPlayerItem. "currentItem" is readonly property and should not be "retain" which is only for writable properties.