-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathPlayerView.swift
More file actions
136 lines (112 loc) · 3.81 KB
/
PlayerView.swift
File metadata and controls
136 lines (112 loc) · 3.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
//
// PlayerView.swift
// MomsVideoPlayer
//
// Created by Hardik Parmar on 18/01/21.
//
import UIKit
import AVKit
class PlayerView: UIView {
static var videoIsMuted: Bool = true
override class var layerClass: AnyClass {
return AVPlayerLayer.self
}
private var assetPlayer:AVPlayer? {
didSet {
DispatchQueue.main.async {
if let layer = self.layer as? AVPlayerLayer {
layer.player = self.assetPlayer
}
}
}
}
private var playerItem:AVPlayerItem?
private var urlAsset: AVURLAsset?
var isMuted: Bool = true {
didSet {
self.assetPlayer?.isMuted = isMuted
}
}
var url: URL?
init() {
super.init(frame: .zero)
initialSetup()
}
required init?(coder: NSCoder) {
super.init(frame: .zero)
initialSetup()
}
private func initialSetup() {
if let layer = self.layer as? AVPlayerLayer {
layer.videoGravity = AVLayerVideoGravity.resizeAspect
}
}
func prepareToPlay(withUrl url:URL, shouldPlayImmediately: Bool = false) {
guard !(self.url == url && assetPlayer != nil && assetPlayer?.error == nil) else {
if shouldPlayImmediately {
play()
}
return
}
cleanUp()
self.url = url
let options = [AVURLAssetPreferPreciseDurationAndTimingKey : true]
let urlAsset = AVURLAsset(url: url, options: options)
self.urlAsset = urlAsset
let keys = ["tracks"]
urlAsset.loadValuesAsynchronously(forKeys: keys, completionHandler: { [weak self] in
guard let strongSelf = self else { return }
strongSelf.startLoading(urlAsset, shouldPlayImmediately)
})
NotificationCenter.default.addObserver(self, selector: #selector(self.playerItemDidReachEnd), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil)
}
private func startLoading(_ asset: AVURLAsset, _ shouldPlayImmediately: Bool) {
var error:NSError?
let status:AVKeyValueStatus = asset.statusOfValue(forKey: "tracks", error: &error)
if status == AVKeyValueStatus.loaded {
let item = AVPlayerItem(asset: asset)
self.playerItem = item
self.assetPlayer = AVPlayer(playerItem: item)
self.didFinishLoading(self.assetPlayer, shouldPlayImmediately)
}
}
private func didFinishLoading(_ player: AVPlayer?, _ shouldPlayImmediately: Bool) {
guard let player = player, shouldPlayImmediately else { return }
DispatchQueue.main.async {
player.play()
}
}
@objc private func playerItemDidReachEnd(_ notification: Notification) {
guard notification.object as? AVPlayerItem == self.playerItem else { return }
DispatchQueue.main.async {
guard let videoPlayer = self.assetPlayer else { return }
videoPlayer.seek(to: .zero)
videoPlayer.play()
}
}
func play() {
guard self.assetPlayer?.isPlaying == false else { return }
DispatchQueue.main.async {
self.assetPlayer?.play()
}
}
func pause() {
guard self.assetPlayer?.isPlaying == true else { return }
DispatchQueue.main.async {
self.assetPlayer?.pause()
}
}
func cleanUp() {
pause()
urlAsset?.cancelLoading()
urlAsset = nil
assetPlayer = nil
removeObservers()
}
func removeObservers() {
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil)
}
deinit {
cleanUp()
}
}