Подтвердить что ты не робот

Сбой разработки iPhone mpmovieplayer

Я работаю над приложением, которое позволит мне воспроизводить разные видео на iPad удаленно с iPhone. Я следил за примерами с яблоками для видеоплеера, но у меня были некоторые проблемы. Воспроизведение видео очень хорошо, и я могу заставить его играть из разных видео, но переключение между ними несколько раз приведет к сбою, и я получаю это в отладчике:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'An        AVPlayerItem cannot be associated with more than one instance of AVPlayer'
*** First throw call stack:
(0x380da8bf 0x37c261e5 0x30acbcb5 0x30abc1f7 0x30ac3bf3 0x30c93d55 0x30c95f7b 0x380ad2dd   0x380304dd 0x380303a5 0x37e07fcd 0x31bb0743 0x25e5 0x257c)

Это код, который я использую для создания проигрывателя:

MPMoviePlayerController *player = [[MPMoviePlayerController alloc] initWithContentOfURL:movieURL];
if (player) {
    [self setMoviePlayerController:player];
    [self installMovieNotificationObservers];
    [player setContentURL:movieURL];
    [player setMovieSourceType:sourceType];
    [self applyUserSettingsToMoviePlayer];
    [self.view addSubview:self.backgroundView];
    [player.view setFrame:self.view.bounds];
    [player.view setBackgroundColor = [UIColor blackColor];
    [self.view addSubview:player.view];
}

И когда текущий фильм остановлен, я использую:

[[self moviePlayerController] stop];

MPMoviePlayerController *player = [self moviePlayerController];
[player.view removeFromSuperview];

[self removeMovieNotificationHandlers];
[self setMoviePlayerController:nil];

Изменить: Итак, теперь я обнаружил, что это происходит каждый раз, когда я пытаюсь переключить видео в 11-й раз. странно! Я практически вытягиваю свои волосы.

4b9b3361

Ответ 1

Для меня эта проблема была остановлена ​​с помощью MPMoviePlayerController перед выполнением setContentURL.

    MPMoviePlayerController *streamPlayer;

    [streamPlayer stop];
    [streamPlayer setContentURL:[NSURL URLWithString:selectedStation]];

Ответ 2

В реализации, описанной выше, ARC не знает, что MPMoviePlayerController закончен и должен быть выпущен.

Определите MPMoviePlayerController в вашем .h файле и сделайте его доступным через @property (и @synthesize).

@property (strong, nonatomic) MPMoviePlayerController * moviePlayerController;

Затем возьмите результат вашего alloc и init и назначьте ему это. То есть.

self.moviePlayerController = [[MPMoviePlayerController alloc] initWithContentOfURL:movieURL];

Ответ 3

вам следует просто сохранить moviePlayerController, и если вы хотите воспроизвести другое видео, просто используйте

[self.moviePlayerController setContentURL:movieURL];

то в вашем обратном вызове уведомления:

- (void) moviePlayBackDidFinish:(NSNotification*)notification
{
    self.moviePlayer = nil;
    [self initanothermovieplayerandplay];
}

и не удаляйте обработчик уведомлений из центра уведомлений, делайте это только в методе dealloc вашего VC.

теперь добавьте некоторое затухание при выполнении фильма:

- (void) moviePlayBackDidFinish:(NSNotification*)notification
{
    [UIView animateWithDuration:1
                      delay: 0.0
                    options: UIViewAnimationOptionCurveEaseIn
                 animations:^{
                     // one second to fade out the view
                     self.moviePlayer.view.alpha = 0.0;
                 }
                 completion:^(BOOL finished){
                       self.moviePlayer = nil;
                       [self initanothermovieplayerandplay];
                 }
}

Ответ 4

У меня была точно такая же проблема. Ничего не случилось с моим, и я догадываюсь с вашим кодом:) Просто сломанный видеофайл был моей проблемой. Изменение типа *.mov на m4a, например, исправлено. Может быть, один или несколько файлов, которые вы играете, повреждены? Попытайтесь выяснить, какие файлы приводят к сбою, и если вы можете попытаться быстро продвинуть назад позицию игры одного из них во время игры - это должно привести к сбою в нескольких попытках. Вот как я нашел плохие файлы. Кстати, все мои плохие файлы были фильмами .mov сделаны с Snapz Pro X:)

Ответ 5

Не уверен, что это так, но у нас было много проблем, потому что MPMoviePlayer - синглтон где-то под капотом. Мы сделали то, что мы реализовали собственную оболочку MoviePlayer, которая может использоваться из UIView (на самом деле у нас есть только один подкласс UIView MoviePlayerView для показа фильмов) и гарантирует, что существует только один экземпляр MPMoviePlayerController. Код выглядит следующим образом (он содержит некоторые специальные материалы, нам нужно показать превью/превью так, как мы хотим, и т.д. Вы должны очистить, а также некоторые инструкции релиза):

