// // INVideoExportController.swift // Introduce // // Created by 胡志强 on 2021/11/29. // import BFAnalyzeKit import BFCommonKit import BFRecordScreenKit import BFUIKit import Foundation import Photos import SwiftUI import UIKit import BFUploadKit import AliyunOSSiOS class INVideoExportController: BFBaseViewController { let uploadData = PQUploadModel() var hadUploadTask = false var avplayerTimeObserver: NSKeyValueObservation? let recordUid = getRandomStringOfLength(length: 16) let backV : UIView = { let v = UIView() v.backgroundColor = UIColor.hexColor(hexadecimal: "#1A1A1A") return v }() let coverIV : UIImageView = { let iv = UIImageView() iv.backgroundColor = .black iv.alpha = 0.5 iv.contentMode = .scaleAspectFit return iv }() var hasExportAll = false var hasExportOnly = false var hasSaveAll = false var hasSaveOnly = false var saveAllUlr = URL(fileURLWithPath: "aaa") var saveOnlyUlr = URL(fileURLWithPath: "aaa") var playViewFrame: CGRect = CGRect.zero var isExporting = false { didSet { if isExporting { avplayer.pause() } } } var enterBackgroundCancleExport = false // 预览播放进度 var sliderView: BFVideoPlayerSliderView? // 合成进度指示条 lazy var progressView: UIView = { let v = UIView() v.backgroundColor = ThemeStyleColor v.alpha = 0.5 return v }() // 合成进度百分比lable lazy var progressL: UILabel = { let la = UILabel() la.textColor = .white la.textAlignment = .center la.text = "0%" la.font = UIFont.systemFont(ofSize: 28) la.shadowColor = .black la.shadowOffset = CGSize(width: 1, height: 1) return la }() // 播放进度显示 lazy var playDurL: UILabel = { let la = UILabel() la.textAlignment = .center la.font = UIFont.systemFont(ofSize: 12, weight: .medium) la.textColor = .white la.layer.shadowOpacity = 0.4 la.layer.shadowColor = UIColor.black.cgColor la.layer.shadowOffset = CGSize(width: 0, height: 2) la.layer.shadowRadius = 2 la.text = "00:00/00:00" return la }() lazy var saveAllBtn: UIButton = { let btn = UIButton() btn.setImage(UIImage(named: "export_saveall_n"), for: .normal) btn.setImage(UIImage(named: "export_saveall_h"), for: .selected) btn.addTarget(self, action: #selector(saveAllAction(btn:)), for: .touchUpInside) return btn }() lazy var saveAllBtnTips: UILabel = { let la = UILabel() la.textColor = .white la.textAlignment = .center la.text = "savemode_all".BFLocale la.font = UIFont.systemFont(ofSize: 14) return la }() lazy var saveOnlyBtn: UIButton = { let btn = UIButton() btn.setImage(UIImage(named: "export_saveonly_n"), for: .normal) btn.setImage(UIImage(named: "export_saveonly_h"), for: .selected) btn.addTarget(self, action: #selector(saveOnlyAction(btn:)), for: .touchUpInside) return btn }() lazy var saveOnlyBtnTips: UILabel = { let la = UILabel() la.textColor = .white la.textAlignment = .center la.text = "savemode_onlyrecord".BFLocale la.font = UIFont.systemFont(ofSize: 14) return la }() lazy var completeBtn: UIButton = { let btn = UIButton() btn.setTitle("option_Finish".BFLocale, for: .normal) btn.titleLabel?.font = UIFont.systemFont(ofSize: 14) btn.setTitleColor(UIColor.hexColor(hexadecimal: "#6B6B6B"), for: .normal) btn.setTitleColor(.gray, for: .disabled) btn.addTarget(self, action: #selector(completeAction), for: .touchUpInside) btn.isHidden = true return btn }() lazy var saveToPhotoBtn: UIButton = { let btn = UIButton() btn.setTitle(" \("compose_save".BFLocale)", for: .normal) btn.setTitleColor(.white, for: .normal) btn.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16) btn.setImage(UIImage(named: "export_btn"), for: .normal) // btn.backgroundColor = ThemeStyleColor btn.setBackgroundImage(UIImage(color: ThemeStyleColor), for: .normal) btn.setBackgroundImage(UIImage(color: UIColor.hexColor(hexadecimal: "#1C4D80")), for: .highlighted) btn.adjustsImageWhenHighlighted = false btn.adjustsImageWhenDisabled = false btn.isEnabled = false btn.alpha = 0.3 btn.addCorner(roundingCorners: .allCorners, corner: 8) btn.addTarget(self, action: #selector(saveToPhotoNow), for: .touchUpInside) return btn }() lazy var bottomView: UIView = { let vv = UIView() vv.backgroundColor = .black // vv.isHidden = true return vv }() lazy var errorView : UIView = { let errbackV = UIView() errbackV.backgroundColor = .black errbackV.isHidden = true let titleL = UILabel() titleL.text = "compose_fail_compose".BFLocale titleL.font = UIFont.systemFont(ofSize: 36) titleL.textColor = .white titleL.textAlignment = .center errbackV.addSubview(titleL) let subTitleL = UILabel() subTitleL.text = "compose_retry4".BFLocale subTitleL.tag = 33000 subTitleL.font = UIFont.systemFont(ofSize: 24) subTitleL.textColor = UIColor.hexColor(hexadecimal: "#A6A6A6") subTitleL.textAlignment = .center subTitleL.contentCompressionResistancePriority(for: NSLayoutConstraint.Axis.horizontal) subTitleL.numberOfLines = 0 errbackV.addSubview(subTitleL) let retryBtn = UIButton() retryBtn.backgroundColor = ThemeStyleColor retryBtn.setTitle("compose_retry".BFLocale, for: .normal) retryBtn.tag = 33001 retryBtn.setTitleColor(.white, for: .normal) retryBtn.addCorner(corner:5) retryBtn.addTarget(self, action: #selector(retryAction(sender:)), for: .touchUpInside) errbackV.addSubview(retryBtn) retryBtn.snp.makeConstraints { make in make.width.equalTo(245) make.height.equalTo(50) make.centerX.equalToSuperview() make.centerY.equalToSuperview().offset(10) } subTitleL.snp.makeConstraints { make in make.left.right.equalToSuperview() make.bottom.equalTo(retryBtn.snp.top).offset(-30) } titleL.snp.makeConstraints { make in make.left.right.equalToSuperview() make.height.equalTo(70) make.bottom.equalTo(subTitleL.snp.top) } return errbackV }() var playerLayer: AVPlayerLayer! lazy var avplayer: AVPlayer = { let avplayer = AVPlayer() avplayerTimeObserver = avplayer.addPeriodicTimeObserver(forInterval: CMTime(value: 1, timescale: 10), queue: DispatchQueue.global()) { [weak self, weak avplayer] time in // 进度监控 if let item = avplayer?.currentItem, !(self?.sliderView?.isDragingProgressSlder ?? false) { DispatchQueue.main.async { [weak self, weak avplayer] in if avplayer?.currentItem?.status != .readyToPlay { self?.playDurL.text = "00:00/00:00" self?.sliderView?.progress = 0 }else{ self?.playDurL.text = String(format: "%@ / %@", CMTimeGetSeconds(time).formatDurationToHMS(), CMTimeGetSeconds(item.duration).formatDurationToHMS()) self?.sliderView?.progress = CMTimeGetSeconds(item.currentTime()) / CMTimeGetSeconds(item.duration) } } } } as? NSKeyValueObservation NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: avplayer.currentItem, queue: .main) { [weak avplayer, weak self] _ in avplayer?.seek(to: CMTime.zero) self?.sliderView?.playEnd() // self?.changeToOriginalFrame() } return avplayer }() lazy var export: BFRecordExport = { let export = BFRecordExport() export.progress = { [weak self] progress in DispatchQueue.main.async {[weak self] in guard let wself = self else { return } wself.progressL.text = String(format: "%d%%", Int(progress * 100)) wself.progressView.snp.updateConstraints { make in make.width.equalTo(wself.playerLayer.bounds.width * CGFloat(progress)) } } } export.exportCompletion = { [weak self] error, url in DispatchQueue.main.async { [weak self] in guard let wself = self else { return } UIApplication.shared.isIdleTimerDisabled = false wself.resetViewStatus() wself.coverIV.isHidden = true wself.progressView.snp.updateConstraints { make in make.width.equalTo(0) } wself.progressL.text = "0%" if let fileUrl = url { wself.sliderView?.isHidden = false wself.playDurL.isHidden = false wself.sliderView?.playStart() wself.completeBtn.isHidden = false if !wself.hadUploadTask{ wself.uploadData.localPath = fileUrl.absoluteString wself.hadUploadTask = true wself.uploadVideo() } let item = AVPlayerItem(url: fileUrl) wself.avplayer.replaceCurrentItem(with: item) usleep(1000) wself.avplayer.play() wself.playerLayer.borderColor = ThemeStyleColor.cgColor if wself.saveAllBtn.isSelected { wself.saveAllUlr = fileUrl wself.hasExportAll = true } if wself.saveOnlyBtn.isSelected { wself.saveOnlyUlr = fileUrl wself.hasExportOnly = true } // 添加播放进度视图 self?.addVideoSliderView() }else { if let l = wself.errorView.viewWithTag(33000) as? UILabel, let err = error as NSError?,let b = wself.errorView.viewWithTag(33001) as? UIButton { switch err.code { case ExportError.FileNotExist.rawValue : l.text = "compose_fail_delete".BFLocale b.setTitle("compose_retry2".BFLocale, for: .normal) case ExportError.DiskNoSpace.rawValue : l.text = "compose_fail_storage".BFLocale + (err.userInfo["msg"] as! String) b.setTitle("compose_retry".BFLocale, for: .normal) case ExportError.VoiceLost.rawValue : l.text = "compose_fail_records".BFLocale b.setTitle("compose_retry".BFLocale, for: .normal) default: l.text = "compose_retry4".BFLocale b.setTitle("compose_retry".BFLocale, for: .normal) } l.sizeToFit() } wself.errorView.isHidden = false } } // 合成成功上报 BFEventTrackAdaptor.baseReportUpload(businessType: nil, objectType: .ot_composeSuccess, pageSource: .sp_composePage, commonParams: commonParams()) } return export }() deinit { avplayerTimeObserver?.invalidate() NotificationCenter.default.removeObserver(self) } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) PQNotification.addObserver(self, selector: #selector(enterBackground), name: UIApplication.didEnterBackgroundNotification, object: nil) PQNotification.addObserver(self, selector: #selector(willEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil) //进入活跃状态 PQNotification.addObserver(self, selector: #selector(didBecomeActive), name: UIApplication.didBecomeActiveNotification, object: nil) //进入非活跃状态 PQNotification.addObserver(self, selector: #selector(willResignActive), name: UIApplication.willResignActiveNotification, object: nil) showNavigation() // 曝光上报 BFEventTrackAdaptor.baseReportUpload(businessType: .bt_pageView, objectType: nil, pageSource: .sp_composePage, commonParams: commonParams()) } @objc func didBecomeActive(){ BFLog(message: "进入活跃状态") if let sbtn = sliderView?.viewWithTag(1) as? UIButton ,!isExporting { sbtn.isSelected = false avplayer.play() } } @objc func willResignActive(){ BFLog(message: "进入非活跃状态") if let sbtn = sliderView?.viewWithTag(1) as? UIButton , !isExporting{ sbtn.isSelected = true avplayer.pause() } } @objc func enterBackground() { BFLog(message: "进入到后台") if isExporting { enterBackgroundCancleExport = true self.export.cancelExport() }else{ if let sbtn = sliderView?.viewWithTag(1) as? UIButton { sbtn.isSelected = true avplayer.pause() } } } @objc func willEnterForeground() { BFLog(message: "进入到前台") if enterBackgroundCancleExport { export.startExprot(synthesisAll: saveAllBtn.isSelected) enterBackgroundCancleExport = false }else { //重启播放器 if let sbtn = sliderView?.viewWithTag(1) as? UIButton { sbtn.isSelected = false avplayer.play() } } } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) PQNotification.removeObserver(self) UIApplication.shared.isIdleTimerDisabled = false } override func backBtnClick() { if isExporting { whetherCancelExport (msg: "savemode_changes".BFLocale){ self.export.cancelExport() super.backBtnClick() } return } if !(hasExportAll || hasExportOnly) {} export.cancelExport() super.backBtnClick() } override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .black navHeadImageView?.backgroundColor = .clear // uploadData.videoBucketKey = recordUid leftButton(image: nil, imageName: nil, tintColor: UIColor.white) addSubviews() // 默认保留录音合成 saveAllBtn.isSelected = true DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { [weak self] in self?.exportNow() } } func addSubviews() { view.addSubview(bottomView) view.addSubview(backV) view.addSubview(errorView) playerLayer = AVPlayerLayer(player: avplayer) playerLayer.borderWidth = 2 playerLayer.borderColor = UIColor.hexColor(hexadecimal: "#1A1A1A").cgColor backV.layer.addSublayer(playerLayer) backV.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(playAction))) backV.addSubview(coverIV) backV.addSubview(playDurL) backV.addSubview(progressView) backV.addSubview(progressL) bottomView.addSubview(saveAllBtn) saveAllBtn.addSubview(saveAllBtnTips) bottomView.addSubview(saveOnlyBtn) saveOnlyBtn.addSubview(saveOnlyBtnTips) bottomView.addSubview(saveToPhotoBtn) bottomView.addSubview(completeBtn) errorView.snp.makeConstraints { make in make.edges.equalToSuperview() } coverIV.snp.makeConstraints { make in make.bottom.centerX.equalToSuperview() make.width.equalTo(coverIV.snp.height).multipliedBy(cScreenWidth / cScreenHeigth) make.height.equalToSuperview().offset(-1 * cDevice_iPhoneNavBarAndStatusBarHei + 30) } playDurL.snp.makeConstraints { make in make.width.centerX.equalTo(coverIV) make.top.equalTo(coverIV).offset(5) make.height.equalTo(20) } progressView.snp.makeConstraints { make in make.top.left.bottom.equalTo(coverIV) make.width.equalTo(0) } progressL.snp.makeConstraints { make in make.width.centerX.centerY.equalTo(coverIV) make.height.equalTo(28) } backV.snp.makeConstraints { make in make.left.right.top.equalToSuperview() make.bottom.equalTo(bottomView.snp.top) } bottomView.snp.makeConstraints { make in make.left.right.equalToSuperview() if #available(iOS 11.0, *) { make.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom) } else { make.bottom.equalToSuperview() } } completeBtn.snp.makeConstraints { make in // make.left.equalTo(16) // make.right.equalTo(-16) make.centerX.equalToSuperview() make.bottom.equalToSuperview().offset(-7) make.height.equalTo(20) } saveToPhotoBtn.snp.makeConstraints { make in make.left.right.equalTo(completeBtn) make.height.equalTo(46) make.bottom.equalTo(completeBtn.snp.top).offset(-25) } saveAllBtn.snp.makeConstraints { make in make.left.equalTo(completeBtn) make.bottom.equalTo(saveToPhotoBtn.snp.top).offset(-15) make.height.equalTo(70) make.width.equalTo(164) make.top.equalTo(28) make.centerX.equalToSuperview().offset(-82 - 6.5) } saveAllBtnTips.snp.makeConstraints { make in make.bottom.equalToSuperview().offset(-7) make.left.equalToSuperview().offset(2) make.right.equalToSuperview().offset(-2) } saveOnlyBtn.snp.makeConstraints { make in // make.left.equalTo(saveAllBtn.snp.right).offset(16) make.top.height.width.equalTo(saveAllBtn) make.left.equalTo(saveAllBtn.snp.right).offset(13) make.right.equalTo(completeBtn) } saveOnlyBtnTips.snp.makeConstraints { make in make.bottom.equalToSuperview().offset(-7) make.left.equalToSuperview().offset(2) make.right.equalToSuperview().offset(-2) } // DispatchQueue.main.asyncAfter(deadline: .now() + 0) { [weak self] in // guard let wself = self else { // return // } // // } } override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() playerLayer.frame = coverIV.frame } /// 添加播放进度视图 func addVideoSliderView() { if sliderView == nil { sliderView = BFVideoPlayerSliderView(frame: CGRect(x: (backV.frame.width - playerLayer.frame.width) / 2, y: backV.frame.height - 60, width: playerLayer.frame.width, height: 50),isShowFullScreen: false) sliderView?.playerBtn.setImage(UIImage(named: "play_0"), for: .normal) sliderView?.playerBtn.setImage(UIImage(named: "play_1"), for: .selected) sliderView?.playerBtn.imageEdgeInsets = UIEdgeInsets(top: 1, left: 7, bottom: 0, right: 0) sliderView?.valueChangeBloc = { [weak self,weak sliderView] sender in let cmtime = CMTime(seconds: Double(sender.value) * (self?.avplayer.currentItem?.asset.duration.seconds ?? 0), preferredTimescale: 1000) BFLog(message: "cmtime == \(cmtime),\(cmtime.seconds)") self?.avplayer.seek(to: cmtime, toleranceBefore: CMTime(seconds: 1, preferredTimescale: 1000), toleranceAfter: CMTime(seconds: 1, preferredTimescale: 1000)) sliderView?.playStart() self?.avplayer.play() } sliderView?.slideBeginDrag = { [weak self] in self?.avplayer.pause() } sliderView?.btnClickBloc = { [weak self] sender in // 按钮点击 if sender.tag == 1 { self?.play(sender: sender) } else if sender.tag == 2 { if sender.isSelected { self?.changeToFullScreen() } else { self?.changeToOriginalFrame() } } } } sliderView?.duration = avplayer.currentItem?.asset.duration.seconds ?? 0 if sliderView?.superview == nil { backV.addSubview(sliderView!) } } func resetViewStatus() { isExporting = false // wself.bottomView.isHidden = false saveAllBtn.setImage(UIImage(named: "export_saveall_n"), for: .normal) saveOnlyBtn.setImage(UIImage(named: "export_saveonly_n"), for: .normal) saveToPhotoBtn.isEnabled = true saveToPhotoBtn.alpha = 1 completeBtn.isEnabled = true progressView.isHidden = true progressView.snp.updateConstraints { make in make.width.equalTo(0) } progressL.isHidden = true progressL.text = "0%" } // MARK: - 按钮事件 @objc func retryAction(sender:UIButton){ if sender.currentTitle == "compose_retry2".BFLocale { export.cancelExport() navigationController?.popToRootViewController(animated: true) } else { errorView.isHidden = true exportNow() } } func exportNow() { if isExporting { cShowHUB(superView: nil, msg: "compose_loading".BFLocale) return } isExporting = true coverIV.isHidden = false playerLayer.borderColor = UIColor.hexColor(hexadecimal: "#1A1A1A").cgColor avplayer.replaceCurrentItem(with: nil) // bottomView.isHidden = true if saveAllBtn.isSelected { // saveAllBtn.setImage(UIImage(named: "export_saveall_h"), for: .disabled) saveAllBtn.setImage(UIImage(named: "export_saveall_h"), for: .normal) saveOnlyBtn.setImage(UIImage(named: "export_saveonly_n"), for: .normal) saveAllBtnTips.textColor = UIColor.hexColor(hexadecimal: "#389AFF") saveOnlyBtnTips.textColor = UIColor(red: 0.696, green: 0.696, blue: 0.696, alpha: 1) }else{ // saveAllBtn.setImage(UIImage(named: "export_saveall_n"), for: .disabled) saveAllBtn.setImage(UIImage(named: "export_saveall_n"), for: .normal) saveOnlyBtn.setImage(UIImage(named: "export_saveonly_h"), for: .normal) saveOnlyBtnTips.textColor = UIColor.hexColor(hexadecimal: "#389AFF") saveAllBtnTips.textColor = UIColor(red: 0.696, green: 0.696, blue: 0.696, alpha: 1) } saveToPhotoBtn.isEnabled = false saveToPhotoBtn.alpha = 0.3 completeBtn.isEnabled = false progressView.isHidden = false progressL.isHidden = false sliderView?.isHidden = true playDurL.isHidden = true DispatchQueue.global().async {[weak self] in self?.export.startExprot(synthesisAll: self?.saveAllBtn.isSelected ?? true) } UIApplication.shared.isIdleTimerDisabled = true // 开始合成上报 BFEventTrackAdaptor.baseReportUpload(businessType: nil, objectType: .ot_startCompose, pageSource: .sp_composePage, commonParams: commonParams()) } @objc func saveToPhotoNow() { if (saveAllBtn.isSelected && hasSaveAll) || saveOnlyBtn.isSelected && hasSaveOnly { cShowHUB(superView: nil, msg: "compose_tips_saved".BFLocale) return } if let url = (avplayer.currentItem?.asset as? AVURLAsset)?.url { PHPhotoLibrary.shared().performChanges { PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: url) } completionHandler: { [weak self] isFinished, _ in guard let wself = self else { return } if isFinished { cShowHUB(superView: nil, msg: "compose_tips_successfully".BFLocale, style: 1) if wself.saveAllBtn.isSelected { wself.hasSaveAll = true } else if wself.saveOnlyBtn.isSelected { wself.hasSaveOnly = true } } } } // 点击保存至相册上报 BFEventTrackAdaptor.baseReportUpload(businessType: .bt_buttonClick, objectType: .ot_saveToAblum, pageSource: .sp_composePage, extParams: ["saveMode": saveAllBtn.isSelected ? "saveAll" :"saveRecord"], commonParams: commonParams()) } @objc func saveAllAction(btn: UIButton) { if btn.isSelected { return } if isExporting { whetherCancelExport {[weak self] in self?.export.cancelExport() self?.resetViewStatus() self?.saveAllAction(btn: btn) } return } btn.isSelected = true saveOnlyBtn.isSelected = false saveAllBtnTips.textColor = UIColor.hexColor(hexadecimal: "#389AFF") saveOnlyBtnTips.textColor = UIColor(red: 0.696, green: 0.696, blue: 0.696, alpha: 1) avplayer.pause() if !hasExportAll { exportNow() } else { coverIV.isHidden = true avplayer.pause() let item = AVPlayerItem(url: saveAllUlr) avplayer.replaceCurrentItem(with: item) if let sbtn = sliderView?.viewWithTag(1) as? UIButton { sbtn.isSelected = false avplayer.play() sliderView?.duration = avplayer.currentItem?.asset.duration.seconds ?? 0 } } } @objc func saveOnlyAction(btn: UIButton) { if btn.isSelected { return } if isExporting { whetherCancelExport {[weak self ] in self?.export.cancelExport() self?.resetViewStatus() self?.saveOnlyAction(btn: btn) } return } btn.isSelected = true saveAllBtn.isSelected = false saveOnlyBtnTips.textColor = UIColor.hexColor(hexadecimal: "#389AFF") saveAllBtnTips.textColor = UIColor(red: 0.696, green: 0.696, blue: 0.696, alpha: 1) avplayer.pause() if !hasExportOnly { exportNow() } else { coverIV.isHidden = true avplayer.pause() let item = AVPlayerItem(url: saveOnlyUlr) avplayer.replaceCurrentItem(with: item) if let sbtn = sliderView?.viewWithTag(1) as? UIButton { sbtn.isSelected = false avplayer.play() sliderView?.duration = avplayer.currentItem?.asset.duration.seconds ?? 0 } } } @objc func playAction(){ if !isExporting { if let sbtn = sliderView?.viewWithTag(1) as? UIButton{ sbtn.isSelected = !sbtn.isSelected if sbtn.isSelected { avplayer.pause() }else{ avplayer.play() } } } } @objc func completeAction() { // MARK: 删除所有录制资源. 现在放在了选择相册展示时清理cache if !hasSaveAll && !hasSaveOnly { let alertController = UIAlertController(title: "compose_tips_changes".BFLocale, message: "", preferredStyle: .alert) let cancelAction = UIAlertAction(title: "option_cancel".BFLocale, style: .default){_ in } let okAction = UIAlertAction(title: "option_confirm".BFLocale, style: .default) {[weak self] action in guard let wself = self else { return } wself.export.cancelExport() wself.navigationController?.popToRootViewController(animated: true) } alertController.addAction(cancelAction) alertController.addAction(okAction) self.present(alertController, animated: true, completion: nil) // // let remindData = BFBaseModel() // remindData.summary = "合成的视频尚未保存到相册" // let alertV = BFRemindView(frame: view.bounds) // alertV.isBanned = true // alertV.confirmBtn.setTitle("不保存", for: .normal) // alertV.cancelBtn.setTitle("确认保存", for: .normal) // alertV.remindData = remindData // alertV.remindBlock = { [weak self] item, _ in // guard let wself = self else { // return // } // if item.tag == 1 { // 确定返回到上一层 // if wself.hasExportOnly { // PHPhotoLibrary.shared().performChanges { // PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: wself.saveOnlyUlr) // } completionHandler: { _, _ in // } // } // if wself.hasExportAll { // PHPhotoLibrary.shared().performChanges { // PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: wself.saveAllUlr) // } completionHandler: { _, _ in // } // } // } // // wself.export.cancelExport() // wself.navigationController?.popToRootViewController(animated: true) // } // UIApplication.shared.keyWindow?.addSubview(alertV) } else { export.cancelExport() navigationController?.popToRootViewController(animated: true) } } @objc func play(sender: UIButton) { if isExporting { avplayer.pause() return } if avplayer.currentItem != nil { if avplayer.timeControlStatus == .playing || sender.isSelected { avplayer.pause() } else if avplayer.timeControlStatus == .paused { avplayer.play() } } } func whetherCancelExport(msg:String = "savemode_changes2".BFLocale, comfirm: (() -> Void)?) { let alertController = UIAlertController(title: msg, message: "", preferredStyle: .alert) let cancelAction = UIAlertAction(title: "option_cancel".BFLocale, style: .default, handler: nil) let okAction = UIAlertAction(title: "option_ok".BFLocale, style: .default) {[weak self] action in guard let wself = self else { return } wself.export.cancelExport() comfirm?() } alertController.addAction(cancelAction) alertController.addAction(okAction) self.present(alertController, animated: true, completion: nil) // let remindData = BFBaseModel() // remindData.summary = "正在合成中,是否取消?" // let alertV = BFRemindView(frame: view.bounds) // alertV.isBanned = true // alertV.confirmBtn.setTitle("继续合成", for: .normal) // alertV.cancelBtn.setTitle("取消合成", for: .normal) // alertV.remindData = remindData // alertV.remindBlock = { [weak self] item, _ in // guard let wself = self else { // return // } // if item.tag == 1 { // 确定返回到上一层 // wself.export.cancelExport() // comfirm?() // } // } // UIApplication.shared.keyWindow?.addSubview(alertV) } //MARK: - Request func uploadVideo() { let uploadRequest = PQAliOssUtil.shared.allTasks[uploadData.videoBucketKey ?? ""] if uploadRequest != nil, "\(uploadRequest!.callbackParam["code"] ?? "0")" == "1" { return } // 更新进度 DispatchQueue.global().async { PQUploadViewModel.getStsToken { [weak self] response, _ in guard let wself = self else { return } if response == nil { BFLog(1, message: "token 获取失败") return } BFLog(1, message: "取我方服务器STS 返回数据 \(String(describing: response))") wself.multipartUpload(response: response) } } } func multipartUpload(response: [String: Any]?) { let FileName: String = "\(response?["FileName"] ?? "")" let uploadID: String = "\(response?["Upload"] ?? "")" uploadData.stsToken = response uploadData.videoBucketKey = FileName uploadData.uploadID = uploadID if uploadData.asset != nil && isValidURL(url: uploadData.localPath) { PQPHAssetVideoParaseUtil.exportPHAssetToMP4(phAsset: (uploadData.asset)!, isCancelCurrentExport: true) { [weak self] _, _, filePath, _ in if filePath != nil, (filePath?.count ?? 0) > 0 { self?.uploadData.localPath = filePath PQAliOssUtil.multipartUpload(localPath: filePath!, response: response, videoSource: "videoCompose") } } } else { PQAliOssUtil.multipartUpload(localPath: uploadData.localPath ?? "", response: response, videoSource: "videoCompose") } // PQAliOssUtil.shared.aliOssHander = { isMatarialUpload, materialType, _, code, objectkey, _, _, _, _, _, _, _, _, _ in // // } } } extension INVideoExportController { @objc func changeToOriginalFrame() { if !(sliderView?.isFullScreen ?? false) { isHiddenStatus = false // (0.0, 64.0, 375.0, 401.0) navHeadImageView?.isHidden = false backV.frame = CGRect(x: 0, y: navHeadImageView?.frame.maxY ?? 0, width: view.width, height: bottomView.frame.minY - (navHeadImageView?.frame.maxY ?? 0)) let width = backV.height * (cScreenWidth / cScreenHeigth) playerLayer.frame = CGRect(x: (backV.width - width)/2, y: 0, width: width, height: backV.height) // playerLayer.frame = CGRect(x: 0, y: 0, width: view.width, height: bottomView.frame.minY - (navHeadImageView?.frame.maxY ?? 0)) sliderView?.frame = CGRect(x: 0, y: backV.frame.height - 60, width: view.frame.width, height: 50) UIView.animate(withDuration: 0.2, animations: { [weak self] in self?.changeOrientation(orientation: .portrait) self?.backV.center = CGPoint(x: (self?.backV.width ?? 0) / 2, y: (self?.backV.height ?? 0) / 2 + (self?.navHeadImageView?.frame.maxY ?? 0)) }) { [weak self] _ in } } } func changeToFullScreen() { if sliderView?.isFullScreen ?? false { isHiddenStatus = true navHeadImageView?.isHidden = true backV.frame = CGRect(x: 0, y: 0, width: view.frame.height, height: view.frame.width) let width = view.width * (cScreenWidth / cScreenHeigth) playerLayer.frame = CGRect(x: (view.height - width)/2, y: 0, width: width, height: backV.width) // playerLayer.frame = backV.bounds sliderView?.frame = CGRect(x: 0, y: backV.frame.height - 60, width: backV.frame.width, height: 50) UIView.animate(withDuration: 0.2, animations: { [weak self] in let orientation = UIDevice.current.orientation if orientation == .landscapeRight { self?.changeOrientation(orientation: .landscapeLeft) } else { self?.changeOrientation(orientation: .landscapeRight) } self?.backV.center = CGPoint(x: (self?.view.frame.width ?? 0) / 2, y: (self?.view.frame.height ?? 0) / 2) }) { [weak self] _ in } } } func changeOrientation(orientation: UIInterfaceOrientation) { UIView.animate(withDuration: 0.2, animations: { [weak self] in self?.backV.transform = self?.transformRotation(orientation: orientation) as! CGAffineTransform }) { [weak self] _ in } } @objc func transformRotation(orientation: UIInterfaceOrientation) -> CGAffineTransform { if orientation == .portrait { return .identity } else if orientation == .landscapeLeft { return CGAffineTransform(rotationAngle: -CGFloat.pi / 2) } else if orientation == .landscapeRight { return CGAffineTransform(rotationAngle: CGFloat.pi / 2) } return .identity } }