自定义播放器在拖动播放时还有些问题,后面再来优化

This commit is contained in:
bluesea 2024-04-18 15:00:13 +08:00
parent a73cb139a4
commit c228bc37ee
13 changed files with 1146 additions and 149 deletions

View File

@ -21,6 +21,7 @@
006B61DE2BBCFB45003FCB49 /* CustomSheetCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 006B61DD2BBCFB45003FCB49 /* CustomSheetCell.swift */; }; 006B61DE2BBCFB45003FCB49 /* CustomSheetCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 006B61DD2BBCFB45003FCB49 /* CustomSheetCell.swift */; };
0073BD142BCE80F700721885 /* ZZHCustomPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0073BD132BCE80F700721885 /* ZZHCustomPlayer.swift */; }; 0073BD142BCE80F700721885 /* ZZHCustomPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0073BD132BCE80F700721885 /* ZZHCustomPlayer.swift */; };
0073BD182BCF7B3400721885 /* ZZHCustomSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0073BD172BCF7B3400721885 /* ZZHCustomSlider.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 */; }; 009661F82BAD6C7100FCA65F /* CCSpaceAlbumFilterPopView2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 009661F72BAD6C7100FCA65F /* CCSpaceAlbumFilterPopView2.swift */; };
009661FA2BAD876200FCA65F /* PhotosUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 009661F92BAD876200FCA65F /* PhotosUI.framework */; }; 009661FA2BAD876200FCA65F /* PhotosUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 009661F92BAD876200FCA65F /* PhotosUI.framework */; };
009661FC2BADB20D00FCA65F /* CoreMotion.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 009661FB2BADB20D00FCA65F /* CoreMotion.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 */; }; 009662462BB3B39900FCA65F /* External.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 009662452BB3B39900FCA65F /* External.storyboard */; };
0096624A2BB3B45200FCA65F /* ExternalSceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 009662492BB3B45200FCA65F /* ExternalSceneDelegate.swift */; }; 0096624A2BB3B45200FCA65F /* ExternalSceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 009662492BB3B45200FCA65F /* ExternalSceneDelegate.swift */; };
0096624D2BB3BA3B00FCA65F /* ZZHExternalViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0096624C2BB3BA3B00FCA65F /* ZZHExternalViewController.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 */; }; 009DFB032BC63AF0007B56E8 /* CoreImage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 009DFB022BC63AF0007B56E8 /* CoreImage.framework */; };
009DFB0E2BC8CFA2007B56E8 /* FeedbackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 009DFB0D2BC8CFA2007B56E8 /* FeedbackView.swift */; }; 009DFB0E2BC8CFA2007B56E8 /* FeedbackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 009DFB0D2BC8CFA2007B56E8 /* FeedbackView.swift */; };
009DFB112BC8E2E9007B56E8 /* MenuVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 009DFB102BC8E2E9007B56E8 /* MenuVC.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>"; }; 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>"; }; 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>"; }; 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>"; }; 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; }; 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; }; 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>"; }; 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>"; }; 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>"; }; 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; }; 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>"; }; 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>"; }; 009DFB102BC8E2E9007B56E8 /* MenuVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuVC.swift; sourceTree = "<group>"; };
@ -285,6 +287,15 @@
path = CustomSheetController; path = CustomSheetController;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
0072361D2BD0EEFC000595A9 /* deapt */ = {
isa = PBXGroup;
children = (
0073BD1B2BCFCC4500721885 /* CCSpatialVideoDisplayController1.swift */,
0073BD1D2BCFCC6900721885 /* CCSpatialVideoDisplayForVideoTask1.swift */,
);
path = deapt;
sourceTree = "<group>";
};
0096624B2BB3BA0100FCA65F /* ExternalScreen */ = { 0096624B2BB3BA0100FCA65F /* ExternalScreen */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -298,9 +309,10 @@
009662582BB5527200FCA65F /* CCSpatialVideoDisplayController */ = { 009662582BB5527200FCA65F /* CCSpatialVideoDisplayController */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
0072361D2BD0EEFC000595A9 /* deapt */,
1E1EA2932B9364F000A5D5D2 /* CCSpatialVideoDisplayController.swift */, 1E1EA2932B9364F000A5D5D2 /* CCSpatialVideoDisplayController.swift */,
009662592BB552E700FCA65F /* CCSpatialVideoDisplayForVideoTask.swift */,
0073BD132BCE80F700721885 /* ZZHCustomPlayer.swift */, 0073BD132BCE80F700721885 /* ZZHCustomPlayer.swift */,
0073BD192BCFC8E800721885 /* ZZHCustomPlayerForVideoTask.swift */,
0073BD172BCF7B3400721885 /* ZZHCustomSlider.swift */, 0073BD172BCF7B3400721885 /* ZZHCustomSlider.swift */,
); );
path = CCSpatialVideoDisplayController; path = CCSpatialVideoDisplayController;
@ -784,6 +796,7 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
0073BD1A2BCFC8E800721885 /* ZZHCustomPlayerForVideoTask.swift in Sources */,
AF2120CC2B4E973800400B7F /* CCInputTextField.swift in Sources */, AF2120CC2B4E973800400B7F /* CCInputTextField.swift in Sources */,
AF2120C72B4E95DA00400B7F /* UIColor+Add.swift in Sources */, AF2120C72B4E95DA00400B7F /* UIColor+Add.swift in Sources */,
AF2120C52B4E95DA00400B7F /* UIButton+Add.swift in Sources */, AF2120C52B4E95DA00400B7F /* UIButton+Add.swift in Sources */,
@ -863,7 +876,6 @@
1E02C9322B8990C600DD3143 /* CCDeviceOperationListView.swift in Sources */, 1E02C9322B8990C600DD3143 /* CCDeviceOperationListView.swift in Sources */,
AF2120DA2B4E9BD400400B7F /* CCAlert.swift in Sources */, AF2120DA2B4E9BD400400B7F /* CCAlert.swift in Sources */,
006B61D12BBA5DB4003FCB49 /* MembershipProductView.swift in Sources */, 006B61D12BBA5DB4003FCB49 /* MembershipProductView.swift in Sources */,
0096625A2BB552E700FCA65F /* CCSpatialVideoDisplayForVideoTask.swift in Sources */,
1EFB8C702B88DA4800C72119 /* CCBottomMenuCell.swift in Sources */, 1EFB8C702B88DA4800C72119 /* CCBottomMenuCell.swift in Sources */,
AF2120FA2B4EA5BD00400B7F /* CCHomeController.swift in Sources */, AF2120FA2B4EA5BD00400B7F /* CCHomeController.swift in Sources */,
0073BD182BCF7B3400721885 /* ZZHCustomSlider.swift in Sources */, 0073BD182BCF7B3400721885 /* ZZHCustomSlider.swift in Sources */,

