一、AVPlayer 播放时间问题
AVPlayer 播放时间、总时间提供了两种方式去获取,
一个是监听AVPlayerItem 的currentTime属性值变化,我们可以通过实时监听到的时间变化去做先关UI的改变,所有的监听都要在播放器即将销毁时移除监听,否则会收到一个大的惊喜,crush
。
- (void)abserverCurrentPlayerItem{
// 监听当前状态
[self.playerItem addObserver:self forKeyPath:@"status"
options:NSKeyValueObservingOptionNew
context:nil];
// 监听当前播放时间变化
[self.playerItem addObserver:self
forKeyPath:@"loadedTimeRanges"
options:NSKeyValueObservingOptionNew
context:nil];
// 播放完成
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didPlayToEndTime:) name:AVPlayerItemDidPlayToEndTimeNotification object:self.playerItem];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context{
if ([keyPath isEqualToString:@"status"]) {
if (self.playerItem.status == AVPlayerItemStatusReadyToPlay) {
}
else if (self.playerItem.status == AVPlayerItemStatusFailed) {
self.state = CLPlayerStateFailed;
}
} else if ([keyPath isEqualToString:@"loadedTimeRanges"]) {
// 计算缓冲进度
CMTime duration = self.playerItem.duration;
CGFloat totalDuration = CMTimeGetSeconds(duration);
} else if ([keyPath isEqualToString:@"playbackBufferEmpty"]) {
// 当缓冲是空的时候
NSLog(@"当缓冲是空的时候");
if (self.playerItem.isPlaybackBufferEmpty) {
[self bufferingSomeSecond];
}
} else if ([keyPath isEqualToString:@"playbackLikelyToKeepUp"]) {
// 当缓冲好的时候
NSLog(@"当缓冲好的时候");
if(!self.isStop){
if (!_isEnd) {
[self playVideo];
self.state = CLPlayerStatePlaying;
}
}
}
}
另一个是播放器的回调,能在回调中获取当前的播放进度和总时长,相对于监听的方式,,我在项目中使用的是这个,感觉比较方便。
- (void) abserverCurrentPlayerTime{
__weak typeof(self)weakSelf = self;
[self.player addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(1,1) queue:nil usingBlock:^(CMTime time) {
__strong typeof(weakSelf)self = weakSelf;
AVPlayerItem* currentItem = self.player.currentItem;
NSArray* loadedRanges = currentItem.seekableTimeRanges;
if (loadedRanges.count > 0){
CMTimeRange range = [[loadedRanges objectAtIndex:0] CMTimeRangeValue];
NSTimeInterval duration = CMTimeGetSeconds(range.start) + CMTimeGetSeconds(range.duration);
// 当前播放总时间
NSTimeInterval curDuration = CMTimeGetSeconds(time);
NSLog(@"eidt player:%g", curDuration);
self.model.curTime = curDuration;
self.model.totalTime = duration;
if (self.callBack) {
self.callBack(self.model);
}
}
}];
// 播放完成
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didPlayToEndTime:) name:AVPlayerItemDidPlayToEndTimeNotification object:self.playerItem];
}
二、AVPlayer seek问题
//seek到第一帧
[self.player seekToTime:CMTimeMake(0, 1)];
[self.player seekToTime:kCMTimeZero toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
//seek 到滑动条滑动到位置
- (void)setProgress:(float)progress{
_progress = progress;
[self.player seekToTime:CMTimeMake(progress, 1)];
}
//另一个seek的方法也是比较推荐的方法,当seek完成之后再做播放的操作
[self.player seekToTime:kCMTimeZero toleranceBefore:(CMTime)kCMTimeZero toleranceAfter:kCMTimeZero completionHandler:^(BOOL finished) {
[self.player play];
}];
//弄了很久的问题:因为在外部的block中调用了play方法,使得seek的操作可能没有在主线程中调用,所以导致seek一直没起作用,如下放在主线程调用就OK了。
- (void)play{
dispatch_async(dispatch_get_main_queue(), ^{
if (self.model.isEnd) {
[self.player seekToTime:kCMTimeZero toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
}
[self.player play];
self.model.isEnd = NO;
self.model.isPause = NO;
if (self.callBack) {
self.callBack(self.model);
}
});
}
网友评论