• 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大师代发,拒绝转载,转载需要作者授权

  • 相关阅读:
    Elementary Methods in Number Theory Exercise 1.2.25
    Elementary Methods in Number Theory Exercise 1.2.14
    图解欧几里德算法
    图解欧几里德算法
    Elementary Methods in Number Theory Exercise 1.2.14
    Android中的长度单位详解(dp、sp、px、in、pt、mm)
    分享下多年积累的对JAVA程序员成长之路的总结
    android异常之都是deamon惹的祸The connection to adb is down, and a severe error has occured.
    TomatoCartv1.1.8.2部署时报错
    JavaScript浏览器对象之二Document对象
  • 原文地址:https://www.cnblogs.com/demodashi/p/8508804.html
Copyright © 2020-2023  润新知