Swift-AVPlayer播放器

功能最全、自定义最高的播放器,也是使用最多得。使用起来较为复杂些。需导入AVKit控件(import AVKit)

相关参数

  • AVPlayer: 负责控制播放器的播放,暂停等操作
  • AVAsset:获取多媒体信息的抽象类,不能直接使用
  • AVURLAsset: AVAsset 的一个子类,使用 URL 进行实例化,实例化对象包换 URL 对应视频资源的所有信息。
  • AVPlayerItem: 管理媒体资源对象,提供播放数据源
  • AVPlayerLayer: 负责显示视频,如果没有添加该类,只有声音没有画面

1、基本播放

播放设置

   //创建媒体资源管理对象
    self.palyerItem = AVPlayerItem(url: NSURL(string: urlString)! as URL)
    //创建ACplayer:负责视频播放
    self.player = AVPlayer.init(playerItem: self.palyerItem)
    self.player.rate = 1.0//播放速度 播放前设置
    //创建显示视频的图层
    let playerLayer = AVPlayerLayer.init(player: self.player)
    playerLayer.videoGravity = .resizeAspect
    playerLayer.frame = self.view.bounds
    self.view.layer .addSublayer(playerLayer)
    //播放
    self.player.play()

播放暂停

    func pauseButtonSelected(sender:UIButton)  {
        sender.isSelected = !sender.isSelected
        if sender.isSelected{
            self.player.pause()
        }else{
            self.player.play()
        }
    }

2、观察AVPlayerItem属性(观察播放状态、缓存情况等)

当前播放状态

KVO观察当前的播放状态

    self.palyerItem.addObserver(self, forKeyPath: "status", options: .new, context: nil)

一共有三种播放状态,准备播放、播放失败、未知。

    func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if keyPath == "status" {
            switch self.palyerItem.status{
                case .readyToPlay:
                    //准备播放
                    self.play()
                case .failed:
                    //播放失败
                    print("failed")
                case.unknown:
                    //未知情况
                    print("unkonwn")
            }
    }

播放时间与总时间

处理时间,有一个结构体CMTime

typedef struct{
    CMTimeValue    value;     // 帧数
    CMTimeScale    timescale;  // 帧率
    CMTimeFlags    flags;        
    CMTimeEpoch    epoch;    
} CMTime;

视频总时间

    let totalTime = CMTimeGetSeconds((self?.player.currentItem?.duration)!)

当前播放时间

    let currentTime = self.playItem.currentTime.value/self.playItem.currentTime.timescale;
实时的获取播放时长和控制进度条
    self.player.addPeriodicTimeObserver(forInterval: CMTimeMake(1, 1), queue: DispatchQueue.main) { [weak self](time) in
        //当前正在播放的时间
        let loadTime = CMTimeGetSeconds(time)
        //视频总时间
        let totalTime = CMTimeGetSeconds((self?.player.currentItem?.duration)!)
        //播放进度设置
        self?.slider.value = Float(loadTime/totalTime)
        //播放的时间(changeTimeFormat方法是转格式的)
        self?.loadTimeLabel.text = self?.changeTimeFormat(timeInterval: loadTime)
        //总时间
        self?.totalTimeLabel.text =self?.changeTimeFormat(timeInterval:CMTimeGetSeconds((self?.player.currentItem?.duraton)!))
    }

播放缓存

与播放缓存相关的观测属性

  • loadedTimeRanges 缓存区间,可用来获取缓存了多少
  • playbackBufferEmpty 缓存不够了 自动暂停播放
  • playbackLikelyToKeepUp 缓存好了 手动播放
    self.palyerItem.addObserver(self, forKeyPath: "loadedTimeRanges", options: .new, context: nil)
    self.palyerItem.addObserver(self, forKeyPath: "playbackBufferEmpty", options: .new, context: nil)
    self.palyerItem.addObserver(self, forKeyPath:"playbackLikelyToKeepUp", options: .new,context:nil)
  override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if keyPath == "status" {
            switch self.palyerItem.status{
                case .readyToPlay:
                    self.play()
                case .failed:
                    print("failed")
                case.unknown:
                    print("unkonwn")
            }
        }else if keyPath == "loadedTimeRanges"{
            let loadTimeArray = self.palyerItem.loadedTimeRanges
            //获取最新缓存的区间
            let newTimeRange : CMTimeRange = loadTimeArray.first as! CMTimeRange
            let startSeconds = CMTimeGetSeconds(newTimeRange.start);
            let durationSeconds = CMTimeGetSeconds(newTimeRange.duration);
            let totalBuffer = startSeconds + durationSeconds;//缓冲总长度
            print("当前缓冲时间:%f",totalBuffer)
        }else if keyPath == "playbackBufferEmpty"{
            print("正在缓存视频请稍等")
        }
        else if keyPath == "playbackLikelyToKeepUp"{
            print("缓存好了继续播放")
            self.player.play()
        }
    }

要记得移除观察,而且这里是self.palyerItem,不要搞错了

   self.palyerItem.removeObserver(self, forKeyPath: "status", context: nil)
   self.palyerItem.removeObserver(self, forKeyPath: "loadedTimeRanges", context: nil)
   self.palyerItem.removeObserver(self, forKeyPath: "playbackBufferEmpty", context: nil)
   self.palyerItem.removeObserver(self,forKeyPath: "playbackLikelyToKeepUp", context: nil)
   NotificationCenter.default.removeObserver(self)

3、AVplayer常用相关通知

//音频中断通知
AVAudioSessionInterruptionNotification
//音频线路改变(耳机插入、拔出)
AVAudioSessionSilenceSecondaryAudioHintNotification
//媒体服务器终止、重启
AVAudioSessionMediaServicesWereLostNotification
AVAudioSessionMediaServicesWereResetNotification
//其他app的音频开始播放或者停止时
AVAudioSessionSilenceSecondaryAudioHintNotification
//播放结束
AVPlayerItemDidPlayToEndTimeNotification   
//进行跳转
AVPlayerItemTimeJumpedNotification           
//异常中断通知
AVPlayerItemPlaybackStalledNotification      
//播放失败
AVPlayerItemFailedToPlayToEndTimeNotification

使用AVPlayerItemDidPlayToEndTime通知

    NotificationCenter.default.addObserver(self, selector: #selector(playToEndTime), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil)
    
    @objc func playToEndTime(){
        print("播放完成")
    }

4、其他

demo地址:swift视频播放器使用
iOS其他播放器的使用:iOS播放器

推荐阅读更多精彩内容