201 lines
5.9 KiB
Swift
201 lines
5.9 KiB
Swift
//
|
||
// BRPlayer.swift
|
||
// BeeReel
|
||
//
|
||
// Created by 长沙鸿瑶 on 2025/6/24.
|
||
//
|
||
|
||
import UIKit
|
||
import SJBaseVideoPlayer
|
||
|
||
|
||
@objc protocol BRPlayerDelegate: NSObjectProtocol {
|
||
|
||
@objc optional func br_playerReadyToPlay(_ player: BRPlayer)
|
||
///更新当前总进度
|
||
@objc optional func br_playerDurationDidChange(_ player: BRPlayer, duration: TimeInterval)
|
||
///更新当前进度
|
||
@objc optional func br_playerCurrentTimeDidChange(_ player: BRPlayer, time: TimeInterval)
|
||
|
||
///播放完成
|
||
@objc optional func br_playerDidPlayFinish(_ player: BRPlayer)
|
||
|
||
///调用了播放但是在缓冲中导致没有正常播放
|
||
@objc optional func br_playerInBufferToPlay(_ player: BRPlayer)
|
||
|
||
///调用了播放,缓冲完成正常播放
|
||
@objc optional func br_playerBufferingCompleted(_ player: BRPlayer)
|
||
}
|
||
|
||
class BRPlayer: NSObject {
|
||
|
||
private(set) var isPlaying = false
|
||
|
||
private lazy var player: SJBaseVideoPlayer = {
|
||
let player = SJBaseVideoPlayer()
|
||
player.autoplayWhenSetNewAsset = false
|
||
player.resumePlaybackWhenAppDidEnterForeground = false
|
||
player.accurateSeeking = true
|
||
player.videoGravity = .resizeAspectFill
|
||
// player.disableVolumeSetting = true
|
||
player.rotationManager?.isDisabledAutorotation = true
|
||
player.controlLayerDataSource = self
|
||
player.resumePlaybackWhenPlayerHasFinishedSeeking = false
|
||
return player
|
||
}()
|
||
|
||
weak var delegate: BRPlayerDelegate?
|
||
|
||
weak var playerView: UIView? {
|
||
didSet {
|
||
playerView?.addSubview(player.view)
|
||
player.view.snp.makeConstraints { make in
|
||
make.edges.equalToSuperview()
|
||
}
|
||
}
|
||
}
|
||
|
||
private(set) weak var br_controlView: BRPlayerControlProtocol?;
|
||
|
||
var coverImageView: UIImageView? {
|
||
return self.player.presentView.placeholderImageView
|
||
}
|
||
|
||
var isLoop = false
|
||
|
||
///精确到秒
|
||
var duration: TimeInterval {
|
||
return self.player.duration
|
||
}
|
||
|
||
var currentTime: TimeInterval {
|
||
return self.player.currentTime
|
||
}
|
||
|
||
var rate: Float {
|
||
get {
|
||
return self.player.rate
|
||
}
|
||
set {
|
||
self.player.rate = newValue
|
||
}
|
||
}
|
||
|
||
deinit {
|
||
brLog(message: "播放器销毁")
|
||
}
|
||
|
||
init(controlView: BRPlayerControlProtocol?) {
|
||
super.init()
|
||
self.br_controlView = controlView
|
||
|
||
setupPlayer()
|
||
}
|
||
|
||
func setPlayUrl(url: String) {
|
||
self.stop()
|
||
guard let url = URL(string: url) else { return }
|
||
guard let proxyUrl = BRPlayerCache.proxyURL(url: url) else { return }
|
||
|
||
let asset = SJVideoPlayerURLAsset(url: proxyUrl)
|
||
self.player.urlAsset = asset
|
||
}
|
||
|
||
func start() {
|
||
self.isPlaying = true
|
||
self.player.play()
|
||
}
|
||
|
||
func pause() {
|
||
self.isPlaying = false
|
||
self.player.pause()
|
||
}
|
||
|
||
///用户暂停
|
||
// func pauseForUser() {
|
||
// self.isPlaying = false
|
||
// self.player.pauseForUser()
|
||
// }
|
||
|
||
func stop() {
|
||
self.isPlaying = false
|
||
self.player.stop()
|
||
}
|
||
|
||
func replay() {
|
||
player.replay()
|
||
}
|
||
|
||
func seek(toTime: TimeInterval) {
|
||
self.player.seek(toTime: toTime)
|
||
}
|
||
}
|
||
|
||
extension BRPlayer {
|
||
|
||
private func setupPlayer() {
|
||
//设置支持的手势
|
||
self.player.gestureController.supportedGestureTypes = .singleTap
|
||
self.player.gestureController.singleTapHandler = { [weak self] _, _ in
|
||
guard let self = self else { return }
|
||
self.br_controlView?.singleTapEvent()
|
||
}
|
||
|
||
//播放完成回调
|
||
self.player.playbackObserver.playbackDidFinishExeBlock = { [weak self] player in
|
||
guard let self = self else { return }
|
||
if self.isLoop {
|
||
self.replay()
|
||
} else {
|
||
self.delegate?.br_playerDidPlayFinish?(self)
|
||
}
|
||
}
|
||
//播放状态改变
|
||
self.player.playbackObserver.playbackStatusDidChangeExeBlock = { [weak self] player in
|
||
guard let self = self else { return }
|
||
|
||
}
|
||
//播放控制改变的回调
|
||
self.player.playbackObserver.timeControlStatusDidChangeExeBlock = { [weak self] player in
|
||
guard let self = self else { return }
|
||
if player.timeControlStatus == .waitingToPlay {//缓冲中
|
||
self.delegate?.br_playerInBufferToPlay?(self)
|
||
brLog(message: "=======缓冲中 === \(player.reasonForWaitingToPlay ?? "")")
|
||
} else if player.timeControlStatus == .playing {
|
||
self.delegate?.br_playerBufferingCompleted?(self)
|
||
brLog(message: "=======缓冲完成")
|
||
}
|
||
}
|
||
|
||
self.player.playbackObserver.assetStatusDidChangeExeBlock = { [weak self] player in
|
||
guard let self = self else { return }
|
||
brLog(message: "assetStatus === \(player.assetStatus.rawValue)")
|
||
if player.assetStatus == .readyToPlay {
|
||
self.delegate?.br_playerReadyToPlay?(self)
|
||
}
|
||
}
|
||
|
||
//播放时长改变
|
||
self.player.playbackObserver.durationDidChangeExeBlock = { [weak self] player in
|
||
guard let self = self else { return }
|
||
self.delegate?.br_playerDurationDidChange?(self, duration: player.duration)
|
||
}
|
||
//播放进度改变
|
||
self.player.playbackObserver.currentTimeDidChangeExeBlock = { [weak self] player in
|
||
guard let self = self else { return }
|
||
self.delegate?.br_playerCurrentTimeDidChange?(self, time: player.currentTime)
|
||
}
|
||
|
||
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//MARK: -------------- SJVideoPlayerControlLayerDataSource --------------
|
||
extension BRPlayer: SJVideoPlayerControlLayerDataSource {
|
||
func controlView() -> UIView! {
|
||
return self.br_controlView as? UIView
|
||
}
|
||
}
|