View File

@ -515,9 +515,9 @@
filePath = "SwiftProject/Project/Controller/RecordingVideo/CCSpatialVideoDisplayController/CCSpatialVideoDisplayController.swift" filePath = "SwiftProject/Project/Controller/RecordingVideo/CCSpatialVideoDisplayController/CCSpatialVideoDisplayController.swift"
startingColumnNumber = "9223372036854775807" startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807"
startingLineNumber = "388" startingLineNumber = "340"
endingLineNumber = "388" endingLineNumber = "340"
landmarkName = "viewDidAppear(_:)" landmarkName = "notification_didActiveNotification(notification:)"
landmarkType = "7"> landmarkType = "7">
</BreakpointContent> </BreakpointContent>
</BreakpointProxy> </BreakpointProxy>
@ -531,9 +531,9 @@
filePath = "SwiftProject/Project/Controller/RecordingVideo/CCSpatialVideoDisplayController/CCSpatialVideoDisplayController.swift" filePath = "SwiftProject/Project/Controller/RecordingVideo/CCSpatialVideoDisplayController/CCSpatialVideoDisplayController.swift"
startingColumnNumber = "9223372036854775807" startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807"
startingLineNumber = "552" startingLineNumber = "498"
endingLineNumber = "552" endingLineNumber = "498"
landmarkName = "displayUpdate(caDisplayLink:)" landmarkName = "updateTopCenterButtonWhenIsPlayingChange()"
landmarkType = "7"> landmarkType = "7">
<Locations> <Locations>
<Location <Location
@ -581,6 +581,21 @@
endingLineNumber = "552" endingLineNumber = "552"
offsetFromSymbolStart = "56"> offsetFromSymbolStart = "56">
</Location> </Location>
<Location
uuid = "BB183D45-3193-4FC7-92DB-275D529A4AE6 - 1f02ddc6d27b6aec"
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
symbolName = "SwiftProject.CCSpatialVideoDisplayController.updateTopCenterButtonWhenIsPlayingChange() -&gt; ()"
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> </Locations>
</BreakpointContent> </BreakpointContent>
</BreakpointProxy> </BreakpointProxy>

