|
@@ -25,6 +25,11 @@ class WSSEditCutView: UIView {
|
|
fileprivate var imageGenerator: AVAssetImageGenerator
|
|
fileprivate var imageGenerator: AVAssetImageGenerator
|
|
fileprivate var imageArray = [UIImage]()
|
|
fileprivate var imageArray = [UIImage]()
|
|
fileprivate var videoDuration: Float = 0
|
|
fileprivate var videoDuration: Float = 0
|
|
|
|
+
|
|
|
|
+ fileprivate var exportSession: AVAssetExportSession?
|
|
|
|
+ fileprivate var exportSessionDisplayLink: CADisplayLink?
|
|
|
|
+ fileprivate var isUserCancel = false
|
|
|
|
+
|
|
weak var playerView: LXMAVPlayerView? {
|
|
weak var playerView: LXMAVPlayerView? {
|
|
didSet {
|
|
didSet {
|
|
playerView?.playerTimeDidChangeBlock = { [weak self] current, total in
|
|
playerView?.playerTimeDidChangeBlock = { [weak self] current, total in
|
|
@@ -95,6 +100,17 @@ class WSSEditCutView: UIView {
|
|
}
|
|
}
|
|
|
|
|
|
})
|
|
})
|
|
|
|
+
|
|
|
|
+ // --
|
|
|
|
+ NotificationCenter.default.reactive.notifications(forName: Notification.Name.kSVProgressHUDCacnel).take(duringLifetimeOf: self).observeValues { [weak self] _ in
|
|
|
|
+ self?.isUserCancel = true
|
|
|
|
+
|
|
|
|
+ if let exportSession = self?.exportSession {
|
|
|
|
+ exportSession.cancelExport()
|
|
|
|
+ self?.exportSession = nil
|
|
|
|
+ hideHud()
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
convenience init(movieURL: URL) {
|
|
convenience init(movieURL: URL) {
|
|
@@ -105,6 +121,10 @@ class WSSEditCutView: UIView {
|
|
required init?(coder aDecoder: NSCoder) {
|
|
required init?(coder aDecoder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ func releaseObjc() {
|
|
|
|
+ stopExportSessionDisplay()
|
|
|
|
+ }
|
|
|
|
|
|
func cutedStartSeconds() -> TimeInterval {
|
|
func cutedStartSeconds() -> TimeInterval {
|
|
let startTime = TimeInterval(bottomView.sliderView.selectedStart()) * TimeInterval(videoDuration)
|
|
let startTime = TimeInterval(bottomView.sliderView.selectedStart()) * TimeInterval(videoDuration)
|
|
@@ -162,21 +182,28 @@ private extension WSSEditCutView {
|
|
let timeRange = CMTimeRange(start: startTime, end: endTime)
|
|
let timeRange = CMTimeRange(start: startTime, end: endTime)
|
|
|
|
|
|
do {
|
|
do {
|
|
- showHud()
|
|
|
|
|
|
+ self.isUserCancel = false
|
|
let cutedVideo = try WSSMediaOperationTool.cutVideo(withVideoAsset: self.videoAsset, timeRange: timeRange)
|
|
let cutedVideo = try WSSMediaOperationTool.cutVideo(withVideoAsset: self.videoAsset, timeRange: timeRange)
|
|
let exportUrl = kOJSUserDocumentDirectory + "/" + "tmp_edit_video_cuted.mp4"
|
|
let exportUrl = kOJSUserDocumentDirectory + "/" + "tmp_edit_video_cuted.mp4"
|
|
- _ = WSSMediaOperationTool.exportVideo(withVideoAsset: cutedVideo, exportPath: URL(fileURLWithPath: exportUrl), finish: { [weak self] isSucess in
|
|
|
|
- hideHud()
|
|
|
|
-
|
|
|
|
- if isSucess {
|
|
|
|
- DispatchQueue.main.async(execute: {
|
|
|
|
|
|
+ let exportSession = WSSMediaOperationTool.exportVideo(withVideoAsset: cutedVideo, exportPath: URL(fileURLWithPath: exportUrl), finish: { [weak self] isSucess in
|
|
|
|
+ DispatchQueue.main.async(execute: {
|
|
|
|
+ self?.stopExportSessionDisplay()
|
|
|
|
+ if isSucess {
|
|
|
|
+ hideHud()
|
|
self?.saveActionHandle?(exportUrl, startTime.seconds, timeRange.duration.seconds)
|
|
self?.saveActionHandle?(exportUrl, startTime.seconds, timeRange.duration.seconds)
|
|
- })
|
|
|
|
- } else {
|
|
|
|
- showHud(withOnlyText: "截取视频失败")
|
|
|
|
- }
|
|
|
|
|
|
+ } else {
|
|
|
|
+ guard let userCancel = self?.isUserCancel, !userCancel else {
|
|
|
|
+ showHud(withOnlyText: "取消裁剪")
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ showHud(withOnlyText: "截取视频失败")
|
|
|
|
+ }
|
|
|
|
+ })
|
|
})
|
|
})
|
|
|
|
|
|
|
|
+ self.exportSession = exportSession
|
|
|
|
+ self.setupExportSessionDisplayLink()
|
|
|
|
+
|
|
} catch {
|
|
} catch {
|
|
showHud(withOnlyText: "截取视频失败")
|
|
showHud(withOnlyText: "截取视频失败")
|
|
}
|
|
}
|
|
@@ -218,6 +245,38 @@ extension WSSEditCutView: WSSEditCutSliderViewDelegate {
|
|
let endTime = TimeInterval(bottomView.sliderView.selectedEnd()) * TimeInterval(videoDuration)
|
|
let endTime = TimeInterval(bottomView.sliderView.selectedEnd()) * TimeInterval(videoDuration)
|
|
cutTimeRangeChangeHandle?(startTime, endTime - startTime)
|
|
cutTimeRangeChangeHandle?(startTime, endTime - startTime)
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ // MARK: exportSession
|
|
|
|
+
|
|
|
|
+ func setupExportSessionDisplayLink() {
|
|
|
|
+ if exportSessionDisplayLink != nil {
|
|
|
|
+ exportSessionDisplayLink?.isPaused = true
|
|
|
|
+ exportSessionDisplayLink?.invalidate()
|
|
|
|
+ exportSessionDisplayLink = nil
|
|
|
|
+ }
|
|
|
|
+ let displayLink = CADisplayLink(target: self, selector: #selector(updateExportSessionProgress))
|
|
|
|
+ DispatchQueue.main.async {
|
|
|
|
+ displayLink.add(to: .current, forMode: .common)
|
|
|
|
+ self.exportSessionDisplayLink = displayLink
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ func stopExportSessionDisplay() {
|
|
|
|
+ if let displayLink = exportSessionDisplayLink {
|
|
|
|
+ displayLink.isPaused = true
|
|
|
|
+ displayLink.invalidate()
|
|
|
|
+ exportSessionDisplayLink = nil
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @objc func updateExportSessionProgress() {
|
|
|
|
+ if let exportSession = exportSession {
|
|
|
|
+ let progress = exportSession.progress
|
|
|
|
+ showProgressCancelHub(progress: progress, status: "正在裁剪...")
|
|
|
|
+ } else {
|
|
|
|
+ stopExportSessionDisplay()
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
// MARK: - PublicMethod
|
|
// MARK: - PublicMethod
|