iPhone开发mpmovieplayer崩溃

我正在开发一款应用程序,让我可以通过iPhone远程播放iPad上的不同video。 我一直在跟随一个video播放器苹果的例子,但我一直有一些麻烦。 这些video播放效果很好,我可以从各种video中播放video,但在它们之间切换几次会崩溃,我在debugging器中得到这个:

*** 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) 

这是我用来创build播放器的代码:

 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次切换video时,都会发生这种情况。 奇怪的! 我几乎把我的头发拉出来。

什么解决这个问题对我来说是在执行setContentURL之前停止MPMoviePlayerController。

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

在上面的实现中,ARC不知道MPMoviePlayerController已经完成,需要释放。

在.h文件中定义MPMoviePlayerController,并通过@property(和@synthesize)使其可访问。

 @property (strong, nonatomic) MPMoviePlayerController * moviePlayerController; 

然后把你的alloc&init的结果分配给它。 IE

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

你应该保持moviePlayerController,如果你想播放另一个video,只需使用

 [self.moviePlayerController setContentURL:movieURL]; 

然后在你的通知callback中:

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

请不要从通知中心删除通知处理程序,只能在VC的dealloc方法中执行此操作。

现在,让我们添加一些淡入淡出时完成电影:

 - (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]; } } 

我有完全一样的问题。 没有什么是我的错误,我想你的代码:)只是一个破碎的video文件是我的问题。 例如修改* .movtypes为m4a。 也许一个或多个你玩的文件被破坏? 试图找出哪些文件导致崩溃,并比如果你可以尝试快速向后转播其中一个玩的位置 – 这将导致在几次尝试中崩溃。 这是我如何find坏的文件。 顺便说一句,我所有的坏文件都是使用Snapz Pro X制作的电影.mov 🙂

不知道这是否是这种情况,但是我们遇到了很多问题,因为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 
 ... player = [[MPMoviePlayerController alloc] initWithContentURL: [NSURL URLWithString:... ... 

但我没有给互联网连接电话(Wi-Fi):)

我有同样的问题。 我的解决scheme是使用prepareToPlay:

 MPMoviePlayerController *player = [[MPMoviePlayerController alloc] initWithContentOfURL:movieURL]; if (player) { [player prepareToPlay]; //... } 

这个错误似乎是由于许多不同的原因而引发的,但是我发现的原因是,如果您按照特定的顺序调用方法,MPMoviePlayerController类会吓坏了。 来自IRC频道:

“显然,如果你调用prepareToPlay WHILE设置源types,而不是设置视图导致这个崩溃”

所以我解决了这个问题,只要确保我调用了prepareToPlay: LAST(或倒数第二,最后一个play: prepareToPlay:

这也是奇怪的,因为我原来的代码在iOS 5.1中工作,但这个问题突然performance在我开始使用iOS 6.0 sdk。 这可能是MPMoviePlayerController代码中的一个错误,所以我将要提交一个关于它的雷达报告,就像调用prepareToPlay:在设置视图/设置sourceFileType不应该抛出一个exception(或者至less是一个看似有与实际错误无关)