AVPlayer的用法

AVPlayer的用法

基本概念:

AVPlayer的组成:

  • AVPlayer
  • AVPlayerItem
  • AVPlayerLayer

AVPlayer:控制播放过程,相当于ViewController
AVPlayerItem:提供播放的资源,相当于Model
AVPlayerLayer: 显示播放的播放器,相当于View

创建过程

使用AVPlayerItem创建AVPlayer,使用创建好的AVPlayer创建AVPlayerLayer

// view容器
playerView = UIView()
        playerView.backgroundColor = UIColor.white
        view.addSubview(playerView)
        playerView.snp.makeConstraints { (make) in
            make.top.equalTo(navView.snp.bottom)
            make.left.right.equalTo(view)
            make.bottom.equalTo(bottomView.snp.top)
        }
        
        // 使用URL创建AVPlayerItem
        let item = AVPlayerItem(url: URL(string: currentUrl)!)
        playerItem = item
        
        // 使用创建好的AVPlayerItem创建AVPlayer
        player = AVPlayer(playerItem: playerItem)
        
        // 使用创建好的AVPlayer创建AVPlayerLayer
        playerLayer = AVPlayerLayer(player: player)
        playerLayer.videoGravity = AVLayerVideoGravityResizeAspect
        playerLayer.backgroundColor = UIColor.white.cgColor
        playerView.setNeedsDisplay()
        playerView.layoutIfNeeded()
        playerLayer.frame = CGRect(x: 0, y: 0, width: CGFloat(playerView.width), height: CGFloat(playerView.height))
        playerView.layer.addSublayer(playerLayer)

AVPlayer的控制方法

AVPlayer可以播放网络资源,进行切换时使用方法:

playerItem = nil
playerItem = AVPlayerItem(url: URL(string: video.videoUrl)!)
player.replaceCurrentItem(with: playerItem)

播放:player.play()
暂停:player.pause()
AVPlayer没有playing方法,故通过rate来判断是否正在播放

        if playerItem.status != AVPlayerItemStatus.failed {
            if player.rate == 0 { //暂停
                button.isSelected = true
                player.play()
            } else if player.rate == 1{ // 播放
                button.isSelected = false
                player.pause()
            }
        }

AVPlayerItem提供播放时需要的信息

通过KVO来获取播放过程的信息

// 播放状态
playerItem.addObserver(self, forKeyPath: "status", options: NSKeyValueObservingOptions.new, context: nil)
// 缓冲状态
playerItem.addObserver(self, forKeyPath: "loadedTimeRanges", options: NSKeyValueObservingOptions.new, context: nil)
// 播放完成的通知        
NotificationCenter.default.addObserver(self, selector: #selector(playEndAction), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: playerItem)

    // 播放完成通知事件
    @objc fileprivate func playEndAction(){
        player.seek(to: kCMTimeZero) { end in
            self.playButton.isSelected = false
            self.propressSlider.value = 0.0
            self.currentTime.text = "00:00"
        }
    }

// KVO监听方法
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        // 拿到PLayerItem
        let item = object as! AVPlayerItem
        
        if (keyPath == "status") {
            if (item.status == AVPlayerItemStatus.readyToPlay){
                //开始播放
                player.play()
                playButton.isSelected = true
                //隐藏加载状态
                SVProgressHUD.dismiss()
                // 当前视频资源的总时间
                let totalSecond = Int(item.duration.value) / Int(item.duration.timescale) // 转换为秒
                propressSlider.maximumValue = Float(totalSecond)

                let m = totalSecond / 60
                let s = totalSecond - m * 60
                totalTime.text = String(format: "%02d:%02d", m, s)
                
                // 更新时间进度,此为AVPlayer的观察者事件,每1秒更新一次
                timeObserver = player.addPeriodicTimeObserver(forInterval: CMTimeMake(1, 1), queue: nil, using: { (time) in
                    let currentSecond = Int(item.currentTime().value)  / Int(item.currentTime().timescale)
                    let m = currentSecond / 60
                    let s = currentSecond - m * 60
                    self.currentTime.text = String(format: "%02d:%02d", m, s)
                    
                    self.propressSlider.setValue(Float(currentSecond), animated: true)
                }) 
                
            }else if (item.status == AVPlayerItemStatus.failed){
                SVProgressHUD.dismiss()
                SVProgressHUD.showError(withStatus: "加载失败")
            }
        }else if (keyPath == "loadedTimeRanges"){
            // 缓冲时间进度
            let timtInter = availableDuration()
            
            // 总时间
            let duration = playerItem.duration
            let totalDuration = CMTimeGetSeconds(duration)
            
            let  value = timtInter / totalDuration
            
            bufferProgress.setProgress(Float(value), animated: true)
        }
    }
}

// 缓冲时间获取
func availableDuration() -> TimeInterval{
        // 获取缓冲区域
        let loadTimeRanges = player.currentItem?.loadedTimeRanges
        let timeRange = loadTimeRanges?.first?.timeRangeValue
        
        // 开始时间区域
        let startSeconds = CMTimeGetSeconds((timeRange?.start)!)
        // 时间区域值
        let durationSeconds = CMTimeGetSeconds((timeRange?.duration)!)
        
        // 缓冲总进度
        let result = startSeconds + durationSeconds
        return result
    }

此方法中总共使用了4个observer。
在页面返回或切换下一首上一首时都需要移除,否则观察的不是当前的AVPlayerItem

    fileprivate func removePlayerPlayerItemObserver(){
        playerItem.removeObserver(self, forKeyPath: "status")
        playerItem.removeObserver(self, forKeyPath: "loadedTimeRanges")
        NotificationCenter.default.removeObserver(self, name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: playerItem)
        // 播放时间监听移除
        if timeObserver != nil {
            player.removeTimeObserver(timeObserver)
        }
        if player.rate == 1{
            player.pause()
        }
        playButton.isSelected = false
    }

通过slider来跳转视频播放进度:

    // 视频跳转事件
    @objc fileprivate func videoSliderChangeValueClick(){
        if (player.status == AVPlayerStatus.readyToPlay) {
            playerItem.seek(to: CMTime(value: CMTimeValue(propressSlider.value), timescale: 1))
        }
    }

通过slider进行视频音量控制

    // 控制音量
    @objc fileprivate func volumeSliderChangeValueClick(){
        player.volume = volumeProgressSlider.value
    }
    
    // 增加音量 button事件
    @objc fileprivate func addVolumeClick(){
        if player.volume >= 1.0 {return}
        
        player.volume += 0.1
        
        volumeProgressSlider.setValue(player.volume, animated: true)
    }
    
    // 减小音量 button事件
    @objc fileprivate func decreaseVolumeClick(){
        if player.volume <= 0.0 {return}
        
        player.volume -= 0.1
        
        volumeProgressSlider.setValue(player.volume, animated: true)
    }

你可能感兴趣的:(iOS进阶)