Squatch
Squatch

Reputation: 1027

MPMoviePlayerController plays only when called twice. Only occurs in iOS 4

I have an app for iOS 4.0-5.1 that uses HTTP Live Streaming to play videos. I have a simple setup with a button in a view that starts playing the stream when it is tapped. This works fine in iOS 5 but the button needs to be tapped twice before the stream begins playing in iOS 4. Does anybody know why this is happening and how to make the video play on the first tap of the button?

Here is what I'm doing:

.h

#import <UIKit/UIKit.h>
#import <MediaPlayer/MediaPlayer.h>

@interface ViewController : UIViewController{
    MPMoviePlayerController *moviePlayer;
}

@property (nonatomic, strong) MPMoviePlayerController *moviePlayer;

-(IBAction)playApple:(id)sender;

@end

.m

-(IBAction)playApple:(id)sender{
    if(self.moviePlayer){
        self.moviePlayer = nil;
    }

    //Use Apple's sample stream
    NSURL *mediaURL = [NSURL URLWithString:@"http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8"];
    self.moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:mediaURL];

    //Begin observing the moviePlayer's load state.
    [[NSNotificationCenter defaultCenter] addObserver:self 
           selector:@selector(moviePlayerLoadStateChanged:) 
           name:MPMoviePlayerLoadStateDidChangeNotification 
           object:self.moviePlayer];

    [self.moviePlayer setMovieSourceType:MPMovieSourceTypeStreaming];
    [self.moviePlayer setShouldAutoplay:NO];//Stop it from autoplaying
    [self.moviePlayer prepareToPlay];//Start preparing the video
}

#pragma mark Notification Center
- (void)moviePlayerLoadStateChanged:(NSNotification *)notification{
    NSLog(@"State changed to: %d\n", moviePlayer.loadState);
    if(self.moviePlayer.loadState == MPMovieLoadStatePlayable){
        //if load state is ready to play
        [self.view addSubview:[self.moviePlayer view]];
        [self.moviePlayer setFullscreen:YES];
        [self.moviePlayer play];//play the video
    }

}

Upvotes: 1

Views: 3931

Answers (1)

Till
Till

Reputation: 27597

I can see some possible issues - just try it out and let us know if any or all of this did the trick.

1. loadstate masking

The loadstate should not be directly compared but masked before comparing as it might contain a mixture of multiple states.

MPMovieLoadState

Constants describing the network load state of the movie player.

enum {
   MPMovieLoadStateUnknown        = 0,
   MPMovieLoadStatePlayable       = 1 << 0,
   MPMovieLoadStatePlaythroughOK  = 1 << 1,
   MPMovieLoadStateStalled        = 1 << 2,
};
typedef NSInteger MPMovieLoadState;

So instead of directly comparing it, as you are, mask it to be on the safe side.

2. view setup

Why not setting up the player view right before starting the playback. I have never seen it the way you do it (not that I was positively sure that this is the problem - still, seems odd to me). Additionally, even though the player will not actually use the view you are assigning (fullscreen mode does it a bit differently), you may want to enhance the view-setup with assigning a proper frame.

All of the above rolled into this new version of your code...

-(IBAction)playApple:(id)sender
{
    if(self.moviePlayer)
    {
        self.moviePlayer = nil;
    }

    //Use Apple's sample stream
    NSURL *mediaURL = [NSURL URLWithString:@"http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8"];
    self.moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:mediaURL];

    //Begin observing the moviePlayer's load state.
    [[NSNotificationCenter defaultCenter] addObserver:self 
           selector:@selector(moviePlayerLoadStateChanged:) 
           name:MPMoviePlayerLoadStateDidChangeNotification 
           object:self.moviePlayer];

    self.moviePlayer.view.frame = self.view.bounds;
    [self.view addSubview:[self.moviePlayer view]];
    [self.moviePlayer setFullscreen:YES];
    [self.moviePlayer setMovieSourceType:MPMovieSourceTypeStreaming];
    [self.moviePlayer setShouldAutoplay:NO];   //Stop it from autoplaying
    [self.moviePlayer prepareToPlay];          //Start preparing the video
}

- (void)moviePlayerLoadStateChanged:(NSNotification *)notification
{
    NSLog(@"State changed to: %d\n", moviePlayer.loadState);
    if((self.moviePlayer.loadState & MPMovieLoadStatePlayable) == MPMovieLoadStatePlayable)
    {
        //if load state is ready to play
        [self.moviePlayer play];//play the video
    }
}

Upvotes: 5

Related Questions