// // VideoHelperViewController.m // Lighting // // Created by 曹云霄 on 2016/11/25. // Copyright © 2016年 上海勾芒科技有限公司. All rights reserved. // #import "VideoHelperViewController.h" @interface VideoHelperViewController ()<UIDocumentInteractionControllerDelegate> { UISlider* volumeViewSlider;//保存需要改变的量 float systemVolume;//系统音量值 CGPoint startPoint;//起始位置 } /** 导航栏、工具类是否隐藏 */ @property (nonatomic,assign) BOOL toolNaviViewIsHide; @end @implementation VideoHelperViewController - (void)viewDidLoad { [super viewDidLoad]; [self uiConfigAction]; } #pragma mark - UI - (void)uiConfigAction { self.videoNavigationView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.5]; self.videoToolView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.5]; [self.view addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hideOrShowNavigationBarAndToolBar)]]; //获取系统音量 MPVolumeView *volumeView = [[MPVolumeView alloc] init]; volumeViewSlider = nil; for (UIView *view in [volumeView subviews]){ if ([view.class.description isEqualToString:@"MPVolumeSlider"]){ volumeViewSlider = (UISlider *)view; break; } } systemVolume = volumeViewSlider.value; } #pragma mark - 播放地址 - (void)setLearningItem:(CustomStudyEntity *)learningItem { _learningItem = learningItem; [self resetPlayer]; if (_learningItem) { [self setUpAVPlayer]; [self addAVPlayerKVO]; [self addProgressObserver]; } } #pragma mark - SetUp AVPlayer - (void)setUpAVPlayer { VIResourceLoaderManager *resourceLoaderManager = [VIResourceLoaderManager new]; self.resourceLoaderManager = resourceLoaderManager; self.playerItem = [resourceLoaderManager playerItemWithURL:[NSURL URLWithString:self.learningItem.attachment.fileUrl]]; VICacheConfiguration *configuration = [VICacheManager cacheConfigurationForURL:[NSURL URLWithString:self.learningItem.attachment.fileUrl]]; if (configuration.progress >= 1.0) { NSLog(@"缓存完成"); } [XBLoadingView showHUDViewWithDefaultWithView:self.view]; self.customPlayer = [[AVPlayer alloc] initWithPlayerItem:self.playerItem]; self.playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.customPlayer]; self.playerLayer.frame = CGRectMake(0, 0, ScreenWidth*2/3, ScreenHeight/2); [self.view.layer insertSublayer:self.playerLayer atIndex:0]; self.videoTitleLabel.text = self.learningItem.title; } #pragma mark - AVPlayer KVO - (void)addAVPlayerKVO { //播放状态属性 [self.playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil]; //监控网络加载情况属性 [self.playerItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil]; //给AVPlayerItem添加播放完成通知 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playFinish) name:AVPlayerItemDidPlayToEndTimeNotification object:nil]; } #pragma mark -KVO回调 -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{ WS(weakSelf); if ([keyPath isEqualToString:@"status"]) {//播放状态 NSInteger status = [[change objectForKey:NSKeyValueChangeNewKey] integerValue]; switch (status) { case AVPlayerStatusFailed: self.bufferProgressView.progress = ZERO; self.playButton.selected = YES; [XBLoadingView hideHUDViewWithDefaultWithView:self.view]; [XBLoadingView showHUDViewWithText:@"播放失败"]; break; case AVPlayerStatusReadyToPlay://正在播放 { self.playButton.selected = NO; [XBLoadingView hideHUDViewWithDefaultWithView:self.view]; self.playItemTotalTimeLabel.text = [NSString stringWithFormat:@"/ %@",[self convertTime:CMTimeGetSeconds(self.playerItem.duration)]]; NSString *timeString = [self timeFormatted:[self.learningItem.attachment.playTime integerValue]]; if (![[self class] isBlankString:timeString]) { [self.customPlayer pause]; self.playButton.selected = YES; [self promptBoxWithMessage:[NSString stringWithFormat:@"上次播放时间:%@,是否继续播放",timeString] cancelBlock:^{ [weakSelf.customPlayer play]; weakSelf.playButton.selected = NO; } sureBlock:^{ [weakSelf.customPlayer seekToTime:CMTimeMake([weakSelf.learningItem.attachment.playTime integerValue], ONE) toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero]; weakSelf.playButton.selected = NO; }]; } break; } default: break; } }else if ([keyPath isEqualToString:@"loadedTimeRanges"]){//缓冲 NSTimeInterval timeInterval = [self availableDuration];// 计算缓冲进度 if (timeInterval > self.getCurrentPlayingTime+5 && !self.playButton.selected){ // 缓存 大于 播放 当前时长+5 [self.customPlayer play]; } } } #pragma mark - 返回当前视频播放时长 - (double)getCurrentPlayingTime{ return self.customPlayer.currentTime.value/self.customPlayer.currentTime.timescale; } #pragma mark - 返回当前视频缓存时长 - (NSTimeInterval)availableDuration{ NSArray *loadedTimeRanges = [[self.customPlayer currentItem] loadedTimeRanges]; CMTimeRange timeRange = [loadedTimeRanges.firstObject CMTimeRangeValue];// 获取缓冲区域 float startSeconds = CMTimeGetSeconds(timeRange.start); float durationSeconds = CMTimeGetSeconds(timeRange.duration); NSTimeInterval result = startSeconds + durationSeconds;// 计算缓冲总进度 return result; } #pragma mark -播放进度条更新 -(void)addProgressObserver { WS(weakSelf); AVPlayerItem *playerItem = self.customPlayer.currentItem; self.avplayerServer = [self.customPlayer addPeriodicTimeObserverForInterval:CMTimeMake(1.0, 1.0) queue:dispatch_get_main_queue() usingBlock:^(CMTime time){ float current = CMTimeGetSeconds(time); float total = CMTimeGetSeconds(playerItem.duration); //更新进度条 float progress = current/total; weakSelf.bufferProgressView.progress = progress; //更新播放时间 CMTime ctime = weakSelf.customPlayer.currentTime; weakSelf.playingTimeLabel.text = [weakSelf convertTime:ctime.value/ctime.timescale]; //更新播放百分比 if ([weakSelf.progressDelegate respondsToSelector:@selector(videoPlayProportion:withIndexPath:)]) { [weakSelf.progressDelegate videoPlayProportion:[weakSelf getCurrentPlayingTime]/CMTimeGetSeconds(weakSelf.playerItem.duration)*100 withIndexPath:weakSelf.indexPath]; } }]; } #pragma mark - 隐藏(显示)状态栏、工具栏 - (void)hideOrShowNavigationBarAndToolBar { [UIView animateWithDuration:0.4 animations:^{ self.videoNavigationView.alpha = self.toolNaviViewIsHide?1:0; self.videoToolView.alpha = self.toolNaviViewIsHide?1:0; }completion:^(BOOL finished) { self.toolNaviViewIsHide = !self.toolNaviViewIsHide; if (!self.toolNaviViewIsHide) { dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [self hideOrShowNavigationBarAndToolBar]; }); } }]; } #pragma mark -计算时间 - (NSString *)convertTime:(CGFloat)second { NSDate *date = [NSDate dateWithTimeIntervalSince1970:second]; NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; if (second/3600 >= 1) { [formatter setDateFormat:@"HH:mm:ss"]; } else { [formatter setDateFormat:@"mm:ss"]; } NSString *showtimeNew = [formatter stringFromDate:date]; return showtimeNew; } #pragma mark - 播放完成 - (void)playFinish { self.playButton.selected = YES; if ([self.delegate respondsToSelector:@selector(videoPlayFinish:)]) { [self.delegate videoPlayFinish:self.learningItem]; } } #pragma mark - 播放、暂停 - (IBAction)playOrPauseButtonClickAction:(UIButton *)sender { sender.selected = !sender.selected; if (sender.selected) { [self.customPlayer pause]; }else { [self.customPlayer play]; } } #pragma mark - 退出播放 - (IBAction)exitPlayControllerButtonClick:(UIButton *)sender { if (self.playerLayer.frame.size.height == ScreenHeight) { if (self.zoomButtonClickBlock) { self.zoomButtonClickBlock(NO); } }else { [self.navigationController popViewControllerAnimated:YES]; } } #pragma mark - 后退5秒 - (IBAction)backFiveSecondButtnClick:(UIButton *)sender { [self.customPlayer pause]; self.playButton.selected = YES; [self.customPlayer seekToTime:CMTimeMake([self getCurrentPlayingTime]-5, 1) toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero]; } #pragma mark - 放大缩小按钮 - (IBAction)zoomButtonClick:(UIButton *)sender { sender.selected = !sender.selected; if (self.zoomButtonClickBlock) { self.zoomButtonClickBlock(sender.selected); } } #pragma mark - 页面消失后释放播放器 - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; [self.customPlayer pause]; [self.customPlayer.currentItem cancelPendingSeeks]; [self.customPlayer.currentItem.asset cancelLoading]; } #pragma mark - 重置播放器 - (void)resetPlayer { [self.customPlayer pause]; [self.customPlayer seekToTime:kCMTimeZero]; [self customDealloc]; self.playButton.selected = YES; self.bufferProgressView.progress = 0; [self.playerLayer removeFromSuperlayer]; self.playingTimeLabel.text = @"00:00"; } #pragma mark - 释放KVO - (void)customDealloc { [self.playerItem removeObserver:self forKeyPath:@"status"]; [self.playerItem removeObserver:self forKeyPath:@"loadedTimeRanges"]; [self.customPlayer removeTimeObserver:self.avplayerServer]; [[NSNotificationCenter defaultCenter] removeObserver:self]; } #pragma mark -开始滑动时 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ if(event.allTouches.count == 1){ //保存当前触摸的位置 CGPoint point = [[touches anyObject] locationInView:self.view]; startPoint = point; } } #pragma mark -手势滑动的距离 -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{ if(event.allTouches.count == 1){ //计算位移 CGPoint point = [[touches anyObject] locationInView:self.view]; float dy = point.y - startPoint.y; int index = (int)dy; //20是因为排除横向滑动时的偏差 if(index > 20){ if(index%5==0){//每10个像素声音减一格 if(systemVolume > 0.1){ systemVolume = systemVolume-0.05; [volumeViewSlider setValue:systemVolume animated:YES]; [volumeViewSlider sendActionsForControlEvents:UIControlEventTouchUpInside]; } } }else if (index < -20){ if(index%5==0){//每10个像素声音增加一格 if(systemVolume>=0 && systemVolume<1){ systemVolume = systemVolume+0.05; [volumeViewSlider setValue:systemVolume animated:YES]; [volumeViewSlider sendActionsForControlEvents:UIControlEventTouchUpInside]; } } } //音量调节 [self volumeSet:volumeViewSlider]; } } #pragma mark -调节音量 - (void)volumeSet:(UISlider *)slider { NSArray *audioTracks = [self.playerItem.asset tracksWithMediaType:AVMediaTypeAudio]; NSMutableArray *allAudioParams = [NSMutableArray array]; for (AVAssetTrack *track in audioTracks) { AVMutableAudioMixInputParameters *audioInputParams = [AVMutableAudioMixInputParameters audioMixInputParameters]; [audioInputParams setVolume:slider.value atTime:kCMTimeZero]; [audioInputParams setTrackID:[track trackID]]; [allAudioParams addObject:audioInputParams]; } AVMutableAudioMix *audioMix = [AVMutableAudioMix audioMix]; [audioMix setInputParameters:allAudioParams]; [self.playerItem setAudioMix:audioMix]; } - (void)dealloc { [self customDealloc]; } @end