An AVPlayerItem cannot be associated with more than one instance of AVPlayer in iOS 8.4
Asked Answered
I

2

37

After updating to iOS 8.4 I am getting the infamous exception with MPMoviePlayerController that says:

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

I have seen several workarounds that mainly consist of reinitialising the player before reusing it. However, for me the crash doesn't happen when I try to play a new video, but rather when I turn off fullscreen for the player by rotating to portrait mode.

This is my code:

@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

The change to fullscreen happens in the UIViewController that has the MoviePlayerViewController as u subview:

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

There is no problem when I go in or out of fullscreen manually using the fullscreen-button in the player. Also I can rotate the player into fullscreen just fine. However, when I try to rotate it out of fullscreen (i.e. from landscape to portrait) I get the exception, seemingly in the line:

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

Here is my stack trace when the exception occurs:

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
Incommunicable answered 10/7, 2015 at 9:55 Comment(8)
Please add a stack trace at the point when the exception is thrown. type bt all at the lldb prompt to get it.Hogtie
stack trace just like apple support forums.developer.apple.com/thread/7958Herbivore
Yeah, the stack trace is similar to the one provided by evan. However, I have actually decided to drop MPMoviePlayerController altogether and replace it with AVPlayer and AVPlayerViewController. MPMoviePlayerController is being deprecated in iOS9 anyway so I won't waste more time on something that must be replaced anyway.Incommunicable
@NobleK - FYI, I'm using AVPlayer and saw the same crash with AVPlayer and AVPlayerItem. The underlying cause is basically what the description says - that a playerItem instance cannot be attached to more than one player instance. There are three API calls through which a playerItem can be attached to a player: +playerWithPlayerItem:, -initWithPlayerItem:, -replaceCurrentItemWithPlayerItem:. Just take care in ensuring that once a playerItem has been attached to a player, you don't try to attach it to another player.Hogtie
Anurag, my original issue is when using MPMoviePlayerController, meaning that I don't have direct contact with neither AVPlayer nor AVPlayerItem. Furthermore, while people often report this issue when playing a new video, for me it happens in other situations, like when exiting full screen. To me it really seems like a bug since the exception comes at a time then I am not initiating any new streams or anything. Also, the issue never occurred before iOS 8.4.Incommunicable
I just realized that my stack trace is not quite the same as the one in the Apple forum post that evan has linked to, so I provided my own. Sorry about that.Incommunicable
@Hogtie if my guess is correct,you might be attaching multiple player items to a single instance of AVPlayer.Dungaree
Someone found a working solution/workaround to this issue ?Gamester
P
1

The solution is:

Don't use MPMoviePlayerController, sorry. Refactor to use AVPlayerViewController instead. This is a more modern API; the one you are using has been deprecated so it is not shocking that it has a strange mysterious crash on a newer version of iOS.

Preconize answered 27/10, 2015 at 11:55 Comment(5)
AVPlayerViewController is only available on iOS 8 and laterSupererogation
Yep, and the question specifically asks about iOS 8.4Preconize
The question asks about the behavior of the app when run on iOS 8.4, but the deployment target of the app is not necessarily iOS 8 or later.Supererogation
But seriously, a downvote for recommending that someone move away from a deprecated API?Preconize
"deprecated" by definition means it is supposed to work. If it doesn't work, then it would be "removed".Supererogation
C
0

I had a problem that sounds somewhat familiar to yours, but may or may not be exactly the same thing. I had multiple view controllers and I was arranging for one view controller to suspend its movie so another could play. But when the device rotated, the standard iOS tab bar controller that I was using would load the other view controllers (calling viewDidLoad I believe) for any other tabs on the tab bar if they had not been loaded yet already. I was not expecting this behavior, as the tabs were never selected by me. My code to load the movie was in viewDidLoad, and so it was trying to start playing another movie on the other view controller that had never been asked to "appear". It took me a while to even realize what was going on because the two view controllers were inheriting from the same base class and it looked like the right object in the debugger, until I looked closer.

If memory serves, I moved the code to load and start playing my movies into viewWillAppear so that it would not execute unless the tab was really selected. Then when the device is rotated, and the other view controller is suddenly loaded, it has no adverse side effects. It's still weird to see it do that though.

Cislunar answered 30/3, 2016 at 7:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.