AVPlayerItem fails with AVStatusFailed and error code “Cannot Decode”

后端 未结 4 1418
悲&欢浪女
悲&欢浪女 2020-11-27 02:55

I\'m running into a strange issue, I hope someone can help.

In my iOS app I create a video with a custom soundtrack using MutableComposition by combini

相关标签:
4条回答
  • 2020-11-27 02:57

    Ok everyone, I have the answer to this straight from Apple. I used one of my developer TSI lifelines to ask the question, and I'll summarize the response.

    There is a limit on the number of concurrent video players that AVFoundation will allow. It is due to the limitations of iOS hardware. The limit for current devices is 4 players. If you create a 5th player, you will get the "cannot decode" error. It is not a limit on the number of instances of AVPlayer, or AVPlayerItem. Rather,it is the association of AVPlayerItem with an AVPlayer which creates a "render pipeline", and you are limited to 4 of these. For example, this causes a new render pipeline:

    AVPlayer *player = [AVPlayer playerWithPlayerItem:somePlayerItem];  
    // assuming the AVPlayerItem is ready to go with an AVAsset that has been loaded
    

    I was also warned that you cannot assume that you will have 4 pipelines available to you. Another App may be using one or more. Indeed, I have seen this happen on an iPad, but it was not clear which app was using a pipeline.

    So, there you go, it was totally undocumented, but that is the story.

    0 讨论(0)
  • 2020-11-27 03:06

    This one was absolutely killing me until I figured it out, picking up clues from this thread and a few others. The biggest single problem in my code was that I was instantiating my video player controller every time I wanted to play a video. Now, it gets instantiated once in the primary controller (in this case, my DetailViewContoller):

    @interface DetailViewController () {
        VideoPlayerViewController *videoPlayerViewController;
    }
    
    - (void) viewDidLoad
    {
        [super viewDidLoad];
    
        videoPlayerViewController = [[VideoPlayerViewController alloc] initWithNibName: nil bundle: nil];
    }
    

    When I want to show a video, I call my DetailViewController's startVideoPlayback method:

    - (void) startVideoPlayback: (NSString *)videoUID
    {
        videoPlayerViewController.videoUID = videoUID;
        [self presentModalViewController: videoPlayerViewController animated: YES];
    }
    

    (NOTE: I'm passing it 'videoUID' -- a unique identified that was used to create the video in another part of the app.)

    In the VideoPlayerViewController (which is largely cribbed from Apple's AVPlayerDemo sample), the one-time screen setup (initializing the AVPlayer, setting up the toolbar, etc.) is done in viewDidLoad -- which now only get's called once, and all per-video setup gets done within viewWillAppear, which then calls prepareToPlay:

    - (void) prepareToPlay
    {
        [self initScrubberTimer];   
        [self syncPlayPauseButtons];
        [self syncScrubber];
    
        NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
        //*** Retrieve and play video at associated with this videoUID
        NSString *destinationPath = [documentsDirectory stringByAppendingFormat: @"/%@.mov", videoUID];
        if ([self fileExists: destinationPath]) {
    
            //*** Show the activity indicator spinny thing
            [pleaseWait startAnimating];
            [self setURL: [NSURL fileURLWithPath: destinationPath]];
            //*** Get things going with the first video in this session
            if (isFirst) {
                isFirst = NO;
            //*** Subseqeunt videos replace the first one
            } else {
                [self.mPlayer replaceCurrentItemWithPlayerItem: [AVPlayerItem playerItemWithURL: [NSURL fileURLWithPath: destinationPath]]];
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-27 03:13

    OK, I figured out a solution, I hope this is helpful to anyone who may stumble on something similar to this problem.

    The solution in my case was to initialize the asset for the AVPlayer and the AVPlayerItem on the main thread and make sure I don't create the actual AVPlayerLayer before the playerItem and the player objects return with status "ReadyToPlay".

    This proved to be tricky to isolate and I still don't know why it worked the first 4 times and then failed consistently on the 5th time.

    Till, I couldn't really include the code, it wasn't a matter of one line or even a few functions. It was a complex problem that I couldn't isolate to begin with. Thanks for the comments though.

    0 讨论(0)
  • 2020-11-27 03:15

    I ran into the same error message after creating 4 AVPlayer instances, the fix in my case wasn't exactly the same though. Perhaps this will help anyone else who comes across this problem.

    What I eventually found is that the AVPlayers were not being released when I had thought they were. In my case I was pushing my AVPlayer View Controller onto a Navigation Controller. Even though I was only creating one AVPlayer instance at a time, when the View Controllers are popped off a nav controller they were not being released immediately. It was then very easy for me to reach 4 AVPlayer instances before the old View Controllers were cleaned up.

    It wasn't until I made sure that the previous players were released that this problem went away. To be complete I released the AVPlayerItem, AVPlayer and set the player on the AVPlayerLayer to nil before releasing.

    I have to wonder if there is some limit on AVPlayer instances, unintentional or not. A related bit of info from the docs: https://developer.apple.com/library/ios/#documentation/AudioVideo/Conceptual/AVFoundationPG/Articles/02_Playback.html

    "Multiple player layers: You can create arbitrarily many AVPlayerLayer objects from a single AVPlayer instance, but only the most-recently-created such layer will display any video content on-screen."

    0 讨论(0)
提交回复
热议问题