【问题标题】:AVPlayerItem fails with AVStatusFailed and error code "Cannot Decode"AVPlayerItem 失败并显示 AVStatusFailed 和错误代码“无法解码”
【发布时间】:2012-01-26 08:55:15
【问题描述】:

我遇到了一个奇怪的问题,希望有人能提供帮助。

在我的 iOS 应用程序中,我使用 MutableComposition 通过组合来自用户照片库的视频和来自应用程序包的音频文件来创建一个带有自定义配乐的视频。然后我使用AVPlayerAVPlayerItem 使用我制作的自定义视频播放器将视频播放回给用户。

每次创建新组合时,资产、播放器和组合都会被清除、释放,并且它基本上是从一个干净的初始状态开始的。

一切正常,直到以这种方式创建了 4 个成功的视频之后,所有其他创建播放器的尝试都失败并出现错误 Cannot Decode。我正在重新创建的同一视频是否与视频或音频文件的大小/长度无关,它总是在第五次尝试时完全失败,就像发条一样。一旦失败,就永远失败!

这很奇怪,因为它只是将同一个视频解码四次都没有问题,所以突然就失败了?所以,如果有人有线索,请告诉我。

【问题讨论】:

  • 对不起...这里有一些问题正在我脑海中浮现: 1. “无法解码”错误的原因是什么 2. 有没有人遇到过类似的之前的情况,如果是,解决方法是什么 3. 调查后发现即使我只是使用视频资产(不是整个合成)也会失败,所以问题肯定出在资产初始化或播放器初始化.那里可能出了什么问题(我在堆上分配它们并在制作新电影时释放它们)? 4. 一般有什么想法吗?谢谢
  • 您为什么不添加有问题的代码,或者至少不添加那些您不确定的部分?我们仍然需要猜测。

标签: iphone ios avfoundation avplayer


【解决方案1】:

好的,我想出了一个解决方案,我希望这对任何可能偶然发现类似问题的人有所帮助。

在我的情况下,解决方案是在主线程上初始化 AVPlayer 和 AVPlayerItem 的资产,并确保在 playerItem 和播放器对象返回状态为“ReadyToPlay”之前我没有创建实际的 AVPlayerLayer。

这被证明很难隔离,我仍然不知道为什么它在前 4 次有效,然后在第 5 次始终失败。

直到,我无法真正包含代码,这不是一行甚至几个函数的问题。这是一个复杂的问题,我一开始就无法孤立。不过感谢 cmets。

【讨论】:

  • 我完全理解这一点。常见的方法是将其归结为最小的实现,然后可能会发现问题。通常情况下,最小的实现会突然起作用,这可以确保问题出在其他地方,在一个你永远不会怀疑的角落:D ...圣诞快乐!
【解决方案2】:

我在创建 4 个 AVPlayer 实例后遇到了相同的错误消息,但在我的情况下修复并不完全相同。也许这会帮助遇到这个问题的其他人。

我最终发现 AVPlayer 并没有在我认为的时候发布。在我的情况下,我将我的 AVPlayer 视图控制器推到导航控制器上。即使我一次只创建一个 AVPlayer 实例,当视图控制器从导航控制器中弹出时,它们也不会立即释放。在清理旧的视图控制器之前,我很容易达到 4 个 AVPlayer 实例。

直到我确定之前的播放器被释放后,这个问题才消失。为了完整起见,我发布了 AVPlayerItem、AVPlayer 并在发布前将 AVPlayerLayer 上的播放器设置为 nil。

我想知道 AVPlayer 实例是否有一些限制,不管是不是有意的。来自文档的相关信息: https://developer.apple.com/library/ios/#documentation/AudioVideo/Conceptual/AVFoundationPG/Articles/02_Playback.html

“多个播放器层:您可以从单个 AVPlayer 实例创建任意多个 AVPlayerLayer 对象,但只有最近创建的此类层才会在屏幕上显示任何视频内容。”

【讨论】:

    【解决方案3】:

    大家好,我直接从 Apple 那里得到了答案。我使用我的开发人员 TSI 生命线之一提出了这个问题,我将总结一下回复。

    AVFoundation 允许的并发视频播放器数量存在限制。这是由于iOS硬件的限制。当前设备的限制是 4 名玩家。如果您创建第 5 个播放器,您将收到“无法解码”错误。它不是对 AVPlayer 或 AVPlayerItem 实例数量的限制。相反,它是 AVPlayerItem 与创建“渲染管道”的 AVPlayer 的关联,您只能使用其中的 4 个。例如,这会导致一个新的渲染管道:

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

    我还被警告过,您不能假设您将拥有 4 个可用的管道。另一个应用程序可能正在使用一个或多个。确实,我在 iPad 上看到过这种情况,但不清楚哪个应用程序正在使用管道。

    所以,你去吧,它完全没有记录,但这就是故事。

    【讨论】:

    • 您究竟是如何解决这个问题的?您是否创建了包含许多物品的播放器并在它们之间切换?您是否在播放每个视频之前都创建了新的播放器和项目?
    • 对于任何感兴趣的人,我已经在 tvOS 上确认了这个问题。但是,实际上,在问题出现之前,我最多可以访问大约 18 个管道。最大计数必须取决于平台/硬件。此外,当我达到限制并且播放失败时,没有错误:没有来自 AVKit 的日志,也没有任何播放器发出错误(错误属性为 nil,状态良好)。
    • 播放器项目确实会发出错误,但您必须键值观察播放器项目状态变量,当它更改为 .error 时,您可以打印与播放器项目关联的错误变量。
    • 当我遇到这个问题时,由于内存问题stackoverflow.com/q/64485366/4833705,我的应用程序从太多播放器中崩溃了。原来不是玩家太多,就像@one09jason说的,和玩家关联的AVPlayerItem太多了stackoverflow.com/a/64485645/4833705
    【解决方案4】:

    这绝对是杀死我,直到我弄清楚,从这个线程和其他一些线程中获取线索。我的代码中最大的一个问题是我每次都在实例化我的视频播放器控制器,因为我想播放视频。现在,它在主控制器(在本例中为我的 DetailViewContoller)中被实例化一次

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

    当我想显示视频时,我调用了 DetailViewController 的 startVideoPlayback 方法:

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

    (注意:我传递的是“videoUID” - 一个唯一标识,用于在应用的另一部分创建视频。)

    在 VideoPlayerViewController(大部分抄自 Apple 的 AVPlayerDemo 示例)中,一次性屏幕设置(初始化 AVPlayer、设置工具栏等)在 viewDidLoad 中完成 - - 现在只调用 once,所有每个视频的设置都在 viewWillAppear 中完成,然后调用 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]]];
            }
        }
    }
    

    【讨论】:

      【解决方案5】:

      似乎这个问题可能是由任何解码任务引起的,而不仅仅是实际的玩家。

      当我使用generateCGImagesAsynchronously从当前播放的视频中提取帧时,我随机遇到了这个问题

      我需要在屏幕上显示 4 个视频,而竞争条件有时会导致在视频开始播放之前开始帧提取,我将永远等待isReadyForDisplay

      如果你一开始就无法避免这种情况,我不确定什么是好的恢复策略,我可能会尝试replaceCurrentItem

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-07-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-03-17
        • 1970-01-01
        • 2018-06-26
        相关资源
        最近更新 更多