//  MoviePlayer.h

#import <Foundation/Foundation.h>
#import <MediaPlayer/MediaPlayer.h>
#import "Logger.h"

@class MoviePlayerView;

@interface MoviePlayer : NSObject
{
  @private
  MPMoviePlayerController *controller;
  MoviePlayerView *currentView;
}

@property (nonatomic, readonly) MPMoviePlayerController *controller;

+(MoviePlayer *) instance;

-(void) playMovie:(NSURL*)movieURL onView:(MoviePlayerView *)view;
-(void) stopMovie;

@end



//  MoviePlayer.m




#import "MoviePlayer.h"
#import "MoviePlayerView.h"

@implementation MoviePlayer

@synthesize controller;

static MoviePlayer *player = nil;

#pragma mark Singleton management

+(MoviePlayer *) instance
{
  @synchronized([MoviePlayer class])
  {
    if (player == nil) 
    {
      player = [[super allocWithZone:NULL] init];
      player->controller = [[MPMoviePlayerController alloc] init];
      player->controller.shouldAutoplay = NO;
      player->controller.scalingMode = MPMovieScalingModeAspectFit;
      player->currentView = nil;
    }
    return player;
  }
}

+(id) allocWithZone:(NSZone *)zone
{
  return [[self instance] retain];
}

-(id) copyWithZone:(NSZone *)zone
{
  return self;
}

-(id) retain
{
  return self;
}

-(NSUInteger) retainCount
{
  return NSUIntegerMax; 
}

-(oneway void) release
{
  // singleton will never be released
}

-(id) autorelease
{
  return self;
}

#pragma mark MoviePlayer implementations

-(void) stopMovie
{
  @synchronized(self)
  {
    if (controller.view.superview)
    {
      [controller.view removeFromSuperview];
    }
    if (controller.playbackState != MPMoviePlaybackStateStopped)
    {
      [controller pause];
      [controller stop];
    }
    if (currentView)
    {
      NSNotificationCenter *ntfc = [NSNotificationCenter defaultCenter];
      [ntfc removeObserver:currentView name:MPMoviePlayerLoadStateDidChangeNotification object:controller];
      [ntfc removeObserver:currentView name:MPMoviePlayerPlaybackStateDidChangeNotification object:controller];
      currentView = nil;
    }
  }
}

-(void) playMovie:(NSURL*)movieURL onView:(MoviePlayerView *)view
{
  @synchronized(self)
  {
    [self stopMovie];
    currentView = view;

    NSNotificationCenter *ntfc = [NSNotificationCenter defaultCenter];
    [ntfc addObserver:currentView 
             selector:@selector(loadStateDidChange:)
                 name:MPMoviePlayerLoadStateDidChangeNotification 
               object:controller];
    [ntfc addObserver:currentView 
             selector:@selector(playbackStateDidChange:)
                 name:MPMoviePlayerPlaybackStateDidChangeNotification
               object:controller];

    [controller setContentURL:movieURL];
    controller.view.frame = view.bounds;
    [view addSubview: controller.view];
    [controller play];
  }
}

@end


//  MoviePlayerView.h

#import <UIKit/UIKit.h>
#import "MoviePlayer.h"


@interface MoviePlayerView : MediaView 
{
  NSURL *movieURL;
  NSURL *thumbnailURL;
  UIImageView *previewImage;
  UIView *iconView;
  BOOL hasPreviewImage;
}

-(id) initWithFrame:(CGRect)frame thumbnailURL:(NSURL *)thumbnail movieURL:(NSURL *)movie;
-(void) loadStateDidChange:(NSNotification *)ntf;
-(void) playbackStateDidChange:(NSNotification *)ntf;

@end



//  MoviePlayerView.m

#import "MoviePlayerView.h"

@interface MoviePlayerView()
-(void) initView;
-(void) initController;
-(void) playMovie;
-(void) setActivityIcon;
-(void) setMovieIcon:(float)alpha;
-(void) clearIcon;
-(CGPoint) centerPoint;
@end

@implementation MoviePlayerView

-(id) initWithFrame:(CGRect)frame thumbnailURL:(NSURL *)thumbnail movieURL:(NSURL *)movie
{
  self = [super initWithFrame:frame];
  if (self) 
  {
    movieURL = [movie retain];
    thumbnailURL = [thumbnail retain];
    [self initView];
    [self initController];
    hasPreviewImage = NO;
    loadingFinished = YES;
  }
  return self;
}

-(void) dealloc
{
  [iconView release];
  [previewImage release];
  [movieURL release];
  [super dealloc];
}

