PQSingletoVideoPlayer.swift 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. //
  2. // PQVideoPlayer.swift
  3. // PQSpeed
  4. //
  5. // Created by SanW on 2020/6/3.
  6. // Copyright © 2020 BytesFlow. All rights reserved.
  7. //
  8. import UIKit
  9. public class PQSingletoVideoPlayer: NSObject {
  10. public static let shared = PQSingletoVideoPlayer()
  11. public var isPlayEnd: Bool = false // 是否已播放完成
  12. public var isRealPlay: Bool = false // 是否已真实播放
  13. public var isSemiRealPlay: Bool = false // 是否已播放到十秒
  14. public var isPlayBegin: Bool = false // 是否已缓冲完成开始播放
  15. public var isFirstFrame: Bool = false // 是否已显示第一帧加载完成
  16. public var isPlayerError: Bool = false // 是否播放失败
  17. public var loadingTime: TimeInterval = 0 // 加载时长
  18. public var playId: String = getUniqueId(desc: "playId") // 播放ID
  19. /// 进度回调
  20. public var progressBloc: ((_ loadProgress: Float, _ playProgress: Float, _ duration: Float) -> Void)?
  21. /// 播放状态回调
  22. public var playStatusBloc: ((_ playStatus: PQVIDEO_PLAY_STATUS) -> Void)?
  23. public var playControllerView: UIView?
  24. public var playVideoData: PQVideoListModel?
  25. public var isPlaying: Bool {
  26. return player.isPlaying()
  27. }
  28. public lazy var player: TXVodPlayer = {
  29. let player = TXVodPlayer()
  30. let config = TXVodPlayConfig()
  31. config.cacheFolderPath = videoCacheDirectory
  32. config.maxCacheItems = 5
  33. player.config = config
  34. player.vodDelegate = self
  35. player.setRenderMode(.RENDER_MODE_FILL_SCREEN)
  36. return player
  37. }()
  38. public func configPlyer(videoData: PQVideoListModel, controllerView: UIView) {
  39. isPlayEnd = false
  40. isRealPlay = false
  41. isSemiRealPlay = false
  42. isPlayBegin = false
  43. isFirstFrame = false
  44. isPlayerError = false
  45. loadingTime = Date().timeIntervalSince1970 * 1000
  46. player.stopPlay()
  47. player.removeVideoWidget()
  48. player.setupVideoWidget(controllerView, insert: 0)
  49. player.enableHWAcceleration = true
  50. playControllerView = controllerView
  51. playVideoData = videoData
  52. if playVideoData!.playProgress >= 0.0 {
  53. //
  54. var progress: CGFloat = playVideoData!.playProgress
  55. if progress > 5.0, progress < 20 {
  56. progress = progress - 5.0
  57. if progress <= 0 {
  58. progress = 0
  59. }
  60. }
  61. BFLog(message: "xxx.playProgress =\(playVideoData!.playProgress),\(progress)")
  62. player.setStartTime(progress)
  63. }
  64. playId = getUniqueId(desc: "playId")
  65. BFLog(message: "\(String(describing: videoData.title)) 开始播放 \(videoData.videoPath ?? "")")
  66. player.startPlay(videoData.videoPath)
  67. if PQSingletoMemoryUtil.shared.playCount < 4 {
  68. PQSingletoMemoryUtil.shared.playCount = PQSingletoMemoryUtil.shared.playCount + 1
  69. }
  70. }
  71. public func resetPlayer() {
  72. if playControllerView != nil {
  73. player.removeVideoWidget()
  74. player.setupVideoWidget(playControllerView, insert: 0)
  75. if playVideoData!.playProgress >= 0.0 {
  76. //
  77. var progress: CGFloat = playVideoData!.playProgress
  78. if progress > 5.0, progress < 20 {
  79. progress = progress - 5.0
  80. if progress <= 0 {
  81. progress = 0
  82. }
  83. }
  84. BFLog(message: "xxx.playProgress =\(playVideoData!.playProgress),\(progress)")
  85. player.setStartTime(progress)
  86. }
  87. playId = getUniqueId(desc: "playId")
  88. player.startPlay(playVideoData!.videoPath)
  89. }
  90. }
  91. public func pausePlayer() {
  92. player.pause()
  93. }
  94. public func resumePlayer() {
  95. player.resume()
  96. }
  97. public func stopPlayer(isRemove: Bool = true) {
  98. player.stopPlay()
  99. if isRemove {
  100. player.removeVideoWidget()
  101. playControllerView = nil
  102. playVideoData = nil
  103. }
  104. }
  105. override private init() {
  106. super.init()
  107. }
  108. override public func copy() -> Any {
  109. return self
  110. }
  111. override public func mutableCopy() -> Any {
  112. return self
  113. }
  114. }
  115. extension PQSingletoVideoPlayer: TXVodPlayListener {
  116. /// 播放进度回调
  117. /// - Parameters:
  118. /// - player: <#player description#>
  119. /// - EvtID: <#EvtID description#>
  120. /// - param: <#param description#>
  121. public func onPlayEvent(_ player: TXVodPlayer!, event EvtID: Int32, withParam param: [AnyHashable: Any]!) {
  122. switch EvtID {
  123. case PLAY_EVT_PLAY_PROGRESS.rawValue: // 播放进度
  124. // 加载进度, 单位是秒
  125. let loadProgress: Float = param[EVT_PLAYABLE_DURATION] as! Float
  126. // 播放进度, 单位是秒
  127. let playProgress: Float = param[EVT_PLAY_PROGRESS] as! Float
  128. // 总长度, 单位是秒
  129. let duration: Float = param[EVT_PLAY_DURATION] as! Float
  130. if player.currentPlaybackTime() >= 10.0, player.currentPlaybackTime() <= 10.1 {
  131. // 10.0上报
  132. if !isSemiRealPlay, playVideoData != nil {
  133. isSemiRealPlay = true
  134. // 播放上报
  135. PQEventTrackViewModel.videoRelationReportUpload(reportLogType: .reportLogType_Action, videoData: playVideoData, pageSource: nil, businessType: .bt_videoSemiRealPlay, objectType: nil, extParams: nil, shareId: nil, videoIds: nil, playId: playId)
  136. }
  137. }
  138. if player.currentPlaybackTime() >= 20.0 || ((playProgress / duration) >= 0.3) {
  139. // 视频播放到20s或播放到总时长30%,哪个先到为准
  140. if !isRealPlay, playVideoData != nil {
  141. isRealPlay = true
  142. // 播放上报
  143. PQEventTrackViewModel.videoRelationReportUpload(reportLogType: .reportLogType_realPlay, videoData: playVideoData, pageSource: nil, businessType: .bt_videoRealPlay, objectType: nil, extParams: nil, shareId: nil, videoIds: nil, playId: playId)
  144. }
  145. }
  146. playVideoData!.playProgress = CGFloat(playProgress)
  147. if progressBloc != nil {
  148. progressBloc!(loadProgress, playProgress, duration)
  149. }
  150. case PLAY_EVT_RCV_FIRST_I_FRAME.rawValue:
  151. // 首帧完成开始播放
  152. if !isPlayBegin, playVideoData != nil {
  153. isPlayBegin = true
  154. // 播放上报
  155. PQEventTrackViewModel.videoRelationReportUpload(reportLogType: .reportLogType_Action, videoData: playVideoData, pageSource: nil, businessType: .bt_videoPlaySuccess, objectType: nil, extParams: nil, shareId: nil, videoIds: nil, playId: playId)
  156. }
  157. case PLAY_EVT_PLAY_LOADING.rawValue: // 视频播放loading
  158. if playStatusBloc != nil {
  159. playStatusBloc!(.PQVIDEO_PLAY_STATUS_LOADING)
  160. }
  161. case PLAY_EVT_PLAY_BEGIN.rawValue: // 开始播放
  162. if playStatusBloc != nil {
  163. playStatusBloc!(.PQVIDEO_PLAY_STATUS_BEGIN)
  164. }
  165. // 首帧加载完成
  166. if !isFirstFrame, playVideoData != nil {
  167. isFirstFrame = true
  168. // 播放上报
  169. PQEventTrackViewModel.videoRelationReportUpload(reportLogType: .reportLogType_play, videoData: playVideoData, pageSource: nil, businessType: nil, objectType: nil, extParams: nil, shareId: nil, videoIds: nil, playId: playId)
  170. let duration = Int((Date().timeIntervalSince1970 * 1000) - loadingTime)
  171. BFLog(message: "加载时长:\(duration)")
  172. // 加载时间上报
  173. 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)
  174. }
  175. BFLog(message: "首帧加载完成")
  176. case PLAY_EVT_PLAY_END.rawValue: // 播放结束
  177. player.pause()
  178. playId = getUniqueId(desc: "playId")
  179. if playStatusBloc != nil {
  180. playStatusBloc!(.PQVIDEO_PLAY_STATUS_END)
  181. }
  182. if !isPlayEnd, playVideoData != nil {
  183. isPlayEnd = true
  184. // 播放结束上报
  185. PQEventTrackViewModel.videoRelationReportUpload(reportLogType: .reportLogType_Action, videoData: playVideoData, pageSource: nil, businessType: .bt_videoPlayEnd, objectType: nil, extParams: nil, shareId: nil, videoIds: nil, playId: playId)
  186. }
  187. case PLAY_ERR_NET_DISCONNECT.rawValue: // 重连失败
  188. if playStatusBloc != nil {
  189. playStatusBloc!(.PQVIDEO_PLAY_STATUS_DISCONNECT)
  190. }
  191. if !isPlayerError, playVideoData != nil {
  192. isPlayerError = true
  193. // 播放失败
  194. 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)
  195. }
  196. case PLAY_ERR_FILE_NOT_FOUND.rawValue: // 播放文件不存在
  197. if playStatusBloc != nil {
  198. playStatusBloc!(.PQVIDEO_PLAY_STATUS_NOT_FOUND)
  199. }
  200. if !isPlayerError, playVideoData != nil {
  201. isPlayerError = true
  202. // 播放失败
  203. 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)
  204. }
  205. 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获取失败,获取点播文件信息失败,当前视频解码失败,当前音频解码失败
  206. if !isPlayerError, playVideoData != nil {
  207. isPlayerError = true
  208. // 播放失败
  209. 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)
  210. }
  211. case PLAY_WARNING_RECONNECT.rawValue: // 断线重连已启动重新连接
  212. if playStatusBloc != nil {
  213. playStatusBloc!(.PQVIDEO_PLAY_STATUS_RECONNECT)
  214. }
  215. case PLAY_WARNING_RECV_DATA_LAG.rawValue, PLAY_WARNING_VIDEO_PLAY_LAG.rawValue: // 网络来包不稳:可能是下行带宽不足 | 当前视频播放出现卡顿(用户直观感受)
  216. // 播放失败
  217. 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)
  218. default:
  219. break
  220. }
  221. }
  222. /// 网络状态回调
  223. /// - Parameters:
  224. /// - player: <#player description#>
  225. /// - param: <#param description#>
  226. public func onNetStatus(_: TXVodPlayer!, withParam _: [AnyHashable: Any]!) {
  227. // BFLog(message: "onNetStatus:\(param)")
  228. }
  229. }