自定义播放器在拖动播放时还有些问题,后面再来优化
This commit is contained in:
parent
a73cb139a4
commit
c228bc37ee
@ -21,6 +21,7 @@
|
||||
006B61DE2BBCFB45003FCB49 /* CustomSheetCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 006B61DD2BBCFB45003FCB49 /* CustomSheetCell.swift */; };
|
||||
0073BD142BCE80F700721885 /* ZZHCustomPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0073BD132BCE80F700721885 /* ZZHCustomPlayer.swift */; };
|
||||
0073BD182BCF7B3400721885 /* ZZHCustomSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0073BD172BCF7B3400721885 /* ZZHCustomSlider.swift */; };
|
||||
0073BD1A2BCFC8E800721885 /* ZZHCustomPlayerForVideoTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0073BD192BCFC8E800721885 /* ZZHCustomPlayerForVideoTask.swift */; };
|
||||
009661F82BAD6C7100FCA65F /* CCSpaceAlbumFilterPopView2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 009661F72BAD6C7100FCA65F /* CCSpaceAlbumFilterPopView2.swift */; };
|
||||
009661FA2BAD876200FCA65F /* PhotosUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 009661F92BAD876200FCA65F /* PhotosUI.framework */; };
|
||||
009661FC2BADB20D00FCA65F /* CoreMotion.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 009661FB2BADB20D00FCA65F /* CoreMotion.framework */; };
|
||||
@ -28,7 +29,6 @@
|
||||
009662462BB3B39900FCA65F /* External.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 009662452BB3B39900FCA65F /* External.storyboard */; };
|
||||
0096624A2BB3B45200FCA65F /* ExternalSceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 009662492BB3B45200FCA65F /* ExternalSceneDelegate.swift */; };
|
||||
0096624D2BB3BA3B00FCA65F /* ZZHExternalViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0096624C2BB3BA3B00FCA65F /* ZZHExternalViewController.swift */; };
|
||||
0096625A2BB552E700FCA65F /* CCSpatialVideoDisplayForVideoTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = 009662592BB552E700FCA65F /* CCSpatialVideoDisplayForVideoTask.swift */; };
|
||||
009DFB032BC63AF0007B56E8 /* CoreImage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 009DFB022BC63AF0007B56E8 /* CoreImage.framework */; };
|
||||
009DFB0E2BC8CFA2007B56E8 /* FeedbackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 009DFB0D2BC8CFA2007B56E8 /* FeedbackView.swift */; };
|
||||
009DFB112BC8E2E9007B56E8 /* MenuVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 009DFB102BC8E2E9007B56E8 /* MenuVC.swift */; };
|
||||
@ -130,6 +130,9 @@
|
||||
006B61DD2BBCFB45003FCB49 /* CustomSheetCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomSheetCell.swift; sourceTree = "<group>"; };
|
||||
0073BD132BCE80F700721885 /* ZZHCustomPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZZHCustomPlayer.swift; sourceTree = "<group>"; };
|
||||
0073BD172BCF7B3400721885 /* ZZHCustomSlider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZZHCustomSlider.swift; sourceTree = "<group>"; };
|
||||
0073BD192BCFC8E800721885 /* ZZHCustomPlayerForVideoTask.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZZHCustomPlayerForVideoTask.swift; sourceTree = "<group>"; };
|
||||
0073BD1B2BCFCC4500721885 /* CCSpatialVideoDisplayController1.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CCSpatialVideoDisplayController1.swift; sourceTree = "<group>"; };
|
||||
0073BD1D2BCFCC6900721885 /* CCSpatialVideoDisplayForVideoTask1.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CCSpatialVideoDisplayForVideoTask1.swift; sourceTree = "<group>"; };
|
||||
009661F72BAD6C7100FCA65F /* CCSpaceAlbumFilterPopView2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CCSpaceAlbumFilterPopView2.swift; sourceTree = "<group>"; };
|
||||
009661F92BAD876200FCA65F /* PhotosUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PhotosUI.framework; path = System/Library/Frameworks/PhotosUI.framework; sourceTree = SDKROOT; };
|
||||
009661FB2BADB20D00FCA65F /* CoreMotion.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMotion.framework; path = System/Library/Frameworks/CoreMotion.framework; sourceTree = SDKROOT; };
|
||||
@ -137,7 +140,6 @@
|
||||
009662452BB3B39900FCA65F /* External.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = External.storyboard; sourceTree = "<group>"; };
|
||||
009662492BB3B45200FCA65F /* ExternalSceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExternalSceneDelegate.swift; sourceTree = "<group>"; };
|
||||
0096624C2BB3BA3B00FCA65F /* ZZHExternalViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZZHExternalViewController.swift; sourceTree = "<group>"; };
|
||||
009662592BB552E700FCA65F /* CCSpatialVideoDisplayForVideoTask.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CCSpatialVideoDisplayForVideoTask.swift; sourceTree = "<group>"; };
|
||||
009DFB022BC63AF0007B56E8 /* CoreImage.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreImage.framework; path = System/Library/Frameworks/CoreImage.framework; sourceTree = SDKROOT; };
|
||||
009DFB0D2BC8CFA2007B56E8 /* FeedbackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbackView.swift; sourceTree = "<group>"; };
|
||||
009DFB102BC8E2E9007B56E8 /* MenuVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuVC.swift; sourceTree = "<group>"; };
|
||||
@ -285,6 +287,15 @@
|
||||
path = CustomSheetController;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0072361D2BD0EEFC000595A9 /* deapt */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0073BD1B2BCFCC4500721885 /* CCSpatialVideoDisplayController1.swift */,
|
||||
0073BD1D2BCFCC6900721885 /* CCSpatialVideoDisplayForVideoTask1.swift */,
|
||||
);
|
||||
path = deapt;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0096624B2BB3BA0100FCA65F /* ExternalScreen */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -298,9 +309,10 @@
|
||||
009662582BB5527200FCA65F /* CCSpatialVideoDisplayController */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0072361D2BD0EEFC000595A9 /* deapt */,
|
||||
1E1EA2932B9364F000A5D5D2 /* CCSpatialVideoDisplayController.swift */,
|
||||
009662592BB552E700FCA65F /* CCSpatialVideoDisplayForVideoTask.swift */,
|
||||
0073BD132BCE80F700721885 /* ZZHCustomPlayer.swift */,
|
||||
0073BD192BCFC8E800721885 /* ZZHCustomPlayerForVideoTask.swift */,
|
||||
0073BD172BCF7B3400721885 /* ZZHCustomSlider.swift */,
|
||||
);
|
||||
path = CCSpatialVideoDisplayController;
|
||||
@ -784,6 +796,7 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
0073BD1A2BCFC8E800721885 /* ZZHCustomPlayerForVideoTask.swift in Sources */,
|
||||
AF2120CC2B4E973800400B7F /* CCInputTextField.swift in Sources */,
|
||||
AF2120C72B4E95DA00400B7F /* UIColor+Add.swift in Sources */,
|
||||
AF2120C52B4E95DA00400B7F /* UIButton+Add.swift in Sources */,
|
||||
@ -863,7 +876,6 @@
|
||||
1E02C9322B8990C600DD3143 /* CCDeviceOperationListView.swift in Sources */,
|
||||
AF2120DA2B4E9BD400400B7F /* CCAlert.swift in Sources */,
|
||||
006B61D12BBA5DB4003FCB49 /* MembershipProductView.swift in Sources */,
|
||||
0096625A2BB552E700FCA65F /* CCSpatialVideoDisplayForVideoTask.swift in Sources */,
|
||||
1EFB8C702B88DA4800C72119 /* CCBottomMenuCell.swift in Sources */,
|
||||
AF2120FA2B4EA5BD00400B7F /* CCHomeController.swift in Sources */,
|
||||
0073BD182BCF7B3400721885 /* ZZHCustomSlider.swift in Sources */,
|
||||
|
||||
Binary file not shown.
@ -515,9 +515,9 @@
|
||||
filePath = "SwiftProject/Project/Controller/RecordingVideo/CCSpatialVideoDisplayController/CCSpatialVideoDisplayController.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "388"
|
||||
endingLineNumber = "388"
|
||||
landmarkName = "viewDidAppear(_:)"
|
||||
startingLineNumber = "340"
|
||||
endingLineNumber = "340"
|
||||
landmarkName = "notification_didActiveNotification(notification:)"
|
||||
landmarkType = "7">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
@ -531,9 +531,9 @@
|
||||
filePath = "SwiftProject/Project/Controller/RecordingVideo/CCSpatialVideoDisplayController/CCSpatialVideoDisplayController.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "552"
|
||||
endingLineNumber = "552"
|
||||
landmarkName = "displayUpdate(caDisplayLink:)"
|
||||
startingLineNumber = "498"
|
||||
endingLineNumber = "498"
|
||||
landmarkName = "updateTopCenterButtonWhenIsPlayingChange()"
|
||||
landmarkType = "7">
|
||||
<Locations>
|
||||
<Location
|
||||
@ -581,6 +581,21 @@
|
||||
endingLineNumber = "552"
|
||||
offsetFromSymbolStart = "56">
|
||||
</Location>
|
||||
<Location
|
||||
uuid = "BB183D45-3193-4FC7-92DB-275D529A4AE6 - 1f02ddc6d27b6aec"
|
||||
shouldBeEnabled = "Yes"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
symbolName = "SwiftProject.CCSpatialVideoDisplayController.updateTopCenterButtonWhenIsPlayingChange() -> ()"
|
||||
moduleName = "SwiftProject"
|
||||
usesParentBreakpointCondition = "Yes"
|
||||
urlString = "file:///Users/aaa/Documents/IOS%20Dev/VR/SwiftProject/SwiftProject/Project/Controller/RecordingVideo/CCSpatialVideoDisplayController/CCSpatialVideoDisplayController.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "497"
|
||||
endingLineNumber = "497"
|
||||
offsetFromSymbolStart = "1248">
|
||||
</Location>
|
||||
</Locations>
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "icon@1x.png",
|
||||
"filename" : "play.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 741 KiB |
BIN
SwiftProject/SwiftProject/Assets.xcassets/customPlayer/custom_playBtn.imageset/play.png
vendored
Normal file
BIN
SwiftProject/SwiftProject/Assets.xcassets/customPlayer/custom_playBtn.imageset/play.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.0 KiB |
@ -54,9 +54,7 @@ class CCSpatialVideoDisplayController: BaseController {
|
||||
(icon:"type_check",title:NSLocalizedString("交叉眼", comment: ""),isHiden:false)]
|
||||
}
|
||||
//更新串流UI
|
||||
// DispatchQueue.main.asyncAfter(deadline: .now() + 5, execute: {
|
||||
self.setttinisScreenMirroring(isScreenMirroring: self.isAirPlayActive)
|
||||
// })
|
||||
self.setttinisScreenMirroring(isScreenMirroring: self.isAirPlayActive)
|
||||
|
||||
}
|
||||
|
||||
@ -77,12 +75,7 @@ class CCSpatialVideoDisplayController: BaseController {
|
||||
return label
|
||||
}()
|
||||
|
||||
var assetReader:AVAssetReader?
|
||||
|
||||
var assetOutput:AVAssetReaderTrackOutput?
|
||||
|
||||
var assetTrack:AVAssetTrack?
|
||||
|
||||
|
||||
let kNowTimeToUserDefaultKey_VideoDisplayController:String = "kNowTimeToUserDefaultKey_VideoDisplayController"
|
||||
var link = false//是否已连接设备
|
||||
var isPlaying = false {//是否正在串流播放
|
||||
@ -95,17 +88,18 @@ class CCSpatialVideoDisplayController: BaseController {
|
||||
{
|
||||
didSet{
|
||||
//进行相应解码操作,边解边播
|
||||
customPlayer.selectedIndex = selectedIndex
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
let videoTranserConvertor = PlayByTransferConvertor()
|
||||
// let videoTranserConvertor = PlayByTransferConvertor()
|
||||
|
||||
lazy var videoOriginalAsset:AVAsset = {
|
||||
let asset = AVAsset(url: sourceVideoURL!)
|
||||
return asset
|
||||
}()
|
||||
// lazy var videoOriginalAsset:AVAsset = {
|
||||
// let asset = AVAsset(url: sourceVideoURL!)
|
||||
// return asset
|
||||
// }()
|
||||
|
||||
var videoOriginalPHAsset:PHAsset?
|
||||
|
||||
@ -113,13 +107,16 @@ class CCSpatialVideoDisplayController: BaseController {
|
||||
var sourceVideoURL:URL?
|
||||
var imgData:Data?
|
||||
|
||||
var player:AVPlayer?
|
||||
// var player:AVPlayer?
|
||||
// var needRestReaderTimeRange = false//标识是否需呀重置时间读取范围
|
||||
var playerController:AVPlayerViewController?
|
||||
// var playerController:AVPlayerViewController?
|
||||
var customPlayer:ZZHCustomPlayer = {
|
||||
let cp = ZZHCustomPlayer(frame: .zero)
|
||||
return cp
|
||||
}()
|
||||
|
||||
lazy var mTopImgView:UIImageView = {
|
||||
//393*236
|
||||
// let view = UIImageView(frame: CGRect(x: 0, y: 0, width: SCREEN_Width, height: SCREEN_Height * 236/393))
|
||||
let view = UIImageView(frame: CGRect(x: 0, y: 0, width: SCREEN_Width, height: 236))
|
||||
|
||||
view.image = UIImage.init(named: "BG_Top")
|
||||
@ -218,9 +215,6 @@ class CCSpatialVideoDisplayController: BaseController {
|
||||
let img2:UIImage = UIImage.init(named: NSLocalizedString("displayvc_desc", comment: ""))!
|
||||
button.setImage(img2, for: UIControl.State.normal)
|
||||
button.frame = CGRect(x: 0, y: 0, width: 173, height: 42)
|
||||
// button.titleLabel?.font = KFont_Regular(14)
|
||||
// button.titleLabel?.adjustsFontSizeToFitWidth = true
|
||||
// button.updateBtnEdgeInsets(style: .Left, space: 8)
|
||||
button.centerY = progressView.top - 70
|
||||
button.centerX = self.view.centerX
|
||||
|
||||
@ -229,36 +223,13 @@ class CCSpatialVideoDisplayController: BaseController {
|
||||
|
||||
|
||||
//监听播放完毕
|
||||
@objc func notification_PlayerEndTime(notification:Notification){
|
||||
print("PlayerEndTime....")
|
||||
player?.seek(to: .zero)
|
||||
player?.play()
|
||||
//
|
||||
// self.playerController?.view.layer.sublayers?.forEach({ clayer in
|
||||
// print("clayer.......\(clayer.self)")
|
||||
// clayer.backgroundColor = UIColor.red.cgColor
|
||||
// clayer.sublayers?.forEach({ sclayer in
|
||||
// print("sclayer.......\(sclayer.self)")
|
||||
// sclayer.backgroundColor = UIColor.blue.cgColor
|
||||
// sclayer.sublayers?.forEach({ sscalyer in
|
||||
// print("sscalyer.......\(sscalyer.self)")
|
||||
// if let avPlayerLayer = sscalyer as? AVPlayerLayer {
|
||||
// sscalyer.backgroundColor = UIColor.orange.cgColor
|
||||
// sscalyer.sublayers?.forEach({ avSubLayer in
|
||||
// print("avSubLayer.......\(avSubLayer.self)")
|
||||
// avSubLayer.backgroundColor = UIColor.systemPink.cgColor
|
||||
// if let avaPlayerLayer2 = avSubLayer as? AVPlayerLayer {
|
||||
// avaPlayerLayer2.backgroundColor = UIColor.white.cgColor
|
||||
//
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
//
|
||||
// })
|
||||
// })
|
||||
// })
|
||||
// @objc func notification_PlayerEndTime(notification:Notification){
|
||||
// print("PlayerEndTime....")
|
||||
// player?.seek(to: .zero)
|
||||
// player?.play()
|
||||
|
||||
}
|
||||
|
||||
// }
|
||||
|
||||
//监听拖动播放的进度事件
|
||||
// @objc func notification_PlayerTimeJump(notification:Notification){
|
||||
@ -273,38 +244,41 @@ class CCSpatialVideoDisplayController: BaseController {
|
||||
super.viewDidLoad()
|
||||
configureUI()
|
||||
ZZHHelper.setNowTimeToUserDefaultWithKey(kNowTimeToUserDefaultKey_VideoDisplayController)
|
||||
Task {
|
||||
print("ccs viewdid load ---------")
|
||||
await self.loadVideoAssetReader()
|
||||
DispatchQueue.main.asyncAfter(deadline: .now()+0.01) {[weak self] in
|
||||
self?.setUPPlayer()
|
||||
// 检查当前是否已连接到 AirPlay 设备
|
||||
self?.checkAirPlayStatus()
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
// Task {
|
||||
// print("ccs viewdid load ---------")
|
||||
// await self.loadVideoAssetReader()
|
||||
// DispatchQueue.main.asyncAfter(deadline: .now()+0.01) {[weak self] in
|
||||
// self?.setUPPlayer()
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
// }
|
||||
// }
|
||||
self.customPlayer.setUPPlayer()
|
||||
// 检查当前是否已连接到 AirPlay 设备
|
||||
self.checkAirPlayStatus()
|
||||
}
|
||||
|
||||
func setUPPlayer(){
|
||||
print("getPlayerItem ========")
|
||||
player = AVPlayer()
|
||||
player?.allowsExternalPlayback = true
|
||||
player?.usesExternalPlaybackWhileExternalScreenIsActive = true
|
||||
|
||||
print("getPlayerItem >>>>>>>")
|
||||
|
||||
playerController = AVPlayerViewController()
|
||||
playerController?.player = player
|
||||
playerController!.view.backgroundColor = .clear
|
||||
playerController?.view.frame = CGRect.init(x: 0, y: 170, width: self.view.frame.size.width, height: 400)
|
||||
|
||||
self.addChild(playerController!)
|
||||
self.view.addSubview(playerController!.view)
|
||||
|
||||
self.maskLabel.frame = playerController!.view.frame
|
||||
self.view.addSubview(self.maskLabel)
|
||||
}
|
||||
// func setUPPlayer(){
|
||||
// print("getPlayerItem ========")
|
||||
// player = AVPlayer()
|
||||
// player?.allowsExternalPlayback = true
|
||||
// player?.usesExternalPlaybackWhileExternalScreenIsActive = true
|
||||
//
|
||||
// print("getPlayerItem >>>>>>>")
|
||||
//
|
||||
// playerController = AVPlayerViewController()
|
||||
// playerController?.player = player
|
||||
// playerController!.view.backgroundColor = .clear
|
||||
// playerController?.view.frame = CGRect.init(x: 0, y: 170, width: self.view.frame.size.width, height: 400)
|
||||
//
|
||||
// self.addChild(playerController!)
|
||||
// self.view.addSubview(playerController!.view)
|
||||
//
|
||||
// self.maskLabel.frame = playerController!.view.frame
|
||||
// self.view.addSubview(self.maskLabel)
|
||||
// }
|
||||
|
||||
|
||||
func configureUI(){
|
||||
@ -322,7 +296,20 @@ class CCSpatialVideoDisplayController: BaseController {
|
||||
navtionBar?.addSubview(mTopCenterTypeButton)
|
||||
|
||||
self.view.addSubview(tipsButton)
|
||||
self.view.addSubview(self.customPlayer)
|
||||
self.customPlayer.snp.makeConstraints { make in
|
||||
make.left.right.centerY.equalToSuperview()
|
||||
make.height.equalTo(460)
|
||||
}
|
||||
self.customPlayer.sourceVideoURL = sourceVideoURL
|
||||
|
||||
self.view.addSubview(self.maskLabel)
|
||||
self.maskLabel.snp.makeConstraints { make in
|
||||
make.left.equalTo(customPlayer.snp.left)
|
||||
make.right.equalTo(customPlayer.snp.right)
|
||||
make.top.equalTo(customPlayer.snp.top)
|
||||
make.bottom.equalTo(customPlayer.snp.bottom)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -334,7 +321,7 @@ class CCSpatialVideoDisplayController: BaseController {
|
||||
|
||||
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(notification_PlayerEndTime(notification:)), name: AVPlayerItem.didPlayToEndTimeNotification, object: nil)
|
||||
// NotificationCenter.default.addObserver(self, selector: #selector(notification_PlayerEndTime(notification:)), name: AVPlayerItem.didPlayToEndTimeNotification, object: nil)
|
||||
// NotificationCenter.default.addObserver(self, selector: #selector(notification_PlayerTimeJump(notification:)), name: AVPlayerItem.timeJumpedNotification, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(notificatin_failedToPlayToEndTimeNotification(notifiation: )), name: AVPlayerItem.failedToPlayToEndTimeNotification, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(notificatin_failedToPlayToEndTimeNotification(notifiation: )), name: AVPlayerItem.newErrorLogEntryNotification, object: nil)
|
||||
@ -344,7 +331,8 @@ class CCSpatialVideoDisplayController: BaseController {
|
||||
|
||||
//屏幕进入后台
|
||||
@objc func notification_didEnterBackgroundNotification(notification:Notification) {
|
||||
player?.pause()
|
||||
// player?.pause()
|
||||
customPlayer.play(false)
|
||||
|
||||
print("ccs .....notification_didEnterBackgroundNotification")
|
||||
}
|
||||
@ -370,7 +358,8 @@ class CCSpatialVideoDisplayController: BaseController {
|
||||
if externalVC != nil {
|
||||
externalVC?.playerLayer?.player = nil
|
||||
}
|
||||
player?.pause()
|
||||
// player?.pause()
|
||||
customPlayer.play(false)
|
||||
releaseVideoComposition()
|
||||
|
||||
let sec:TimeInterval = ZZHHelper.getSecFromUserDefaultByKey(kNowTimeToUserDefaultKey_VideoDisplayController)
|
||||
@ -385,18 +374,18 @@ class CCSpatialVideoDisplayController: BaseController {
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
|
||||
if self.player?.currentItem == nil {//此处需要判断是否为空:1,在didload的时候会设置一次,在viewDidDisappear的时候会被置空
|
||||
let playerItem = self.getPlayerItem()
|
||||
self.player?.replaceCurrentItem(with: playerItem)
|
||||
}
|
||||
|
||||
if self.externalVC != nil {//恢复外接屏幕的视频播放
|
||||
if self.externalVC?.playerLayer?.player == nil {
|
||||
self.activeSession()
|
||||
self.externalVC?.playerLayer?.player = self.player
|
||||
}
|
||||
}
|
||||
self.player?.play()
|
||||
// if self.player?.currentItem == nil {//此处需要判断是否为空:1,在didload的时候会设置一次,在viewDidDisappear的时候会被置空
|
||||
// let playerItem = self.getPlayerItem()
|
||||
// self.player?.replaceCurrentItem(with: playerItem)
|
||||
// }
|
||||
//
|
||||
// if self.externalVC != nil {//恢复外接屏幕的视频播放
|
||||
// if self.externalVC?.playerLayer?.player == nil {
|
||||
// self.activeSession()
|
||||
// self.externalVC?.playerLayer?.player = self.player
|
||||
// }
|
||||
// }
|
||||
// self.player?.play()
|
||||
}
|
||||
|
||||
//MARK: - 监听设备投流
|
||||
@ -462,14 +451,11 @@ class CCSpatialVideoDisplayController: BaseController {
|
||||
|
||||
//当外接屏幕连接时
|
||||
func dealTaskWhenExternalScreenConnect(){
|
||||
// if link == true {
|
||||
// return
|
||||
// }
|
||||
|
||||
|
||||
link = true
|
||||
isPlaying = true
|
||||
let playerItem = self.getPlayerItem()
|
||||
player?.replaceCurrentItem(with: playerItem)
|
||||
// let playerItem = self.getPlayerItem()
|
||||
// player?.replaceCurrentItem(with: playerItem)
|
||||
print("外接屏幕已连接.....")
|
||||
activeSession()
|
||||
|
||||
@ -517,8 +503,8 @@ class CCSpatialVideoDisplayController: BaseController {
|
||||
//当外接屏幕断开时
|
||||
func dealTaskWhenExternalScreenDisConnect(){
|
||||
print("外接屏幕已断开.....")
|
||||
let playerItem = self.getPlayerItem()
|
||||
player?.replaceCurrentItem(with: playerItem)
|
||||
// let playerItem = self.getPlayerItem()
|
||||
// player?.replaceCurrentItem(with: playerItem)
|
||||
|
||||
link = false
|
||||
isPlaying = false
|
||||
@ -543,8 +529,8 @@ class CCSpatialVideoDisplayController: BaseController {
|
||||
//隐藏弹出列表尾部
|
||||
menuView.showFooterView(isShow: false, showText: "")
|
||||
externalVC?.playerLayer?.player = nil
|
||||
self.playerController?.player = player
|
||||
player?.play()
|
||||
// self.playerController?.player = player
|
||||
// player?.play()
|
||||
externalVC = nil
|
||||
}
|
||||
|
||||
@ -553,9 +539,9 @@ class CCSpatialVideoDisplayController: BaseController {
|
||||
if has_exvc.playerLayer?.player == nil {
|
||||
has_exvc.imageView?.isHidden = true
|
||||
has_exvc.playerLayer?.isHidden = false
|
||||
self.playerController?.player = nil
|
||||
has_exvc.playerLayer?.player = player
|
||||
player?.play()
|
||||
// self.playerController?.player = nil
|
||||
// has_exvc.playerLayer?.player = player
|
||||
// player?.play()
|
||||
externalDispalylink?.invalidate()
|
||||
externalDispalylink = nil
|
||||
}
|
||||
@ -567,7 +553,6 @@ class CCSpatialVideoDisplayController: BaseController {
|
||||
deinit {
|
||||
print("patialvideodisplaycontroler deinit......")
|
||||
releaseVideoComposition()
|
||||
assetReader?.cancelReading()
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
// player?.removeObserver(self, forKeyPath: "status")
|
||||
}
|
||||
@ -577,8 +562,8 @@ class CCSpatialVideoDisplayController: BaseController {
|
||||
externalDispalylink?.invalidate()
|
||||
externalDispalylink = nil
|
||||
}
|
||||
self.player?.currentItem?.videoComposition = nil
|
||||
self.player?.replaceCurrentItem(with: nil)
|
||||
// self.player?.currentItem?.videoComposition = nil
|
||||
// self.player?.replaceCurrentItem(with: nil)
|
||||
}
|
||||
|
||||
|
||||
@ -641,26 +626,28 @@ class CCSpatialVideoDisplayController: BaseController {
|
||||
isPlaying = false
|
||||
if self.externalVC != nil {
|
||||
externalVC?.playerLayer?.player = nil
|
||||
player?.pause()
|
||||
// player?.pause()
|
||||
customPlayer.play(false)
|
||||
releaseVideoComposition()
|
||||
DispatchQueue.main.asyncAfter(deadline: .now()+0.15, execute: {[weak self] in
|
||||
let playerItem = self?.getPlayerItem()
|
||||
self?.player?.replaceCurrentItem(with: playerItem)
|
||||
self?.playerController?.player = self?.player
|
||||
self?.player?.play()
|
||||
// let playerItem = self?.getPlayerItem()
|
||||
// self?.player?.replaceCurrentItem(with: playerItem)
|
||||
// self?.playerController?.player = self?.player
|
||||
// self?.player?.play()
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
else {//开始串流
|
||||
if self.externalVC != nil {
|
||||
self.playerController?.player = nil
|
||||
player?.pause()
|
||||
releaseVideoComposition()
|
||||
let playerItem = self.getPlayerItem()
|
||||
player?.replaceCurrentItem(with: playerItem)
|
||||
externalVC?.playerLayer?.player = player
|
||||
player?.play()
|
||||
// self.playerController?.player = nil
|
||||
// player?.pause()
|
||||
// releaseVideoComposition()
|
||||
// let playerItem = self.getPlayerItem()
|
||||
// player?.replaceCurrentItem(with: playerItem)
|
||||
// externalVC?.playerLayer?.player = player
|
||||
// player?.play()
|
||||
isPlaying = true
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,12 +9,36 @@ import Foundation
|
||||
import UIKit
|
||||
import AVKit
|
||||
class ZZHCustomPlayer: UIView {
|
||||
//视频资源
|
||||
var sourceVideoURL:URL?
|
||||
var assetTrack:AVAssetTrack?
|
||||
lazy var videoOriginalAsset:AVAsset = {
|
||||
let asset = AVAsset(url: sourceVideoURL!)
|
||||
return asset
|
||||
}()
|
||||
|
||||
var assetReader:AVAssetReader?
|
||||
var assetOutput:AVAssetReaderTrackOutput?
|
||||
|
||||
let videoTranserConvertor = PlayByTransferConvertor()
|
||||
var selectedIndex:SpatialType = .parallelEyes//记录当前选择的菜单选项
|
||||
{
|
||||
didSet{
|
||||
//进行相应解码操作,边解边播
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//ui
|
||||
var playerLayerBgView:UIView?
|
||||
var avPlayer:AVPlayer?
|
||||
var avPlayerLayer:AVPlayerLayer?
|
||||
var timeSlider:ZZHCustomSlider?
|
||||
var prePlayingState:Bool?//标记 在滑块拖动前,player的播放状态,以便在拖动完毕之后回复播放状态
|
||||
let playerPauseBgColor:UIColor = UIColor(r: 245, g: 245, b: 245, a: 0.2)//暂停时的背景颜色
|
||||
let playerPauseBgColor:UIColor = UIColor(r: 20, g: 20, b: 20, a: 0.2)//暂停时的背景颜色
|
||||
|
||||
//线程锁
|
||||
// let lock = NSLock()
|
||||
|
||||
lazy var maskPlayerView:UIView? = {//播放按钮 背景
|
||||
let bgView = UIView()
|
||||
@ -24,7 +48,7 @@ class ZZHCustomPlayer: UIView {
|
||||
|
||||
self.playStateImgView.snp.makeConstraints { make in
|
||||
make.centerX.centerY.equalToSuperview()
|
||||
make.width.height.equalTo(40)
|
||||
make.width.height.equalTo(80)
|
||||
}
|
||||
|
||||
let btn = UIButton()
|
||||
@ -42,8 +66,25 @@ class ZZHCustomPlayer: UIView {
|
||||
return imgView
|
||||
}()
|
||||
|
||||
deinit {
|
||||
print("zzhcustomplayer deinit......")
|
||||
releaseVideoComposition()
|
||||
assetReader?.cancelReading()
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
}
|
||||
|
||||
func releaseVideoComposition() {
|
||||
self.avPlayer?.currentItem?.videoComposition = nil
|
||||
self.avPlayer?.replaceCurrentItem(with: nil)
|
||||
}
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(notification_PlayerEndTime(notification:)), name: AVPlayerItem.didPlayToEndTimeNotification, object: nil)
|
||||
|
||||
|
||||
|
||||
|
||||
let playerWidth = KScreenWidth
|
||||
let playerHeight = 200
|
||||
playerLayerBgView = UIView()
|
||||
@ -54,10 +95,14 @@ class ZZHCustomPlayer: UIView {
|
||||
make.height.equalTo(playerHeight)
|
||||
}
|
||||
avPlayer = AVPlayer()
|
||||
avPlayer?.addPeriodicTimeObserver(forInterval: CMTime(value: 1, timescale: self.avPlayer?.currentItem?.duration.timescale ?? 600), queue: DispatchQueue.main, using: {[weak self] ct in
|
||||
self?.updateSliderUI(ct: ct)
|
||||
})
|
||||
|
||||
avPlayerLayer = AVPlayerLayer(player: avPlayer)
|
||||
avPlayerLayer?.frame = CGRect(x: 0, y: 0, width: Int(playerWidth), height: playerHeight)
|
||||
playerLayerBgView!.layer.addSublayer(avPlayerLayer!)
|
||||
playerLayerBgView?.backgroundColor = UIColor.orange
|
||||
playerLayerBgView?.backgroundColor = UIColor.clear
|
||||
|
||||
self.maskPlayerView?.frame = avPlayerLayer!.frame
|
||||
playerLayerBgView?.addSubview(maskPlayerView!)
|
||||
@ -65,8 +110,8 @@ class ZZHCustomPlayer: UIView {
|
||||
|
||||
|
||||
timeSlider = ZZHCustomSlider(frame: .zero)
|
||||
timeSlider?.processChangeValueCallback = { (value,isMoving) in
|
||||
print("value:\(value) isMoving:\(isMoving)")
|
||||
timeSlider?.processChangeValueCallback = {[weak self] (value,isMoving) in
|
||||
self?.manualToSeekPlay(value:value,isMoving: isMoving)
|
||||
}
|
||||
self.addSubview(timeSlider!)
|
||||
timeSlider!.snp.makeConstraints { make in
|
||||
@ -75,8 +120,57 @@ class ZZHCustomPlayer: UIView {
|
||||
make.bottom.equalToSuperview().offset(0)
|
||||
make.height.equalTo(120)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
//通过slider进行seek播放时间点
|
||||
func manualToSeekPlay(value:Float,isMoving:Bool){
|
||||
if isMoving {
|
||||
self.play(false)
|
||||
}
|
||||
else {
|
||||
let totalSec = CMTimeGetSeconds((self.avPlayer?.currentItem?.duration)!)
|
||||
var atSec = Float(totalSec) * value
|
||||
var timeScale:CMTimeScale? = self.avPlayer?.currentItem?.duration.timescale
|
||||
if let ts = timeScale {
|
||||
atSec = atSec * Float(ts)
|
||||
}
|
||||
else {
|
||||
timeScale = CMTimeScale(1)
|
||||
}
|
||||
let ct = CMTime(value:CMTimeValue(atSec) , timescale: timeScale!)
|
||||
quickLoadAReaderWhenSeek(startCT: ct)
|
||||
|
||||
// self.releaseVideoComposition()
|
||||
// self.avPlayer?.replaceCurrentItem(with: self.getPlayerItem())
|
||||
|
||||
print("正在seek.....\(ct)")
|
||||
self.avPlayer?.seek(to: ct,toleranceBefore:.zero,toleranceAfter: .zero, completionHandler: {[weak self] finished in
|
||||
if finished {
|
||||
self?.quickLoadAReaderWhenSeek(startCT: ct)
|
||||
self?.play(true)
|
||||
}
|
||||
|
||||
print("seek result:\(finished)")
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
//初始化播放器信息
|
||||
func setUPPlayer() {
|
||||
Task {[weak self] in
|
||||
await self?.loadVideoAssetReader()
|
||||
self?.avPlayer?.replaceCurrentItem(with: self?.getPlayerItem())
|
||||
self?.play(true)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//重新状态播放
|
||||
private func reLoadPlay(){
|
||||
self.releaseVideoComposition()
|
||||
self.avPlayer?.replaceCurrentItem(with: self.getPlayerItem())
|
||||
self.play(true)
|
||||
}
|
||||
|
||||
//暂停或者播放
|
||||
@ -107,12 +201,24 @@ class ZZHCustomPlayer: UIView {
|
||||
updatePlayMaskView(value)
|
||||
}
|
||||
|
||||
// func seek(ct:CMTime) {
|
||||
// self.avPlayer?.seek(to: ct)
|
||||
// }
|
||||
|
||||
//根据状态更新播放器遮罩视图显示与隐藏
|
||||
func updatePlayMaskView(_ value:Bool) {
|
||||
playStateImgView.isHidden = value
|
||||
self.maskPlayerView?.backgroundColor = value ? .clear : playerPauseBgColor
|
||||
}
|
||||
|
||||
//根据播放进度更新slider的 ui
|
||||
func updateSliderUI(ct:CMTime) {
|
||||
let sec = CMTimeGetSeconds(ct)
|
||||
let totalSec = CMTimeGetSeconds((self.avPlayer?.currentItem?.duration)!)
|
||||
let s = sec / totalSec
|
||||
self.timeSlider?.exUpdateProcessValue(value: Float(s),currSec: Int(sec),totalSec: Int(totalSec))
|
||||
}
|
||||
|
||||
override func draw(_ rect: CGRect) {
|
||||
super.draw(rect)
|
||||
|
||||
@ -121,4 +227,25 @@ class ZZHCustomPlayer: UIView {
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//MARK: - 视频资源加载
|
||||
|
||||
|
||||
|
||||
//MARK: - 播放器控制
|
||||
|
||||
//监听播放完毕
|
||||
@objc func notification_PlayerEndTime(notification:Notification){
|
||||
print("PlayerEndTime....")
|
||||
// self.quickLoadAReaderWhenReplayBack()
|
||||
avPlayer?.seek(to: .zero,toleranceBefore: .zero,toleranceAfter: .zero,completionHandler: {[weak self] finish in
|
||||
self?.quickLoadAReaderWhenReplayBack()
|
||||
self?.avPlayer?.play()
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,162 @@
|
||||
//
|
||||
// ZZHCustomPlayerForVideoTask.swift
|
||||
// SwiftProject
|
||||
//
|
||||
// Created by aaa on 2024/4/17.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import AVFoundation
|
||||
import Photos
|
||||
import AVKit
|
||||
import VideoToolbox
|
||||
|
||||
extension ZZHCustomPlayer {
|
||||
func getPlayerItem() -> AVPlayerItem {
|
||||
let temItem = AVPlayerItem(asset: self.videoOriginalAsset)
|
||||
AVVideoComposition.videoComposition(with: temItem.asset) { [weak self] request in
|
||||
|
||||
print("正在请求解码图片frame....")
|
||||
guard let weakSelf = self else {
|
||||
print("self 被销毁了.....")
|
||||
return
|
||||
}
|
||||
// self?.lock.lock()
|
||||
weakSelf.convertFrame(request:request)
|
||||
// self?.lock.unlock()
|
||||
|
||||
} completionHandler: { ac, err in
|
||||
if err != nil {
|
||||
print("初始化coposition报错:\(err)")
|
||||
}
|
||||
else{
|
||||
print("composition 生成ok....")
|
||||
temItem.videoComposition = ac
|
||||
}
|
||||
}
|
||||
|
||||
return temItem
|
||||
}
|
||||
|
||||
|
||||
func convertFrame(request:AVAsynchronousCIImageFilteringRequest){
|
||||
let compositionTime = request.compositionTime
|
||||
let end:CMTime = CMTimeMake(value: Int64(compositionTime.value+1), timescale: compositionTime.timescale)
|
||||
let tr = CMTimeRange(start: compositionTime, end: end)
|
||||
|
||||
var ciImg:CIImage? = nil
|
||||
switch self.selectedIndex {
|
||||
case .monocular2D://双眼2d
|
||||
ciImg = request.sourceImage
|
||||
break
|
||||
|
||||
default :
|
||||
ciImg = self.otherModeImgWithMode(mode: self.selectedIndex,tr:tr,compositionTime: compositionTime)
|
||||
break
|
||||
}
|
||||
if let ciImg {
|
||||
request.finish(with: ciImg, context: nil)
|
||||
}
|
||||
else {
|
||||
print("未合成成功.....")
|
||||
request.finish(with: request.sourceImage, context: nil)
|
||||
}
|
||||
}
|
||||
|
||||
func otherModeImgWithMode(mode:SpatialType,tr:CMTimeRange,compositionTime:CMTime)->CIImage? {
|
||||
guard let ao = self.assetOutput else {
|
||||
print("assetOutput 应该是没有被创建成功.....")
|
||||
return nil
|
||||
}
|
||||
|
||||
var ciImg:CIImage? = nil
|
||||
switch mode {
|
||||
case .crossedEyes://交叉眼
|
||||
ciImg = self.videoTranserConvertor.convertVideo(asset: self.videoOriginalAsset, assetOutput: ao, type: self.selectedIndex, time: compositionTime)
|
||||
break
|
||||
|
||||
|
||||
case .fsbs://3d全宽
|
||||
ciImg = self.videoTranserConvertor.convertVideo(asset: self.videoOriginalAsset, assetOutput: ao, type: self.selectedIndex, time: compositionTime)
|
||||
break
|
||||
|
||||
|
||||
case .hsbs://3d半宽
|
||||
ciImg = self.videoTranserConvertor.convertVideo(asset: self.videoOriginalAsset, assetOutput: ao, type: self.selectedIndex, time: compositionTime)
|
||||
break
|
||||
|
||||
|
||||
case .parallelEyes://平行眼
|
||||
ciImg = self.videoTranserConvertor.convertVideo(asset: self.videoOriginalAsset, assetOutput: ao, type: self.selectedIndex, time: compositionTime)
|
||||
break
|
||||
|
||||
case .redBlueSolid://红蓝立体
|
||||
ciImg = self.videoTranserConvertor.convertVideo(asset: self.videoOriginalAsset, assetOutput: ao, type: self.selectedIndex, time: compositionTime)
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
return ciImg
|
||||
|
||||
}
|
||||
|
||||
//加载assetReader和output
|
||||
func loadVideoAssetReader() async {
|
||||
do {
|
||||
if self.assetTrack == nil {
|
||||
assetTrack = try await self.videoOriginalAsset.loadTracks(withMediaType: .video).first!
|
||||
}
|
||||
|
||||
let timeRange = CMTimeRange(start: .zero, duration: .positiveInfinity)
|
||||
DispatchQueue.main.async {
|
||||
self.quickLoadAReader(timeRange: timeRange)
|
||||
}
|
||||
} catch {
|
||||
print("Error loading video: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func quickLoadAReader(timeRange:CMTimeRange) {
|
||||
// self.lock.lock()
|
||||
if(assetReader != nil){
|
||||
assetReader?.cancelReading()
|
||||
}
|
||||
assetReader = try! AVAssetReader(asset: self.videoOriginalAsset)
|
||||
quickLoadAssetOutput()
|
||||
assetReader!.timeRange = timeRange
|
||||
assetReader!.add(assetOutput!)
|
||||
assetReader!.startReading()
|
||||
// self.lock.unlock()
|
||||
}
|
||||
|
||||
//在播放器的slider 拖动播放时调用
|
||||
func quickLoadAReaderWhenSeek(startCT:CMTime) {
|
||||
let timeRange = CMTimeRange(start: startCT, duration: .positiveInfinity)
|
||||
self.quickLoadAReader(timeRange: timeRange)
|
||||
}
|
||||
|
||||
//用于循环播放时调用,重置assetreader的timeRange
|
||||
func quickLoadAReaderWhenReplayBack() {
|
||||
let timeRange = CMTimeRange(start: .zero, duration: .positiveInfinity)
|
||||
self.quickLoadAReader(timeRange: timeRange)
|
||||
}
|
||||
|
||||
func quickLoadAssetOutput() {
|
||||
if(assetOutput != nil){
|
||||
assetOutput?.markConfigurationAsFinal()
|
||||
assetOutput = nil
|
||||
}
|
||||
|
||||
assetOutput = AVAssetReaderTrackOutput(
|
||||
track: self.assetTrack!,
|
||||
outputSettings: [
|
||||
AVVideoDecompressionPropertiesKey: [
|
||||
kVTDecompressionPropertyKey_RequestedMVHEVCVideoLayerIDs: [0, 1] as CFArray,
|
||||
],
|
||||
]
|
||||
)
|
||||
// assetOutput?.supportsRandomAccess = true
|
||||
// assetOutput?.alwaysCopiesSampleData = false
|
||||
}
|
||||
}
|
||||
@ -15,10 +15,12 @@ class ZZHCustomSlider: UIView {
|
||||
var timeSlider:CustomSlider?
|
||||
var processChangeValueCallback:CustomSliderProcessChangeValueCallback?
|
||||
var preValue:Float = 0.0 //更新进度前的value
|
||||
|
||||
var totalSec:Int = -1//代表视频总时长
|
||||
let bgView:UIView = UIView()
|
||||
|
||||
|
||||
deinit {
|
||||
print("zzhcustomslider....deinit...")
|
||||
}
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
@ -83,12 +85,15 @@ class ZZHCustomSlider: UIView {
|
||||
if isMoving {
|
||||
var currentValue = max(0, min(value, 1))
|
||||
//格式化为0.x
|
||||
let formattedValue = String(format: "%.1f", currentValue)
|
||||
let formattedValue = String(format: "%.2f", currentValue)
|
||||
currentValue = Float(formattedValue)!
|
||||
|
||||
//保证相邻2次的值不同才有必要去触发进度的改变
|
||||
if currentValue > preValue || currentValue < preValue {
|
||||
preValue = currentValue
|
||||
processChangeValueCallback(preValue,isMoving)
|
||||
if self.totalSec > 0 {//已经获取到总时长的情况下再去更新起始位置的时间文本值
|
||||
self.sLabel?.text = ZZHHelper.formatVideoTime(second: Int(preValue*Float(self.totalSec)))
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -98,9 +103,14 @@ class ZZHCustomSlider: UIView {
|
||||
}
|
||||
|
||||
//外部播放时的更新当前滑块
|
||||
func exUpdateProcessValue(value:Float) {
|
||||
self.timeSlider!.value = value
|
||||
preValue = value
|
||||
func exUpdateProcessValue(value:Float,currSec:Int,totalSec:Int) {
|
||||
self.totalSec = totalSec
|
||||
self.sLabel?.text = ZZHHelper.formatVideoTime(second: currSec)
|
||||
self.eLabel?.text = ZZHHelper.formatVideoTime(second: totalSec)
|
||||
let formattedValue = String(format: "%.1f", value)
|
||||
let rv = Float(formattedValue)!
|
||||
self.timeSlider!.setValue(value, animated: false)
|
||||
preValue = rv
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,684 @@
|
||||
//
|
||||
// CCSpatialVideoDisplayController.swift
|
||||
// SwiftProject
|
||||
//
|
||||
// Created by Zhang, Joyce on 2024/3/2.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import AVFoundation
|
||||
import Photos
|
||||
import AVKit
|
||||
import VideoToolbox
|
||||
import Firebase
|
||||
enum SpatialType : Int {
|
||||
|
||||
/*
|
||||
单眼2D
|
||||
平行眼
|
||||
红蓝立体
|
||||
交叉眼
|
||||
|
||||
*/
|
||||
|
||||
case monocular2D = 1
|
||||
case parallelEyes = 0
|
||||
case redBlueSolid = 2
|
||||
case crossedEyes = 3
|
||||
//以下两种标记:外部串流时使用
|
||||
case hsbs = 4
|
||||
case fsbs = 5
|
||||
}
|
||||
|
||||
class CCSpatialVideoDisplayController: BaseController {
|
||||
var externalDispalylink:CADisplayLink?
|
||||
var externalVC:ZZHExternalViewController?
|
||||
var isAirPlayActive:Bool = false {
|
||||
didSet{
|
||||
//跟新selectedIndex、typeData的值
|
||||
if(isAirPlayActive){
|
||||
selectedIndex = .fsbs//在串流模式下,默认选项为hsbs
|
||||
typeData = [(icon:"type_check",title:"3D FSBS",isHiden:false),
|
||||
(icon:"type_check",title:"3D HSBS",isHiden:false)
|
||||
]
|
||||
}
|
||||
else{
|
||||
selectedIndex = .parallelEyes//在非串流模式下,默认选项为monocular2D
|
||||
typeData = [
|
||||
(icon:"type_check",title:NSLocalizedString("平行眼", comment: ""),isHiden:false),
|
||||
(icon:"type_check",title:NSLocalizedString("单眼2D", comment: ""),isHiden:false),
|
||||
|
||||
|
||||
|
||||
(icon:"type_check",title:NSLocalizedString("红蓝立体", comment: ""),isHiden:false),
|
||||
(icon:"type_check",title:NSLocalizedString("交叉眼", comment: ""),isHiden:false)]
|
||||
}
|
||||
//更新串流UI
|
||||
// DispatchQueue.main.asyncAfter(deadline: .now() + 5, execute: {
|
||||
self.setttinisScreenMirroring(isScreenMirroring: self.isAirPlayActive)
|
||||
// })
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
lazy var maskLabel:UILabel = {
|
||||
let label = UILabel()
|
||||
label.numberOfLines = 0
|
||||
label.textColor = .white
|
||||
label.font = UIFont.systemFont(ofSize: 14)
|
||||
label.textAlignment = .center
|
||||
label.layer.cornerRadius = 6
|
||||
label.layer.masksToBounds = true
|
||||
label.backgroundColor = UIColor.colorWithRGB(_r: 60.0, _g: 60.0, _b: 60.0, alpha: 0.1)
|
||||
label.text = NSLocalizedString("外部串流中", comment: "")
|
||||
label.isHidden = true
|
||||
return label
|
||||
}()
|
||||
|
||||
var assetReader:AVAssetReader?
|
||||
|
||||
var assetOutput:AVAssetReaderTrackOutput?
|
||||
|
||||
var assetTrack:AVAssetTrack?
|
||||
|
||||
let kNowTimeToUserDefaultKey_VideoDisplayController:String = "kNowTimeToUserDefaultKey_VideoDisplayController"
|
||||
var link = false//是否已连接设备
|
||||
var isPlaying = false {//是否正在串流播放
|
||||
didSet {
|
||||
maskLabel.isHidden = !isPlaying
|
||||
}
|
||||
}
|
||||
|
||||
var selectedIndex:SpatialType = .parallelEyes//记录当前选择的菜单选项
|
||||
{
|
||||
didSet{
|
||||
//进行相应解码操作,边解边播
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
let videoTranserConvertor = PlayByTransferConvertor()
|
||||
|
||||
lazy var videoOriginalAsset:AVAsset = {
|
||||
let asset = AVAsset(url: sourceVideoURL!)
|
||||
return asset
|
||||
}()
|
||||
|
||||
var videoOriginalPHAsset:PHAsset?
|
||||
|
||||
//图片源数据
|
||||
var sourceVideoURL:URL?
|
||||
var imgData:Data?
|
||||
|
||||
var player:AVPlayer?
|
||||
// var needRestReaderTimeRange = false//标识是否需呀重置时间读取范围
|
||||
var playerController:AVPlayerViewController?
|
||||
|
||||
lazy var mTopImgView:UIImageView = {
|
||||
//393*236
|
||||
// let view = UIImageView(frame: CGRect(x: 0, y: 0, width: SCREEN_Width, height: SCREEN_Height * 236/393))
|
||||
let view = UIImageView(frame: CGRect(x: 0, y: 0, width: SCREEN_Width, height: 236))
|
||||
|
||||
view.image = UIImage.init(named: "BG_Top")
|
||||
return view
|
||||
}()
|
||||
|
||||
lazy var transformButton: UIButton = {
|
||||
|
||||
//76*56
|
||||
let transformButton = UIButton.init(type: UIButton.ButtonType.custom)
|
||||
|
||||
transformButton.tag = 201
|
||||
transformButton.isSelected = false
|
||||
transformButton.backgroundColor = UIColor(hexString: "#5326D6")
|
||||
transformButton.addTarget(self, action: #selector(navgationButtonClick2(sender:)), for: UIControl.Event.touchUpInside)
|
||||
let img2:UIImage = UIImage.init(named: "transform_button" as String)!
|
||||
transformButton.setImage(img2, for: UIControl.State.normal)
|
||||
transformButton.frame = CGRect(x: 0, y: 0, width: 56, height: 36)
|
||||
transformButton.layer.cornerRadius = 18
|
||||
transformButton.layer.masksToBounds = true
|
||||
transformButton.centerY = StatuBar_Height + NavBar_Height * 0.5
|
||||
transformButton.right = SCREEN_Width - 24
|
||||
|
||||
return transformButton
|
||||
}()
|
||||
|
||||
lazy var mTopCenterTypeButton: UIButton = {
|
||||
//173*36
|
||||
let button = UIButton()
|
||||
button.backgroundColor = UIColor.hexStringToColor(hexString: "#1F1E20")
|
||||
button.tag = 202
|
||||
button.isSelected = false
|
||||
button.addTarget(self, action: #selector(navgationButtonClick2(sender:)), for: UIControl.Event.touchUpInside)
|
||||
button.frame = CGRect(x: 2, y: 10, width: SCREEN_Width * 0.4 + 20, height: 36)
|
||||
button.centerY = StatuBar_Height + NavBar_Height * 0.5
|
||||
button.centerX = SCREEN_Width * 0.5
|
||||
button.clipsToBounds = true
|
||||
button.layer.cornerRadius = 18
|
||||
button.layer.borderWidth = 1
|
||||
button.layer.borderColor = UIColor.white.cgColor
|
||||
button.setTitle(NSLocalizedString("平行眼", comment: ""), for: UIControl.State.normal)
|
||||
button.setImage(UIImage.init(named: "type_button_arrow_down"), for: .normal)
|
||||
button.updateBtnEdgeInsets(style: .Right, space: 10)
|
||||
button.setTitleColor(UIColor.white, for: UIControl.State.normal)
|
||||
button.titleLabel?.font = KFont_Medium(14)
|
||||
return button
|
||||
}()
|
||||
|
||||
|
||||
|
||||
var typeData:[(icon:String,title:String,isHiden:Bool)] = [(icon:"type_check",title:NSLocalizedString("平行眼", comment: ""),isHiden:false),
|
||||
(icon:"type_check",title:NSLocalizedString("单眼2D", comment: ""),isHiden:false),
|
||||
|
||||
(icon:"type_check",title:NSLocalizedString("红蓝立体", comment: ""),isHiden:false),
|
||||
(icon:"type_check",title:NSLocalizedString("交叉眼", comment: ""),isHiden:false)]
|
||||
{
|
||||
didSet {
|
||||
menuView.setData(datas: self.typeData)
|
||||
}
|
||||
}
|
||||
|
||||
lazy var menuView: CCSpatialDisplayTypeView = {
|
||||
//设置参数
|
||||
let parameters:[CCSpatialDisplayTypeConfigure] = [
|
||||
.PopMenuTextColor(UIColor.white),
|
||||
.popMenuItemHeight(40),
|
||||
.PopMenuTextFont(KFont_Medium(12)),
|
||||
.PopMenuBackgroudColor(UIColor(hexString: "#1F1E20"))
|
||||
]
|
||||
|
||||
|
||||
//init (test随机生成点位置,注意:arrow点是基于屏幕的位置)
|
||||
let pointOnScreen = navtionImgView!.convert(CGPointMake(navtionImgView!.centerX, navtionImgView!.bottom), to: KWindow)
|
||||
let popMenu = CCSpatialDisplayTypeView(menuWidth: SCREEN_Width * 0.4, arrow: pointOnScreen, datas: typeData,configures: parameters){[weak self] in
|
||||
//dissmiss回调
|
||||
self?.mTopCenterTypeButton.setImage(UIImage.init(named: "type_button_arrow_down"), for: .normal)
|
||||
}
|
||||
return popMenu
|
||||
}()
|
||||
|
||||
lazy var progressView: UIProgressView = {
|
||||
var view = UIProgressView (progressViewStyle:.default)
|
||||
view.frame = CGRect(x: 24, y: SCREEN_Height - KStatusBarHeight - 20, width: SCREEN_Width-48, height: 36)
|
||||
view.progress = 0.0 //默认进度50%
|
||||
return view
|
||||
}()
|
||||
|
||||
|
||||
lazy var tipsButton: UIButton = {
|
||||
|
||||
//76*56
|
||||
let button = UIButton.init(type: UIButton.ButtonType.custom)
|
||||
button.tag = 203
|
||||
button.backgroundColor = .clear
|
||||
button.addTarget(self, action: #selector(navgationButtonClick2(sender:)), for: UIControl.Event.touchUpInside)
|
||||
let img2:UIImage = UIImage.init(named: NSLocalizedString("displayvc_desc", comment: ""))!
|
||||
button.setImage(img2, for: UIControl.State.normal)
|
||||
button.frame = CGRect(x: 0, y: 0, width: 173, height: 42)
|
||||
// button.titleLabel?.font = KFont_Regular(14)
|
||||
// button.titleLabel?.adjustsFontSizeToFitWidth = true
|
||||
// button.updateBtnEdgeInsets(style: .Left, space: 8)
|
||||
button.centerY = progressView.top - 70
|
||||
button.centerX = self.view.centerX
|
||||
|
||||
return button
|
||||
}()
|
||||
|
||||
|
||||
//监听播放完毕
|
||||
@objc func notification_PlayerEndTime(notification:Notification){
|
||||
print("PlayerEndTime....")
|
||||
player?.seek(to: .zero)
|
||||
player?.play()
|
||||
//
|
||||
// self.playerController?.view.layer.sublayers?.forEach({ clayer in
|
||||
// print("clayer.......\(clayer.self)")
|
||||
// clayer.backgroundColor = UIColor.red.cgColor
|
||||
// clayer.sublayers?.forEach({ sclayer in
|
||||
// print("sclayer.......\(sclayer.self)")
|
||||
// sclayer.backgroundColor = UIColor.blue.cgColor
|
||||
// sclayer.sublayers?.forEach({ sscalyer in
|
||||
// print("sscalyer.......\(sscalyer.self)")
|
||||
// if let avPlayerLayer = sscalyer as? AVPlayerLayer {
|
||||
// sscalyer.backgroundColor = UIColor.orange.cgColor
|
||||
// sscalyer.sublayers?.forEach({ avSubLayer in
|
||||
// print("avSubLayer.......\(avSubLayer.self)")
|
||||
// avSubLayer.backgroundColor = UIColor.systemPink.cgColor
|
||||
// if let avaPlayerLayer2 = avSubLayer as? AVPlayerLayer {
|
||||
// avaPlayerLayer2.backgroundColor = UIColor.white.cgColor
|
||||
//
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
//
|
||||
// })
|
||||
// })
|
||||
// })
|
||||
|
||||
}
|
||||
|
||||
//监听拖动播放的进度事件
|
||||
// @objc func notification_PlayerTimeJump(notification:Notification){
|
||||
//// needRestReaderTimeRange = true
|
||||
//
|
||||
// print("time jump....")
|
||||
//
|
||||
// }
|
||||
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
configureUI()
|
||||
ZZHHelper.setNowTimeToUserDefaultWithKey(kNowTimeToUserDefaultKey_VideoDisplayController)
|
||||
Task {
|
||||
print("ccs viewdid load ---------")
|
||||
await self.loadVideoAssetReader()
|
||||
DispatchQueue.main.asyncAfter(deadline: .now()+0.01) {[weak self] in
|
||||
self?.setUPPlayer()
|
||||
// 检查当前是否已连接到 AirPlay 设备
|
||||
self?.checkAirPlayStatus()
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func setUPPlayer(){
|
||||
print("getPlayerItem ========")
|
||||
player = AVPlayer()
|
||||
player?.allowsExternalPlayback = true
|
||||
player?.usesExternalPlaybackWhileExternalScreenIsActive = true
|
||||
|
||||
print("getPlayerItem >>>>>>>")
|
||||
|
||||
playerController = AVPlayerViewController()
|
||||
playerController?.player = player
|
||||
playerController!.view.backgroundColor = .clear
|
||||
playerController?.view.frame = CGRect.init(x: 0, y: 170, width: self.view.frame.size.width, height: 400)
|
||||
|
||||
self.addChild(playerController!)
|
||||
self.view.addSubview(playerController!.view)
|
||||
|
||||
self.maskLabel.frame = playerController!.view.frame
|
||||
self.view.addSubview(self.maskLabel)
|
||||
}
|
||||
|
||||
|
||||
func configureUI(){
|
||||
self.view.backgroundColor = UIColor(hexString: "#060507")
|
||||
|
||||
//设置返回按钮图片
|
||||
self.setLeftOneBtnImg(imgStr: "spatial_back_button")
|
||||
self.setNavgationBarColorImg(color: .clear)
|
||||
self.setNavgationBarLine(color: .clear)
|
||||
|
||||
self.view.addSubview(mTopImgView)
|
||||
self.view.bringSubviewToFront(self.navtionBar!)
|
||||
|
||||
navtionBar?.addSubview(transformButton)
|
||||
navtionBar?.addSubview(mTopCenterTypeButton)
|
||||
|
||||
self.view.addSubview(tipsButton)
|
||||
|
||||
|
||||
|
||||
|
||||
// 监听 AirPlay 设备的连接状态
|
||||
//添加外接屏幕链接通知
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(exScreenWillConnectNotification(notification:)), name: UIScene.willConnectNotification, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(exScreenDisConnectNotification(notification:)), name: UIScene.didDisconnectNotification, object: nil)
|
||||
|
||||
|
||||
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(notification_PlayerEndTime(notification:)), name: AVPlayerItem.didPlayToEndTimeNotification, object: nil)
|
||||
// NotificationCenter.default.addObserver(self, selector: #selector(notification_PlayerTimeJump(notification:)), name: AVPlayerItem.timeJumpedNotification, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(notificatin_failedToPlayToEndTimeNotification(notifiation: )), name: AVPlayerItem.failedToPlayToEndTimeNotification, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(notificatin_failedToPlayToEndTimeNotification(notifiation: )), name: AVPlayerItem.newErrorLogEntryNotification, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(notification_didEnterBackgroundNotification(notification: )), name: UIApplication.didEnterBackgroundNotification, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(notification_didActiveNotification(notification: )), name: UIApplication.didBecomeActiveNotification, object: nil)
|
||||
}
|
||||
|
||||
//屏幕进入后台
|
||||
@objc func notification_didEnterBackgroundNotification(notification:Notification) {
|
||||
player?.pause()
|
||||
|
||||
print("ccs .....notification_didEnterBackgroundNotification")
|
||||
}
|
||||
//屏幕进入前台
|
||||
@objc func notification_didActiveNotification(notification:Notification) {
|
||||
self.checkAirPlayStatus()
|
||||
print("ccs .....notification_didEnterBackgroundNotification")
|
||||
}
|
||||
|
||||
|
||||
|
||||
@objc func notificatin_failedToPlayToEndTimeNotification(notifiation:Notification) {
|
||||
print("notificatin_failedToPlayToEndTimeNotification....")
|
||||
|
||||
}
|
||||
|
||||
@objc func notificatin_newErrorLogEntryNotification(notifiation:Notification) {
|
||||
print("notificatin_newErrorLogEntryNotification....")
|
||||
}
|
||||
|
||||
override func viewDidDisappear(_ animated: Bool) {
|
||||
super.viewDidDisappear(animated)
|
||||
if externalVC != nil {
|
||||
externalVC?.playerLayer?.player = nil
|
||||
}
|
||||
player?.pause()
|
||||
releaseVideoComposition()
|
||||
|
||||
let sec:TimeInterval = ZZHHelper.getSecFromUserDefaultByKey(kNowTimeToUserDefaultKey_VideoDisplayController)
|
||||
Analytics.logEvent("preview_pv", parameters: ["refer_page":"视频预览页面","duration":sec])
|
||||
|
||||
print(".........ccs viewdid disappear....")
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
|
||||
if self.player?.currentItem == nil {//此处需要判断是否为空:1,在didload的时候会设置一次,在viewDidDisappear的时候会被置空
|
||||
let playerItem = self.getPlayerItem()
|
||||
self.player?.replaceCurrentItem(with: playerItem)
|
||||
}
|
||||
|
||||
if self.externalVC != nil {//恢复外接屏幕的视频播放
|
||||
if self.externalVC?.playerLayer?.player == nil {
|
||||
self.activeSession()
|
||||
self.externalVC?.playerLayer?.player = self.player
|
||||
}
|
||||
}
|
||||
self.player?.play()
|
||||
}
|
||||
|
||||
//MARK: - 监听设备投流
|
||||
@objc private func airPlayStatusDidChange(_ notification: Notification) {
|
||||
checkAirPlayStatus()
|
||||
if(isAirPlayActive) {
|
||||
Analytics.logEvent("streaming_live", parameters: ["refer_page":"视频预览页面"])
|
||||
ZZHHelper.setNowTimeToUserDefaultWithKey("kNowTimeToUserDefaultKey_VideoDisplayController_airplay")
|
||||
}
|
||||
else {
|
||||
let sec:TimeInterval = ZZHHelper.getSecFromUserDefaultByKey("kNowTimeToUserDefaultKey_VideoDisplayController_airplay")
|
||||
Analytics.logEvent("streaming_live", parameters: ["refer_page":"视频预览页面","duration":sec])
|
||||
}
|
||||
}
|
||||
|
||||
@objc func exScreenWillConnectNotification(notification:Notification){
|
||||
print("exScreenWillConnectNotification>>>>>")
|
||||
airPlayStatusDidChange( notification)
|
||||
}
|
||||
|
||||
@objc func exScreenDisConnectNotification(notification:Notification){
|
||||
print("exScreenDisConnectNotification>>>>>")
|
||||
airPlayStatusDidChange( notification)
|
||||
}
|
||||
|
||||
|
||||
private func checkAirPlayStatus() {
|
||||
print("设备连接变化")
|
||||
|
||||
let currentRoute = AVAudioSession.sharedInstance().currentRoute
|
||||
self.isAirPlayActive = currentRoute.outputs.contains { output in
|
||||
return output.portType == AVAudioSession.Port.HDMI ||
|
||||
output.portType == AVAudioSession.Port.airPlay
|
||||
}
|
||||
}
|
||||
|
||||
func setttinisScreenMirroring(isScreenMirroring:Bool){
|
||||
releaseVideoComposition()
|
||||
|
||||
//已连接
|
||||
if(isScreenMirroring){
|
||||
self.dealTaskWhenExternalScreenConnect()
|
||||
|
||||
|
||||
}else{
|
||||
//未连接
|
||||
self.dealTaskWhenExternalScreenDisConnect()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
//激活一下session
|
||||
func activeSession(){
|
||||
do {
|
||||
try AVAudioSession.sharedInstance().setActive(true)
|
||||
try AVAudioSession.sharedInstance().setCategory(.playback,options: .allowAirPlay)
|
||||
}
|
||||
catch {
|
||||
print("err: set audiosession:\(error)")
|
||||
}
|
||||
}
|
||||
|
||||
//当外接屏幕连接时
|
||||
func dealTaskWhenExternalScreenConnect(){
|
||||
// if link == true {
|
||||
// return
|
||||
// }
|
||||
|
||||
link = true
|
||||
isPlaying = true
|
||||
let playerItem = self.getPlayerItem()
|
||||
player?.replaceCurrentItem(with: playerItem)
|
||||
print("外接屏幕已连接.....")
|
||||
activeSession()
|
||||
|
||||
UIApplication.shared.connectedScenes.forEach { us in
|
||||
print("uisence:\(us)\n")
|
||||
let ws = us as! UIWindowScene
|
||||
if ws.session.role.rawValue == "UIWindowSceneSessionRoleExternalDisplayNonInteractive"{
|
||||
externalVC = ws.windows.first?.rootViewController as? ZZHExternalViewController
|
||||
if externalVC != nil {
|
||||
if let ed = externalDispalylink {
|
||||
ed.invalidate()
|
||||
}
|
||||
externalDispalylink = ws.windows.first?.screen.displayLink(withTarget: self, selector: #selector(displayUpdate(caDisplayLink:)))
|
||||
externalDispalylink?.add(to: RunLoop.main, forMode: RunLoop.Mode.common)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateTopCenterButtonWhenIsPlayingChange()
|
||||
|
||||
}
|
||||
|
||||
//当处理外部设备连接状态时,串流状态更新
|
||||
func updateTopCenterButtonWhenIsPlayingChange() {
|
||||
//串流播放中
|
||||
mTopCenterTypeButton.setImage(UIImage.init(named: "linked_button"), for: .normal)
|
||||
mTopCenterTypeButton.setTitleColor(UIColor(hexString: "#D0C0FF"), for: .normal)
|
||||
mTopCenterTypeButton.layer.borderColor = UIColor(hexString: "#D0C0FF").cgColor
|
||||
mTopCenterTypeButton.backgroundColor = UIColor(hexString: "#5326D6")
|
||||
mTopCenterTypeButton.updateBtnEdgeInsets(style: .Left, space: 5)
|
||||
|
||||
|
||||
//展示弹出列表尾部
|
||||
if isPlaying {
|
||||
//正在串流中 --- 按钮显示为【结束串流】
|
||||
menuView.showFooterView(isShow: true, showText: NSLocalizedString("结束串流", comment: ""))
|
||||
mTopCenterTypeButton.setTitle(NSLocalizedString("外部串流中", comment: ""), for: UIControl.State.normal)
|
||||
}else{
|
||||
//未串流 --- 按钮显示为【开始串流】
|
||||
menuView.showFooterView(isShow: true, showText: NSLocalizedString("开始串流", comment: ""))
|
||||
mTopCenterTypeButton.setTitle(NSLocalizedString("已连接外部设备", comment: ""), for: UIControl.State.normal)
|
||||
}
|
||||
}
|
||||
|
||||
//当外接屏幕断开时
|
||||
func dealTaskWhenExternalScreenDisConnect(){
|
||||
print("外接屏幕已断开.....")
|
||||
let playerItem = self.getPlayerItem()
|
||||
player?.replaceCurrentItem(with: playerItem)
|
||||
|
||||
link = false
|
||||
isPlaying = false
|
||||
// 当前未连接到 AirPlay 设备
|
||||
if self.selectedIndex == .monocular2D {
|
||||
mTopCenterTypeButton.setTitle(NSLocalizedString("单眼2D", comment: ""), for: UIControl.State.normal)
|
||||
}else if self.selectedIndex == .redBlueSolid {
|
||||
mTopCenterTypeButton.setTitle(NSLocalizedString("红蓝立体", comment: ""), for: UIControl.State.normal)
|
||||
}else if self.selectedIndex == .crossedEyes {
|
||||
mTopCenterTypeButton.setTitle(NSLocalizedString("交叉眼", comment: ""), for: UIControl.State.normal)
|
||||
}
|
||||
else if self.selectedIndex == .parallelEyes {
|
||||
mTopCenterTypeButton.setTitle(NSLocalizedString("平行眼", comment: ""), for: UIControl.State.normal)
|
||||
}
|
||||
|
||||
mTopCenterTypeButton.setImage(UIImage.init(named: "type_button_arrow_down"), for: .normal)
|
||||
mTopCenterTypeButton.setTitleColor(UIColor.white, for: UIControl.State.normal)
|
||||
mTopCenterTypeButton.layer.borderColor = UIColor.white.cgColor
|
||||
mTopCenterTypeButton.backgroundColor = UIColor(hexString: "#1F1E20")
|
||||
mTopCenterTypeButton.updateBtnEdgeInsets(style: .Right, space: 10)
|
||||
|
||||
//隐藏弹出列表尾部
|
||||
menuView.showFooterView(isShow: false, showText: "")
|
||||
externalVC?.playerLayer?.player = nil
|
||||
self.playerController?.player = player
|
||||
player?.play()
|
||||
externalVC = nil
|
||||
}
|
||||
|
||||
@objc func displayUpdate(caDisplayLink:CADisplayLink) {
|
||||
if let has_exvc = externalVC {
|
||||
if has_exvc.playerLayer?.player == nil {
|
||||
has_exvc.imageView?.isHidden = true
|
||||
has_exvc.playerLayer?.isHidden = false
|
||||
self.playerController?.player = nil
|
||||
has_exvc.playerLayer?.player = player
|
||||
player?.play()
|
||||
externalDispalylink?.invalidate()
|
||||
externalDispalylink = nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
deinit {
|
||||
print("patialvideodisplaycontroler deinit......")
|
||||
releaseVideoComposition()
|
||||
assetReader?.cancelReading()
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
// player?.removeObserver(self, forKeyPath: "status")
|
||||
}
|
||||
|
||||
func releaseVideoComposition() {
|
||||
if externalDispalylink != nil {
|
||||
externalDispalylink?.invalidate()
|
||||
externalDispalylink = nil
|
||||
}
|
||||
self.player?.currentItem?.videoComposition = nil
|
||||
self.player?.replaceCurrentItem(with: nil)
|
||||
}
|
||||
|
||||
|
||||
//MARK: - action
|
||||
@objc public func navgationButtonClick2(sender:UIButton){
|
||||
|
||||
if sender.tag == 200 {
|
||||
//左边按钮
|
||||
}else if sender.tag == 201 {
|
||||
//右边按钮
|
||||
let transVC = VRVideoTransformController()
|
||||
transVC.videoOriginalPHAsset = self.videoOriginalPHAsset
|
||||
transVC.sourceVideoURL = sourceVideoURL
|
||||
self.navigationController?.pushViewController(transVC, animated: true)
|
||||
Analytics.logEvent("preview_trans_click", parameters: nil)
|
||||
}else if sender.tag == 202 {
|
||||
//中间按钮
|
||||
|
||||
menuView.show()
|
||||
if link {
|
||||
//展示弹出列表尾部
|
||||
if isPlaying {
|
||||
//正在串流中 --- 按钮显示为【结束串流】
|
||||
menuView.showFooterView(isShow: true, showText: NSLocalizedString("结束串流", comment: ""))
|
||||
mTopCenterTypeButton.setTitle(NSLocalizedString("外部串流中", comment: ""), for: UIControl.State.normal)
|
||||
}else{
|
||||
//未串流 --- 按钮显示为【开始串流】
|
||||
menuView.showFooterView(isShow: true, showText: NSLocalizedString("开始串流", comment: ""))
|
||||
mTopCenterTypeButton.setTitle(NSLocalizedString("已连接外部设备", comment: ""), for: UIControl.State.normal)
|
||||
}
|
||||
}else{
|
||||
mTopCenterTypeButton.setImage(UIImage.init(named: "type_button_arrow_up"), for: .normal)
|
||||
}
|
||||
|
||||
|
||||
//顶部中间的按钮选中某个选项后的回调click
|
||||
menuView.didSelectMenuBlock = { [weak self](index:Int)->Void in
|
||||
print("block select \(index)")
|
||||
self?.selectedSpatialType(selectedIndex: index)
|
||||
|
||||
let title = self?.typeData[index].title
|
||||
self?.mTopCenterTypeButton.setTitle(title, for: UIControl.State.normal)
|
||||
}
|
||||
|
||||
//开始、结束串流的回调
|
||||
menuView.tapFooterActionBlock = {[weak self] in
|
||||
self?.startOrEndExternalVR()
|
||||
}
|
||||
|
||||
}else if sender.tag == 203 {
|
||||
//tips
|
||||
let view = CCDeviceOperationListView.init(frame: CGRectMake(0, 0, KScreenWidth, KScreenHeight))
|
||||
KWindow?.addSubview(view)
|
||||
}
|
||||
}
|
||||
|
||||
func startOrEndExternalVR() {
|
||||
if(link == true){
|
||||
if isPlaying {//结束串流
|
||||
isPlaying = false
|
||||
if self.externalVC != nil {
|
||||
externalVC?.playerLayer?.player = nil
|
||||
player?.pause()
|
||||
releaseVideoComposition()
|
||||
DispatchQueue.main.asyncAfter(deadline: .now()+0.15, execute: {[weak self] in
|
||||
let playerItem = self?.getPlayerItem()
|
||||
self?.player?.replaceCurrentItem(with: playerItem)
|
||||
self?.playerController?.player = self?.player
|
||||
self?.player?.play()
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
else {//开始串流
|
||||
if self.externalVC != nil {
|
||||
self.playerController?.player = nil
|
||||
player?.pause()
|
||||
releaseVideoComposition()
|
||||
let playerItem = self.getPlayerItem()
|
||||
player?.replaceCurrentItem(with: playerItem)
|
||||
externalVC?.playerLayer?.player = player
|
||||
player?.play()
|
||||
isPlaying = true
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
updateTopCenterButtonWhenIsPlayingChange()
|
||||
}
|
||||
|
||||
func selectedSpatialType(selectedIndex:Int){
|
||||
var si = selectedIndex
|
||||
if self.typeData.count == 2 {
|
||||
si = selectedIndex + 4
|
||||
}
|
||||
let rsi : SpatialType = SpatialType(rawValue: si) ?? .monocular2D
|
||||
self.selectedIndex = rsi
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -154,9 +154,9 @@ extension CCSpatialVideoDisplayController {
|
||||
assetReader!.startReading()
|
||||
//加载完毕之后再进行play
|
||||
// DispatchQueue.main.async {
|
||||
//
|
||||
//
|
||||
// self.player?.play()
|
||||
//
|
||||
//
|
||||
// print("资产加载完毕。。。。开始播放player\n err:\(self.player?.error)")
|
||||
// }
|
||||
}
|
||||
Binary file not shown.
Loading…
Reference in New Issue
Block a user