123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248 |
- //
- // PQVideoPlayer.swift
- // PQSpeed
- //
- // Created by SanW on 2020/6/3.
- // Copyright © 2020 BytesFlow. All rights reserved.
- //
- import UIKit
- public class PQSingletoVideoPlayer: NSObject {
- public static let shared = PQSingletoVideoPlayer()
- public var isPlayEnd: Bool = false // 是否已播放完成
- public var isRealPlay: Bool = false // 是否已真实播放
- public var isSemiRealPlay: Bool = false // 是否已播放到十秒
- public var isPlayBegin: Bool = false // 是否已缓冲完成开始播放
- public var isFirstFrame: Bool = false // 是否已显示第一帧加载完成
- public var isPlayerError: Bool = false // 是否播放失败
- public var loadingTime: TimeInterval = 0 // 加载时长
- public var playId: String = getUniqueId(desc: "playId") // 播放ID
- /// 进度回调
- public var progressBloc: ((_ loadProgress: Float, _ playProgress: Float, _ duration: Float) -> Void)?
- /// 播放状态回调
- public var playStatusBloc: ((_ playStatus: PQVIDEO_PLAY_STATUS) -> Void)?
- public var playControllerView: UIView?
- public var playVideoData: PQVideoListModel?
- public var isPlaying: Bool {
- return player.isPlaying()
- }
- public lazy var player: TXVodPlayer = {
- let player = TXVodPlayer()
- let config = TXVodPlayConfig()
- config.cacheFolderPath = videoCacheDirectory
- config.maxCacheItems = 5
- player.config = config
- player.vodDelegate = self
- player.setRenderMode(.RENDER_MODE_FILL_SCREEN)
- return player
- }()
- public func configPlyer(videoData: PQVideoListModel, controllerView: UIView) {
- isPlayEnd = false
- isRealPlay = false
- isSemiRealPlay = false
- isPlayBegin = false
- isFirstFrame = false
- isPlayerError = false
- loadingTime = Date().timeIntervalSince1970 * 1000
- player.stopPlay()
- player.removeVideoWidget()
- player.setupVideoWidget(controllerView, insert: 0)
- player.enableHWAcceleration = true
- playControllerView = controllerView
- playVideoData = videoData
- if playVideoData!.playProgress >= 0.0 {
- //
- var progress: CGFloat = playVideoData!.playProgress
- if progress > 5.0, progress < 20 {
- progress = progress - 5.0
- if progress <= 0 {
- progress = 0
- }
- }
- BFLog(message: "xxx.playProgress =\(playVideoData!.playProgress),\(progress)")
- player.setStartTime(progress)
- }
- playId = getUniqueId(desc: "playId")
- BFLog(message: "\(String(describing: videoData.title)) 开始播放 \(videoData.videoPath ?? "")")
- player.startPlay(videoData.videoPath)
- if PQSingletoMemoryUtil.shared.playCount < 4 {
- PQSingletoMemoryUtil.shared.playCount = PQSingletoMemoryUtil.shared.playCount + 1
- }
- }
- public func resetPlayer() {
- if playControllerView != nil {
- player.removeVideoWidget()
- player.setupVideoWidget(playControllerView, insert: 0)
- if playVideoData!.playProgress >= 0.0 {
- //
- var progress: CGFloat = playVideoData!.playProgress
- if progress > 5.0, progress < 20 {
- progress = progress - 5.0
- if progress <= 0 {
- progress = 0
- }
- }
- BFLog(message: "xxx.playProgress =\(playVideoData!.playProgress),\(progress)")
- player.setStartTime(progress)
- }
- playId = getUniqueId(desc: "playId")
- player.startPlay(playVideoData!.videoPath)
- }
- }
- public func pausePlayer() {
- player.pause()
- }
- public func resumePlayer() {
- player.resume()
- }
- public func stopPlayer(isRemove: Bool = true) {
- player.stopPlay()
- if isRemove {
- player.removeVideoWidget()
- playControllerView = nil
- playVideoData = nil
- }
- }
- override private init() {
- super.init()
- }
- override public func copy() -> Any {
- return self
- }
- override public func mutableCopy() -> Any {
- return self
- }
- }
- extension PQSingletoVideoPlayer: TXVodPlayListener {
- /// 播放进度回调
- /// - Parameters:
- /// - player: <#player description#>
- /// - EvtID: <#EvtID description#>
- /// - param: <#param description#>
- public func onPlayEvent(_ player: TXVodPlayer!, event EvtID: Int32, withParam param: [AnyHashable: Any]!) {
- switch EvtID {
- case PLAY_EVT_PLAY_PROGRESS.rawValue: // 播放进度
- // 加载进度, 单位是秒
- let loadProgress: Float = param[EVT_PLAYABLE_DURATION] as! Float
- // 播放进度, 单位是秒
- let playProgress: Float = param[EVT_PLAY_PROGRESS] as! Float
- // 总长度, 单位是秒
- let duration: Float = param[EVT_PLAY_DURATION] as! Float
- if player.currentPlaybackTime() >= 10.0, player.currentPlaybackTime() <= 10.1 {
- // 10.0上报
- if !isSemiRealPlay, playVideoData != nil {
- isSemiRealPlay = true
- // 播放上报
- PQEventTrackViewModel.videoRelationReportUpload(reportLogType: .reportLogType_Action, videoData: playVideoData, pageSource: nil, businessType: .bt_videoSemiRealPlay, objectType: nil, extParams: nil, shareId: nil, videoIds: nil, playId: playId)
- }
- }
- if player.currentPlaybackTime() >= 20.0 || ((playProgress / duration) >= 0.3) {
- // 视频播放到20s或播放到总时长30%,哪个先到为准
- if !isRealPlay, playVideoData != nil {
- isRealPlay = true
- // 播放上报
- PQEventTrackViewModel.videoRelationReportUpload(reportLogType: .reportLogType_realPlay, videoData: playVideoData, pageSource: nil, businessType: .bt_videoRealPlay, objectType: nil, extParams: nil, shareId: nil, videoIds: nil, playId: playId)
- }
- }
- playVideoData!.playProgress = CGFloat(playProgress)
- if progressBloc != nil {
- progressBloc!(loadProgress, playProgress, duration)
- }
- case PLAY_EVT_RCV_FIRST_I_FRAME.rawValue:
- // 首帧完成开始播放
- if !isPlayBegin, playVideoData != nil {
- isPlayBegin = true
- // 播放上报
- PQEventTrackViewModel.videoRelationReportUpload(reportLogType: .reportLogType_Action, videoData: playVideoData, pageSource: nil, businessType: .bt_videoPlaySuccess, objectType: nil, extParams: nil, shareId: nil, videoIds: nil, playId: playId)
- }
- case PLAY_EVT_PLAY_LOADING.rawValue: // 视频播放loading
- if playStatusBloc != nil {
- playStatusBloc!(.PQVIDEO_PLAY_STATUS_LOADING)
- }
- case PLAY_EVT_PLAY_BEGIN.rawValue: // 开始播放
- if playStatusBloc != nil {
- playStatusBloc!(.PQVIDEO_PLAY_STATUS_BEGIN)
- }
- // 首帧加载完成
- if !isFirstFrame, playVideoData != nil {
- isFirstFrame = true
- // 播放上报
- PQEventTrackViewModel.videoRelationReportUpload(reportLogType: .reportLogType_play, videoData: playVideoData, pageSource: nil, businessType: nil, objectType: nil, extParams: nil, shareId: nil, videoIds: nil, playId: playId)
- let duration = Int((Date().timeIntervalSince1970 * 1000) - loadingTime)
- BFLog(message: "加载时长:\(duration)")
- // 加载时间上报
- PQEventTrackViewModel.videoRelationReportUpload(reportLogType: .reportLogType_Frontend, videoData: playVideoData, pageSource: nil, businessType: .bt_videoPlaySuccessTime, objectType: nil, extParams: ["duration": duration, "proxyEnable": "0", "url": playVideoData?.videoPath ?? "", "videoId": playVideoData?.uniqueId ?? "0"], shareId: nil, videoIds: nil, playId: playId)
- }
- BFLog(message: "首帧加载完成")
- case PLAY_EVT_PLAY_END.rawValue: // 播放结束
- player.pause()
- playId = getUniqueId(desc: "playId")
- if playStatusBloc != nil {
- playStatusBloc!(.PQVIDEO_PLAY_STATUS_END)
- }
- if !isPlayEnd, playVideoData != nil {
- isPlayEnd = true
- // 播放结束上报
- PQEventTrackViewModel.videoRelationReportUpload(reportLogType: .reportLogType_Action, videoData: playVideoData, pageSource: nil, businessType: .bt_videoPlayEnd, objectType: nil, extParams: nil, shareId: nil, videoIds: nil, playId: playId)
- }
- case PLAY_ERR_NET_DISCONNECT.rawValue: // 重连失败
- if playStatusBloc != nil {
- playStatusBloc!(.PQVIDEO_PLAY_STATUS_DISCONNECT)
- }
- if !isPlayerError, playVideoData != nil {
- isPlayerError = true
- // 播放失败
- PQEventTrackViewModel.videoRelationReportUpload(reportLogType: .reportLogType_Frontend, videoData: playVideoData, pageSource: nil, businessType: .bt_videoPlayError, objectType: nil, extParams: ["pageSource": playVideoData!.pageSource.rawValue, "networkType": networkStatus(), "extra": "0", "hasRetry": true, "url": playVideoData?.videoPath ?? "", "videoId": playVideoData?.uniqueId ?? "0", "what": EvtID], shareId: nil, videoIds: nil, playId: playId)
- }
- case PLAY_ERR_FILE_NOT_FOUND.rawValue: // 播放文件不存在
- if playStatusBloc != nil {
- playStatusBloc!(.PQVIDEO_PLAY_STATUS_NOT_FOUND)
- }
- if !isPlayerError, playVideoData != nil {
- isPlayerError = true
- // 播放失败
- PQEventTrackViewModel.videoRelationReportUpload(reportLogType: .reportLogType_Frontend, videoData: playVideoData, pageSource: nil, businessType: .bt_videoPlayError, objectType: nil, extParams: ["pageSource": playVideoData!.pageSource.rawValue, "networkType": networkStatus(), "extra": "0", "hasRetry": false, "url": playVideoData?.videoPath ?? "", "videoId": playVideoData?.uniqueId ?? "0", "what": EvtID], shareId: nil, videoIds: nil, playId: playId)
- }
- case PLAY_ERR_HEVC_DECODE_FAIL.rawValue, PLAY_ERR_HLS_KEY.rawValue, PLAY_ERR_GET_PLAYINFO_FAIL.rawValue, PLAY_WARNING_VIDEO_DECODE_FAIL.rawValue, PLAY_WARNING_AUDIO_DECODE_FAIL.rawValue: // H265解码失败,HLS解码key获取失败,获取点播文件信息失败,当前视频解码失败,当前音频解码失败
- if !isPlayerError, playVideoData != nil {
- isPlayerError = true
- // 播放失败
- PQEventTrackViewModel.videoRelationReportUpload(reportLogType: .reportLogType_Frontend, videoData: playVideoData, pageSource: nil, businessType: .bt_videoPlayError, objectType: nil, extParams: ["pageSource": playVideoData!.pageSource.rawValue, "networkType": networkStatus(), "extra": "0", "hasRetry": false, "url": playVideoData?.videoPath ?? "", "videoId": playVideoData?.uniqueId ?? "0", "what": EvtID], shareId: nil, videoIds: nil, playId: playId)
- }
- case PLAY_WARNING_RECONNECT.rawValue: // 断线重连已启动重新连接
- if playStatusBloc != nil {
- playStatusBloc!(.PQVIDEO_PLAY_STATUS_RECONNECT)
- }
- case PLAY_WARNING_RECV_DATA_LAG.rawValue, PLAY_WARNING_VIDEO_PLAY_LAG.rawValue: // 网络来包不稳:可能是下行带宽不足 | 当前视频播放出现卡顿(用户直观感受)
- // 播放失败
- PQEventTrackViewModel.videoRelationReportUpload(reportLogType: .reportLogType_Frontend, videoData: playVideoData, pageSource: nil, businessType: .bt_videoPlaySlow, objectType: nil, extParams: ["pageSource": playVideoData!.pageSource.rawValue, "networkType": networkStatus(), "url": playVideoData?.videoPath ?? "", "videoId": playVideoData?.uniqueId ?? "0", "what": EvtID, "position": player.currentPlaybackTime()], shareId: nil, videoIds: nil, playId: playId)
- default:
- break
- }
- }
- /// 网络状态回调
- /// - Parameters:
- /// - player: <#player description#>
- /// - param: <#param description#>
- public func onNetStatus(_: TXVodPlayer!, withParam _: [AnyHashable: Any]!) {
- // BFLog(message: "onNetStatus:\(param)")
- }
- }
|