以下问题 . 我有两个AVPlayers,每个都用不同的AVPlayerItem初始化 . 成功加载AVPlayerItem后,我将AVPlayerLayer添加到视图层 . 正如您在下面的代码中看到的那样 .
- (void)viewDidLoad
{
[super viewDidLoad];
self.playerItem = [[AVPlayerItem alloc] initWithURL:[self.video getVideoPath]];
[self.playerItem addObserver:self forKeyPath:@"status" options:0 context:nil];
[self.playerItem addObserver:self forKeyPath:@"playbackBufferEmpty" options:0 context:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(videoEnded)
name:AVPlayerItemDidPlayToEndTimeNotification
object:nil];
self.player = [[AVPlayer alloc] initWithPlayerItem:playerItem];
self.overlayPlayerItem = [[AVPlayerItem alloc] initWithURL:[self.compareVideo getVideoPath]];
[self.overlayPlayerItem addObserver:self forKeyPath:@"status" options:0 context:nil];
[self.overlayPlayerItem addObserver:self forKeyPath:@"playbackBufferEmpty" options:0 context:nil];
if (self.overlayPlayer==nil) {
self.overlayPlayer = [[AVPlayer alloc] initWithPlayerItem:self.overlayPlayerItem];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([object isKindOfClass:[AVPlayerItem class]])
{
AVPlayerItem *item = (AVPlayerItem *)object;
//playerItem status value changed?
if ([keyPath isEqualToString:@"status"])
{ //yes->check it...
switch(item.status)
{
case AVPlayerItemStatusFailed:
NSLog(@"player item status failed");
break;
case AVPlayerItemStatusReadyToPlay:
{
NSLog(@"player item status is ready to play");
if (item == self.playerItem && !videoLayerAdded) {
videoLayerAdded = YES;
AVPlayerLayer* layer = [AVPlayerLayer playerLayerWithPlayer:player];
layer.frame = self.videoContainer.bounds;
[self.videoContainer.layer insertSublayer:layer atIndex:0];
} else if (item == self.overlayPlayerItem && !overlayLayerAdded){
overlayLayerAdded = YES;
AVPlayerLayer* layer = [AVPlayerLayer playerLayerWithPlayer:overlayPlayer];
layer.frame = self.videoOverlayContainer.bounds;
[self.videoOverlayContainer.layer insertSublayer:layer atIndex:0];
}
break;
}
case AVPlayerItemStatusUnknown:
NSLog(@"player item status is unknown");
break;
}
}
else if ([keyPath isEqualToString:@"playbackBufferEmpty"])
{
if (item.playbackBufferEmpty)
{
NSLog(@"player item playback buffer is empty");
}
}
}
}
当我点击播放按钮时,视频会播放 . 如果我再次击中它们就停止了,到目前为止一切顺利 .
- (IBAction)playButtonClicked:(id)sender{
//is playing
if(self.player.rate>0.0 || self.overlayPlayer.rate>0.0){
[self.player pause];
[self.overlayPlayer pause];
} else {
[self.player play];
[self.overlayPlayer play];
}
}
我有两个UISlider,允许我在每个视频中前进和后退 . 我使用seekToTime跳转到视频中的某个时间 .
- (IBAction)sliderChanged:(id)sender{
UISlider *slider = (UISlider *)sender;
//stop any video when using the slider
if(self.player.rate>0.0){
[self.player pause];
}
if(self.overlayPlayer.rate>0.0){
[self.overlayPlayer pause];
}
if (slider.tag == 1) {
double time = (self.playerTimeSlider.value * CMTimeGetSeconds(self.player.currentItem.asset.duration));
[self.player seekToTime:CMTimeMakeWithSeconds(time, NSEC_PER_SEC) toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
} else if (slider.tag == 2){
double time = (self.overlayTimeSlider.value * CMTimeGetSeconds(self.overlayPlayer.currentItem.asset.duration));
[self.overlayPlayer seekToTime:CMTimeMakeWithSeconds(time, NSEC_PER_SEC) toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
}
}
视频也可以有不同的长度 . 但是,如果视频结束,我会将其设置为开头,同时使用seekToTime .
我的问题是我最初可以播放两个视频 . 我可以毫无问题地暂停和恢复它们 . 但是一旦我暂停并使用seekToTime进行任何视频和恢复,或者如果视频结束,我使用seekToTime重置它们并再次点击播放我的状态观察者为两个PlayerItem激活AVPlayerItemStatusFailed .
然后这些项目的持续时间变为0.我检查过,PlayerItems不是零 .
我没有崩溃,但我不能再播放视频了 . 当我只使用一个播放器时,我可以使用seekToTime跳过它,并在视频结尾处重置它而没有问题 .
我通过论坛阅读,人们说你显然可以使用多达4个AVPlayers,所以我想我应该用2保存 . 我还读到其他应用程序可以用尽视频渲染管道,但我确保我没有我的iPad上有后台任何其他应用程序 .
任何帮助,为什么这不适合我,甚至更好,一个修复,非常感谢 .
Update: 我实际上是从AVPlayerItem对象中记录了错误:
error: Error Domain=AVFoundationErrorDomain Code=-11819 "Cannot Complete Action"
UserInfo=0x19e370 {NSLocalizedRecoverySuggestion=Try again later.,
NSLocalizedDescription=Cannot Complete Action}
代码-11819代表AVErrorMediaServicesWereReset . 这有助于任何人帮助我吗?
1 回答
这可能是一个很长的过程,但请查看文档的以下页面:
AV Foundation Programming Guide - Seeking—Repositioning the Playhead
我的提示是,通过给出零容差(之前和之后),您可能会使解码器从计算确切请求帧的关键帧中解脱出来 .
这与同时播放两个项目一起,可能导致分配给iOS内部媒体服务的资源耗尽 . 从而导致重置 . 我想这取决于许多因素是所播放视频的质量和格式最重要的因素 .
如果您在擦洗中不需要精确的时间控制(!),请尝试使用公差 . 我建议您尝试使用略大于最大关键帧间隔的值 .
该值(最大关键帧间隔)很可能是依赖于电影的 .
如果您可以控制电影,并且可以使用疯狂的电影文件大小,请尝试使用最大关键帧间隔1(!)进行导出,然后旋转 .