代码地址如下:
http://www.demodashi.com/demo/11168.html
一、运行效果
二、实现过程
①、创建播放器avPlayer
//创建播放器url = [url stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];AVPlayer *player = [AVPlayer playerWithURL:[NSURL URLWithString:url]];self.avPlayer = player;
②、创建显示屏_videoLayer
- (void)createDisplay{// 显示图像的_videoLayer = [AVPlayerLayer playerLayerWithPlayer:self.avPlayer];//锚点的坐标_videoLayer.position = CGPointMake(KPLAYVIEWWIDTH/2, KPLAYVIEWHEIGHT/2);_videoLayer.bounds = CGRectMake(0, 0, KPLAYVIEWWIDTH, KPLAYVIEWHEIGHT);// 锚点,值只能是0,1之间_videoLayer.anchorPoint = CGPointMake(0.5, 0.5);// AVLayerVideoGravityResizeAspect 按比例压缩,视频不会超出Layer的范围(默认)// AVLayerVideoGravityResizeAspectFill 按比例填充Layer,不会有黑边// AVLayerVideoGravityResize 填充整个Layer,视频会变形// 视频内容拉伸的选项_videoLayer.videoGravity = AVLayerVideoGravityResizeAspect;// //播放时,视频实际占的区域// NSLog(@"%@", NSStringFromCGRect(videoLayer.videoRect));//Layer只能添加到Layer上面[self.displayView.layer addSublayer:_videoLayer];
}
③、添加观察者和通知,用于监测更新视频播放的状态、进度、屏幕方向、状态栏属性、音量等等。
主要代码如下:
//监测屏幕旋转[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChange:) name:UIDeviceOrientationDidChangeNotification object:nil];//添加AVPlayerItem播放结束通知[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playFinished:) name:AVPlayerItemDidPlayToEndTimeNotification object:self.avPlayer.currentItem];//添加AVPlayerItem开始缓冲通知[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(bufferStart:) name:AVPlayerItemPlaybackStalledNotification object:self.avPlayer.currentItem];//KOV监控 播放器进度更新
- (void)addObserverForAVPlayer
{AVPlayerItem *playerItem = self.avPlayer.currentItem;// 给AVPlayer添加观察者 必须实现 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context;//监控播放速率[self.avPlayer addObserver:self forKeyPath:@"rate" options:NSKeyValueObservingOptionNew context:nil];//监控状态属性(AVPlayer也有一个status属性,通过监控它的status也可以获得播放状态)[playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];//监控网络加载缓冲情况属性[playerItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];//监控是否可播放[playerItem addObserver:self forKeyPath:@"playbackLikelyToKeepUp" options:NSKeyValueObservingOptionNew context:nil];//播放进度观察者 //设置每0.1秒执行一次__weak GOVVideoView *weakSelf = self;_playerTimeObserver = [self.avPlayer addPeriodicTimeObserverForInterval:CMTimeMake(1.0, 10.0) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {if (weakSelf.dragSlider) {return ;}CGFloat current = CMTimeGetSeconds(time);weakSelf.current = current;CMTime totalTime = weakSelf.avPlayer.currentItem.duration;CGFloat total = CMTimeGetSeconds(totalTime);weakSelf.total = total;weakSelf.slider.value = current/total;weakSelf.currentTimeLabel.text = [weakSelf timeFormatted:current];weakSelf.totalTimeLabel.text = [NSString stringWithFormat:@"/%@",[weakSelf timeFormatted:total]] ;}];
}//通过KVO监控回调
//keyPath 监控属性 object 监视器 change 状态改变 context 上下文
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{if ([keyPath isEqualToString:@"loadedTimeRanges"]) {//监控网络加载情况属性NSArray *array = self.avPlayer.currentItem.loadedTimeRanges;//本次缓冲时间范围CMTimeRange timeRange = [array.firstObject CMTimeRangeValue];CGFloat startSeconds = CMTimeGetSeconds(timeRange.start);CGFloat durationSeconds = CMTimeGetSeconds(timeRange.duration);//现有缓冲总长度CGFloat totalBuffer = startSeconds + durationSeconds;//视频总时长CMTime totalTime = self.avPlayer.currentItem.duration;CGFloat total = CMTimeGetSeconds(totalTime);if (totalBuffer/total <= 1.0 ) {[self.progressView setProgress:totalBuffer/total animated:YES];}}else if([keyPath isEqualToString:@"playbackLikelyToKeepUp"]){if (self.avPlayer.currentItem.playbackLikelyToKeepUp == YES) {if (_activityView != nil) {[self.activityView startAnimating];[self.activityView removeFromSuperview];_activityView = nil;}}}else if ([keyPath isEqualToString:@"status"]){//监控状态属性AVPlayerStatus status = [[change objectForKey:@"new"] intValue];switch ((status)) {case AVPlayerStatusReadyToPlay:break;case AVPlayerStatusUnknown:break;case AVPlayerStatusFailed:break;}}else if ([keyPath isEqualToString:@"rate"]){if (self.avPlayer.rate == 1) {}}}
隐藏/显示状态栏的方法:
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationNone];这个方法在iOS9之后弃用了,并且需要
将View controller-based status bar appearance设置为NO;而下面的重写方法需要将View controller-based status bar appearance设置为YES,这个方法在iOS7之后就有了;
//刷新状态栏状态
[self setNeedsStatusBarAppearanceUpdate];
#pragma mark -- 隐藏/显示状态栏的方法
/*[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationNone];这个方法在iOS9之后弃用了,并且需要将View controller-based status bar appearance设置为NO;而下面的重写方法需要将View controller-based status bar appearance设置为YES,这个方法在iOS7之后就有了;
//刷新状态栏状态[self setNeedsStatusBarAppearanceUpdate];*/
//设置样式
- (UIStatusBarStyle)preferredStatusBarStyle {return UIStatusBarStyleLightContent;
}
//设置是否隐藏
- (BOOL)prefersStatusBarHidden {return self.isHiddenStatusBar;
}
//设置隐藏动画
- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation {return UIStatusBarAnimationNone;
}
④、创建用于处理播放结束、关闭播放器、全屏/退出全屏、隐藏/展示footBar和topBar的Block回调方法和代理方法,方便用户做些自定义的操作。
//Block回调方法
typedef void(^FullScreenBlock)(BOOL isFull);typedef void(^ClosePLayerBlock)();typedef void(^ShowBarBlock)(BOOL isShow);typedef void(^PlayFinishedBlock)();@class GOVVideoPlayer;
//代理方法
@protocol GOVVideoPlayerDelegate <NSObject>//播放结束
- (void)videoPlayerPlayFinished:(GOVVideoPlayer *)videoPlayer;//关闭播放器
- (void)videoPlayerClosePlayer:(GOVVideoPlayer *)videoPlayer;//全屏按钮
- (void)videoPlayerFullScreen:(GOVVideoPlayer *)videoPlayer withIsFull:(BOOL)isFull;//隐藏/展示footBar和topBar
- (void)videoPlayerShowBar:(GOVVideoPlayer *)videoPlayer withIsShow:(BOOL)isShow;
三、项目结构图
四、补充
GOVVideoPlayer是在继承于UIView的基础上封装的视频View;
GOVVideoController是在继承于UIViewController的基础上封装的视频视图控制器。
两者最大的不同是在全屏和取消全屏的处理上面:前者是一个视图View,可以直接加在父视图上面,全屏时是加在 [UIApplication sharedApplication].keyWindow上的,而后者,小屏时是取GOVVideoController的View加在父视图上,全屏和取消全屏时是采用present和dismiss模态化转场的方法 。
iOS AVPlayer视频播放器
代码地址如下:
http://www.demodashi.com/demo/11168.html注:本文著作权归作者,由demo大师发表,拒绝转载,转载需要作者授权