我遇到了一个奇怪的问题,我希望有人可以提供帮助。
在我的iOS应用中,我使用MutableComposition
通过组合用户照片库中的视频和应用套装中的音频文件来创建带有自定义音轨的视频。然后我使用AVPlayer
和AVPlayerItem
使用我制作的自定义视频播放器将视频播放回用户。
每次创建新合成时,资产,播放器和合成都会被清除,释放,并且它基本上从干净的初始状态开始。
一切正常,直到用这种方式创建了4个成功的视频后,每次创建播放器的其他尝试都会失败并显示错误Cannot Decode
。如果我正在重新创建的视频相同,与视频的大小/长度或音频文件没有任何关系,它在第五次尝试时完全失败,就像发条一样无关紧要。一旦失败,它将永远失败!
这很奇怪,因为它只是对同一个视频进行了四次解码而没有任何问题,所以突然它失败了?所以,如果有人有线索,请告诉我。
答案 0 :(得分:72)
大家好,我直接从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个管道可供你使用。另一个App可能正在使用一个或多个。事实上,我已经在iPad上看到过这种情况,但目前尚不清楚哪个应用程序正在使用管道。
所以,你去了,它完全没有记录,但这就是故事。
答案 1 :(得分:7)
我在创建4个AVPlayer实例后遇到了相同的错误消息,但我的情况下的修复程序并不完全相同。也许这会帮助遇到这个问题的其他人。
我最终发现AVPlayers在我认为它们的时候并没有被释放。就我而言,我正在将AVPlayer View Controller推送到导航控制器上。尽管我一次只创建一个AVPlayer实例,但当视图控制器弹出导航控制器时,它们并没有立即释放。在清理旧的View Controller之前,我很容易就能到达4个AVPlayer实例。
直到我确定先前的球员被释放后,这个问题才消失。为了完成,我发布了AVPlayerItem,AVPlayer,并在释放之前将AVPlayerLayer上的播放器设置为nil。
我不得不怀疑AVPlayer实例是否有一些限制,无意或无意。来自文档的相关信息: https://developer.apple.com/library/ios/#documentation/AudioVideo/Conceptual/AVFoundationPG/Articles/02_Playback.html
“多个玩家图层:您可以从单个AVPlayer实例创建任意多个AVPlayerLayer对象,但只有最近创建的此类图层才会在屏幕上显示任何视频内容。”
答案 2 :(得分:3)
这个人绝对杀死我,直到我弄明白,从这个帖子和其他一些人那里获取线索。我的代码中最大的一个问题就是我每次我想要播放视频时实例化我的视频播放器控制器。现在,它在主控制器中实例化一次(在本例中,我的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 - 现在只能被称为一次,所有的每个视频设置都在 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]]];
}
}
}
答案 3 :(得分:2)
好的,我想出了一个解决方案,我希望这对任何可能偶然发现类似问题的人都有帮助。
我的解决方案是在主线程上初始化AVPlayer和AVPlayerItem的资产,并确保在playerItem和播放器对象返回状态为“ReadyToPlay”之前不创建实际的AVPlayerLayer。
这被证明是很难分离的,我仍然不知道为什么它在前4次工作然后在第5次一直失败。
直到我无法真正包含代码,这不是一行甚至是一些功能。这是一个复杂的问题,我无法开始孤立。感谢您的评论。
答案 4 :(得分:1)
似乎任何解码任务都可能导致该问题,而不仅仅是实际播放器。
当我使用 generateCGImagesAsynchronously
执行后台任务以从当前播放的视频中提取帧时,我偶然遇到了这个问题
我需要在屏幕上显示 4 个视频,竞争条件有时会导致帧提取在视频开始播放之前开始,我会永远等待 isReadyForDisplay
。
如果您一开始就无法避免这种情况,我不确定什么是好的恢复策略,我可能会尝试replaceCurrentItem