zoukankan      html  css  js  c++  java
  • Objective-C AVPlayer播放视频的使用与封装

    大致效果

    不要介意。界面有点丑。。。

    AVPlayer封装.gif

    界面搭建

    看下成员变量就知道我怎么搭建的了,这里我将video播放层的size作为参照量,对所有控件的size按照其video的size宽高进行比例缩放

    @interface VideoPlayerView()
    @property (nonatomic,copy) NSString *path;                  //播放地址 自动判断文件路径和网址路径
    @property (nonatomic,strong) AVPlayer *player;              //播放类
    @property (nonatomic,strong) AVPlayerLayer *playerlayer;    //显示区域
    @property (nonatomic,strong) UIButton *playBtn;             //播放暂停
    @property (nonatomic,strong) UIButton *stopBtn;             // 停止
    @property (nonatomic,strong) UIButton *fullScreenBtn;       //全屏
    @property (nonatomic,strong) UISlider *playSlider;          //进度选择
    @property (nonatomic,strong) UIProgressView *progress;      //进度
    @property (nonatomic,strong) UILabel *currentTimeLab;       //当前时间
    @property (nonatomic,strong) UILabel *durationLab;          //总时间
    @property (nonatomic,strong) UIView *toolView;              //工具栏view
    @property (nonatomic,assign) BOOL isFullScreen;             //全屏判断
    @property (nonatomic,assign) CGFloat videoHeight;           //video高
    @property (nonatomic,assign) CGFloat videoWidth;            //video宽
    @end
    

    所有控件使用懒加载 如下

    //播放暂停
    - (UIButton *)playBtn {
        if (!_playBtn) {
            _playBtn = [[UIButton alloc] initWithFrame:CGRectMake(kLrMargin, kUIy, kBtnWidth, kUIHeight)];
            _playBtn.backgroundColor  =[UIColor greenColor];
            _playBtn.selected = NO;
            _playBtn.enabled = NO;
            _playBtn.titleLabel.adjustsFontSizeToFitWidth = YES;
            [_playBtn setTitle:@"播放" forState:UIControlStateNormal];
            [_playBtn setTitle:@"暂停" forState:UIControlStateSelected];
            [_playBtn addTarget:self action:@selector(play) forControlEvents:UIControlEventTouchUpInside];
        }
        return _playBtn;
    }
    

    屏幕适配

    由于涉及到屏幕的旋转和适配。我这里没有使用第三方框架来做约束,而是使用最基本的按百分比设置frame。旋转屏幕时通过调用本类- (void)resetFrame:(CGSize)size;方法来重设frame。所以需要重设frame的控件在懒加载中设置frame,调用时即刷新frame。

    • 先看下初始化 对video的size设置是时始终用最小的边来确定高度,宽度与屏幕当前宽度相当
    //初始化
    - (instancetype)initWithFrame:(CGRect)frame andPath:(NSString*)path {
        self = [super initWithFrame:frame];
        if (self) {
            self.backgroundColor = [UIColor clearColor];
            self.path = path;
            CGFloat width = [UIScreen mainScreen].bounds.size.width;
            CGFloat height = [UIScreen mainScreen].bounds.size.height;
            self.videoHeight = height > width ? width * 0.6 : height * 0.6;
            self.videoWidth = [UIScreen mainScreen].bounds.size.width-2*kLrMargin;
            [self.layer addSublayer:self.playerlayer];
            [self addSubview:self.toolView];
        }
        return self;
    }
    
    • 屏幕旋转时做一些事
    //屏幕旋转时触发 这里写在父类中
    - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {    
        [self.videoView resetFrame:size];
    }
    
    //旋转屏幕重设frame
    - (void)resetFrame:(CGSize)size {
        CGFloat width = size.width;
        CGFloat height = size.height;
        self.videoHeight = height > width ? width * 0.6 : height * 0.6;
        self.videoWidth = size.width - 2 * kLrMargin;
        if (self.isFullScreen) {
            //全屏时旋转
            [self setPlayerWithPosition:CGPointZero andSize:size];
        } else {
            //普通旋转
            [self setPlayerWithPosition:CGPointMake(kLrMargin, kTopMargin) andSize:CGSizeMake(self.videoWidth, self.videoHeight)];
            //刷新frame
            [self toolView];
            [self playSlider];
            [self progress];
        }    
    }
    
    • 懒加载刷新frame
    //进度懒加载 调用时只刷新frame
    - (UIProgressView *)progress {
        if (!_progress) {
            _progress = [[UIProgressView alloc] init];
            _progress.progress = 0;
        }
        _progress.frame = CGRectMake(2, self.playSlider.frame.size.height/2, self.playSlider.frame.size.width-2-2, kUIHeight);
        return _progress;
    }
    

    AVPlayer的基本操作

    基本操作包括 播放 、暂停、 停止、 播放指定位置、缓存进度
    播放网络地址时 在info.plist中添加 App Transport Security Settings字典中添加Allow Arbitrary Loads元素 值为YES

    添加项.png
    使用AVPlayer播放视频就必须用到AVPlayerlayer用来显示播放视图。

    //加载显示层
    - (AVPlayerLayer*)playerlayer {
        if (!_playerlayer) {
            _playerlayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
            _playerlayer.bounds = CGRectMake(0, 0, self.videoWidth, self.videoHeight);
            _playerlayer.anchorPoint = CGPointMake(0, 0);
            _playerlayer.position = CGPointMake(kLrMargin, kTopMargin);
            _playerlayer.backgroundColor = [UIColor blackColor].CGColor;
        }
        return _playerlayer;
    }
    
    //加载播放类
    - (AVPlayer *)player {
        if (!_player) {
            _player = [AVPlayer playerWithURL:[self getUrlPath:self.path]];
            //kvo注册
            [self addObservers];
        }
        return _player;
    }
    
    • 使用KVO对状态和缓存进行检测,添加KVO时养成习惯写好移除操作
    //注册kvo
    - (void)addObservers{
        [self.player.currentItem addObserver:self forKeyPath:kItemStatus options:NSKeyValueObservingOptionNew context:nil];
        [self.player.currentItem addObserver:self forKeyPath:kItemLoadedTimeRanges options:NSKeyValueObservingOptionNew context:nil];
    }
    
    //移除kvo
    - (void)dealloc {
        [self.player.currentItem removeObserver:self forKeyPath:kItemStatus];
        [self.player.currentItem removeObserver:self forKeyPath:kItemLoadedTimeRanges];
    }
    
    //kvo回调
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
        if ([keyPath isEqualToString:kItemStatus]) {
            AVPlayerItem *item = object;
            if (item.status == AVPlayerItemStatusReadyToPlay) {
                //准备播放
                [self readyToplayWithItem:item];
            }else if (item.status == AVPlayerItemStatusUnknown) {
                //播放失败
               //这里写个alertView提示下就行
            }else if (item.status == AVPlayerItemStatusFailed) {
                //播放失败
                //同上
            }
        } else if ([keyPath isEqualToString:kItemLoadedTimeRanges]) {
            AVPlayerItem *item = object;
            [self getLoadedTimeRanges:item];
        }
    }
    
    • 基础功能
    //播放 暂停
    - (void)play {
        if (self.playBtn.selected) {
            self.playBtn.selected = NO;
            [self.player pause];
        } else {
            self.playBtn.selected = YES;
            [self.player play];
            [self timerStar];
        }
    }
    
    //停止
    - (void)stop {
        [self.player pause];
        [self.player seekToTime:CMTimeMake(0, 1)];
        self.playBtn.selected = NO;
    }
    //全屏
    - (void)fullScreen {
        self.toolView.hidden = YES;
        self.isFullScreen = YES;
        self.backgroundColor = [UIColor blackColor];
        self.playerlayer.bounds = [UIScreen mainScreen].bounds;
        self.playerlayer.anchorPoint = CGPointMake(0, 0);
        self.playerlayer.position = CGPointMake(0, 0);
    }
    
    //播放指定位置
    - (void)playCurrentVideo {
        self.playBtn.selected = YES;
        NSTimeInterval second = self.playSlider.value;
        [self.player.currentItem seekToTime:CMTimeMake(second,1)];
        [self.player play];
        [self timerStar];
    }
    
    • 具体操作
      • 包括格式化时间
      • 格式化路径
      • 播放准备
      • 缓存计算
      • 触摸关闭全屏
      • 设置video的大小位置
    //设置video的frame
    - (void)setPlayerWithPosition:(CGPoint)position andSize:(CGSize)size {
        self.playerlayer.anchorPoint = CGPointMake(0, 0);
        self.playerlayer.position = position;
        self.playerlayer.bounds = CGRectMake(0, 0, size.width, size.height);
    }
    
    //准备播放
    - (void)readyToplayWithItem:(AVPlayerItem*)item {
        self.playBtn.enabled = YES;
        long long durationSecond = item.duration.value / item.duration.timescale;
        self.durationLab.text = [NSString stringWithFormat:@" / %@",[self getFormatDate:durationSecond]];
        self.playSlider.maximumValue = durationSecond;
        self.playSlider.minimumValue = 0;
        [self.playSlider addTarget:self action:@selector(playCurrentVideo) forControlEvents:UIControlEventValueChanged];
    
    }
    
    //获得缓存
    - (void)getLoadedTimeRanges:(AVPlayerItem*)item {
        NSValue *value = [item.loadedTimeRanges lastObject];
        CMTimeRange range = [value CMTimeRangeValue];
        long long cacheSecond = range.start.value/range.start.timescale + range.duration.value/range.duration.timescale;
        long long currentSecond = item.currentTime.value / item.currentTime.timescale;
        self.progress.progress = (currentSecond + cacheSecond) * 0.1;
      
    }
    
    
    //格式化时间
    - (NSString*)getFormatDate:(NSTimeInterval)time {
        int seconds = (int)time % 60;
        int minutes = (int)(time / 60) % 60;
        int hours = (int)time / 3600;
        return [NSString stringWithFormat:@"%02d:%02d:%02d",hours,minutes,seconds];
    }
    
    //格式化url路径
    - (NSURL*)getUrlPath:(NSString*)path {
        NSURL *url;
        if ([self.path containsString:@"http"]) {
            url = [NSURL URLWithString:self.path];
        } else {
            url = [NSURL fileURLWithPath:self.path];
        }
        return url;
    }
    
    //开启定时
    - (void)timerStar {
        //定时回调
        __weak typeof(self) weakSelf = self;
        [self.player addPeriodicTimeObserverForInterval:CMTimeMake(1, 1) queue:NULL usingBlock:^(CMTime time) {
            long long current = weakSelf.player.currentItem.currentTime.value / weakSelf.player.currentItem.currentTime.timescale;
            weakSelf.playSlider.value = current;
            NSString *currentFormat = [weakSelf getFormatDate:current];
            weakSelf.currentTimeLab.text = [NSString stringWithFormat:@"%@",currentFormat];
        }];
        
    }
    
    
    //触摸关闭全屏
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
        
        if (self.isFullScreen) {
            self.toolView.hidden = NO;
            self.backgroundColor = [UIColor clearColor];
            [self setPlayerWithPosition:CGPointMake(kLrMargin, kTopMargin) andSize:CGSizeMake(self.videoWidth, self.videoHeight)];
            
            [self toolView];
            [self playSlider];
            [self progress];
            self.isFullScreen = NO;
        }
    }
    

    这样一个简单AVPlayer的封装就做好了

    Demo地址

    https://github.com/gongxiaokai/AVPlayerDemo

  • 相关阅读:
    [每天解决一问题系列
    [每天解决一问题系列
    [每天解决一问题系列
    nodejs&mongo&angularjs
    [转]Express框架
    [转]Use HandleBars in Express
    10 Tips for Optimizing Your Website’s Speed
    One difference between AngularJS' $location and window.location
    Why does Http header contains "X-SourceFiles"?
    JavaScript数组常用方法
  • 原文地址:https://www.cnblogs.com/gongxiaokai/p/7123824.html
Copyright © 2011-2022 走看看