在iOS 8.4中,一个AVPlayerItem不能与多个AVPlayer实例关联。

37

在更新到iOS 8.4后,我遇到了臭名昭著的MPMoviePlayerController异常,错误信息如下:

An AVPlayerItem cannot be associated with more than one instance of AVPlayer

我看到有几种解决方法,主要是重新初始化播放器以便重用。但是对于我来说,崩溃不是发生在尝试播放新视频时,而是在将播放器退出全屏模式并旋转到纵向模式时。

这是我的代码:

@implementation MoviePlayerViewController

-(void)viewDidLoad
{
    [super viewDidLoad];

    self.moviePlayer.controlStyle = MPMovieControlStyleEmbedded;

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(moviePlayerWillEnterFullscreenNotification:) name:MPMoviePlayerWillEnterFullscreenNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(moviePlayerWillExitFullscreenNotification:) name:MPMoviePlayerWillExitFullscreenNotification object:nil];
}

- (void) moviePlayerWillEnterFullscreenNotification:(NSNotification*)notification
{
    [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceOrientationDidChange) name:UIDeviceOrientationDidChangeNotification object:nil];
}

- (void) moviePlayerWillExitFullscreenNotification:(NSNotification*)notification
{
    [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];
}

- (void)deviceOrientationDidChange
{
    UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
    if (orientation == UIDeviceOrientationPortrait) {
        [self.moviePlayer setFullscreen:NO animated:YES];
    }
}

@end

进入全屏模式的变化发生在拥有 MoviePlayerViewController 作为子视图的 UIViewController 中:

-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
    if (!self.moviePlayerViewController.moviePlayer.fullscreen &&
        UIInterfaceOrientationIsPortrait(fromInterfaceOrientation)) {
            [self.moviePlayerViewController.moviePlayer setFullscreen:YES animated:YES];
    }
}

当我使用播放器中的全屏按钮手动进入或退出全屏时,没有问题。我也可以很好地将播放器旋转到全屏模式。但是,当我尝试将其从全屏模式旋转出来(即从横屏模式旋转到竖屏模式),我会收到异常提示,似乎是在以下行中:


[self.moviePlayer setFullscreen:NO animated:YES];

当异常发生时,以下是我的堆栈跟踪:

Thread : Fatal Exception: NSInvalidArgumentException
0  CoreFoundation                 0x00000001865e02d8 __exceptionPreprocess
1  libobjc.A.dylib                0x0000000197f3c0e4 objc_exception_throw
2  AVFoundation                   0x0000000184db4b50 -[AVPlayerItem _attachToFigPlayer]
3  AVFoundation                   0x0000000184da7770 -[AVPlayer _attachItem:andPerformOperation:withObject:]
4  AVFoundation                   0x0000000184dc8f00 -[AVQueuePlayer insertItem:afterItem:]
5  MediaPlayer                    0x00000001889d1d30 -[MPQueuePlayer insertItem:afterItem:]
6  MediaPlayer                    0x000000018893de7c -[MPAVQueueCoordinator _syncPlayerItems]
7  MediaPlayer                    0x000000018893d8a4 -[MPAVQueueCoordinator _syncItems]
8  MediaPlayer                    0x000000018893c68c -[MPAVQueueCoordinator reloadItemsKeepingCurrentItem:]
9  MediaPlayer                    0x000000018899fd38 -[MPAVPlaylistManager setPlaylistFeeder:startIndex:keepPlaying:]
10 MediaPlayer                    0x000000018899fb4c __67-[MPAVPlaylistManager reloadWithPlaybackContext:completionHandler:]_block_invoke
11 MediaPlayer                    0x000000018889fa5c -[MPArrayQueueFeeder reloadWithPlaybackContext:completionHandler:]
12 MediaPlayer                    0x000000018899f9b4 -[MPAVPlaylistManager reloadWithPlaybackContext:completionHandler:]
13 MediaPlayer                    0x00000001888b7550 -[MPAVController reloadWithPlaybackContext:completionHandler:]
14 MediaPlayer                    0x000000018888d114 -[MPMoviePlayerControllerNew _prepareToPlayWithStartIndex:]
15 MediaPlayer                    0x000000018888a988 -[MPMoviePlayerControllerNew _moviePlayerDidBecomeActiveNotification:]
16 CoreFoundation                 0x00000001865862c4 __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__
17 CoreFoundation                 0x00000001864c3450 _CFXNotificationPost
18 Foundation                     0x00000001873f2a80 -[NSNotificationCenter postNotificationName:object:userInfo:]
19 MediaPlayer                    0x000000018888d530 -[MPMoviePlayerControllerNew _postNotificationName:object:userInfo:]
20 MediaPlayer                    0x000000018888d494 -[MPMoviePlayerControllerNew _postNotificationName:object:]
21 MediaPlayer                    0x00000001888878dc -[MPMoviePlayerControllerNew setFullscreen:animated:]
22 myApp                          0x000000010004ddf8 -[MoviePlayerViewController deviceOrientationDidChange] (MoviePlayerViewController.m:36)
23 CoreFoundation                 0x00000001865862c4 __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__
24 CoreFoundation                 0x00000001864c3450 _CFXNotificationPost
25 Foundation                     0x00000001873f2a80 -[NSNotificationCenter postNotificationName:object:userInfo:]
26 UIKit                          0x000000018b059b34 -[UIDevice setOrientation:animated:]
27 UIKit                          0x000000018b0597f0 -[UIApplication handleEvent:withNewEvent:]
28 UIKit                          0x000000018b059080 -[UIApplication sendEvent:]
29 UIKit                          0x000000018b0c52c4 _UIApplicationHandleEvent
30 GraphicsServices               0x000000018fdc9194 _PurpleEventCallback
31 GraphicsServices               0x000000018fdc8c84 PurpleEventCallback
32 CoreFoundation                 0x0000000186597a54 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__
33 CoreFoundation                 0x00000001865979b4 __CFRunLoopDoSource1
34 CoreFoundation                 0x0000000186595934 __CFRunLoopRun
35 CoreFoundation                 0x00000001864c12d4 CFRunLoopRunSpecific
36 GraphicsServices               0x000000018fdc76fc GSEventRunModal
37 UIKit                          0x000000018b0bef40 UIApplicationMain
38 myApp                          0x000000010002b2dc main (main.m:16)
39 libdyld.dylib                  0x00000001985e6a08 start

