问题主要在线程处理的地方
This commit is contained in:
parent
c228bc37ee
commit
0270796016
@ -19,6 +19,8 @@
|
|||||||
006B61D32BBAA938003FCB49 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 006B61D22BBAA938003FCB49 /* StoreKit.framework */; };
|
006B61D32BBAA938003FCB49 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 006B61D22BBAA938003FCB49 /* StoreKit.framework */; };
|
||||||
006B61DC2BBCFAC4003FCB49 /* CustomSheetController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 006B61DB2BBCFAC4003FCB49 /* CustomSheetController.swift */; };
|
006B61DC2BBCFAC4003FCB49 /* CustomSheetController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 006B61DB2BBCFAC4003FCB49 /* CustomSheetController.swift */; };
|
||||||
006B61DE2BBCFB45003FCB49 /* CustomSheetCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 006B61DD2BBCFB45003FCB49 /* CustomSheetCell.swift */; };
|
006B61DE2BBCFB45003FCB49 /* CustomSheetCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 006B61DD2BBCFB45003FCB49 /* CustomSheetCell.swift */; };
|
||||||
|
0072361F2BD13B9D000595A9 /* ZZHCustomVideoCompositor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0072361E2BD13B9D000595A9 /* ZZHCustomVideoCompositor.swift */; };
|
||||||
|
007236212BD13C75000595A9 /* ZZHCustomVideoCompositionInstruction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 007236202BD13C75000595A9 /* ZZHCustomVideoCompositionInstruction.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 */; };
|
0073BD1A2BCFC8E800721885 /* ZZHCustomPlayerForVideoTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0073BD192BCFC8E800721885 /* ZZHCustomPlayerForVideoTask.swift */; };
|
||||||
@ -128,6 +130,8 @@
|
|||||||
006B61D22BBAA938003FCB49 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; };
|
006B61D22BBAA938003FCB49 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; };
|
||||||
006B61DB2BBCFAC4003FCB49 /* CustomSheetController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomSheetController.swift; sourceTree = "<group>"; };
|
006B61DB2BBCFAC4003FCB49 /* CustomSheetController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomSheetController.swift; sourceTree = "<group>"; };
|
||||||
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>"; };
|
||||||
|
0072361E2BD13B9D000595A9 /* ZZHCustomVideoCompositor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZZHCustomVideoCompositor.swift; sourceTree = "<group>"; };
|
||||||
|
007236202BD13C75000595A9 /* ZZHCustomVideoCompositionInstruction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZZHCustomVideoCompositionInstruction.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>"; };
|
0073BD192BCFC8E800721885 /* ZZHCustomPlayerForVideoTask.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZZHCustomPlayerForVideoTask.swift; sourceTree = "<group>"; };
|
||||||
@ -314,6 +318,8 @@
|
|||||||
0073BD132BCE80F700721885 /* ZZHCustomPlayer.swift */,
|
0073BD132BCE80F700721885 /* ZZHCustomPlayer.swift */,
|
||||||
0073BD192BCFC8E800721885 /* ZZHCustomPlayerForVideoTask.swift */,
|
0073BD192BCFC8E800721885 /* ZZHCustomPlayerForVideoTask.swift */,
|
||||||
0073BD172BCF7B3400721885 /* ZZHCustomSlider.swift */,
|
0073BD172BCF7B3400721885 /* ZZHCustomSlider.swift */,
|
||||||
|
0072361E2BD13B9D000595A9 /* ZZHCustomVideoCompositor.swift */,
|
||||||
|
007236202BD13C75000595A9 /* ZZHCustomVideoCompositionInstruction.swift */,
|
||||||
);
|
);
|
||||||
path = CCSpatialVideoDisplayController;
|
path = CCSpatialVideoDisplayController;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -816,6 +822,7 @@
|
|||||||
009DFB0E2BC8CFA2007B56E8 /* FeedbackView.swift in Sources */,
|
009DFB0E2BC8CFA2007B56E8 /* FeedbackView.swift in Sources */,
|
||||||
AF2120C42B4E95DA00400B7F /* UIImage+Add.swift in Sources */,
|
AF2120C42B4E95DA00400B7F /* UIImage+Add.swift in Sources */,
|
||||||
1EFAF0C02B8B7A59002A1773 /* VRPhotoTransformController.swift in Sources */,
|
1EFAF0C02B8B7A59002A1773 /* VRPhotoTransformController.swift in Sources */,
|
||||||
|
0072361F2BD13B9D000595A9 /* ZZHCustomVideoCompositor.swift in Sources */,
|
||||||
AF2120D82B4E9AC500400B7F /* CCAddImageView.swift in Sources */,
|
AF2120D82B4E9AC500400B7F /* CCAddImageView.swift in Sources */,
|
||||||
00D33BF42B998BF700604A44 /* SpatialImageConvertor.swift in Sources */,
|
00D33BF42B998BF700604A44 /* SpatialImageConvertor.swift in Sources */,
|
||||||
006B61CA2BBA4B0D003FCB49 /* MembershipVC.swift in Sources */,
|
006B61CA2BBA4B0D003FCB49 /* MembershipVC.swift in Sources */,
|
||||||
@ -852,6 +859,7 @@
|
|||||||
AF2120E62B4E9DE000400B7F /* CCTableSwitchView.swift in Sources */,
|
AF2120E62B4E9DE000400B7F /* CCTableSwitchView.swift in Sources */,
|
||||||
0096624D2BB3BA3B00FCA65F /* ZZHExternalViewController.swift in Sources */,
|
0096624D2BB3BA3B00FCA65F /* ZZHExternalViewController.swift in Sources */,
|
||||||
00D33BFA2B9AB21A00604A44 /* ZZHAVExtension.swift in Sources */,
|
00D33BFA2B9AB21A00604A44 /* ZZHAVExtension.swift in Sources */,
|
||||||
|
007236212BD13C75000595A9 /* ZZHCustomVideoCompositionInstruction.swift in Sources */,
|
||||||
009661F82BAD6C7100FCA65F /* CCSpaceAlbumFilterPopView2.swift in Sources */,
|
009661F82BAD6C7100FCA65F /* CCSpaceAlbumFilterPopView2.swift in Sources */,
|
||||||
009DFB132BC8EA90007B56E8 /* MenuVCCell.swift in Sources */,
|
009DFB132BC8EA90007B56E8 /* MenuVCCell.swift in Sources */,
|
||||||
AF2120E02B4E9C8000400B7F /* Timer+Add.swift in Sources */,
|
AF2120E02B4E9C8000400B7F /* Timer+Add.swift in Sources */,
|
||||||
|
|||||||
Binary file not shown.
@ -521,84 +521,6 @@
|
|||||||
landmarkType = "7">
|
landmarkType = "7">
|
||||||
</BreakpointContent>
|
</BreakpointContent>
|
||||||
</BreakpointProxy>
|
</BreakpointProxy>
|
||||||
<BreakpointProxy
|
|
||||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
|
||||||
<BreakpointContent
|
|
||||||
uuid = "BB183D45-3193-4FC7-92DB-275D529A4AE6"
|
|
||||||
shouldBeEnabled = "Yes"
|
|
||||||
ignoreCount = "0"
|
|
||||||
continueAfterRunningActions = "No"
|
|
||||||
filePath = "SwiftProject/Project/Controller/RecordingVideo/CCSpatialVideoDisplayController/CCSpatialVideoDisplayController.swift"
|
|
||||||
startingColumnNumber = "9223372036854775807"
|
|
||||||
endingColumnNumber = "9223372036854775807"
|
|
||||||
startingLineNumber = "498"
|
|
||||||
endingLineNumber = "498"
|
|
||||||
landmarkName = "updateTopCenterButtonWhenIsPlayingChange()"
|
|
||||||
landmarkType = "7">
|
|
||||||
<Locations>
|
|
||||||
<Location
|
|
||||||
uuid = "BB183D45-3193-4FC7-92DB-275D529A4AE6 - bc6a78627bfebfd5"
|
|
||||||
shouldBeEnabled = "Yes"
|
|
||||||
ignoreCount = "0"
|
|
||||||
continueAfterRunningActions = "No"
|
|
||||||
symbolName = "SwiftProject.CCSpatialVideoDisplayController.displayUpdate(caDisplayLink: __C.CADisplayLink) -> ()"
|
|
||||||
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 = "531"
|
|
||||||
endingLineNumber = "531"
|
|
||||||
offsetFromSymbolStart = "56">
|
|
||||||
</Location>
|
|
||||||
<Location
|
|
||||||
uuid = "BB183D45-3193-4FC7-92DB-275D529A4AE6 - bc6a78627bfebc61"
|
|
||||||
shouldBeEnabled = "Yes"
|
|
||||||
ignoreCount = "0"
|
|
||||||
continueAfterRunningActions = "No"
|
|
||||||
symbolName = "SwiftProject.CCSpatialVideoDisplayController.displayUpdate(caDisplayLink: __C.CADisplayLink) -> ()"
|
|
||||||
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 = "551"
|
|
||||||
endingLineNumber = "551"
|
|
||||||
offsetFromSymbolStart = "56">
|
|
||||||
</Location>
|
|
||||||
<Location
|
|
||||||
uuid = "BB183D45-3193-4FC7-92DB-275D529A4AE6 - bc6a78627bfebc00"
|
|
||||||
shouldBeEnabled = "Yes"
|
|
||||||
ignoreCount = "0"
|
|
||||||
continueAfterRunningActions = "No"
|
|
||||||
symbolName = "SwiftProject.CCSpatialVideoDisplayController.displayUpdate(caDisplayLink: __C.CADisplayLink) -> ()"
|
|
||||||
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 = "552"
|
|
||||||
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>
|
|
||||||
<BreakpointProxy
|
<BreakpointProxy
|
||||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||||
<BreakpointContent
|
<BreakpointContent
|
||||||
@ -663,5 +585,21 @@
|
|||||||
landmarkType = "7">
|
landmarkType = "7">
|
||||||
</BreakpointContent>
|
</BreakpointContent>
|
||||||
</BreakpointProxy>
|
</BreakpointProxy>
|
||||||
|
<BreakpointProxy
|
||||||
|
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||||
|
<BreakpointContent
|
||||||
|
uuid = "F69C7D02-67BE-4F9F-8AAB-A7CA1271B99E"
|
||||||
|
shouldBeEnabled = "No"
|
||||||
|
ignoreCount = "0"
|
||||||
|
continueAfterRunningActions = "No"
|
||||||
|
filePath = "SwiftProject/Project/Util/PlayByTransferConvertor.swift"
|
||||||
|
startingColumnNumber = "9223372036854775807"
|
||||||
|
endingColumnNumber = "9223372036854775807"
|
||||||
|
startingLineNumber = "20"
|
||||||
|
endingLineNumber = "20"
|
||||||
|
landmarkName = "convertVideo(asset:assetOutput:type:time:)"
|
||||||
|
landmarkType = "7">
|
||||||
|
</BreakpointContent>
|
||||||
|
</BreakpointProxy>
|
||||||
</Breakpoints>
|
</Breakpoints>
|
||||||
</Bucket>
|
</Bucket>
|
||||||
|
|||||||
@ -422,20 +422,17 @@ class CCSpatialVideoDisplayController: BaseController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//当isAirPlayActive值改变时会调用该方法
|
||||||
func setttinisScreenMirroring(isScreenMirroring:Bool){
|
func setttinisScreenMirroring(isScreenMirroring:Bool){
|
||||||
releaseVideoComposition()
|
releaseVideoComposition()
|
||||||
|
|
||||||
//已连接
|
//已连接
|
||||||
if(isScreenMirroring){
|
if(isScreenMirroring){
|
||||||
self.dealTaskWhenExternalScreenConnect()
|
self.dealTaskWhenExternalScreenConnect()
|
||||||
|
|
||||||
|
|
||||||
}else{
|
}else{
|
||||||
//未连接
|
//未连接
|
||||||
self.dealTaskWhenExternalScreenDisConnect()
|
self.dealTaskWhenExternalScreenDisConnect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//激活一下session
|
//激活一下session
|
||||||
@ -456,8 +453,9 @@ class CCSpatialVideoDisplayController: BaseController {
|
|||||||
isPlaying = true
|
isPlaying = true
|
||||||
// let playerItem = self.getPlayerItem()
|
// let playerItem = self.getPlayerItem()
|
||||||
// player?.replaceCurrentItem(with: playerItem)
|
// player?.replaceCurrentItem(with: playerItem)
|
||||||
|
|
||||||
print("外接屏幕已连接.....")
|
print("外接屏幕已连接.....")
|
||||||
activeSession()
|
// activeSession()
|
||||||
|
|
||||||
UIApplication.shared.connectedScenes.forEach { us in
|
UIApplication.shared.connectedScenes.forEach { us in
|
||||||
print("uisence:\(us)\n")
|
print("uisence:\(us)\n")
|
||||||
@ -528,10 +526,11 @@ class CCSpatialVideoDisplayController: BaseController {
|
|||||||
|
|
||||||
//隐藏弹出列表尾部
|
//隐藏弹出列表尾部
|
||||||
menuView.showFooterView(isShow: false, showText: "")
|
menuView.showFooterView(isShow: false, showText: "")
|
||||||
externalVC?.playerLayer?.player = nil
|
if let externalVC {
|
||||||
// self.playerController?.player = player
|
customPlayer.recoveryPlayerLayer(otherLayer: (externalVC.playerLayer)!)
|
||||||
// player?.play()
|
self.externalVC = nil
|
||||||
externalVC = nil
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func displayUpdate(caDisplayLink:CADisplayLink) {
|
@objc func displayUpdate(caDisplayLink:CADisplayLink) {
|
||||||
@ -539,9 +538,7 @@ 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
|
customPlayer.moveToOtherPlayerLayer(destLayer: has_exvc.playerLayer!)
|
||||||
// has_exvc.playerLayer?.player = player
|
|
||||||
// player?.play()
|
|
||||||
externalDispalylink?.invalidate()
|
externalDispalylink?.invalidate()
|
||||||
externalDispalylink = nil
|
externalDispalylink = nil
|
||||||
}
|
}
|
||||||
@ -554,7 +551,6 @@ class CCSpatialVideoDisplayController: BaseController {
|
|||||||
print("patialvideodisplaycontroler deinit......")
|
print("patialvideodisplaycontroler deinit......")
|
||||||
releaseVideoComposition()
|
releaseVideoComposition()
|
||||||
NotificationCenter.default.removeObserver(self)
|
NotificationCenter.default.removeObserver(self)
|
||||||
// player?.removeObserver(self, forKeyPath: "status")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func releaseVideoComposition() {
|
func releaseVideoComposition() {
|
||||||
@ -562,8 +558,6 @@ class CCSpatialVideoDisplayController: BaseController {
|
|||||||
externalDispalylink?.invalidate()
|
externalDispalylink?.invalidate()
|
||||||
externalDispalylink = nil
|
externalDispalylink = nil
|
||||||
}
|
}
|
||||||
// self.player?.currentItem?.videoComposition = nil
|
|
||||||
// self.player?.replaceCurrentItem(with: nil)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -8,7 +8,14 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import UIKit
|
import UIKit
|
||||||
import AVKit
|
import AVKit
|
||||||
|
|
||||||
|
//专门用于assetoutput资源释放的 线程控制
|
||||||
|
//let AssetGlobalQueue = DispatchQueue.global(qos: DispatchQoS.QoSClass.default)
|
||||||
|
let CustomPlayerShareSemaphore = DispatchSemaphore(value: 1)
|
||||||
|
|
||||||
class ZZHCustomPlayer: UIView {
|
class ZZHCustomPlayer: UIView {
|
||||||
|
|
||||||
|
|
||||||
//视频资源
|
//视频资源
|
||||||
var sourceVideoURL:URL?
|
var sourceVideoURL:URL?
|
||||||
var assetTrack:AVAssetTrack?
|
var assetTrack:AVAssetTrack?
|
||||||
@ -18,13 +25,19 @@ class ZZHCustomPlayer: UIView {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
var assetReader:AVAssetReader?
|
var assetReader:AVAssetReader?
|
||||||
var assetOutput:AVAssetReaderTrackOutput?
|
var assetOutput:AVAssetReaderTrackOutput? {
|
||||||
|
didSet {
|
||||||
|
custominstruction?.assetOutput = assetOutput
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var custominstruction:ZZHCustomVideoCompositionInstruction?
|
||||||
|
|
||||||
let videoTranserConvertor = PlayByTransferConvertor()
|
let videoTranserConvertor = PlayByTransferConvertor()
|
||||||
var selectedIndex:SpatialType = .parallelEyes//记录当前选择的菜单选项
|
var selectedIndex:SpatialType = .parallelEyes//记录当前选择的菜单选项
|
||||||
{
|
{
|
||||||
didSet{
|
didSet{
|
||||||
//进行相应解码操作,边解边播
|
//进行相应解码操作,边解边播
|
||||||
|
custominstruction?.selectedIndex = selectedIndex
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,7 +47,7 @@ class ZZHCustomPlayer: 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 = true //标记 在滑块拖动前,player的播放状态,以便在拖动完毕之后回复播放状态
|
||||||
let playerPauseBgColor:UIColor = UIColor(r: 20, g: 20, b: 20, a: 0.2)//暂停时的背景颜色
|
let playerPauseBgColor:UIColor = UIColor(r: 20, g: 20, b: 20, a: 0.2)//暂停时的背景颜色
|
||||||
|
|
||||||
//线程锁
|
//线程锁
|
||||||
@ -126,8 +139,10 @@ class ZZHCustomPlayer: UIView {
|
|||||||
func manualToSeekPlay(value:Float,isMoving:Bool){
|
func manualToSeekPlay(value:Float,isMoving:Bool){
|
||||||
if isMoving {
|
if isMoving {
|
||||||
self.play(false)
|
self.play(false)
|
||||||
|
print("此处已暂停播放,那么后面希望不要出现 sta.....> 的打印信息")
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
|
Task {
|
||||||
let totalSec = CMTimeGetSeconds((self.avPlayer?.currentItem?.duration)!)
|
let totalSec = CMTimeGetSeconds((self.avPlayer?.currentItem?.duration)!)
|
||||||
var atSec = Float(totalSec) * value
|
var atSec = Float(totalSec) * value
|
||||||
var timeScale:CMTimeScale? = self.avPlayer?.currentItem?.duration.timescale
|
var timeScale:CMTimeScale? = self.avPlayer?.currentItem?.duration.timescale
|
||||||
@ -138,24 +153,48 @@ class ZZHCustomPlayer: UIView {
|
|||||||
timeScale = CMTimeScale(1)
|
timeScale = CMTimeScale(1)
|
||||||
}
|
}
|
||||||
let ct = CMTime(value:CMTimeValue(atSec) , timescale: timeScale!)
|
let ct = CMTime(value:CMTimeValue(atSec) , timescale: timeScale!)
|
||||||
quickLoadAReaderWhenSeek(startCT: ct)
|
// CustomPlayerShareSemaphore.wait()
|
||||||
|
// self.quickLoadAReaderWhenSeek(startCT: ct)
|
||||||
// self.releaseVideoComposition()
|
// CustomPlayerShareSemaphore.signal()
|
||||||
// self.avPlayer?.replaceCurrentItem(with: self.getPlayerItem())
|
print("正在seek.....\(ct) ismainthread:\(Thread.isMainThread)")
|
||||||
|
DispatchQueue.main.async {
|
||||||
print("正在seek.....\(ct)")
|
self.avPlayer?.seek(to: ct,toleranceBefore:.zero,toleranceAfter: .zero, completionHandler: { finished in
|
||||||
self.avPlayer?.seek(to: ct,toleranceBefore:.zero,toleranceAfter: .zero, completionHandler: {[weak self] finished in
|
|
||||||
if finished {
|
if finished {
|
||||||
self?.quickLoadAReaderWhenSeek(startCT: ct)
|
if(!isMoving) {//结束拖动时,再进行播放
|
||||||
self?.play(true)
|
CustomPlayerShareSemaphore.wait()
|
||||||
|
self.quickLoadAReaderWhenSeek(startCT: ct)
|
||||||
|
CustomPlayerShareSemaphore.signal()
|
||||||
|
self.play(true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
print("seek result:\(finished)")
|
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//检查视频的当前播放时间是否落后于readeroutput的copynextSampleBuffer的对应time,如果是,则seek到copynextSampleBuffer下一个时间点
|
||||||
|
func checkFBTime(ct_Buffer:CMTime?) {
|
||||||
|
return //该方法目前有问题,行不通,会闪屏,并且会卡顿
|
||||||
|
// guard let ct_Buffer,let playerCurrCT = self.avPlayer?.currentTime() else {
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// print("checkFBTime......call CMTimeGetSeconds:\(CMTimeGetSeconds(playerCurrCT))")
|
||||||
|
// if ct_Buffer > playerCurrCT{
|
||||||
|
// print("in checkFBTime......call\nct_Buffer: \(ct_Buffer),\nplayerCurrCT: \(playerCurrCT)")
|
||||||
|
// let nct = CMTime(value: ct_Buffer.value+20, timescale: ct_Buffer.timescale)
|
||||||
|
// self.avPlayer?.seek(to: nct,toleranceBefore:.zero,toleranceAfter: .zero, completionHandler: {finished in
|
||||||
|
// print("checkFBTime seek result:\(finished)")
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//初始化播放器信息
|
//初始化播放器信息
|
||||||
func setUPPlayer() {
|
func setUPPlayer() {
|
||||||
Task {[weak self] in
|
Task {[weak self] in
|
||||||
@ -166,24 +205,52 @@ class ZZHCustomPlayer: UIView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//重新状态播放
|
//重新播放 状态
|
||||||
private func reLoadPlay(){
|
private func reLoadPlay(){
|
||||||
self.releaseVideoComposition()
|
self.quickLoadAReaderWhenReplayBack()
|
||||||
self.avPlayer?.replaceCurrentItem(with: self.getPlayerItem())
|
|
||||||
self.play(true)
|
self.play(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//改变avplayer所在的avplayerLayer视图曾层:用户外接屏幕发声改变时
|
||||||
|
func moveToOtherPlayerLayer(destLayer:AVPlayerLayer) {
|
||||||
|
print("moveToOtherPlayerLayer 准备暂停播放")
|
||||||
|
self.play(false)
|
||||||
|
print("avPlayerLayer 准备移除player")
|
||||||
|
self.avPlayerLayer?.player = nil
|
||||||
|
print("avPlayerLayer 已经移除player")
|
||||||
|
destLayer.player = self.avPlayer
|
||||||
|
if assetTrack != nil {
|
||||||
|
quickLoadAReaderWhenSeek(startCT: (self.avPlayer?.currentTime())!)
|
||||||
|
}
|
||||||
|
|
||||||
|
print("外屏destLayer 已添加player")
|
||||||
|
self.play(true)
|
||||||
|
print("moveToOtherPlayerLayer 恢复播放play")
|
||||||
|
}
|
||||||
|
|
||||||
|
//当外接屏幕断开时,恢复到原来的layer层上
|
||||||
|
func recoveryPlayerLayer(otherLayer:AVPlayerLayer) {
|
||||||
|
print("recoveryPlayerLayer 准备暂停播放")
|
||||||
|
self.play(false)
|
||||||
|
print("otherLayer 准备移除player")
|
||||||
|
otherLayer.player = nil
|
||||||
|
print("otherLayer 已经移除player")
|
||||||
|
avPlayerLayer?.player = self.avPlayer
|
||||||
|
quickLoadAReaderWhenSeek(startCT: (self.avPlayer?.currentTime())!)
|
||||||
|
print("手机屏幕avPlayerLayer 已添加player")
|
||||||
|
self.play(true)
|
||||||
|
print("recoveryPlayerLayer 恢复播放play")
|
||||||
|
}
|
||||||
//暂停或者播放
|
//暂停或者播放
|
||||||
@objc func playOrPause(sender:UIButton) {
|
@objc func playOrPause(sender:UIButton) {
|
||||||
if sender.tag == 0 {//播放
|
if prePlayingState == false {//播放
|
||||||
play(true)
|
play(true)
|
||||||
sender.tag = 1
|
|
||||||
print("bofang...")
|
print("bofang...")
|
||||||
}
|
}
|
||||||
else {//暂停
|
else {//暂停
|
||||||
print("暂停...")
|
print("暂停...")
|
||||||
play(false)
|
play(false)
|
||||||
sender.tag = 0
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,9 +268,7 @@ class ZZHCustomPlayer: UIView {
|
|||||||
updatePlayMaskView(value)
|
updatePlayMaskView(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// func seek(ct:CMTime) {
|
|
||||||
// self.avPlayer?.seek(to: ct)
|
|
||||||
// }
|
|
||||||
|
|
||||||
//根据状态更新播放器遮罩视图显示与隐藏
|
//根据状态更新播放器遮罩视图显示与隐藏
|
||||||
func updatePlayMaskView(_ value:Bool) {
|
func updatePlayMaskView(_ value:Bool) {
|
||||||
@ -215,6 +280,9 @@ class ZZHCustomPlayer: UIView {
|
|||||||
func updateSliderUI(ct:CMTime) {
|
func updateSliderUI(ct:CMTime) {
|
||||||
let sec = CMTimeGetSeconds(ct)
|
let sec = CMTimeGetSeconds(ct)
|
||||||
let totalSec = CMTimeGetSeconds((self.avPlayer?.currentItem?.duration)!)
|
let totalSec = CMTimeGetSeconds((self.avPlayer?.currentItem?.duration)!)
|
||||||
|
if totalSec.isNaN {
|
||||||
|
return
|
||||||
|
}
|
||||||
let s = sec / totalSec
|
let s = sec / totalSec
|
||||||
self.timeSlider?.exUpdateProcessValue(value: Float(s),currSec: Int(sec),totalSec: Int(totalSec))
|
self.timeSlider?.exUpdateProcessValue(value: Float(s),currSec: Int(sec),totalSec: Int(totalSec))
|
||||||
}
|
}
|
||||||
@ -230,22 +298,13 @@ class ZZHCustomPlayer: UIView {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//MARK: - 视频资源加载
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//MARK: - 播放器控制
|
//MARK: - 播放器控制
|
||||||
|
|
||||||
//监听播放完毕
|
//监听播放完毕
|
||||||
@objc func notification_PlayerEndTime(notification:Notification){
|
@objc func notification_PlayerEndTime(notification:Notification){
|
||||||
print("PlayerEndTime....")
|
print("PlayerEndTime....")
|
||||||
// self.quickLoadAReaderWhenReplayBack()
|
|
||||||
avPlayer?.seek(to: .zero,toleranceBefore: .zero,toleranceAfter: .zero,completionHandler: {[weak self] finish in
|
avPlayer?.seek(to: .zero,toleranceBefore: .zero,toleranceAfter: .zero,completionHandler: {[weak self] finish in
|
||||||
self?.quickLoadAReaderWhenReplayBack()
|
self?.reLoadPlay()
|
||||||
self?.avPlayer?.play()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,29 +12,44 @@ import AVKit
|
|||||||
import VideoToolbox
|
import VideoToolbox
|
||||||
|
|
||||||
extension ZZHCustomPlayer {
|
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
|
||||||
|
// }
|
||||||
|
// weakSelf.convertFrame(request:request)
|
||||||
|
//
|
||||||
|
// } completionHandler: { ac, err in
|
||||||
|
// if err != nil {
|
||||||
|
// print("初始化coposition报错:\(err)")
|
||||||
|
// }
|
||||||
|
// else{
|
||||||
|
// print("composition 生成ok....")
|
||||||
|
// temItem.videoComposition = ac
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return temItem
|
||||||
|
// }
|
||||||
|
|
||||||
func getPlayerItem() -> AVPlayerItem {
|
func getPlayerItem() -> AVPlayerItem {
|
||||||
let temItem = AVPlayerItem(asset: self.videoOriginalAsset)
|
let temItem = AVPlayerItem(asset: self.videoOriginalAsset)
|
||||||
AVVideoComposition.videoComposition(with: temItem.asset) { [weak self] request in
|
let timeRange = CMTimeRange(start: CMTime.zero, duration: temItem.asset.duration)
|
||||||
|
let videoTracks = temItem.asset.tracks(withMediaType: AVMediaType.video)
|
||||||
print("正在请求解码图片frame....")
|
guard let sourceVideoTrack = videoTracks.first else {
|
||||||
guard let weakSelf = self else {
|
return temItem
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let videoComposition = AVMutableVideoComposition(propertiesOf: temItem.asset)
|
||||||
|
videoComposition.customVideoCompositorClass = ZZHCustomVideoCompositor.self
|
||||||
|
let instruction = ZZHCustomVideoCompositionInstruction(track: sourceVideoTrack, timeRange: timeRange, transform: sourceVideoTrack.preferredTransform, targetSize: sourceVideoTrack.naturalSize,sourceVideoURL: self.sourceVideoURL!)
|
||||||
|
custominstruction = instruction
|
||||||
|
videoComposition.instructions = [instruction]
|
||||||
|
temItem.videoComposition = videoComposition
|
||||||
return temItem
|
return temItem
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,32 +85,35 @@ extension ZZHCustomPlayer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var ciImg:CIImage? = nil
|
var ciImg:CIImage? = nil
|
||||||
|
var presentTime:CMTime? = nil
|
||||||
switch mode {
|
switch mode {
|
||||||
case .crossedEyes://交叉眼
|
case .crossedEyes://交叉眼
|
||||||
ciImg = self.videoTranserConvertor.convertVideo(asset: self.videoOriginalAsset, assetOutput: ao, type: self.selectedIndex, time: compositionTime)
|
(ciImg,presentTime) = self.videoTranserConvertor.convertVideo(asset: self.videoOriginalAsset, assetOutput: ao, type: self.selectedIndex, time: compositionTime)
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
case .fsbs://3d全宽
|
case .fsbs://3d全宽
|
||||||
ciImg = self.videoTranserConvertor.convertVideo(asset: self.videoOriginalAsset, assetOutput: ao, type: self.selectedIndex, time: compositionTime)
|
(ciImg,presentTime) = self.videoTranserConvertor.convertVideo(asset: self.videoOriginalAsset, assetOutput: ao, type: self.selectedIndex, time: compositionTime)
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
case .hsbs://3d半宽
|
case .hsbs://3d半宽
|
||||||
ciImg = self.videoTranserConvertor.convertVideo(asset: self.videoOriginalAsset, assetOutput: ao, type: self.selectedIndex, time: compositionTime)
|
(ciImg,presentTime) = self.videoTranserConvertor.convertVideo(asset: self.videoOriginalAsset, assetOutput: ao, type: self.selectedIndex, time: compositionTime)
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
case .parallelEyes://平行眼
|
case .parallelEyes://平行眼
|
||||||
ciImg = self.videoTranserConvertor.convertVideo(asset: self.videoOriginalAsset, assetOutput: ao, type: self.selectedIndex, time: compositionTime)
|
(ciImg,presentTime) = self.videoTranserConvertor.convertVideo(asset: self.videoOriginalAsset, assetOutput: ao, type: self.selectedIndex, time: compositionTime)
|
||||||
break
|
break
|
||||||
|
|
||||||
case .redBlueSolid://红蓝立体
|
case .redBlueSolid://红蓝立体
|
||||||
ciImg = self.videoTranserConvertor.convertVideo(asset: self.videoOriginalAsset, assetOutput: ao, type: self.selectedIndex, time: compositionTime)
|
(ciImg,presentTime) = self.videoTranserConvertor.convertVideo(asset: self.videoOriginalAsset, assetOutput: ao, type: self.selectedIndex, time: compositionTime)
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
//检查当前buffer的时间,如果符合反补条件,则进行反补
|
||||||
|
// checkFBTime(ct_Buffer: presentTime)
|
||||||
return ciImg
|
return ciImg
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -118,16 +136,20 @@ extension ZZHCustomPlayer {
|
|||||||
|
|
||||||
|
|
||||||
func quickLoadAReader(timeRange:CMTimeRange) {
|
func quickLoadAReader(timeRange:CMTimeRange) {
|
||||||
// self.lock.lock()
|
|
||||||
if(assetReader != nil){
|
if(assetReader != nil){
|
||||||
assetReader?.cancelReading()
|
assetReader?.cancelReading()
|
||||||
}
|
}
|
||||||
assetReader = try! AVAssetReader(asset: self.videoOriginalAsset)
|
do {
|
||||||
|
assetReader = try AVAssetReader(asset: self.videoOriginalAsset)
|
||||||
quickLoadAssetOutput()
|
quickLoadAssetOutput()
|
||||||
assetReader!.timeRange = timeRange
|
assetReader!.timeRange = timeRange
|
||||||
assetReader!.add(assetOutput!)
|
assetReader!.add(assetOutput!)
|
||||||
assetReader!.startReading()
|
assetReader!.startReading()
|
||||||
// self.lock.unlock()
|
}
|
||||||
|
catch {
|
||||||
|
print("quickLoadAReader err:\(error)")
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//在播放器的slider 拖动播放时调用
|
//在播放器的slider 拖动播放时调用
|
||||||
@ -136,6 +158,8 @@ extension ZZHCustomPlayer {
|
|||||||
self.quickLoadAReader(timeRange: timeRange)
|
self.quickLoadAReader(timeRange: timeRange)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//用于循环播放时调用,重置assetreader的timeRange
|
//用于循环播放时调用,重置assetreader的timeRange
|
||||||
func quickLoadAReaderWhenReplayBack() {
|
func quickLoadAReaderWhenReplayBack() {
|
||||||
let timeRange = CMTimeRange(start: .zero, duration: .positiveInfinity)
|
let timeRange = CMTimeRange(start: .zero, duration: .positiveInfinity)
|
||||||
@ -144,8 +168,11 @@ extension ZZHCustomPlayer {
|
|||||||
|
|
||||||
func quickLoadAssetOutput() {
|
func quickLoadAssetOutput() {
|
||||||
if(assetOutput != nil){
|
if(assetOutput != nil){
|
||||||
|
print("正在释放assetoutput----assetOutput:\(assetOutput) \n\(Date.now.timeIntervalSince1970)")
|
||||||
assetOutput?.markConfigurationAsFinal()
|
assetOutput?.markConfigurationAsFinal()
|
||||||
|
print("正在释放assetoutput....assetOutput:\(assetOutput) \n\(Date.now.timeIntervalSince1970)")
|
||||||
assetOutput = nil
|
assetOutput = nil
|
||||||
|
print("释放完毕assetoutput....thread:\(Thread.current) \n\(Date.now.timeIntervalSince1970)")
|
||||||
}
|
}
|
||||||
|
|
||||||
assetOutput = AVAssetReaderTrackOutput(
|
assetOutput = AVAssetReaderTrackOutput(
|
||||||
|
|||||||
@ -0,0 +1,44 @@
|
|||||||
|
//
|
||||||
|
// ZZHCustomVideoCompositionInstruction.swift
|
||||||
|
// SwiftProject
|
||||||
|
//
|
||||||
|
// Created by aaa on 2024/4/18.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import AVFoundation
|
||||||
|
|
||||||
|
final class ZZHCustomVideoCompositionInstruction: NSObject, AVVideoCompositionInstructionProtocol {
|
||||||
|
// Fixed
|
||||||
|
let enablePostProcessing: Bool = true
|
||||||
|
let containsTweening: Bool = false
|
||||||
|
let passthroughTrackID: CMPersistentTrackID = kCMPersistentTrackID_Invalid
|
||||||
|
|
||||||
|
// Variable
|
||||||
|
let timeRange: CMTimeRange
|
||||||
|
let requiredSourceTrackIDs: [NSValue]?
|
||||||
|
let videoTrackID: CMPersistentTrackID
|
||||||
|
let targetSize: CGSize
|
||||||
|
let transform: CGAffineTransform
|
||||||
|
|
||||||
|
|
||||||
|
//后面自己添加的
|
||||||
|
var selectedIndex:SpatialType = .parallelEyes//记录当前选择的菜单选项
|
||||||
|
lazy var videoOriginalAsset:AVAsset = {
|
||||||
|
let asset = AVAsset(url: sourceVideoURL!)
|
||||||
|
return asset
|
||||||
|
}()
|
||||||
|
var sourceVideoURL:URL?
|
||||||
|
var assetOutput:AVAssetReaderTrackOutput?
|
||||||
|
|
||||||
|
|
||||||
|
init(track: AVAssetTrack, timeRange: CMTimeRange, transform: CGAffineTransform, targetSize: CGSize,sourceVideoURL:URL) {
|
||||||
|
self.requiredSourceTrackIDs = [NSNumber(value: track.trackID)]
|
||||||
|
self.timeRange = timeRange
|
||||||
|
self.videoTrackID = track.trackID
|
||||||
|
self.transform = transform
|
||||||
|
self.targetSize = targetSize
|
||||||
|
self.sourceVideoURL = sourceVideoURL
|
||||||
|
super.init()
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,169 @@
|
|||||||
|
//
|
||||||
|
// ZZHCustomVideoCompositor.swift
|
||||||
|
// SwiftProject
|
||||||
|
//
|
||||||
|
// Created by aaa on 2024/4/18.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import Dispatch
|
||||||
|
import AVFoundation
|
||||||
|
import CoreImage
|
||||||
|
import CoreVideo
|
||||||
|
|
||||||
|
enum ZZHCustomVideoCompositoringError: Error {
|
||||||
|
case invalidRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
final class ZZHCustomVideoCompositor: NSObject, AVVideoCompositing {
|
||||||
|
//自定义需要用的属性
|
||||||
|
private let videoTranserConvertor = PlayByTransferConvertor()
|
||||||
|
// 使用数组跟踪正在处理的请求
|
||||||
|
var activeRequests: [AVAsynchronousVideoCompositionRequest] = []
|
||||||
|
|
||||||
|
//类初始化时的重要配置
|
||||||
|
private let queue = DispatchQueue(label: "ca.gurulogic.layer-video-compositor.render", qos: .default)
|
||||||
|
private var renderContext: AVVideoCompositionRenderContext = AVVideoCompositionRenderContext()
|
||||||
|
private var cancelled: Bool = false
|
||||||
|
private static let pixelFormat = kCVPixelFormatType_32ARGB
|
||||||
|
private let colorSpace = CGColorSpaceCreateDeviceRGB()
|
||||||
|
private let ciContext: CIContext = {
|
||||||
|
if let eaglContext = EAGLContext(api: .openGLES3) ?? EAGLContext(api: .openGLES2) {
|
||||||
|
return CIContext(eaglContext: eaglContext)
|
||||||
|
}
|
||||||
|
return CIContext()
|
||||||
|
}()
|
||||||
|
|
||||||
|
let sourcePixelBufferAttributes: [String : Any]? = [
|
||||||
|
kCVPixelBufferPixelFormatTypeKey as String : NSNumber(value: ZZHCustomVideoCompositor.pixelFormat),
|
||||||
|
kCVPixelBufferOpenGLESCompatibilityKey as String : NSNumber(value: true),
|
||||||
|
]
|
||||||
|
|
||||||
|
let requiredPixelBufferAttributesForRenderContext: [String : Any] = [
|
||||||
|
kCVPixelBufferPixelFormatTypeKey as String : NSNumber(value: ZZHCustomVideoCompositor.pixelFormat),
|
||||||
|
kCVPixelBufferOpenGLESCompatibilityKey as String : NSNumber(value: true),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
func renderContextChanged(_ newRenderContext: AVVideoCompositionRenderContext) {
|
||||||
|
renderContext = newRenderContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func startRequest(_ request: AVAsynchronousVideoCompositionRequest) {
|
||||||
|
queue.async{
|
||||||
|
// 将请求添加到正在处理的请求列表中
|
||||||
|
self.activeRequests.append(request)
|
||||||
|
|
||||||
|
print("startRequest ....AVAsynchronousVideoCompositionRequest: \(self.cancelled) request:\(request)")
|
||||||
|
guard !self.cancelled else {
|
||||||
|
print("startRequest cancell....")
|
||||||
|
request.finishCancelledRequest()
|
||||||
|
self.activeRequests.removeAll { $0 === request }
|
||||||
|
// self.cancelled = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
print("startRequest queue:\(self.queue) current:\(Thread.current)")
|
||||||
|
CustomPlayerShareSemaphore.wait()
|
||||||
|
guard let renderedBuffer = self.renderFrame(forRequest: request) else {
|
||||||
|
request.finish(with: ZZHCustomVideoCompositoringError.invalidRequest)
|
||||||
|
print("报了个异常,但是应该执行不到....")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
CustomPlayerShareSemaphore.signal()
|
||||||
|
request.finish(withComposedVideoFrame: renderedBuffer)
|
||||||
|
// 从请求列表中移除已完成的请求
|
||||||
|
self.activeRequests.removeAll { $0 === request }
|
||||||
|
print("完成执行 finish.....")
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func cancelAllPendingVideoCompositionRequests() {
|
||||||
|
print("取消所有的pending 视频")
|
||||||
|
cancelled = true
|
||||||
|
queue.async(flags: .barrier) {
|
||||||
|
print("取消所有的pending 视频 barrier")
|
||||||
|
self.cancelled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private func renderFrame(forRequest request: AVAsynchronousVideoCompositionRequest)-> CVPixelBuffer? {
|
||||||
|
|
||||||
|
|
||||||
|
return autoreleasepool {
|
||||||
|
guard let instruction = request.videoCompositionInstruction as? ZZHCustomVideoCompositionInstruction else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
guard let videoFrameBuffer = request.sourceFrame(byTrackID: instruction.videoTrackID) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
let compositionTime = request.compositionTime
|
||||||
|
var ciImg:CIImage? = nil
|
||||||
|
switch instruction.selectedIndex {
|
||||||
|
case .monocular2D://双眼2d
|
||||||
|
// ciImg = request.sourceImage
|
||||||
|
break
|
||||||
|
|
||||||
|
default :
|
||||||
|
|
||||||
|
ciImg = self.otherModeImgWithMode(mode: instruction.selectedIndex,compositionTime: compositionTime,videoOriginalAsset: instruction.videoOriginalAsset,ao: instruction.assetOutput!)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if let ciImg {
|
||||||
|
guard let renderedBuffer = renderContext.newPixelBuffer() else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
ciContext.render(ciImg, to: renderedBuffer, bounds: ciImg.extent, colorSpace: self.colorSpace)
|
||||||
|
|
||||||
|
return renderedBuffer
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
print("未合成成功.....")
|
||||||
|
return videoFrameBuffer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func otherModeImgWithMode(mode:SpatialType,compositionTime:CMTime,videoOriginalAsset:AVAsset,ao:AVAssetReaderTrackOutput)->CIImage? {
|
||||||
|
var ciImg:CIImage? = nil
|
||||||
|
var presentTime:CMTime? = nil
|
||||||
|
switch mode {
|
||||||
|
case .crossedEyes://交叉眼
|
||||||
|
(ciImg,presentTime) = self.videoTranserConvertor.convertVideo(asset: videoOriginalAsset, assetOutput: ao, type:mode, time: compositionTime)
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
|
case .fsbs://3d全宽
|
||||||
|
(ciImg,presentTime) = self.videoTranserConvertor.convertVideo(asset: videoOriginalAsset, assetOutput: ao, type: mode, time: compositionTime)
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
|
case .hsbs://3d半宽
|
||||||
|
(ciImg,presentTime) = self.videoTranserConvertor.convertVideo(asset: videoOriginalAsset, assetOutput: ao, type: mode, time: compositionTime)
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
|
case .parallelEyes://平行眼
|
||||||
|
(ciImg,presentTime) = self.videoTranserConvertor.convertVideo(asset: videoOriginalAsset, assetOutput: ao, type: mode, time: compositionTime)
|
||||||
|
break
|
||||||
|
|
||||||
|
case .redBlueSolid://红蓝立体
|
||||||
|
(ciImg,presentTime) = self.videoTranserConvertor.convertVideo(asset: videoOriginalAsset, assetOutput: ao, type: mode, time: compositionTime)
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return ciImg
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -14,17 +14,20 @@ import ImageIO
|
|||||||
|
|
||||||
|
|
||||||
class PlayByTransferConvertor {
|
class PlayByTransferConvertor {
|
||||||
func convertVideo(asset:AVAsset, assetOutput:AVAssetReaderTrackOutput,type:SpatialType,time: CMTime)->(CIImage?) {
|
func convertVideo(asset:AVAsset, assetOutput:AVAssetReaderTrackOutput,type:SpatialType,time: CMTime)->(CIImage?,CMTime?) {
|
||||||
var newpb:CIImage? = nil
|
var newpb:CIImage? = nil
|
||||||
// print("sta.....>>>>>>>\(Date.now.timeIntervalSince1970)")
|
var presentationTime:CMTime? = nil
|
||||||
while let nextSampleBuffer = assetOutput.copyNextSampleBuffer() {
|
print("sta.....>>>>>>>thread:\(Thread.current) assetOutput:\(assetOutput) \n\(Date.now.timeIntervalSince1970)")
|
||||||
// print("nextSampleBuffer.....+++++++\(Date.now.timeIntervalSince1970)")
|
|
||||||
// return nil
|
while let nextSampleBuffer = assetOutput.copyNextSampleBuffer() {
|
||||||
|
presentationTime = CMSampleBufferGetPresentationTimeStamp(nextSampleBuffer)
|
||||||
|
print("presentationTime: \(presentationTime) \ntime: \(time)")
|
||||||
|
if presentationTime! > time {//如果当前获取的buffer的时间>time的时间,则直接返回即可
|
||||||
|
print("如果当前获取的buffer的时间>time的时间,则直接返回即可...")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
// print("PlayByTransferConvertor while")
|
|
||||||
let presentationTime = CMSampleBufferGetPresentationTimeStamp(nextSampleBuffer)
|
|
||||||
if presentationTime == time {
|
if presentationTime == time {
|
||||||
// print("PlayByTransferConvertor while break")
|
|
||||||
guard let taggedBuffers = nextSampleBuffer.taggedBuffers else { break }
|
guard let taggedBuffers = nextSampleBuffer.taggedBuffers else { break }
|
||||||
|
|
||||||
let leftEyeBuffer = taggedBuffers.first(where: {
|
let leftEyeBuffer = taggedBuffers.first(where: {
|
||||||
@ -78,7 +81,9 @@ class PlayByTransferConvertor {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return newpb
|
print("PlayByTransferConvertor 测试看是否有返回....")
|
||||||
|
return (newpb,presentationTime)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user