// 初始化KRVideoPlayerController
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super init];
if (self) {
self.view.frame = frame;
self.view.backgroundColor = [UIColor blackColor];
self.controlStyle = MPMovieControlStyleNone;
[self.view addSubview:self.videoControl];
self.videoControl.frame = self.view.bounds;
[self configObserver];
[self configControlAction];
}
return self;
}
// 懒加载KRVideoPlayerControlView
- (KRVideoPlayerControlView *)videoControl
{
if (!_videoControl) {
_videoControl = [[KRVideoPlayerControlView alloc] init];
}
return _videoControl;
}
// 1、即将开始画中画 - (void)playerViewControllerWillStartPictureInPicture:(AVPlayerViewController *)playerViewController; // 2、开始画中画 - (void)playerViewControllerDidStartPictureInPicture:(AVPlayerViewController *)playerViewController; // 3、画中画失败 - (void)playerViewController:(AVPlayerViewController *)playerViewController failedToStartPictureInPictureWithError:(NSError *)error; // 4、即将结束画中画 - (void)playerViewControllerWillStopPictureInPicture:(AVPlayerViewController *)playerViewController; // 5、结束画中画 - (void)playerViewControllerDidStopPictureInPicture:(AVPlayerViewController *)playerViewController;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor = [UIColor whiteColor];
self.avPlayerItem = [AVPlayerItem playerItemWithURL:[NSURL URLWithString:MovieURL]];
self.avPlayer = [[AVPlayer alloc]initWithPlayerItem:self.avPlayerItem];
self.avPlayerLayer = [AVPlayerLayer playerLayerWithPlayer:self.avPlayer];
self.avPlayerLayer.frame = CGRectMake(10, 100, 355, 200);
[self.view.layer addSublayer:self.avPlayerLayer];
// 添加观察者
[self addObserverWithAVPlayerItem];
}
#pragma mark --
#pragma mark -- KVO
-(void)addObserverWithAVPlayerItem{
//状态添加观察者
[self.avPlayerItem addObserver:self forKeyPath:@"status" options:(NSKeyValueObservingOptionNew) context:nil];
// 缓存进度添加观察者
[self.avPlayerItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];
}
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
AVPlayerItem * avplayeritem = (AVPlayerItem *)object;
if ([keyPath isEqualToString:@"status"]) {
AVPlayerStatus status = [[change objectForKey:@"new"] intValue];
if (status == AVPlayerStatusReadyToPlay) {
NSLog(@"准备好播放");
CMTime duration = avplayeritem.duration;
NSLog(@"视频总时长:%.2f",CMTimeGetSeconds(duration));
// 播放
[self.avPlayer play];
}else if (status == AVPlayerStatusFailed){
NSLog(@"视频准备发生错误");
}else{
NSLog(@"位置错误");
}
}else if ([keyPath isEqualToString:@"loadedTimeRanges"]){
// 可以自定义缓存进度
NSTimeInterval timeInterval = [self alreadyCacheVideoProgress];
NSLog(@"视频已经缓存的时长:%.2f",timeInterval);
}
}
#pragma mark --
#pragma mark -- alreadyCacheVideoProgress
-(NSTimeInterval)alreadyCacheVideoProgress{
// 先获取到它的缓存的进度
NSArray * cacheVideoTime = [self.avPlayerItem loadedTimeRanges];
// CMTimeRange 结构体 start duration 表示起始位置 和 持续时间
// 获取缓冲区域
CMTimeRange timeRange = [cacheVideoTime.firstObject CMTimeRangeValue];
float startSeconds = CMTimeGetSeconds(timeRange.start);
float durationSeconds = CMTimeGetSeconds(timeRange.duration);
// 计算总缓冲时间 = start + duration
NSTimeInterval result = startSeconds + durationSeconds;
return result;
}
/*!
@typedef CMTime
@abstract Rational time value represented as int64/int32.
*/
typedef struct
{
CMTimeValue value; /*! @field value The value of the CMTime. value/timescale = seconds. 帧数 */
CMTimeScale timescale; /*! @field timescale The timescale of the CMTime. value/timescale = seconds.帧率(影片每秒有几帧)*/ CMTimeFlags flags; /*! @field flags The flags, eg. kCMTimeFlags_Valid, kCMTimeFlags_PositiveInfinity, etc. */ CMTimeEpoch epoch; /*! @field epoch Differentiates between equal timestamps that are actually different because of looping, multi-item sequencing, etc. Will be used during comparison: greater epochs happen after lesser ones. Additions/subtraction is only possible within a single epoch, however, since epoch length may be unknown/variable. */} CMTime;
CMTime duration = avplayeritem.duration; NSLog(@"视频总时长:%.2f",CMTimeGetSeconds(duration));
- (id)addPeriodicTimeObserverForInterval:(CMTime)interval queue:(nullable dispatch_queue_t)queue usingBlock:(void (^)(CMTime time))block;
[self.avPlayer addPeriodicTimeObserverForInterval:CMTimeMake(1, 10) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
// CMTime的timescale的定义帮助理解下面代码
// @field timescale The timescale of the CMTime. value/timescale = seconds.
float currentPlayTime = (double)self.avPlayerItem.currentTime.value/ self.avPlayerItem.currentTime.timescale;
NSLog(@"当前播放进度:%f",currentPlayTime);
}];
/* Note that NSNotifications posted by AVPlayerItem may be posted on a different thread from the one on which the observer was registered. */ // notifications description AVF_EXPORT NSString *const AVPlayerItemTimeJumpedNotification NS_AVAILABLE(10_7, 5_0); // the item's current time has changed discontinuously AVF_EXPORT NSString *const AVPlayerItemDidPlayToEndTimeNotification NS_AVAILABLE(10_7, 4_0); // item has played to its end time AVF_EXPORT NSString *const AVPlayerItemFailedToPlayToEndTimeNotification NS_AVAILABLE(10_7, 4_3); // item has failed to play to its end time AVF_EXPORT NSString *const AVPlayerItemPlaybackStalledNotification NS_AVAILABLE(10_9, 6_0); // media did not arrive in time to continue playback AVF_EXPORT NSString *const AVPlayerItemNewAccessLogEntryNotification NS_AVAILABLE(10_9, 6_0); // a new access log entry has been added AVF_EXPORT NSString *const AVPlayerItemNewErrorLogEntryNotification NS_AVAILABLE(10_9, 6_0); // a new error log entry has been added // notification userInfo key type AVF_EXPORT NSString *const AVPlayerItemFailedToPlayToEndTimeErrorKey NS_AVAILABLE(10_7, 4_3); // NSError
机械节能产品生产企业官网模板...
大气智能家居家具装修装饰类企业通用网站模板...
礼品公司网站模板
宽屏简约大气婚纱摄影影楼模板...
蓝白WAP手机综合医院类整站源码(独立后台)...苏ICP备2024110244号-2 苏公网安备32050702011978号 增值电信业务经营许可证编号:苏B2-20251499 | Copyright 2018 - 2025 源码网商城 (www.ymwmall.com) 版权所有