-(void)initView
{
  self.backgroundColor = [UIColor blackColor];

  // add preview image view and icon view
  previewImage = [[UIImageView alloc] initWithFrame:self.bounds];
  [previewImage setContentMode:UIViewContentModeScaleAspectFit];
  UIImage *img = nil;
  if (thumbnailURL)
  {
    img = [ImageUtils loadImageFromURL:thumbnailURL];
    if (img)
    {
      previewImage.image = img;
      hasPreviewImage = YES;
    }
  }
  [self addSubview:previewImage];
  [self setMovieIcon:(hasPreviewImage ? 0.8f : 0.3f)];
}

-(void)initController
{
  UITapGestureRecognizer *rec = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(playMovie)];
  [self addGestureRecognizer:rec];
  [rec release];
}

-(void)playMovie
{
  [[MoviePlayer instance] playMovie:movieURL onView:self];
  [self setActivityIcon];
}

-(void) loadStateDidChange:(NSNotification *)ntf
{
  MPMoviePlayerController *controller = [ntf object];
  switch (controller.loadState)
  {
    case MPMovieLoadStatePlayable:
    {
      [self clearIcon];
      [controller setFullscreen:YES animated:YES];
      break;
    }
    case MPMovieLoadStateStalled:
    {
      [self setActivityIcon];
      break;
    }
    default:
    {
      break; // nothing to be done
    }
  }
}

-(void) playbackStateDidChange:(NSNotification *)ntf
{
  MPMoviePlayerController *controller = [ntf object];
  switch (controller.playbackState) 
  {
    case MPMoviePlaybackStatePlaying:
    {
      [self clearIcon];
      break;
    }
    case MPMoviePlaybackStateStopped:
    {
      [self setMovieIcon:(hasPreviewImage ? 0.8f : 0.3f)];
      break;
    }
    case MPMoviePlaybackStatePaused:
    {
      [self setMovieIcon:0.8f];
      break;
    }
    case MPMoviePlaybackStateInterrupted:
    {
      [self setActivityIcon];
      break;
    }
    default:
    {
      break; // nothing to be done
    }
  }
}

-(void) setActivityIcon
{
  [self clearIcon];
  iconView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
  iconView.center = [self centerPoint];
  [self addSubview:iconView];
  [iconView performSelector:@selector(startAnimating)];
}

-(void) setMovieIcon:(float)alpha
{
  [self clearIcon];
  iconView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"icon_movie.png"]];
  iconView.center = [self centerPoint];
  iconView.alpha = alpha;
  [self addSubview:iconView];
}

-(void) clearIcon
{
  if (iconView)
  {
    SEL stop = @selector(stopAnimating);
    if ([iconView respondsToSelector:stop])
    {
      [iconView performSelector:stop];
    }
    [iconView removeFromSuperview];
    [iconView release];
    iconView = nil;
  }
}

-(CGPoint) centerPoint
{
  return CGPointMake(roundf(self.bounds.size.width / 2.0f), roundf(self.bounds.size.height / 2.0f));
}

-(void)resize
{
  for (UIView *view in [self subviews]) 
  {
    if (view == iconView)
    {
      iconView.center = [self centerPoint];
      continue;
    }
    view.frame = self.bounds;
  }
  [self addCaptionLabel];
}

-(void) layoutSubviews
{
  [super layoutSubviews];
  [self resize];
}

@end

Ответ 6

...
player = [[MPMoviePlayerController alloc] initWithContentURL: [NSURL URLWithString:...
...

но я не подключил интернет к телефону (wi-fi):)

Ответ 7

У меня была та же проблема. Мое решение использует prepareToPlay:

MPMoviePlayerController *player = [[MPMoviePlayerController alloc] initWithContentOfURL:movieURL];

if (player) {
   [player prepareToPlay];
   //...
}

Ответ 8

Эта ошибка, похоже, выбрасывается по разным причинам, но причина, по которой я обнаружил, заключается в том, что класс MPMoviePlayerController запутывается, если вы вызываете методы в определенном порядке. От канала IRC:

", по-видимому, если вы вызовете setupToPlay WHILE, задав тип источника и НЕ установленное представление еще вызывает этот сбой"

Поэтому я исправил это, просто удостоверившись, что я назвал prepareToPlay: LAST (или второй, чтобы последний, с последним play:).

Это также странно, потому что мой исходный код работал в iOS 5.1, но эта проблема внезапно проявилась, когда я начал использовать sdk iOS 6.0. Возможно, это ошибка в коде MPMoviePlayerController, поэтому я собираюсь подать на него радарный отчет, как вызов prepareToPlay: перед установкой представления/параметра sourceFileType не должен генерировать исключение (или, по крайней мере, исключение что, по-видимому, не имеет ничего общего с фактической ошибкой)