1
堆栈跟踪就像苹果支持一样。https://forums.developer.apple.com/thread/7958 - evan
2
是的,堆栈跟踪与Evan提供的相似。然而,我已经决定完全放弃MPMoviePlayerController并用AVPlayerAVPlayerViewController替换它。MPMoviePlayerController在iOS9中已被弃用,所以我不会再浪费时间在必须被替换的东西上了。 - pajevic
2
@NobleK - 我正在使用 AVPlayer,并且在使用 AVPlayerAVPlayerItem 时遇到了相同的崩溃问题。根本原因基本上就是描述所说的 - playerItem 实例不能附加到多个 player 实例上。有三个 API 调用可以将 playerItem 附加到 player 上:+playerWithPlayerItem:-initWithPlayerItem:-replaceCurrentItemWithPlayerItem:。请注意确保一旦将 playerItem 附加到 player 上,就不要尝试将其附加到另一个 player 上。 - Anurag
1
Anurag,我的原本问题是在使用MPMoviePlayerController时,这意味着我既没有直接联系AVPlayer也没有直接联系AVPlayerItem。此外,虽然人们经常报告在播放新视频时会出现此问题,但对我来说,它会在其他情况下发生,例如退出全屏模式时。 对我来说,这似乎确实像是一个错误,因为异常情况发生的时间我并没有启动任何新的流或其他操作。此外,在iOS 8.4之前从未出现过这个问题。 - pajevic
我刚意识到我的堆栈跟Evan链接的苹果论坛帖子里的不太一样,所以我提供了自己的。对此我很抱歉。 - pajevic
显示剩余3条评论
2个回答

1

解决方案是:

不要使用 MPMoviePlayerController, 抱歉。重构以改用 AVPlayerViewController 替代。这是一个更现代的API;你正在使用的那个已经被弃用了,因此在较新版本的iOS上出现奇怪的神秘崩溃并不令人惊讶。


AVPlayerViewController 仅适用于 iOS 8 及以上版本。 - user102008
是的,问题特别提到了iOS 8.4。 - buildsucceeded
1
问题询问的是当应用在iOS 8.4上运行时的行为,但应用的部署目标不一定是iOS 8或更高版本。 - user102008
但是说真的,因为建议某人远离已弃用的API而被踩? - buildsucceeded
"Deprecated"根据定义意味着它应该起作用。如果它不起作用,那就会被"删除"。 - user102008

0
我曾经遇到过一个问题,听起来与你的问题有些相似,但可能并不完全相同。我有多个视图控制器,我正在安排一个视图控制器暂停其电影播放,以便另一个可以播放。但是当设备旋转时,我使用的标准iOS选项卡栏控制器会为选项卡栏上的任何其他选项卡加载其他视图控制器(我认为是调用viewDidLoad),如果它们尚未被加载。我没有预料到这种行为,因为这些选项卡从未被我选择过。我的加载电影的代码在viewDidLoad中,因此它试图在另一个从未被要求“出现”的视图控制器上开始播放另一个电影。由于这两个视图控制器都继承自相同的基类,并且在调试器中看起来像正确的对象,所以我花了一段时间才意识到发生了什么。
如果我没记错的话,我将加载和开始播放我的电影的代码移到了viewWillAppear中,这样它就不会执行,除非真正选择了该选项卡。然后,当设备旋转并突然加载其他视图控制器时,它没有任何不良副作用。虽然看到它这样做还是很奇怪的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接