完美解决播放卡顿问题

This commit is contained in:
Zhihai Zhu 2024-04-20 11:31:53 +08:00
parent 0270796016
commit 1eb4326d61
8 changed files with 233 additions and 76 deletions

View File

@ -12,102 +12,202 @@
<key>DeviceKit.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>13</integer>
<integer>2</integer>
</dict>
<key>FBSDKCoreKit.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>31</integer>
</dict>
<key>FacebookCore.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>21</integer>
</dict>
<key>Firebase.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>15</integer>
</dict>
<key>FirebaseABTesting-FirebaseABTesting_Privacy.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>26</integer>
</dict>
<key>FirebaseABTesting.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>16</integer>
</dict>
<key>FirebaseAnalytics.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>33</integer>
</dict>
<key>FirebaseCore-FirebaseCore_Privacy.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>11</integer>
</dict>
<key>FirebaseCore.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>0</integer>
<integer>29</integer>
</dict>
<key>FirebaseCoreExtension.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>12</integer>
</dict>
<key>FirebaseCoreInternal-FirebaseCoreInternal_Privacy.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>27</integer>
</dict>
<key>FirebaseCoreInternal.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>6</integer>
<integer>14</integer>
</dict>
<key>FirebaseCrashlytics.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>2</integer>
</dict>
<key>FirebaseInstallations-FirebaseInstallations_Privacy.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>12</integer>
</dict>
<key>FirebaseInstallations.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>8</integer>
<integer>20</integer>
</dict>
<key>FirebaseMessaging.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>19</integer>
</dict>
<key>FirebaseRemoteConfig-FirebaseRemoteConfig_Privacy.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>6</integer>
</dict>
<key>FirebaseRemoteConfig.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>10</integer>
</dict>
<key>FirebaseRemoteConfigInterop.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>7</integer>
</dict>
<key>FirebaseSessions.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>15</integer>
</dict>
<key>FirebaseSharedSwift.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>9</integer>
</dict>
<key>GoogleAppMeasurement.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>34</integer>
</dict>
<key>GoogleDataTransport.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>9</integer>
</dict>
<key>GoogleUtilities-GoogleUtilities_Privacy.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>28</integer>
</dict>
<key>GoogleUtilities.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>16</integer>
<integer>4</integer>
</dict>
<key>KeychainAccess.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>17</integer>
</dict>
<key>Kingfisher-Kingfisher.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>18</integer>
<integer>32</integer>
</dict>
<key>Kingfisher.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>10</integer>
<integer>24</integer>
</dict>
<key>LLCycleScrollView.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>21</integer>
<integer>25</integer>
</dict>
<key>Pods-SwiftProject.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>20</integer>
<integer>3</integer>
</dict>
<key>PromisesObjC-FBLPromises_Privacy.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>30</integer>
</dict>
<key>PromisesObjC.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>5</integer>
<integer>19</integer>
</dict>
<key>PromisesSwift.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>17</integer>
</dict>
<key>SVProgressHUD.xcscheme_^#shared#^_</key>
<key>SDWebImage-SDWebImage.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>3</integer>
<integer>23</integer>
</dict>
<key>SnapKit.xcscheme_^#shared#^_</key>
<key>SDWebImage.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>1</integer>
</dict>
<key>SVProgressHUD.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>18</integer>
</dict>
<key>SnapKit.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>13</integer>
</dict>
<key>TZImagePickerController.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>7</integer>
<integer>8</integer>
</dict>
<key>nanopb-nanopb_Privacy.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>22</integer>
</dict>
<key>nanopb.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>11</integer>
<integer>5</integer>
</dict>
</dict>
</dict>

View File

@ -7,7 +7,7 @@
<key>SwiftProject.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>4</integer>
<integer>0</integer>
</dict>
</dict>
</dict>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>SchemeUserState</key>
<dict>
<key>Promises (Playground) 1.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>36</integer>
</dict>
<key>Promises (Playground) 2.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>37</integer>
</dict>
<key>Promises (Playground).xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>35</integer>
</dict>
</dict>
</dict>
</plist>

View File

