//
|
// AVKitPlayerController.swift
|
// OKProject
|
//
|
// Created by 无故事王国 on 2022/5/18.
|
// Copyright © 2022 yangwang. All rights reserved.
|
//
|
|
import UIKit
|
import AVKit
|
|
class AVKitPlayerController: YYViewController {
|
|
@IBOutlet weak var playBGView: UIView!
|
private var playerItem: AVPlayerItem?
|
private var playerController: AVPlayerViewController!
|
var playURL: String!
|
|
deinit {
|
removeObserver()
|
}
|
|
override func viewDidLoad() {
|
super.viewDidLoad()
|
setupAVPlayerViewController()
|
addObserver()
|
}
|
|
override func viewWillAppear(_ animated: Bool) {
|
super.viewWillAppear(animated)
|
AudioHelper.onlyActivePlay()
|
}
|
|
override func viewWillDisappear(_ animated: Bool) {
|
super.viewWillDisappear(animated)
|
AudioHelper.notAffectedBackgroundPlay()
|
}
|
|
@IBAction func tapReturnAction(_ sender: Any) {
|
self.dismiss(animated: true)
|
// self.navigationController?.popViewController(animated: true)
|
}
|
|
private func setupAVPlayerViewController() {
|
guard let url = URL(string: playURL) else {
|
return
|
}
|
playerController = AVPlayerViewController()
|
playerController.delegate = self
|
playerItem = AVPlayerItem(url: url)
|
playerController.player = AVPlayer(playerItem: playerItem)
|
playerController.videoGravity = .resizeAspect
|
playBGView.addSubview(playerController.view)
|
playerController.view.snp.remakeConstraints { make in
|
make.edges.equalToSuperview()
|
}
|
AudioHelper.onlyActivePlay()
|
}
|
|
private func addObserver() {
|
// 监听loadedTimeRanges属性对缓冲进度更新
|
playerItem?.addObserver(self,
|
forKeyPath: "loadedTimeRanges",
|
options: .new,
|
context: nil)
|
// 监听status属性进行播放
|
playerItem?.addObserver(self,
|
forKeyPath: "status",
|
options: .new,
|
context: nil)
|
}
|
|
private func removeObserver() {
|
playerItem?.removeObserver(self, forKeyPath: "status")
|
playerItem?.removeObserver(self, forKeyPath: "loadedTimeRanges")
|
}
|
|
override func observeValue(forKeyPath keyPath: String?,
|
of object: Any?,
|
change: [NSKeyValueChangeKey : Any]?,
|
context: UnsafeMutableRawPointer?) {
|
guard let object = object as? AVPlayerItem else { return }
|
guard let keyPath = keyPath else { return }
|
if keyPath == "status" {
|
if object.status == .readyToPlay {
|
playerController?.player?.play()
|
print("正在播放...,视频总长度:\(formatPlayTime(seconds: CMTimeGetSeconds(object.duration)))")
|
} else if object.status == .failed || object.status == .unknown {
|
print("播放出错")
|
}
|
self.dealwithFullScreenButton()
|
} else if keyPath == "loadedTimeRanges" {
|
let loadedTime = availableDurationWithplayerItem()
|
print("当前加载进度\(loadedTime)")
|
}
|
}
|
|
/// 将全屏按钮换成返回图标,并在其上层添加返回按钮
|
func dealwithFullScreenButton() {
|
var contentView: UIView?
|
for sub in playerController.view.subviews {
|
|
if "\(sub.classForCoder)" == "AVPlayerViewControllerContentView" {
|
contentView = sub
|
break
|
}
|
}
|
guard let guardContentView = contentView else {
|
return
|
}
|
|
var controlsView: UIView?
|
for sub in guardContentView.subviews {
|
if "\(sub.classForCoder)" == "AVPlaybackControlsView" {
|
controlsView = sub
|
break
|
}
|
}
|
guard let guardControlsView = controlsView else {
|
return
|
}
|
|
var ignoringView: UIView?
|
for sub in guardControlsView.subviews {
|
if "\(sub.classForCoder)" == "AVTouchIgnoringView" {
|
ignoringView = sub
|
break
|
}
|
}
|
guard let guardIgnoringView = ignoringView else {
|
return
|
}
|
|
var layoutView: UIView?
|
for sub in guardIgnoringView.subviews {
|
if "\(sub.classForCoder)" == "AVLayoutView" {
|
layoutView = sub
|
break
|
}
|
}
|
guard let guardLayoutView = layoutView else {
|
return
|
}
|
|
for (index, sub) in guardLayoutView.subviews.enumerated() {
|
if "\(sub.classForCoder)" == "AVButton" {
|
print("AVButton AVButton \(index)")
|
if let avBut = sub as? UIButton {
|
avBut.setImage(UIImage(named: "icon_back_white"), for: .normal)
|
avBut.setImage(UIImage(named: "icon_back_white"), for: .selected)
|
}
|
let returnBut = UIButton()
|
returnBut.backgroundColor = .clear
|
returnBut.addTarget(self, action: #selector(tapReturnAction(_:)), for: .touchUpInside)
|
sub.superview?.addSubview(returnBut)
|
returnBut.snp.remakeConstraints { make in
|
make.edges.equalToSuperview()
|
}
|
}
|
}
|
}
|
|
/// 将秒转成时间字符串的方法,因为我们将得到秒
|
private func formatPlayTime(seconds: Float64) -> String {
|
let min = Int(seconds / 60)
|
let sec = Int(seconds.truncatingRemainder(dividingBy: 60))
|
return String(format: "%02d:%02d", min, sec)
|
}
|
|
/// 计算当前的缓冲进度
|
private func availableDurationWithplayerItem() -> TimeInterval {
|
guard let loadedTimeRanges = playerController.player?.currentItem?.loadedTimeRanges,
|
let first = loadedTimeRanges.first else {
|
fatalError()
|
}
|
let timeRange = first.timeRangeValue
|
// 本次缓冲起始时间
|
let startSeconds = CMTimeGetSeconds(timeRange.start)
|
// 缓冲时间
|
let durationSecound = CMTimeGetSeconds(timeRange.duration)
|
// 缓冲总长度
|
let result = startSeconds + durationSecound
|
return result
|
}
|
|
}
|
|
extension AVKitPlayerController: AVPlayerViewControllerDelegate {
|
|
func playerViewController(_ playerViewController: AVPlayerViewController, willBeginFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator) {
|
}
|
|
func playerViewController(_ playerViewController: AVPlayerViewController, willEndFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator) {
|
self.navigationController?.popViewController(animated: true)
|
}
|
}
|
|
|
struct AudioHelper {
|
|
/// APP内播放音视频,不影响后台音乐播放
|
static func notAffectedBackgroundPlay() {
|
do {
|
try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.ambient, options: [.mixWithOthers, .defaultToSpeaker])
|
try AVAudioSession.sharedInstance().setActive(true)
|
} catch {
|
|
}
|
}
|
|
/// 静音播放
|
static func mutePlay() {
|
do {
|
/// try AVAudioSession.sharedInstance().setActive(false, options: AVAudioSession.SetActiveOptions.notifyOthersOnDeactivation)
|
try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.ambient, options: [.mixWithOthers, .defaultToSpeaker])
|
try AVAudioSession.sharedInstance().setActive(false)
|
} catch {
|
|
}
|
}
|
|
/// 单独播放APP内视频
|
static func onlyActivePlay() {
|
do {
|
try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback)
|
try AVAudioSession.sharedInstance().setActive(true)
|
} catch {
|
|
}
|
}
|
|
}
|