13

I am facing an issue with MPMoviePlayerController in iOS 7. I enter the fullscreen and then click (just a single tap) on seek forward button (>>|) , and the video playback ends and gives a black screen with a text "Loading" on the header.

I registered notification for "MPMoviePlayerPlaybackStateDidChangeNotification".

**[[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(moviePlayerPlaybackStateDidChange:)
                                                 name:MPMoviePlayerPlaybackStateDidChangeNotification
                                               object:self.player];**

It does not get fired on a single click of seek forward button.

Also on registration of "MPMoviePlayerPlaybackDidFinishNotification"

**[[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(moviePlayerPlaybackDidFinish:)
                                                 name:MPMoviePlayerPlaybackDidFinishNotification
                                               object:nil];**

I get "MPMovieFinishReasonPlaybackEnded" event fired on that single click of seek forward button. Any one knows the reason why? Is this a bug in apple?

I need to either stop this behavior of showing a black screen on single click , or just disable single click of seek forward button so that nothing happens.

Any one knows how to achieve this?

Meet Doshi
  • 4,241
  • 10
  • 40
  • 81
XYZ
  • 597
  • 1
  • 7
  • 19
  • Sounds like a video encoding issue - make sure you test that against some well formed / well known content examples like e.g. Apple's [BipBop](http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8)! – Till Oct 25 '13 at 11:38
  • 1
    But in that case video should not be played at all.. I am only facing this issue when I press the seek forward button and that too on a single tap. If I do a Long press on that button , the video seeks to end properly. – XYZ Oct 25 '13 at 14:17
  • your assumption is incorrect. The encoding (e.g. I-frame rate) does significantly affect the seek behaviour. – Till Oct 25 '13 at 14:43
  • How to check if my video is properly encoded? – XYZ Oct 25 '13 at 14:49
  • How about following my hint and using a video that is properly encoded first? – Till Oct 25 '13 at 14:49
  • 1
    I tried with the Apple's BipBop. But the same behavior. When I click the button , Its shows a black screen which is always spinning and shows "Loading..." – XYZ Oct 25 '13 at 15:05
  • 2
    @XYZ Hey, have you found any solutions to this issue? – valbu17 Feb 02 '15 at 21:17
  • 1
    I think it is the bug in iOS. – ViruMax May 05 '15 at 10:42

3 Answers3

2

I fixed this by removing the MPMoviePlayer object completely, setting it to nil, removing it from it's superview and re-adding it using the original video Url. Code below:

- (void)addPlayerForUrl:(NSURL *)url {
  self.player = [[MPMoviePlayerController alloc] initWithContentURL:url];
  self.player.view.frame = self.videoView.bounds;
  self.player.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
  self.player.controlStyle = MPMovieControlStyleDefault;
  [self.videoView insertSubview:self.player.view atIndex:0];

  [[NSNotificationCenter defaultCenter] addObserver:self
                                           selector:@selector(moviePlayerLoadStateDidChangedNotification:)
                                               name:MPMoviePlayerReadyForDisplayDidChangeNotification
                                             object:self.player];

  [[NSNotificationCenter defaultCenter] addObserver:self
                                           selector:@selector(moviePlayerPlaybackStateDidChangeNotification:)
                                               name:MPMoviePlayerPlaybackStateDidChangeNotification
                                             object:self.player];
}


#pragma mark - Notifications

- (void)moviePlayerLoadStateDidChangedNotification:(NSNotification *)notification {
  self.isVideoPreloaded = YES;
  self.videoPlayButton.hidden = YES;
  self.photoImageView.hidden = YES;
  self.videoLoadingImageView.hidden = YES;
}
- (void)moviePlayerPlaybackStateDidChangeNotification:(NSNotification *)notification {
      NSURL *url = self.player.contentURL;
      switch (self.player.playbackState) {
        case MPMoviePlaybackStateSeekingBackward:
        case MPMoviePlaybackStateSeekingForward:
          break;
        case MPMoviePlaybackStatePlaying:
          self.videoPlayButton.hidden = YES;

          if (!self.isVideoPreloaded) {
            self.videoLoadingImageView.hidden = NO;
            [self.videoLoadingImageView startAnimating];
          } else {
            self.videoLoadingImageView.hidden = YES;
          }
          break;
        case MPMoviePlaybackStatePaused:
        case MPMoviePlaybackStateStopped:
          self.videoPlayButton.hidden = NO;
          self.videoLoadingImageView.hidden = YES;
          [self.player endSeeking];
          [self.player.view removeFromSuperview];
          [self.player setFullscreen:NO];
          self.player = nil;
          [self addPlayerForUrl:url];
          break;
        default:
          break;
      }
    }

Notice how I keep the NSURL, right before the switch statement in the moviePlayerPlaybackStateDidChangeNotification. That way, I can re-initialize and re-add the MPMoviePlayer object.

Btw, my mpmovieplayer is on a tableviewCell if you're wondering. Hope this helps and let me know if you have questions. Good luck!

C0D3
  • 6,440
  • 8
  • 43
  • 67
2

MPMoviePlayerLoadStateDidChangeNotification will be called when you single tap on the fast-forward or rewind button. You should check the loadState and just give it the path to your video and prepareToPlay again.

- (void)moviePlayerLoadStateChanged:(NSNotification *)notification {

    MPMoviePlayerController *moviePlayer = notification.object;
    MPMovieLoadState loadState = moviePlayer.loadState;

    if(loadState == MPMovieLoadStateUnknown) {
        moviePlayer.contentURL = [NSURL fileURLWithPath:videoPath]
        [moviePlayer prepareToPlay];
    }

    .....
}
n6xej
  • 461
  • 5
  • 15
0

The reason you're getting MPMovieFinishReasonPlaybackEnded is because playback reached the end of the video (sorry if this is obvious). So it seem's your seek forward actions are seeking all the way to the end of the video. You can check the playback state with MPMoviePlaybackStateSeekingForward.

A quick solution could be to create your own forward button that seek's ahead by a specified time (ie. 5 seconds). But perhaps this isn't the functionality you're looking for.

timgcarlson
  • 3,017
  • 25
  • 52
  • 1
    I checked with playback state MPMoviePlaybackStateSeekingForward. It gets fired only when I do a long press on seek forward button. I need to control the behavior of single click not long press on that button. – XYZ Oct 25 '13 at 07:59
  • I don't think any notifications are fired on user interaction with the standard player buttons, and this is why you will have to implement you're own UI for the player controls. You can then determine the actions for a single touch, long touch, etc... Then, you can add whatever functionality you wish, like increasing the play rate, or simply seeking to a time. On iOS, MPMoviePlayer is a simple player that just gives you play, pause, prev, and next. – timgcarlson Oct 25 '13 at 21:00
  • timgcarlson : Do you know how can we check if there is any other video track available to play when you click on prev or next button? – XYZ Oct 30 '13 at 11:58