@ -11,7 +11,8 @@ import AVKit
//assetoutput 线
//let AssetGlobalQueue = DispatchQueue.global(qos: DispatchQoS.QoSClass.default)
let CustomPlayerShareSemaphore = DispatchSemaphore(value: 1)
//let CustomPlayerShareSemaphore = DispatchSemaphore(value: 1)
//let CustomPlayerShareRecursiveLock = NSRecursiveLock()
class ZZHCustomPlayer: UIView {
@ -41,6 +42,8 @@ class ZZHCustomPlayer: UIView {
}
}
var playerIsSeeking:Bool = false//
//ui
var playerLayerBgView:UIView?
@ -137,12 +140,13 @@ class ZZHCustomPlayer: UIView {
//sliderseek
func manualToSeekPlay(value:Float,isMoving:Bool){
if isMoving {
self.play(false)
print("此处已暂停播放,那么后面希望不要出现 sta.....> 的打印信息")
}
Task {
// Task {
let totalSec = CMTimeGetSeconds((self.avPlayer?.currentItem?.duration)!)
var atSec = Float(totalSec) * value
var timeScale:CMTimeScale? = self.avPlayer?.currentItem?.duration.timescale
@ -154,24 +158,30 @@ class ZZHCustomPlayer: UIView {
}
let ct = CMTime(value:CMTimeValue(atSec) , timescale: timeScale!)
// CustomPlayerShareSemaphore.wait()
// CustomPlayerShareRecursiveLock.lock()
// self.quickLoadAReaderWhenSeek(startCT: ct)
// CustomPlayerShareRecursiveLock.unlock()
// CustomPlayerShareSemaphore.signal()
print("正在seek.....\(ct) ismainthread:\(Thread.isMainThread)")
DispatchQueue.main.async {
// DispatchQueue.main.async {
playerIsSeeking = true
self.avPlayer?.seek(to: ct,toleranceBefore:.zero,toleranceAfter: .zero, completionHandler: { finished in
if finished {
if(!isMoving) {//,
CustomPlayerShareSemaphore.wait()
self.quickLoadAReaderWhenSeek(startCT: ct)
CustomPlayerShareSemaphore.signal()
// CustomPlayerShareSemaphore.wait()
// CustomPlayerShareRecursiveLock.lock()
// self.quickLoadAReaderWhenSeek(startCT: ct)
// CustomPlayerShareRecursiveLock.unlock()
// CustomPlayerShareSemaphore.signal()
self.play(true)
self.playerIsSeeking = false
}
}
})
}
// }
}
// }

View File

@ -13,51 +13,51 @@ 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
// }
// 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 {
let temItem = AVPlayerItem(asset: self.videoOriginalAsset)
let timeRange = CMTimeRange(start: CMTime.zero, duration: temItem.asset.duration)
let videoTracks = temItem.asset.tracks(withMediaType: AVMediaType.video)
guard let sourceVideoTrack = videoTracks.first else {
return temItem
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
}
}
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
}
// func getPlayerItem() -> AVPlayerItem {
// let temItem = AVPlayerItem(asset: self.videoOriginalAsset)
// let timeRange = CMTimeRange(start: CMTime.zero, duration: temItem.asset.duration)
// let videoTracks = temItem.asset.tracks(withMediaType: AVMediaType.video)
// guard let sourceVideoTrack = videoTracks.first else {
// return temItem
// }
//
// 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
// }
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)
// let tr = CMTimeRange(start: compositionTime, end: end)
var ciImg:CIImage? = nil
switch self.selectedIndex {
@ -66,19 +66,31 @@ extension ZZHCustomPlayer {
break
default :
ciImg = self.otherModeImgWithMode(mode: self.selectedIndex,tr:tr,compositionTime: compositionTime)
if self.playerIsSeeking {
quickLoadAReaderWhenSeek(startCT: compositionTime)
ciImg = self.otherModeImgWithMode(mode: self.selectedIndex,compositionTime: compositionTime)
}
else {
ciImg = self.otherModeImgWithMode(mode: self.selectedIndex,compositionTime: compositionTime)
guard let ciImg else {print("未合成成功.....,此处将进行重新构建assetoutput,然后再次重拾")
quickLoadAReaderWhenSeek(startCT: compositionTime)
ciImg = self.otherModeImgWithMode(mode: self.selectedIndex,compositionTime: compositionTime)
break
}
}
break
}
if let ciImg {
request.finish(with: ciImg, context: nil)
}
else {
print("未合成成功.....")
print("未合成成功.....,")
request.finish(with: request.sourceImage, context: nil)
}
}
func otherModeImgWithMode(mode:SpatialType,tr:CMTimeRange,compositionTime:CMTime)->CIImage? {
func otherModeImgWithMode(mode:SpatialType,compositionTime:CMTime)->CIImage? {
guard let ao = self.assetOutput else {
print("assetOutput 应该是没有被创建成功.....")
return nil
@ -168,11 +180,11 @@ extension ZZHCustomPlayer {
func quickLoadAssetOutput() {
if(assetOutput != nil){
print("正在释放assetoutput----assetOutput:\(assetOutput) \n\(Date.now.timeIntervalSince1970)")
// print("assetoutput----assetOutput:\(assetOutput) \n\(Date.now.timeIntervalSince1970)")
assetOutput?.markConfigurationAsFinal()
print("正在释放assetoutput....assetOutput:\(assetOutput) \n\(Date.now.timeIntervalSince1970)")
// print("assetoutput....assetOutput:\(assetOutput) \n\(Date.now.timeIntervalSince1970)")
assetOutput = nil
print("释放完毕assetoutput....thread:\(Thread.current) \n\(Date.now.timeIntervalSince1970)")
// print("assetoutput....thread:\(Thread.current) \n\(Date.now.timeIntervalSince1970)")
}
assetOutput = AVAssetReaderTrackOutput(

View File

@ -55,7 +55,7 @@ final class ZZHCustomVideoCompositor: NSObject, AVVideoCompositing {
//
self.activeRequests.append(request)
print("startRequest ....AVAsynchronousVideoCompositionRequest: \(self.cancelled) request:\(request)")
// print("startRequest ....AVAsynchronousVideoCompositionRequest: \(self.cancelled) request:\(request)")
guard !self.cancelled else {
print("startRequest cancell....")
request.finishCancelledRequest()
@ -64,18 +64,20 @@ final class ZZHCustomVideoCompositor: NSObject, AVVideoCompositing {
return
}
print("startRequest queue:\(self.queue) current:\(Thread.current)")
CustomPlayerShareSemaphore.wait()
// print("startRequest queue:\(self.queue) current:\(Thread.current)")
// CustomPlayerShareSemaphore.wait()
// CustomPlayerShareRecursiveLock.lock()
guard let renderedBuffer = self.renderFrame(forRequest: request) else {
request.finish(with: ZZHCustomVideoCompositoringError.invalidRequest)
print("报了个异常,但是应该执行不到....")
return
}
CustomPlayerShareSemaphore.signal()
// CustomPlayerShareSemaphore.signal()
// CustomPlayerShareRecursiveLock.unlock()
request.finish(withComposedVideoFrame: renderedBuffer)
//
self.activeRequests.removeAll { $0 === request }
print("完成执行 finish.....")
// print(" finish.....")
}
}

View File

@ -17,15 +17,15 @@ class PlayByTransferConvertor {
func convertVideo(asset:AVAsset, assetOutput:AVAssetReaderTrackOutput,type:SpatialType,time: CMTime)->(CIImage?,CMTime?) {
var newpb:CIImage? = nil
var presentationTime:CMTime? = nil
print("sta.....>>>>>>>thread:\(Thread.current) assetOutput:\(assetOutput) \n\(Date.now.timeIntervalSince1970)")
print("sta.....>>>>>>>thread")
while let nextSampleBuffer = assetOutput.copyNextSampleBuffer() {
presentationTime = CMSampleBufferGetPresentationTimeStamp(nextSampleBuffer)
print("presentationTime: \(presentationTime) \ntime: \(time)")
if presentationTime! > time {//buffer>time,
print("如果当前获取的buffer的时间>time的时间,则直接返回即可...")
break
}
// if presentationTime! > time {//buffer>time,
// print("buffer>time,...")
// break
// }
if presentationTime == time {
guard let taggedBuffers = nextSampleBuffer.taggedBuffers else { break }
@ -80,8 +80,11 @@ class PlayByTransferConvertor {
CMSampleBufferInvalidate(nextSampleBuffer)
break
}
else{//,break,time,
break
}
}
print("PlayByTransferConvertor 测试看是否有返回....")
// print("PlayByTransferConvertor ....")
return (newpb,presentationTime)
}