View File

@ -1,7 +1,7 @@
{ {
"images" : [ "images" : [
{ {
"filename" : "icon@1x.png", "filename" : "play.png",
"idiom" : "universal", "idiom" : "universal",
"scale" : "1x" "scale" : "1x"
}, },

Binary file not shown.

Before

Width:  |  Height:  |  Size: 741 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -54,9 +54,7 @@ class CCSpatialVideoDisplayController: BaseController {
(icon:"type_check",title:NSLocalizedString("交叉眼", comment: ""),isHiden:false)] (icon:"type_check",title:NSLocalizedString("交叉眼", comment: ""),isHiden:false)]
} }
//UI //UI
// DispatchQueue.main.asyncAfter(deadline: .now() + 5, execute: {
self.setttinisScreenMirroring(isScreenMirroring: self.isAirPlayActive) self.setttinisScreenMirroring(isScreenMirroring: self.isAirPlayActive)
// })
} }
@ -77,11 +75,6 @@ class CCSpatialVideoDisplayController: BaseController {
return label return label
}() }()
var assetReader:AVAssetReader?
var assetOutput:AVAssetReaderTrackOutput?
var assetTrack:AVAssetTrack?
let kNowTimeToUserDefaultKey_VideoDisplayController:String = "kNowTimeToUserDefaultKey_VideoDisplayController" let kNowTimeToUserDefaultKey_VideoDisplayController:String = "kNowTimeToUserDefaultKey_VideoDisplayController"
var link = false// var link = false//
@ -95,17 +88,18 @@ class CCSpatialVideoDisplayController: BaseController {
{ {
didSet{ didSet{
// //
customPlayer.selectedIndex = selectedIndex
} }
} }
let videoTranserConvertor = PlayByTransferConvertor() // let videoTranserConvertor = PlayByTransferConvertor()
lazy var videoOriginalAsset:AVAsset = { // lazy var videoOriginalAsset:AVAsset = {
let asset = AVAsset(url: sourceVideoURL!) // let asset = AVAsset(url: sourceVideoURL!)
return asset // return asset
}() // }()
var videoOriginalPHAsset:PHAsset? var videoOriginalPHAsset:PHAsset?
@ -113,13 +107,16 @@ class CCSpatialVideoDisplayController: BaseController {
var sourceVideoURL:URL? var sourceVideoURL:URL?
var imgData:Data? var imgData:Data?
var player:AVPlayer? // var player:AVPlayer?
// var needRestReaderTimeRange = false// // var needRestReaderTimeRange = false//
var playerController:AVPlayerViewController? // var playerController:AVPlayerViewController?
var customPlayer:ZZHCustomPlayer = {
let cp = ZZHCustomPlayer(frame: .zero)
return cp
}()
lazy var mTopImgView:UIImageView = { lazy var mTopImgView:UIImageView = {
//393*236 //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)) let view = UIImageView(frame: CGRect(x: 0, y: 0, width: SCREEN_Width, height: 236))
view.image = UIImage.init(named: "BG_Top") view.image = UIImage.init(named: "BG_Top")
@ -218,9 +215,6 @@ class CCSpatialVideoDisplayController: BaseController {
let img2:UIImage = UIImage.init(named: NSLocalizedString("displayvc_desc", comment: ""))! let img2:UIImage = UIImage.init(named: NSLocalizedString("displayvc_desc", comment: ""))!
button.setImage(img2, for: UIControl.State.normal) button.setImage(img2, for: UIControl.State.normal)
button.frame = CGRect(x: 0, y: 0, width: 173, height: 42) 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.centerY = progressView.top - 70
button.centerX = self.view.centerX button.centerX = self.view.centerX
@ -229,36 +223,13 @@ class CCSpatialVideoDisplayController: BaseController {
// //
@objc func notification_PlayerEndTime(notification:Notification){ // @objc func notification_PlayerEndTime(notification:Notification){
print("PlayerEndTime....") // print("PlayerEndTime....")
player?.seek(to: .zero) // player?.seek(to: .zero)
player?.play() // 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){ // @objc func notification_PlayerTimeJump(notification:Notification){
@ -273,38 +244,41 @@ class CCSpatialVideoDisplayController: BaseController {
super.viewDidLoad() super.viewDidLoad()
configureUI() configureUI()
ZZHHelper.setNowTimeToUserDefaultWithKey(kNowTimeToUserDefaultKey_VideoDisplayController) ZZHHelper.setNowTimeToUserDefaultWithKey(kNowTimeToUserDefaultKey_VideoDisplayController)
Task { // Task {
print("ccs viewdid load ---------") // print("ccs viewdid load ---------")
await self.loadVideoAssetReader() // await self.loadVideoAssetReader()
DispatchQueue.main.asyncAfter(deadline: .now()+0.01) {[weak self] in // DispatchQueue.main.asyncAfter(deadline: .now()+0.01) {[weak self] in
self?.setUPPlayer() // self?.setUPPlayer()
//
//
//
//
// }
// }
self.customPlayer.setUPPlayer()
// AirPlay // AirPlay
self?.checkAirPlayStatus() self.checkAirPlayStatus()
}
}
} }
func setUPPlayer(){ // func setUPPlayer(){
print("getPlayerItem ========") // print("getPlayerItem ========")
player = AVPlayer() // player = AVPlayer()
player?.allowsExternalPlayback = true // player?.allowsExternalPlayback = true
player?.usesExternalPlaybackWhileExternalScreenIsActive = true // player?.usesExternalPlaybackWhileExternalScreenIsActive = true
//
print("getPlayerItem >>>>>>>") // print("getPlayerItem >>>>>>>")
//
playerController = AVPlayerViewController() // playerController = AVPlayerViewController()
playerController?.player = player // playerController?.player = player
playerController!.view.backgroundColor = .clear // playerController!.view.backgroundColor = .clear
playerController?.view.frame = CGRect.init(x: 0, y: 170, width: self.view.frame.size.width, height: 400) // playerController?.view.frame = CGRect.init(x: 0, y: 170, width: self.view.frame.size.width, height: 400)
//
self.addChild(playerController!) // self.addChild(playerController!)
self.view.addSubview(playerController!.view) // self.view.addSubview(playerController!.view)
//
self.maskLabel.frame = playerController!.view.frame // self.maskLabel.frame = playerController!.view.frame
self.view.addSubview(self.maskLabel) // self.view.addSubview(self.maskLabel)
} // }
func configureUI(){ func configureUI(){
@ -322,7 +296,20 @@ class CCSpatialVideoDisplayController: BaseController {
navtionBar?.addSubview(mTopCenterTypeButton) navtionBar?.addSubview(mTopCenterTypeButton)
self.view.addSubview(tipsButton) 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(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.failedToPlayToEndTimeNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(notificatin_failedToPlayToEndTimeNotification(notifiation: )), name: AVPlayerItem.newErrorLogEntryNotification, 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) { @objc func notification_didEnterBackgroundNotification(notification:Notification) {
player?.pause() // player?.pause()
customPlayer.play(false)
print("ccs .....notification_didEnterBackgroundNotification") print("ccs .....notification_didEnterBackgroundNotification")
} }
@ -370,7 +358,8 @@ class CCSpatialVideoDisplayController: BaseController {
if externalVC != nil { if externalVC != nil {
externalVC?.playerLayer?.player = nil externalVC?.playerLayer?.player = nil
} }
player?.pause() // player?.pause()
customPlayer.play(false)
releaseVideoComposition() releaseVideoComposition()
let sec:TimeInterval = ZZHHelper.getSecFromUserDefaultByKey(kNowTimeToUserDefaultKey_VideoDisplayController) let sec:TimeInterval = ZZHHelper.getSecFromUserDefaultByKey(kNowTimeToUserDefaultKey_VideoDisplayController)
@ -385,18 +374,18 @@ class CCSpatialVideoDisplayController: BaseController {
override func viewDidAppear(_ animated: Bool) { override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated) super.viewDidAppear(animated)
if self.player?.currentItem == nil {//:1,didload,viewDidDisappear // if self.player?.currentItem == nil {//:1,didload,viewDidDisappear
let playerItem = self.getPlayerItem() // let playerItem = self.getPlayerItem()
self.player?.replaceCurrentItem(with: playerItem) // self.player?.replaceCurrentItem(with: playerItem)
} // }
//
if self.externalVC != nil {// // if self.externalVC != nil {//
if self.externalVC?.playerLayer?.player == nil { // if self.externalVC?.playerLayer?.player == nil {
self.activeSession() // self.activeSession()
self.externalVC?.playerLayer?.player = self.player // self.externalVC?.playerLayer?.player = self.player
} // }
} // }
self.player?.play() // self.player?.play()
} }
//MARK: - //MARK: -
@ -462,14 +451,11 @@ class CCSpatialVideoDisplayController: BaseController {
// //
func dealTaskWhenExternalScreenConnect(){ func dealTaskWhenExternalScreenConnect(){
// if link == true {
// return
// }
link = true link = true
isPlaying = true isPlaying = true
let playerItem = self.getPlayerItem() // let playerItem = self.getPlayerItem()
player?.replaceCurrentItem(with: playerItem) // player?.replaceCurrentItem(with: playerItem)
print("外接屏幕已连接.....") print("外接屏幕已连接.....")
activeSession() activeSession()
@ -517,8 +503,8 @@ class CCSpatialVideoDisplayController: BaseController {
// //
func dealTaskWhenExternalScreenDisConnect(){ func dealTaskWhenExternalScreenDisConnect(){
print("外接屏幕已断开.....") print("外接屏幕已断开.....")
let playerItem = self.getPlayerItem() // let playerItem = self.getPlayerItem()
player?.replaceCurrentItem(with: playerItem) // player?.replaceCurrentItem(with: playerItem)
link = false link = false
isPlaying = false isPlaying = false
@ -543,8 +529,8 @@ class CCSpatialVideoDisplayController: BaseController {
// //
menuView.showFooterView(isShow: false, showText: "") menuView.showFooterView(isShow: false, showText: "")
externalVC?.playerLayer?.player = nil externalVC?.playerLayer?.player = nil
self.playerController?.player = player // self.playerController?.player = player
player?.play() // player?.play()
externalVC = nil externalVC = nil
} }
@ -553,9 +539,9 @@ class CCSpatialVideoDisplayController: BaseController {
if has_exvc.playerLayer?.player == nil { if has_exvc.playerLayer?.player == nil {
has_exvc.imageView?.isHidden = true has_exvc.imageView?.isHidden = true
has_exvc.playerLayer?.isHidden = false has_exvc.playerLayer?.isHidden = false
self.playerController?.player = nil // self.playerController?.player = nil
has_exvc.playerLayer?.player = player // has_exvc.playerLayer?.player = player
player?.play() // player?.play()
externalDispalylink?.invalidate() externalDispalylink?.invalidate()
externalDispalylink = nil externalDispalylink = nil
} }
@ -567,7 +553,6 @@ class CCSpatialVideoDisplayController: BaseController {
deinit { deinit {
print("patialvideodisplaycontroler deinit......") print("patialvideodisplaycontroler deinit......")
releaseVideoComposition() releaseVideoComposition()
assetReader?.cancelReading()
NotificationCenter.default.removeObserver(self) NotificationCenter.default.removeObserver(self)
// player?.removeObserver(self, forKeyPath: "status") // player?.removeObserver(self, forKeyPath: "status")
} }
@ -577,8 +562,8 @@ class CCSpatialVideoDisplayController: BaseController {
externalDispalylink?.invalidate() externalDispalylink?.invalidate()
externalDispalylink = nil externalDispalylink = nil
} }
self.player?.currentItem?.videoComposition = nil // self.player?.currentItem?.videoComposition = nil
self.player?.replaceCurrentItem(with: nil) // self.player?.replaceCurrentItem(with: nil)
} }
@ -641,26 +626,28 @@ class CCSpatialVideoDisplayController: BaseController {
isPlaying = false isPlaying = false
if self.externalVC != nil { if self.externalVC != nil {
externalVC?.playerLayer?.player = nil externalVC?.playerLayer?.player = nil
player?.pause() // player?.pause()
customPlayer.play(false)
releaseVideoComposition() releaseVideoComposition()
DispatchQueue.main.asyncAfter(deadline: .now()+0.15, execute: {[weak self] in DispatchQueue.main.asyncAfter(deadline: .now()+0.15, execute: {[weak self] in
let playerItem = self?.getPlayerItem() // let playerItem = self?.getPlayerItem()
self?.player?.replaceCurrentItem(with: playerItem) // self?.player?.replaceCurrentItem(with: playerItem)
self?.playerController?.player = self?.player // self?.playerController?.player = self?.player
self?.player?.play() // self?.player?.play()
}) })
} }
} }
else {// else {//
if self.externalVC != nil { if self.externalVC != nil {
self.playerController?.player = nil // self.playerController?.player = nil
player?.pause() // player?.pause()
releaseVideoComposition() // releaseVideoComposition()
let playerItem = self.getPlayerItem() // let playerItem = self.getPlayerItem()
player?.replaceCurrentItem(with: playerItem) // player?.replaceCurrentItem(with: playerItem)
externalVC?.playerLayer?.player = player // externalVC?.playerLayer?.player = player
player?.play() // player?.play()
isPlaying = true isPlaying = true
} }
} }

View File

@ -9,12 +9,36 @@ import Foundation
import UIKit import UIKit
import AVKit import AVKit
class ZZHCustomPlayer: UIView { 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 playerLayerBgView:UIView?
var avPlayer:AVPlayer? var avPlayer:AVPlayer?
var avPlayerLayer:AVPlayerLayer? var avPlayerLayer:AVPlayerLayer?
var timeSlider:ZZHCustomSlider? var timeSlider:ZZHCustomSlider?
var prePlayingState:Bool?// ,player,便 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? = {// lazy var maskPlayerView:UIView? = {//
let bgView = UIView() let bgView = UIView()
@ -24,7 +48,7 @@ class ZZHCustomPlayer: UIView {
self.playStateImgView.snp.makeConstraints { make in self.playStateImgView.snp.makeConstraints { make in
make.centerX.centerY.equalToSuperview() make.centerX.centerY.equalToSuperview()
make.width.height.equalTo(40) make.width.height.equalTo(80)
} }
let btn = UIButton() let btn = UIButton()
@ -42,8 +66,25 @@ class ZZHCustomPlayer: UIView {
return imgView 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) { override init(frame: CGRect) {
super.init(frame: frame) super.init(frame: frame)
NotificationCenter.default.addObserver(self, selector: #selector(notification_PlayerEndTime(notification:)), name: AVPlayerItem.didPlayToEndTimeNotification, object: nil)
let playerWidth = KScreenWidth let playerWidth = KScreenWidth
let playerHeight = 200 let playerHeight = 200
playerLayerBgView = UIView() playerLayerBgView = UIView()
@ -54,10 +95,14 @@ class ZZHCustomPlayer: UIView {
make.height.equalTo(playerHeight) make.height.equalTo(playerHeight)
} }
avPlayer = AVPlayer() 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 = AVPlayerLayer(player: avPlayer)
avPlayerLayer?.frame = CGRect(x: 0, y: 0, width: Int(playerWidth), height: playerHeight) avPlayerLayer?.frame = CGRect(x: 0, y: 0, width: Int(playerWidth), height: playerHeight)
playerLayerBgView!.layer.addSublayer(avPlayerLayer!) playerLayerBgView!.layer.addSublayer(avPlayerLayer!)
playerLayerBgView?.backgroundColor = UIColor.orange playerLayerBgView?.backgroundColor = UIColor.clear
self.maskPlayerView?.frame = avPlayerLayer!.frame self.maskPlayerView?.frame = avPlayerLayer!.frame
playerLayerBgView?.addSubview(maskPlayerView!) playerLayerBgView?.addSubview(maskPlayerView!)
@ -65,8 +110,8 @@ class ZZHCustomPlayer: UIView {
timeSlider = ZZHCustomSlider(frame: .zero) timeSlider = ZZHCustomSlider(frame: .zero)
timeSlider?.processChangeValueCallback = { (value,isMoving) in timeSlider?.processChangeValueCallback = {[weak self] (value,isMoving) in
print("value:\(value) isMoving:\(isMoving)") self?.manualToSeekPlay(value:value,isMoving: isMoving)
} }
self.addSubview(timeSlider!) self.addSubview(timeSlider!)
timeSlider!.snp.makeConstraints { make in timeSlider!.snp.makeConstraints { make in
@ -75,8 +120,57 @@ class ZZHCustomPlayer: UIView {
make.bottom.equalToSuperview().offset(0) make.bottom.equalToSuperview().offset(0)
make.height.equalTo(120) make.height.equalTo(120)
} }
}
//sliderseek
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) updatePlayMaskView(value)
} }
// func seek(ct:CMTime) {
// self.avPlayer?.seek(to: ct)
// }
// //
func updatePlayMaskView(_ value:Bool) { func updatePlayMaskView(_ value:Bool) {
playStateImgView.isHidden = value playStateImgView.isHidden = value
self.maskPlayerView?.backgroundColor = value ? .clear : playerPauseBgColor 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) { override func draw(_ rect: CGRect) {
super.draw(rect) super.draw(rect)
@ -121,4 +227,25 @@ class ZZHCustomPlayer: UIView {
required init?(coder: NSCoder) { required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented") 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()
})
}
} }

View File

@ -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
}
//assetReaderoutput
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)
}
//,assetreadertimeRange
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
}
}

View File

@ -15,10 +15,12 @@ class ZZHCustomSlider: UIView {
var timeSlider:CustomSlider? var timeSlider:CustomSlider?
var processChangeValueCallback:CustomSliderProcessChangeValueCallback? var processChangeValueCallback:CustomSliderProcessChangeValueCallback?
var preValue:Float = 0.0 //value var preValue:Float = 0.0 //value
var totalSec:Int = -1//
let bgView:UIView = UIView() let bgView:UIView = UIView()
deinit {
print("zzhcustomslider....deinit...")
}
override init(frame: CGRect) { override init(frame: CGRect) {
super.init(frame: frame) super.init(frame: frame)
@ -83,12 +85,15 @@ class ZZHCustomSlider: UIView {
if isMoving { if isMoving {
var currentValue = max(0, min(value, 1)) var currentValue = max(0, min(value, 1))
//0.x //0.x
let formattedValue = String(format: "%.1f", currentValue) let formattedValue = String(format: "%.2f", currentValue)
currentValue = Float(formattedValue)! currentValue = Float(formattedValue)!
//2
if currentValue > preValue || currentValue < preValue { if currentValue > preValue || currentValue < preValue {
preValue = currentValue preValue = currentValue
processChangeValueCallback(preValue,isMoving) processChangeValueCallback(preValue,isMoving)
if self.totalSec > 0 {//
self.sLabel?.text = ZZHHelper.formatVideoTime(second: Int(preValue*Float(self.totalSec)))
}
} }
} }
else { else {
@ -98,9 +103,14 @@ class ZZHCustomSlider: UIView {
} }
// //
func exUpdateProcessValue(value:Float) { func exUpdateProcessValue(value:Float,currSec:Int,totalSec:Int) {
self.timeSlider!.value = value self.totalSec = totalSec
preValue = value 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
} }

View File

@ -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{
//selectedIndextypeData
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 (testarrow)
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
}
}