zoukankan      html  css  js  c++  java
  • iOS AVPlayer视频播放器

    代码地址如下:
    http://www.demodashi.com/demo/11168.html

    一、运行效果

    总效果.gif

    二、实现过程

    ①、创建播放器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大师代发,拒绝转载,转载需要作者授权

  • 相关阅读:
    DOM(文档对象模型)
    客户端检测
    mysql之触发器
    mysql之select(二)
    浅谈mysql中varchar(m)与char(n)的区别与联系
    mysql之select(一)
    mysql(一)
    mysql5.7.11安装遇到的问题
    Java 网络编程(二)
    Java 网络编程(一)
  • 原文地址:https://www.cnblogs.com/demodashi/p/8508804.html
Copyright © 2011-2022 走看看