I have a custom media player, and I wish to use it universally within my app; however I do not wish to keep copying and pasting the code from page to page, as there are multiple areas that I need this video player to work. How would I go about making this solely in one file and being able to just call it in each individual file that it is needed in? This is strictly for iOS
Here is the code:
let avPlayer = AVPlayer()
var avPlayerLayer: AVPlayerLayer!
let playerButton = UIButton()
var timeWatcher : AnyObject!
var timeRemainingLabel = UILabel()
let seekSlider = UISlider()
var playerRateBeforeSeek : Float = 0
var loadingIndicatorView = UIActivityIndicatorView(activityIndicatorStyle: .whiteLarge)
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .black
// An AVPlayerLayer is a CALayer instance to which the AVPlayer can
// direct its visual output. Without it, the user will see nothing.
avPlayerLayer = AVPlayerLayer(player: avPlayer)
view.layer.insertSublayer(avPlayerLayer, at: 0)
//this is for the button, we will do it through storyboard
view.addSubview(playerButton)
playerButton.addTarget(self, action: #selector(playerButtonTapped), for: .touchUpInside)
let url = NSURL(string: "https://content.jwplatform.com/manifests/vM7nH0Kl.m3u8")
let playerItem = AVPlayerItem(url: url! as URL)
avPlayer.replaceCurrentItem(with: playerItem)
//timer info
let timeInterval : CMTime = CMTimeMakeWithSeconds(1.0, 10)
timeWatcher = avPlayer.addPeriodicTimeObserver(forInterval: timeInterval, queue: DispatchQueue.main, using: { (elapsedTime:CMTime) in
// print("the time has now been:", CMTimeGetSeconds(elapsedTime))
self.observeTime(elapsedTime: elapsedTime)
self.timeRemainingLabel.textColor = .white
self.view.addSubview(self.timeRemainingLabel)
//buffer indicator
self.loadingIndicatorView.hidesWhenStopped = true
self.view.addSubview(self.loadingIndicatorView)
self.avPlayer.addObserver(self, forKeyPath: "currentItem.playbackLikelyToKeepUp", options: .new, context: &playbackLikelyToKeepUpContext)
}) as AnyObject!
}
//buffer
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if context == &playbackLikelyToKeepUpContext {
if avPlayer.currentItem!.isPlaybackLikelyToKeepUp {
loadingIndicatorView.stopAnimating()
} else {
loadingIndicatorView.startAnimating()
}
}
}
deinit {
//timer
avPlayer.removeTimeObserver(timeWatcher)
//buffer
avPlayer.removeObserver(self, forKeyPath: "currentItem.playbackLikelyToKeepUp")
}
private func updateTimeLabel(elapsedTime: Float64, duration: Float64) {
let timeRemaining: Float64 = CMTimeGetSeconds(avPlayer.currentItem!.duration) - elapsedTime
timeRemainingLabel.text = String(format: "%02d:%02d", ((lround(timeRemaining) / 60) % 60), lround(timeRemaining) % 60)
}
private func observeTime(elapsedTime: CMTime) {
let duration = CMTimeGetSeconds(avPlayer.currentItem!.duration)
// if isFinite(duration)
// {
let elapsedTime = CMTimeGetSeconds(elapsedTime)
updateTimeLabel(elapsedTime: elapsedTime, duration: duration)
//}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
loadingIndicatorView.startAnimating() //animating the buffer
avPlayer.play() // Start the playback
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
// Layout subviews manually - replace w/ storyboard
avPlayerLayer.frame = view.bounds
playerButton.frame = view.bounds
//time remaining - replace w/ story board
let controlsHeight: CGFloat = 30
let controlsY: CGFloat = view.bounds.size.height - controlsHeight
timeRemainingLabel.frame = CGRect(x: 5, y: controlsY, width: 60, height: controlsHeight)
//buffer - replace w/ storyboard
loadingIndicatorView.center = CGPoint(x: view.bounds.midX, y: view.bounds.midY)
}
func playerButtonTapped(sender: UIButton) {
let playerIsPlayer = avPlayer.rate > 0
if playerIsPlayer {
avPlayer.pause()
} else {
avPlayer.play()
}
}
// Force the view into landscape mode (which is how most video media is consumed.
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return UIInterfaceOrientationMask.landscape
}
override var shouldAutorotate: Bool {
return true
}