12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022 |
- //
- // PQStuckPointEditerController.swift
- // PQSpeed
- //
- // Created by ak on 2021/4/26.
- // Copyright © 2021 BytesFlow. All rights reserved.
- // 功能:卡点音乐编辑界面
- // 创建不同玩法的类型
- enum createStickersModel {
- case createStickersModelPoint // 卡点
- case createStickersModelSpeed // 快慢速
- }
- import BFCommonKit
- import Foundation
- import ObjectMapper
- import Photos
- import RealmSwift
- import UIKit
- class PQStuckPointEditerController: PQBaseViewController {
- // 是否导出视频成功
- var isExportVideosSuccess: Bool = false
- // 是否请求卡点数据成功
- var isStuckPointDataSuccess: Bool = false
- // 是否同步音乐成功
- var isSynchroMusicInfoSuccess: Bool = false
- /// 当前所有的filter
- var filters: Array = Array<ImageProcessingOperation>.init()
- // 选中的总时长
- var selectedTotalDuration: Float64 = 0
- // 选择的总数
- var selectedDataCount: Int = 0
- // 选择的图片总数
- var selectedImageDataCount: Int = 0
- // 选中的素材数据
- var selectedPhotoData: [PHAsset]? {
- didSet {
- if selectedPhotoData != nil, (selectedPhotoData?.count ?? 0) > 0 {
- selectedMetarialData = Array<PQEditVisionTrackMaterialsModel>.init()
- selectedPhotoData?.forEach { phAsset in
- let metarialData = PQEditVisionTrackMaterialsModel()
- metarialData.asset = phAsset
- metarialData.width = Float(phAsset.pixelWidth)
- metarialData.itemWidth = Float(phAsset.pixelWidth)
- metarialData.height = Float(phAsset.pixelHeight)
- metarialData.itemHeight = Float(phAsset.pixelHeight)
- if phAsset.mediaType == .image {
- metarialData.type = "image"
- } else if phAsset.mediaType == .video {
- metarialData.type = "video"
- metarialData.duration = Float64(phAsset.duration)
- }
- metarialData.canvasFillType = phAsset.canvasFillType ?? ""
- metarialData.locationPath = phAsset.localPath ?? ""
- metarialData.selectedIndex = phAsset.selectedIndex ?? 1
- metarialData.originalData = phAsset.originalData
- metarialData.coverImageUI = phAsset.image
- selectedMetarialData?.append(metarialData)
- }
- }
- }
- }
- var selectedMetarialData: [PQEditVisionTrackMaterialsModel]?
- // 选中的音乐数据
- var stuckPointMusicData: PQVoiceModel?
- // 保存所有段的所有贴纸,音频信息,用于播放器的渲染使用
- var projectModel: PQEditProjectModel = PQEditProjectModel()
- // 从草稿箱进入的项目数据
- var draftProjectModel: PQEditProjectModel?
- var mStickers: [PQEditVisionTrackMaterialsModel]?
- // 播放器的开始和结束时间,1,刚进界面使用推荐的开始结束时间,2,用户修改起结点时修改
- var playeTimeRange: CMTimeRange = CMTimeRange()
- // add by ak 是否是再创作模式
- var isReCreate: Bool = false
- // 下一步
- lazy var nextBtn: UIButton = {
- let nextBtn = UIButton(type: .custom)
- nextBtn.frame = CGRect(x: cScreenWidth - 16 - cDefaultMargin * 6, y: cDevice_iPhoneStatusBarHei + (cDevice_iPhoneNavBarHei - cDefaultMargin * 3) / 2, width: cDefaultMargin * 6, height: cDefaultMargin * 3)
- nextBtn.setTitle("合成", for: .normal)
- nextBtn.titleLabel?.font = UIFont.systemFont(ofSize: 15, weight: .medium)
- nextBtn.addTarget(self, action: #selector(nextBtnClick(sender:)), for: .touchUpInside)
- nextBtn.backgroundColor = UIColor.hexColor(hexadecimal: PQBFConfig.shared.styleColor.rawValue)
- nextBtn.setTitleColor(UIColor.hexColor(hexadecimal: "#FFFFFF"), for: .normal)
- nextBtn.uxy_acceptEventInterval = 0.5
- nextBtn.addCorner(corner: 3)
- return nextBtn
- }()
- // 播放器显示 view
- lazy var playerView: PQGPUImagePlayerView = {
- let playerHeight = cScreenWidth
- let playerView = PQGPUImagePlayerView(frame: CGRect(x: 0, y: navHeadImageView?.frame.maxY ?? 0, width: playerHeight, height: playerHeight))
- playerView.backgroundColor = PQBFConfig.shared.styleBackGroundColor
- playerView.isShowLine = false
- playerView.showGaussianBlur = true
- playerView.playerEmptyView.isHidden = true
- return playerView
- }()
- /// 节奏选择视图
- lazy var sustomSwitchView: PQCustomSwitchView = {
- let sustomSwitchView = PQCustomSwitchView(frame: CGRect(x: (view.frame.width - cDefaultMargin * 28) / 2, y: view.frame.height - cSafeAreaHeight - cDefaultMargin * 3 - cDefaultMargin * 3, width: cDefaultMargin * 28, height: 35), titles: ["快节奏", "适中", "慢节奏"], defaultIndex: stuckPointMusicData?.speed ?? 2)
- sustomSwitchView.switchChangeHandle = { [weak self] sender in
- // 改变速率
- self?.stuckPointMusicData?.speed = sender.tag
- self?.projectModel.sData?.getBGMSession()?.sectionTimeline?.audioTrack?.audioTrackMaterials.first?.bgmInfo?.rhythmMusicSpeed = sender.tag
- // 播放前先暂停
- // self?.playerView.stop()
- // 开始播放
- self?.settingPlayerView()
- // 点击上报:选择节奏
- PQEventTrackViewModel.baseReportUpload(businessType: .bt_buttonClick, objectType: .ot_click_selectRhythm, pageSource: .sp_stuck_previewSyncedUp, extParams: ["rhythmNumber": sender.tag], remindmsg: "点击上报:选择节奏")
- }
- return sustomSwitchView
- }()
- /// 裁剪视图
- lazy var stuckPointCuttingView: PQStuckPointCuttingView = {
- let stuckPointCuttingView = PQStuckPointCuttingView(frame: CGRect(x: 0, y: sustomSwitchView.frame.minY - cDefaultMargin * 14 - cDefaultMargin * 2, width: view.frame.width, height: cDefaultMargin * 14), duration: CGFloat(Float(stuckPointMusicData?.duration ?? "0") ?? 0), startTime: CGFloat(stuckPointMusicData?.startTime ?? 0), endTime: CGFloat(stuckPointMusicData?.endTime ?? 0))
- /// 裁剪进度回调
- stuckPointCuttingView.videoRangeDidChanged = { [weak self] startTime, endTime in
- BFLog(message: "裁剪返回--startTime = \(startTime),endTime = \(endTime)")
- }
- /// 播放进度回调
- stuckPointCuttingView.videoProgressDidChanged = { [weak self] progress in
- BFLog(message: "进度更新返回--progress = \(progress) \(String(describing: self?.playerView.mPlayeTimeRange))")
- }
- /// 拖缀结束的回调 type - 1-拖动左边裁剪结束 2--拖动右边裁剪结束 3-进度条拖动结束 4-滑动结束
- stuckPointCuttingView.videoDidEndDragging = { [weak self] type, startTime, endTime, progress in
- BFLog(message: "拖拽结束返回--type = \(type),startTime = \(startTime),endTime = \(endTime),progress = \(progress)")
- self?.playerView.pause()
- // 修改最新值
- self?.stuckPointMusicData?.startTime = Float64(startTime)
- self?.stuckPointMusicData?.endTime = Float64(endTime)
- // 红的指针完成
- if type == 3 {
- if CMTimeGetSeconds(self?.playerView.mPlayeTimeRange?.end ?? .zero) == 0 {
- BFLog(message: "mPlayeTimeRange is error")
- return
- }
- let newBeginSconds = (Double(startTime) + (Double(endTime) - Double(startTime)) * Double(progress)) * 600
- BFLog(message: " newBeginSconds is \(newBeginSconds)")
- let seekTimeRange: CMTimeRange = CMTimeRange(start: CMTime(value: CMTimeValue(Int64(newBeginSconds)), timescale: 600), end:
- CMTime(value: CMTimeValue(Int64(endTime * 600)), timescale: 600))
- BFLog(message: "修改的开始 \(CMTimeGetSeconds(seekTimeRange.start)) 结束 \(CMTimeGetSeconds(seekTimeRange.end))")
- // 重新设置有效缓存
- self?.playerView.configCache(beginTime: CMTimeGetSeconds(seekTimeRange.start))
- self?.playerView.play(pauseFirstFrame: false, playeTimeRange: seekTimeRange)
- } else {
- // 更改素材开始时间及结束时间
- self?.projectModel.sData?.getBGMSession()?.sectionTimeline?.audioTrack?.audioTrackMaterials.first?.out = Float64(endTime)
- self?.projectModel.sData?.getBGMSession()?.sectionTimeline?.audioTrack?.audioTrackMaterials.first?.model_in = Float64(startTime)
- self?.projectModel.sData?.getBGMSession()?.sectionTimeline?.audioTrack?.audioTrackMaterials.first?.timelineIn = Float64(startTime)
- self?.projectModel.sData?.getBGMSession()?.sectionTimeline?.audioTrack?.audioTrackMaterials.first?.timelineOut = Float64(endTime)
- BFLog(message: "调整后总时长: \(endTime - startTime) startTime:\(startTime) endTime:\(endTime)")
- // 初始化音频的开始和结束时间
- self?.playeTimeRange = CMTimeRange(start: CMTimeMakeWithSeconds(Float64(startTime), preferredTimescale: BASE_FILTER_TIMESCALE), end: CMTimeMakeWithSeconds(Float64(endTime), preferredTimescale: BASE_FILTER_TIMESCALE))
- DispatchQueue.global().async { // 并行、异步
- let beginTime: TimeInterval = Date().timeIntervalSince1970
- self?.mStickers = self?.createStickers(sections: self?.projectModel.sData?.sections ?? List(), inputSize: CGSize(width: CGFloat(self?.projectModel.sData?.videoMetaData?.videoWidth ?? 0), height: CGFloat(self?.projectModel.sData?.videoMetaData?.videoHeight ?? 0)))
- self?.playerView.mStickers = self?.mStickers
- DispatchQueue.main.async { // 串行、异步
- var endTime: TimeInterval = Date().timeIntervalSince1970
- BFLog(message: "endTime is endTimeendTime \(endTime = beginTime)")
- self?.playerView.play(pauseFirstFrame: false, playeTimeRange: self!.playeTimeRange)
- }
- }
- }
- // 埋点上报
- if type == 1 || type == 2 {
- // 点击上报:拖动拖拽条(左/右部分)
- PQEventTrackViewModel.baseReportUpload(businessType: .bt_buttonClick, objectType: type == 1 ? .ot_click_dragFront : .ot_click_dragBehind, pageSource: .sp_stuck_previewSyncedUp, extParams: ["targetTime": type == 1 ? startTime * 1000 : endTime * 1000], remindmsg: "点击上报:拖动拖拽条(左/右部分)")
- }
- }
- return stuckPointCuttingView
- }()
- /// 卡点时长显示视图
- lazy var timeRemindLab: UILabel = {
- let timeRemindLab = UILabel(frame: CGRect(x: 0, y: stuckPointCuttingView.frame.minY - cDefaultMargin * 4 - cDefaultMargin * 3, width: view.frame.width, height: cDefaultMargin * 4))
- timeRemindLab.backgroundColor = UIColor.hexColor(hexadecimal: "#262626")
- timeRemindLab.textAlignment = .center
- timeRemindLab.font = UIFont.systemFont(ofSize: 12)
- timeRemindLab.textColor = UIColor.hexColor(hexadecimal: "#999999")
- let total: Float64 = ((stuckPointMusicData?.endTime ?? Float64(stuckPointMusicData?.duration ?? "0") ?? 0) - (stuckPointMusicData?.startTime ?? 0))
- timeRemindLab.text = "现卡点时长\(total.formatDurationToHMS()) / 原视频总时长\(selectedTotalDuration.formatDurationToHMS())"
- return timeRemindLab
- }()
- /// 音乐标题
- lazy var musicNameView: UIView = {
- let musicNameView = UIView()
- musicNameView.addSubview(musicNameLab)
- let nameWidth: CGFloat = musicNameLab.frame.width + (25 + cDefaultMargin * 3)
- musicNameView.frame = CGRect(x: (view.frame.width - nameWidth) / 2, y: cDevice_iPhoneStatusBarHei + (cDevice_iPhoneNavBarHei - cDefaultMargin * 3) / 2, width: nameWidth, height: cDefaultMargin * 3)
- // musicNameView.backgroundColor = UIColor.hexColor(hexadecimal: "#333333")
- musicNameView.addCorner(corner: musicNameView.frame.height / 2)
- let musicImageView = UIImageView()
- musicImageView.tintColor = PQBFConfig.shared.styleTitleColor
- musicImageView.image = UIImage.moduleImage(named: "stuckPoint_reCreate_music", moduleName: "BFFramework", isAssets: false)?.withRenderingMode(.alwaysTemplate)
- musicImageView.frame = CGRect(x: musicNameView.frame.height / 2 - 5, y: (musicNameView.frame.height - 22) / 2, width: 22, height: 22)
- musicNameView.addSubview(musicImageView)
- musicNameLab.frame.origin.x = musicImageView.frame.maxX + 5
- let ges = UITapGestureRecognizer(target: self, action: #selector(musicNameClick))
- musicNameView.addGestureRecognizer(ges)
- return musicNameView
- }()
- /// 音乐歌曲名称
- lazy var musicNameLab: LMJHorizontalScrollText = {
- let nameWidth: CGFloat = sizeWithText(text: "\(stuckPointMusicData?.musicName ?? "")", font: UIFont.systemFont(ofSize: 13), size: CGSize(width: view.frame.width - ((cDefaultMargin * 6 + 16 * 2) * 2) - (25 + cDefaultMargin * 3), height: cDefaultMargin * 3)).width
- let musicNameLab = LMJHorizontalScrollText(frame: CGRect(x: 0, y: 0, width: nameWidth < cDefaultMargin * 4 ? cDefaultMargin * 4 : nameWidth, height: cDefaultMargin * 3))
- musicNameLab.textColor = PQBFConfig.shared.styleTitleColor
- musicNameLab.textFont = UIFont.systemFont(ofSize: 13)
- musicNameLab.speed = 0.03
- musicNameLab.moveDirection = LMJTextScrollMoveLeft
- musicNameLab.moveMode = LMJTextScrollContinuous
- if nameWidth < cDefaultMargin * 4 {
- musicNameLab.text = " \(stuckPointMusicData?.musicName ?? "") "
- } else {
- musicNameLab.text = " \(stuckPointMusicData?.musicName ?? "") "
- }
- return musicNameLab
- }()
- /// 同步进度显示
- lazy var synchroMarskView: PQStuckPointLoadingView = {
- var synchroMarskView = PQStuckPointLoadingView(frame: CGRect(x: 0, y: 0, width: cScreenWidth, height: cScreenHeigth))
- synchroMarskView.cancelHandle = { [weak self] _ in
- self?.navigationController?.popViewController(animated: true)
- }
- return synchroMarskView
- }()
- override func viewWillAppear(_ animated: Bool) {
- super.viewDidAppear(animated)
- lineView?.isHidden = true
- DispatchQueue.main.async {
- UIApplication.shared.isIdleTimerDisabled = true
- }
- musicNameLab.move()
- PQNotification.addObserver(self, selector: #selector(enterBackground), name: UIApplication.didEnterBackgroundNotification, object: nil)
- }
- @objc func enterBackground() {
- BFLog(message: "进入到后台")
- // 取消导出
- playerView.pause()
- }
- override func backBtnClick() {
- super.backBtnClick()
- playerView.pause()
- // 点击上报:返回按钮
- PQEventTrackViewModel.baseReportUpload(businessType: .bt_buttonClick, objectType: .ot_click_back, pageSource: .sp_stuck_previewSyncedUp, extParams: nil, remindmsg: "卡点视频数据上报-(点击上报:返回按钮)")
- }
- @objc func musicNameClick() {
- // let musicVc = navigationController?.viewControllers.first(where: { vc in
- // vc is PQStuckPointMusicController
- // })
- // if musicVc != nil {
- // navigationController?.popToViewController(musicVc!, animated: true)
- // }
- }
- override func viewWillDisappear(_ animated: Bool) {
- super.viewWillDisappear(animated)
- DispatchQueue.main.async {
- UIApplication.shared.isIdleTimerDisabled = false
- }
- musicNameLab.stop()
- playerView.pause()
- }
- override func viewDidLoad() {
- super.viewDidLoad()
- leftButton(image: UIImage(named: "icon_detail_back"), tintColor: PQBFConfig.shared.styleTitleColor)
- navHeadImageView?.addSubview(nextBtn)
- navHeadImageView?.addSubview(musicNameView)
- // 添加子视图
- addSubViews()
- // 导出相册视频
- exportPhotoData()
- // 同步音乐数据
- synchroMusicInfoData()
- // 曝光上报:预览页面曝光上报
- PQEventTrackViewModel.baseReportUpload(businessType: .bt_windowView, objectType: .ot_view_previewSyncedUp, pageSource: .sp_stuck_previewSyncedUp, extParams: nil, remindmsg: "卡点视频数据上报-(曝光上报:预览页面曝光上报)")
- }
- /// 添加子视图
- /// - Returns: <#description#>
- func addSubViews() {
- if (stuckPointMusicData?.rhythmSdata.count ?? 0) <= 0 {
- return
- }
- view.addSubview(playerView)
- view.addSubview(sustomSwitchView)
- view.addSubview(stuckPointCuttingView)
- // view.addSubview(timeRemindLab)
- // 添加一个背景区分不同色值
- let backView: UIView = UIView()
- backView.backgroundColor = PQBFConfig.shared.styleBackGroundColor
- view.insertSubview(backView, aboveSubview: navHeadImageView!)
- backView.frame = CGRect(x: 0, y: navHeadImageView?.frame.height ?? 0, width: cScreenWidth, height: (stuckPointCuttingView.frame.minY - cDefaultMargin * 3) - (navHeadImageView?.frame.height ?? 0))
- }
- @objc func nextBtnClick(sender _: UIButton) {
- BFLog(message: "去发布")
- playerView.pause()
- // 使用深 copy
- let json = projectModel.toJSONString(prettyPrint: false)
- if json == nil {
- BFLog(message: "数据转换有问题 跳转")
- return
- }
- let tempModel: PQEditProjectModel? = Mapper<PQEditProjectModel>().map(JSONString: json!)
- let materialVC: PQStuckPointMaterialController? = navigationController?.viewControllers.first(where: { (vc) -> Bool in
- vc is PQStuckPointMaterialController
- }) as? PQStuckPointMaterialController
- if materialVC != nil, materialVC?.isToPublicHandle != nil {
- materialVC?.isToPublicHandle!(isReCreate, selectedTotalDuration, selectedDataCount, selectedImageDataCount, mStickers, stuckPointMusicData, tempModel)
- } else {
- let videoExporter = PQStuckPointPublicController()
- videoExporter.isReCreate = isReCreate
- videoExporter.selectedTotalDuration = selectedTotalDuration
- videoExporter.selectedDataCount = selectedDataCount
- videoExporter.selectedImageDataCount = selectedImageDataCount
- videoExporter.mStickers = mStickers
- videoExporter.audioMixModel = stuckPointMusicData
- videoExporter.editProjectModel = tempModel
- navigationController?.pushViewController(videoExporter, animated: true)
- }
- // 点击上报:去合成
- PQEventTrackViewModel.baseReportUpload(businessType: .bt_buttonClick, objectType: .ot_click_commit, pageSource: .sp_stuck_previewSyncedUp, extParams: ["musicName": stuckPointMusicData?.musicName ?? "", "musicId": stuckPointMusicData?.musicId ?? "", "rhythmNumber": stuckPointMusicData?.speed ?? 2, "duration": ((stuckPointMusicData?.endTime ?? 0) - (stuckPointMusicData?.startTime ?? 0)) * 1000], remindmsg: "点击上报:去合成")
- }
- // MARK: - 播放器相关操作
- /// seek 播放器
- /// - Parameter playeTimeRange: 开始和结束时间
- func seekPlayer(playeTimeRange: CMTimeRange) {
- playerView.setEnableSeek(isSeek: true)
- playerView.play(pauseFirstFrame: false, playeTimeRange: playeTimeRange)
- }
- /// 通过传入的 selectedPhotoData 、 stuckPointMusicData 创建 projectModel 模型 后面都使用 projectModel 参数
- func createPorjectData() {
- // 1,添加选择的视觉素材
- let section: PQEditSectionModel = PQEditSectionModel()
- selectedMetarialData?.forEach { model in
- let json = model.toJSONString(prettyPrint: false)
- if json == nil {
- BFLog(message: "数据转换有问题 跳转")
- return
- }
- let tempModel: PQEditVisionTrackMaterialsModel = Mapper<PQEditVisionTrackMaterialsModel>().map(JSONString: json!)!
- section.sectionTimeline?.visionTrack?.visionTrackMaterials.append(tempModel)
- }
- projectModel.sData?.sections.append(section)
- // 2,添加背景音乐
- projectModel.sData?.addBGM(audioMix: stuckPointMusicData!)
- }
- // 设置播放器
- func settingPlayerView() {
- // 1,设置播放器的显示区域 和画布大小
- // - 按第一个素材尺寸自适应
- let playerShowHeight = (stuckPointCuttingView.frame.minY - cDefaultMargin * 3) - (navHeadImageView?.frame.maxY ?? 0)
- var showRect: CGRect = PQPlayerViewModel.getShowCanvasRect(editProjectModel: projectModel, showType: 1, playerViewHeight: playerShowHeight)
- if showRect.size.width == showRect.size.height {
- if cScreenWidth > playerShowHeight {
- showRect.origin.x = (cScreenWidth - playerShowHeight) / 2
- showRect.size.width = playerShowHeight
- showRect.size.height = playerShowHeight
- } else {
- showRect.origin.x = 0
- showRect.size.width = cScreenWidth
- showRect.size.height = cScreenWidth
- }
- }
- showRect.origin.y = (playerShowHeight - showRect.size.height) / 2.0 + (navHeadImageView?.frame.maxY ?? 0)
- if showRect.size.width != 0, showRect.size.height != 0 {
- playerView.resetCanvasFrame(frame: showRect)
- }
- var firstModel: PQEditVisionTrackMaterialsModel?
- for part in projectModel.sData!.sections {
- if part.sectionTimeline?.visionTrack?.getEnableVisionTrackMaterials().count ?? 0 > 0 {
- firstModel = part.sectionTimeline?.visionTrack?.getEnableVisionTrackMaterials().first
- break
- }
- }
- var videoSize: CGSize = CGSize(width: Int(firstModel?.width ?? 0), height: Int(firstModel?.height ?? 0))
- var minSlider = min(videoSize.width, videoSize.height)
- var maxSlider = max(videoSize.width, videoSize.height)
- let ration = 1080 / minSlider
- minSlider = minSlider * ration
- maxSlider = maxSlider * ration
- if videoSize.width > videoSize.height { // 宽屏
- videoSize = CGSize(width: maxSlider, height: minSlider)
- } else {
- videoSize = CGSize(width: minSlider, height: maxSlider)
- }
- let maxValue = max(videoSize.width, videoSize.height ?? 0)
- if maxValue > 1920 {
- let maxRation = 1920 / maxValue
- videoSize = CGSize(width: videoSize.width * CGFloat(maxRation), height: videoSize.height * CGFloat(maxRation))
- BFLog(message: "最长边已经超过 1920 要等比缩小 缩放后\(videoSize)")
- }
- if (Int(videoSize.width) % 2) != 0 {
- videoSize.width = videoSize.width - 1
- }
- if (Int(videoSize.height) % 2) != 0 {
- videoSize.height = videoSize.height - 1
- }
- projectModel.sData?.videoMetaData?.videoWidth = Int(videoSize.width)
- projectModel.sData?.videoMetaData?.videoHeight = Int(videoSize.height)
- // 2,创建滤镜
- let beginTime: TimeInterval = Date().timeIntervalSince1970
- mStickers = createStickers(sections: projectModel.sData?.sections ?? List(), inputSize: CGSize(width: CGFloat(projectModel.sData?.videoMetaData?.videoWidth ?? 0), height: CGFloat(projectModel.sData?.videoMetaData?.videoHeight ?? 0)), model: .createStickersModelPoint)
- playerView.mStickers = mStickers
- let end: TimeInterval = Date().timeIntervalSince1970
- BFLog(message: "createStickers tiskskskskme \(end - beginTime)")
- // 3,设置音频
- let audioPath = stuckPointMusicData?.localPath ?? ""
- BFLog(message: "初始化音频播放器的音频地址为:\(audioPath)")
- playerView.stop()
- // 这里的测试这个音乐播放有问题
- // self.playerView.updateAsset(URL(fileURLWithPath: "63930549652d74e477141e3b79c8d29a9ef8af81625053214516.mp3", relativeTo:Bundle.main.resourceURL!), videoComposition: nil, audioMixModel: nil)
- playerView.updateAsset(URL(fileURLWithPath: documensDirectory + audioPath), videoComposition: nil, audioMixModel: nil)
- let end2: TimeInterval = Date().timeIntervalSince1970
- BFLog(message: "updateAsset tiskskskskme \(end2 - end)")
- // 4, 设置播放器的输出画布大小
- playerView.movie?.mShowVidoSize = CGSize(width: CGFloat(projectModel.sData?.videoMetaData?.videoWidth ?? 0), height: CGFloat(projectModel.sData?.videoMetaData?.videoHeight ?? 0))
- // 5,开始播放
- playerView.isLoop = false
- playerView.showProgressLab = true
- // 初始化音频的开始和结束时间
- BFLog(message: "播放的器 开始\(String(describing: CMTimeGetSeconds(playeTimeRange.start))) 结束 \(String(describing: CMTimeGetSeconds(playeTimeRange.end)))")
- let end3: TimeInterval = Date().timeIntervalSince1970
- playerView.play(pauseFirstFrame: false, playeTimeRange: CMTimeRange(start: playeTimeRange.start, end: playeTimeRange.end))
- let end4: TimeInterval = Date().timeIntervalSince1970
- BFLog(message: " playerView.play tiskskskskme \(end4 - end3)")
- // 6,进度回调
- playerView.progress = { [weak self] currentTime, tatolTime, _ in
- // 更新进度
- let progress = (currentTime - CMTimeGetSeconds(self?.playeTimeRange.start ?? .zero)) / CMTimeGetSeconds(self?.playeTimeRange.duration ?? .zero)
- BFLog(message: "\(currentTime) \(tatolTime) 显示播放器进度为: \(progress)")
- self?.stuckPointCuttingView.videoCropView.updateProgress(progress: CGFloat(progress))
- if self?.synchroMarskView.superview != nil {
- self?.synchroMarskView.removeMarskView()
- }
- }
- }
- deinit {
- BFLog(message: "卡点视频预览界面销毁")
- musicNameLab.stop()
- playerView.pause()
- // 取消所有的导出
- PQSingletoMemoryUtil.shared.allExportSession.forEach { _, exportSession in
- exportSession.cancelExport()
- }
- }
- }
- // MARK: - 视频渲染相关逻辑方法
- extension PQStuckPointEditerController {
- /// 分割视频 这里只设置视频类型的 in 和 out 并不设置显示的开始和结束时间 mp4 ,png ,png ,mp4
- /// - Parameter section: 当前段
- /// - Parameter stuckPoints: 用户选择的,或推荐的卡点数
- /// - Returns: 返回分割后的所有 stickers 和卡点数是一致的
- func clipVideoMerage(section: PQEditSectionModel, stuckPoints: [Float]) -> [PQEditVisionTrackMaterialsModel] {
- var stickers: Array = Array<PQEditVisionTrackMaterialsModel>.init()
- // 第二种情况:有视频要进行分割
- /*
- 1, 确定每个视频素材需要切的段数p
- 2, 将所有视频时长相加,得到总视频素材时长L = l1 + l2 + ... + ln
- 3, 视频素材a1需要切分的个数clipNum = max (round (kongduan * a1 / L) , 1)
- */
- // 要补的空位数
- let kongduan: Int = Int(stuckPoints.count) - Int(section.sectionTimeline!.visionTrack?.getEnableVisionTrackMaterials().count ?? 0)
- // 所有视频总时长
- var videoTotalDuration: Float64 = 0.0
- for video in section.sectionTimeline!.visionTrack!.getEnableVisionTrackMaterials(type: "video") {
- let asset: AVURLAsset = AVURLAsset(url: URL(fileURLWithPath: documensDirectory + video.locationPath), options: nil)
- videoTotalDuration = videoTotalDuration + Float64(CMTimeGetSeconds(asset.duration))
- }
- if videoTotalDuration == 0 {
- BFLog(message: "视频总时长出现错误!!!!这里应该有视频素材的")
- return stickers
- }
- for sticker in section.sectionTimeline!.visionTrack!.getEnableVisionTrackMaterials() {
- if sticker.type == StickerType.VIDEO.rawValue {
- let asset: AVURLAsset = AVURLAsset(url: URL(fileURLWithPath: documensDirectory + sticker.locationPath), options: nil)
- // 要分割的段落
- let clipNum = Int(max(round(Double(kongduan) * CMTimeGetSeconds(asset.duration) / videoTotalDuration), 1))
- sticker.duration = CMTimeGetSeconds(asset.duration)
- BFLog(message: "单个视频\(sticker.locationPath)时长::\(CMTimeGetSeconds(asset.duration)) ,clipNum is:\(clipNum)")
- for clipindex in 0 ... clipNum - 1 {
- // deep copy sticker model 防止只有一个对象
- let stickerjson = sticker.toJSONString(prettyPrint: false)
- let deepCopySticker = Mapper<PQEditVisionTrackMaterialsModel>().map(JSONString: stickerjson!)
- // 设置循环模式和适配模式
- deepCopySticker?.generateDefaultValues()
- deepCopySticker?.model_in = clipindex == 0 ? 0 : CMTimeGetSeconds(asset.duration) / Double(clipNum) * Double(clipindex)
- deepCopySticker?.out = (deepCopySticker?.model_in ?? 0) + CMTimeGetSeconds(asset.duration) / Double(clipNum)
- if (deepCopySticker?.model_in ?? 0) >= CMTimeGetSeconds(asset.duration) || (deepCopySticker?.out ?? 0) >= CMTimeGetSeconds(asset.duration) {
- deepCopySticker?.model_in = CMTimeGetSeconds(asset.duration) - CMTimeGetSeconds(asset.duration) / Double(clipNum)
- deepCopySticker?.out = CMTimeGetSeconds(asset.duration)
- }
- BFLog(message: " crilp is in \(deepCopySticker?.model_in ?? 0) out \(deepCopySticker?.out ?? 0) 总时长\(CMTimeGetSeconds(asset.duration))")
- if deepCopySticker != nil {
- stickers.append(deepCopySticker!)
- }
- }
- } else if sticker.type == StickerType.IMAGE.rawValue {
- sticker.generateDefaultValues()
- stickers.append(sticker)
- }
- }
- return stickers
- }
- /// 创建sticker
- /// - Parameters:
- /// - sections: 项目所有段落数据信息
- /// - inputSize: 画布大小
- /// - Returns: filters 数据 播放器可直接使用
- func createStickers(sections: List<PQEditSectionModel>, inputSize _: CGSize = .zero, model: createStickersModel = .createStickersModelPoint) -> [PQEditVisionTrackMaterialsModel] {
- // 保存滤镜对象数据
- var stickers: Array = Array<PQEditVisionTrackMaterialsModel>.init()
- if model == .createStickersModelPoint {
- for section in sections {
- if section.sectionType == "normal" {
- // 推荐卡点数
- var stuckPoints: Array = Array<Float>.init()
- var stuckPointsTemp = Array<Float>.init()
- for (index, dunshu) in stuckPointMusicData!.rhythmSdata[0].pointTimes.enumerated() {
- BFLog(message: "原所有卡点数:\(index) \(Float(dunshu) / Float(BASE_FILTER_TIMESCALE))")
- if Float64(dunshu) / Float64(BASE_FILTER_TIMESCALE) > CMTimeGetSeconds(playeTimeRange.start), Float64(dunshu) / Float64(BASE_FILTER_TIMESCALE) < CMTimeGetSeconds(playeTimeRange.end) {
- stuckPointsTemp.append(Float(dunshu) / Float(BASE_FILTER_TIMESCALE))
- }
- }
- /* 快慢速模式下取卡点
- - 快节奏为选中区域的所有点位,即0,1,2,3,4 5 6 7 8 9 10 ……
- - 适中为每两个点位取一个,即0,3,6,9 12
- - 慢节奏为每三个点位取一个,即0 5 10 15
- 慢节奏要做特殊处理
- 5d or L/1.23
- (*当输入素材为L ∈(0-10.5]s 时,判断与5d之间的关系,若L/1.2≥5d,则取5d;若L/1.2<5d,则取L/1.2)
- */
- // 跳跃卡点模式下根据不同速度 取卡点 1,2,3
- /*
- - 快节奏为选中区域的所有点位,即0,1,2,3,4……
- - 适中为每两个点位取一个,即0,2,4,6……
- - 慢节奏为每三个点位取一个,即0,3,6,9……
- */
- BFLog(message: "stuckPointMusicData?.speed is \(String(describing: stuckPointMusicData?.speed))")
- for (index, point) in stuckPointsTemp.enumerated() {
- if stuckPointMusicData?.speed == 1 {
- stuckPoints.append(Float(point))
- } else if stuckPointMusicData?.speed == 2 {
- if index % 2 == 0 {
- stuckPoints.append(point)
- }
- } else if stuckPointMusicData?.speed == 3 {
- if index % 3 == 0 {
- stuckPoints.append(point)
- }
- }
- }
- for point in stuckPoints {
- BFLog(message: "没有 start end 计算后的卡点数\(point)")
- }
- if stuckPoints.first != nil {
- stuckPoints.removeFirst()
- }
- if stuckPoints.last != nil {
- stuckPoints.removeLast()
- }
- // 开始时间是服务器返回, 结果时间根据策略计算的
- stuckPoints.insert(Float(CMTimeGetSeconds(playeTimeRange.start)), at: 0)
- stuckPoints.insert(Float(CMTimeGetSeconds(playeTimeRange.end)), at: stuckPoints.count)
- for point in stuckPoints {
- BFLog(message: "有 start end 计算后的卡点数\(point)")
- }
- BFLog(message: "stuckPoints count is \(stuckPoints.count)")
- // 当用户上传视觉素材个数大于等于音乐选择区域节拍分割个数时,无需进行视频分割,只显示卡点数-1 个素材
- if section.sectionTimeline!.visionTrack!.getEnableVisionTrackMaterials().count >= stuckPointMusicData!.rhythmSdata[0].pointTimes.count {
- for (index, sticker) in section.sectionTimeline!.visionTrack!.getEnableVisionTrackMaterials().enumerated() {
- if index == stuckPointMusicData!.rhythmSdata[0].pointTimes.count {
- BFLog(message: "到达卡点数量")
- break
- }
- BFLog(message: "创建 filter start :\(sticker.timelineIn) end :\(sticker.timelineOut) type is \(sticker.type) \(sticker.locationPath)")
- sticker.timelineIn = Float64("\(stuckPoints[index])") ?? 0.0
- sticker.timelineOut = Float64("\(stuckPoints[index + 1])") ?? 0.0
- BFLog(message: "卡点 间隔 \(sticker.timelineIn - sticker.timelineOut)")
- sticker.generateDefaultValues()
- stickers.append(sticker)
- }
- } else {
- // 卡点数 > 选择素材数
- // 第一种情况:全是图片,图片回环播放
- if section.sectionTimeline!.visionTrack!.getEnableVisionTrackMaterials(type: "video").count == 0, section.sectionTimeline!.visionTrack!.getEnableVisionTrackMaterials(type: "image").count > 0 {
- for (index, point) in stuckPoints.enumerated() {
- let sticker: PQEditVisionTrackMaterialsModel = section.sectionTimeline!.visionTrack!.getEnableVisionTrackMaterials()[index % section.sectionTimeline!.visionTrack!.getEnableVisionTrackMaterials().count]
- BFLog(message: "stickerlocationPath sticker : \(sticker.locationPath)")
- let stickerjson = sticker.toJSONString(prettyPrint: false)
- let deepCopySticker = Mapper<PQEditVisionTrackMaterialsModel>().map(JSONString: stickerjson!)
- if deepCopySticker!.type == StickerType.IMAGE.rawValue {
- if index + 1 < stuckPoints.count {
- deepCopySticker!.timelineIn = Float64("\(stuckPoints[index])") ?? 0.0
- deepCopySticker!.timelineOut = Float64("\(stuckPoints[index + 1])") ?? 0.0
- if deepCopySticker != nil {
- deepCopySticker?.generateDefaultValues()
- stickers.append(deepCopySticker!)
- }
- }
- }
- }
- } else {
- // 第二种情况:有视频要进行分割
- let clipFilters = clipVideoMerage(section: section, stuckPoints: stuckPoints)
- for (index, point) in stuckPoints.enumerated() {
- BFLog(message: "aaaaaindexindeindexxindexindexindex \(index) \(point)")
- if index + 1 < stuckPoints.count, index < clipFilters.count {
- BFLog(message: "bbbbbindexindeindexxindexindexindex \(index) \(point)")
- let sticker: PQEditVisionTrackMaterialsModel = clipFilters[index]
- sticker.timelineIn = Float64("\(stuckPoints[index])") ?? 0.0
- // TODO: 不是最好方案
- sticker.timelineOut = Float64("\(stuckPoints[index + 1])") ?? 0.0
- // 卡点的时间 > in out 值 这里就会出现鬼畜效果
- let timelineInterval = sticker.timelineOut - sticker.timelineIn
- let inOutInterval = sticker.out - sticker.model_in
- if timelineInterval > inOutInterval {
- BFLog(message: "实际要显示卡点时长\(timelineInterval) 素材裁剪时长:\(inOutInterval)")
- sticker.out = sticker.model_in + timelineInterval
- // 下面只是 LOG 方便查问题
- let stickerInOut = sticker.out - sticker.model_in
- let stickerTimelineInOut = sticker.timelineOut - sticker.timelineIn
- if stickerInOut != stickerTimelineInOut {
- BFLog(message: "sticker.timelineIn \(sticker.timelineIn) stickerTimelineInOut is\(stickerTimelineInOut) stickerInOut is\(stickerInOut) 相差\(stickerTimelineInOut - stickerInOut)")
- }
- }
- // out > 素材的总时长in out 进行前移操作
- let offsetAssetDuration = sticker.out - sticker.duration
- if offsetAssetDuration > 0 {
- sticker.model_in = sticker.model_in - offsetAssetDuration
- sticker.out = sticker.out - offsetAssetDuration
- }
- BFLog(message: "index is \(index)分割后 创建 filter timelineIn :\(sticker.timelineIn) timelineOut :\(sticker.timelineOut) in :\(sticker.model_in) out:\(sticker.out) type is \(sticker.type) 显示总时长为:\(sticker.timelineOut - sticker.timelineIn) 裁剪总时长\(sticker.out - sticker.model_in)")
- stickers.append(sticker)
- }
- }
- }
- }
- }
- }
- } else {
- for section in sections {
- if section.sectionType == "normal" {
- // 推荐卡点数
- var stuckPoints: Array = Array<Float>.init()
- var stuckPointsTemp = Array<Float>.init()
- for (index, dunshu) in stuckPointMusicData!.rhythmSdata[0].pointTimes.enumerated() {
- BFLog(message: "原所有卡点数:\(index) \(Float(dunshu) / Float(BASE_FILTER_TIMESCALE))")
- if Float64(dunshu) / Float64(BASE_FILTER_TIMESCALE) > CMTimeGetSeconds(playeTimeRange.start), Float64(dunshu) / Float64(BASE_FILTER_TIMESCALE) < CMTimeGetSeconds(playeTimeRange.end) {
- stuckPointsTemp.append(Float(dunshu) / Float(BASE_FILTER_TIMESCALE))
- }
- }
- // 根据不同速度 取卡点 1,2,3
- /*
- - 快节奏为选中区域的所有点位,即0,1,2,3,4……
- - 适中为每两个点位取一个,即0,2,4,6……
- - 慢节奏为每三个点位取一个,即0,3,6,9……
- */
- BFLog(message: "stuckPointMusicData?.speed is \(String(describing: stuckPointMusicData?.speed))")
- for (index, point) in stuckPointsTemp.enumerated() {
- if stuckPointMusicData?.speed == 1 {
- stuckPoints.append(Float(point))
- } else if stuckPointMusicData?.speed == 2 {
- if index % 2 == 0 {
- stuckPoints.append(point)
- }
- } else if stuckPointMusicData?.speed == 3 {
- if index % 3 == 0 {
- stuckPoints.append(point)
- }
- }
- }
- for point in stuckPoints {
- BFLog(message: "没有 start end 计算后的卡点数\(point)")
- }
- if stuckPoints.first != nil {
- stuckPoints.removeFirst()
- }
- if stuckPoints.last != nil {
- stuckPoints.removeLast()
- }
- // 开始时间是服务器返回, 结果时间根据策略计算的
- stuckPoints.insert(Float(CMTimeGetSeconds(playeTimeRange.start)), at: 0)
- stuckPoints.insert(Float(CMTimeGetSeconds(playeTimeRange.end)), at: stuckPoints.count)
- for point in stuckPoints {
- BFLog(message: "有 start end 计算后的卡点数\(point)")
- }
- BFLog(message: "stuckPoints count is \(stuckPoints.count)")
- // 当用户上传视觉素材个数大于等于音乐选择区域节拍分割个数时,无需进行视频分割,只显示卡点数-1 个素材
- if section.sectionTimeline!.visionTrack!.getEnableVisionTrackMaterials().count >= stuckPointMusicData!.rhythmSdata[0].pointTimes.count {
- for (index, sticker) in section.sectionTimeline!.visionTrack!.getEnableVisionTrackMaterials().enumerated() {
- if index == stuckPointMusicData!.rhythmSdata[0].pointTimes.count {
- BFLog(message: "到达卡点数量")
- break
- }
- BFLog(message: "创建 filter start :\(sticker.timelineIn) end :\(sticker.timelineOut) type is \(sticker.type) \(sticker.locationPath)")
- sticker.timelineIn = Float64("\(stuckPoints[index])") ?? 0.0
- sticker.timelineOut = Float64("\(stuckPoints[index + 1])") ?? 0.0
- BFLog(message: "卡点 间隔 \(sticker.timelineIn - sticker.timelineOut)")
- sticker.generateDefaultValues()
- stickers.append(sticker)
- }
- } else {
- // 卡点数 > 选择素材数
- // 第一种情况:全是图片,图片回环播放
- if section.sectionTimeline!.visionTrack!.getEnableVisionTrackMaterials(type: "video").count == 0, section.sectionTimeline!.visionTrack!.getEnableVisionTrackMaterials(type: "image").count > 0 {
- for (index, point) in stuckPoints.enumerated() {
- let sticker: PQEditVisionTrackMaterialsModel = section.sectionTimeline!.visionTrack!.getEnableVisionTrackMaterials()[index % section.sectionTimeline!.visionTrack!.getEnableVisionTrackMaterials().count]
- BFLog(message: "stickerlocationPath sticker : \(sticker.locationPath)")
- let stickerjson = sticker.toJSONString(prettyPrint: false)
- let deepCopySticker = Mapper<PQEditVisionTrackMaterialsModel>().map(JSONString: stickerjson!)
- if deepCopySticker!.type == StickerType.IMAGE.rawValue {
- if index + 1 < stuckPoints.count {
- deepCopySticker!.timelineIn = Float64("\(stuckPoints[index])") ?? 0.0
- deepCopySticker!.timelineOut = Float64("\(stuckPoints[index + 1])") ?? 0.0
- if deepCopySticker != nil {
- deepCopySticker?.generateDefaultValues()
- stickers.append(deepCopySticker!)
- }
- }
- }
- }
- } else {
- // 第二种情况:有视频要进行分割
- let clipFilters = clipVideoMerage(section: section, stuckPoints: stuckPoints)
- for (index, point) in stuckPoints.enumerated() {
- BFLog(message: "aaaaaindexindeindexxindexindexindex \(index) \(point)")
- if index + 1 < stuckPoints.count, index < clipFilters.count {
- BFLog(message: "bbbbbindexindeindexxindexindexindex \(index) \(point)")
- let sticker: PQEditVisionTrackMaterialsModel = clipFilters[index]
- let spit: Int = 2
- sticker.timelineIn = 57.5 + Double(index * spit)
- sticker.timelineOut = sticker.timelineIn + Double(spit)
- sticker.speedRate = index % 2 == 0 ? 0.1 : 2
- sticker.model_in = Double(index * spit)
- sticker.out = sticker.model_in + Double(spit)
- // let spit: Int = 2
- // sticker.timelineIn = 57.5
- // sticker.timelineOut = sticker.timelineIn + 24
- // sticker.speedRate = index % 2 == 0 ? 0.1 : 2
- //// sticker.speedRate = 0.1
- // sticker.model_in = 0
- // sticker.out = sticker.model_in + 24
- if stickers.count < 12 {
- BFLog(message: "index is \(index)分割后 创建 filter timelineIn :\(sticker.timelineIn) timelineOut :\(sticker.timelineOut) in :\(sticker.model_in) out:\(sticker.out) type is \(sticker.type) 显示总时长为:\(sticker.timelineOut - sticker.timelineIn) 裁剪总时长\(sticker.out - sticker.model_in)")
- stickers.append(sticker)
- }
- }
- }
- }
- }
- }
- }
- }
- return stickers
- }
- }
- // MARK: - 同步/下载素材相关
- /// 同步/下载素材相关
- extension PQStuckPointEditerController {
- /// 同步音乐相关数据
- /// - Returns: <#description#>
- func synchroMusicInfoData() {
- if (stuckPointMusicData?.rhythmSdata.count ?? 0) <= 0 {
- if synchroMarskView.superview == nil {
- UIApplication.shared.keyWindow?.addSubview(synchroMarskView)
- }
- PQStuckPointViewModel.stuckPointMusicDetailData(musicId: stuckPointMusicData?.musicId ?? "", originType: stuckPointMusicData?.originType ?? 1) { [weak self] newMusicData, _ in
- if newMusicData != nil, (newMusicData?.rhythmSdata.count ?? 0) > 0 {
- self?.isStuckPointDataSuccess = true
- self?.stuckPointMusicData?.rhythmSdata = newMusicData?.rhythmSdata ?? []
- self?.stuckPointMusicData?.startTime = newMusicData?.startTime ?? 0
- self?.stuckPointMusicData?.endTime = newMusicData?.endTime ?? 0
- if newMusicData?.speed != nil {
- self?.stuckPointMusicData?.speed = newMusicData?.speed ?? 2
- }
- if (self?.stuckPointMusicData?.rhythmSdata.count ?? 0) > 0 && (((self?.selectedDataCount ?? 0) - (self?.selectedImageDataCount ?? 0)) > 0 || (self?.selectedImageDataCount ?? 0) > 0 || (self?.selectedTotalDuration ?? 0) > 0) {
- self?.stuckPointMusicData?.endTime = (self?.stuckPointMusicData?.startTime ?? 0) + (self?.stuckPointMusicData?.stuckPointCuttingTime(videoCount: (self?.selectedDataCount ?? 0) - (self?.selectedImageDataCount ?? 0), imageCount: self?.selectedImageDataCount ?? 0, totalDuration: self?.selectedTotalDuration ?? 0) ?? 0)
- }
- self?.stuckPointCuttingView.updateEndTime(startTime: CGFloat(self?.stuckPointMusicData?.startTime ?? 0), endTime: CGFloat(self?.stuckPointMusicData?.endTime ?? 0))
- if self?.stuckPointMusicData?.localPath == nil || (self?.stuckPointMusicData?.localPath?.count ?? 0) > 0 {
- PQDownloadManager.downLoadFile(url: self?.stuckPointMusicData?.musicPath ?? "") { [weak self] filePath, error in
- if error == nil, filePath != nil {
- self?.isSynchroMusicInfoSuccess = true
- self?.stuckPointMusicData?.localPath = filePath?.replacingOccurrences(of: documensDirectory, with: "")
- // 处理所有数据完成
- self?.dealWithDataSuccess()
- } else {
- if self?.synchroMarskView.superview != nil {
- self?.synchroMarskView.removeMarskView()
- }
- // PQUploadRemindView.showUploadRemindView(title: nil, attributedTitle: NSAttributedString(string: "加载音乐失败,请重新选择音乐"), summary: "", confirmTitle: nil) { [weak self] _, _ in
- // self?.navigationController?.popViewController(animated: true)
- // }
- }
- }
- } else {
- self?.isSynchroMusicInfoSuccess = true
- // 处理所有数据完成
- self?.dealWithDataSuccess()
- }
- // 添加子视图
- self?.addSubViews()
- } else {
- if self?.synchroMarskView.superview != nil {
- self?.synchroMarskView.removeMarskView()
- }
- // PQUploadRemindView.showUploadRemindView(title: nil, attributedTitle: NSAttributedString(string: "加载音乐失败,请重新选择音乐"), summary: "", confirmTitle: nil) { [weak self] _, _ in
- // self?.navigationController?.popViewController(animated: true)
- // }
- }
- }
- } else if stuckPointMusicData?.localPath == nil || (stuckPointMusicData?.localPath?.count ?? 0) > 0 {
- if synchroMarskView.superview == nil {
- UIApplication.shared.keyWindow?.addSubview(synchroMarskView)
- }
- isStuckPointDataSuccess = true
- PQDownloadManager.downLoadFile(url: stuckPointMusicData?.musicPath ?? "") { [weak self] filePath, error in
- if error == nil, filePath != nil {
- self?.isSynchroMusicInfoSuccess = true
- self?.stuckPointMusicData?.localPath = filePath?.replacingOccurrences(of: documensDirectory, with: "")
- // 处理所有数据完成
- self?.dealWithDataSuccess()
- } else {
- if self?.synchroMarskView.superview != nil {
- self?.synchroMarskView.removeMarskView()
- }
- // PQUploadRemindView.showUploadRemindView(title: nil, attributedTitle: NSAttributedString(string: "加载音乐失败,请重新选择音乐"), summary: "", confirmTitle: nil) { [weak self] _, _ in
- // self?.navigationController?.popViewController(animated: true)
- // }
- }
- }
- } else {
- isStuckPointDataSuccess = true
- // 处理所有数据完成
- dealWithDataSuccess()
- }
- }
- /// 导出相册数据
- /// - Returns: <#description#>
- func exportPhotoData() {
- // 取消所有的导出
- PQSingletoMemoryUtil.shared.allExportSession.forEach { _, exportSession in
- exportSession.cancelExport()
- }
- var isHaveVideo: Bool = false
- if selectedMetarialData != nil, (selectedMetarialData?.count ?? 0) > 0 {
- if synchroMarskView.superview == nil {
- UIApplication.shared.keyWindow?.addSubview(synchroMarskView)
- }
- let dispatchGroup = DispatchGroup()
- for photo in selectedMetarialData! {
- if photo.asset != nil, photo.asset?.mediaType == .video {
- if !isHaveVideo {
- isHaveVideo = true
- }
- dispatchGroup.enter()
- PQPHAssetVideoParaseUtil.parasToAVAsset(phAsset: photo.asset!) { avAsset, _, _, _ in
- if avAsset is AVURLAsset {
- // 创建目录
- let fileName = (avAsset as! AVURLAsset).url.absoluteString
- BFLog(message: "video fileName is\(fileName)")
- let tempPhoto = self.selectedMetarialData?.first(where: { material in
- material.asset == photo.asset
- })
- if fileName.count > 0 {
- createDirectory(path: photoLibraryDirectory)
- let outFilePath = photoLibraryDirectory + fileName.md5 + ".mp4"
- // 文件存在先删除老文件
- if FileManager.default.fileExists(atPath: outFilePath) {
- do {
- try FileManager.default.removeItem(at: NSURL.fileURL(withPath: outFilePath))
- } catch {
- BFLog(message: "导出相册视频-error == \(error)")
- }
- }
- do {
- try FileManager.default.copyItem(atPath: fileName.replacingOccurrences(of: "file:///", with: ""), toPath: outFilePath)
- print("Success to copy file.")
- } catch {
- print("Failed to copy file.")
- }
- tempPhoto?.locationPath = outFilePath.replacingOccurrences(of: documensDirectory, with: "")
- BFLog(message: "导出视频相册地址为 \(String(describing: tempPhoto?.locationPath))")
- dispatchGroup.leave()
- }
- }
- }
- }
- }
- dispatchGroup.notify(queue: DispatchQueue.main) { [weak self] in
- self?.isExportVideosSuccess = true
- BFLog(message: "所有相册视频导出成功")
- // 处理所有数据完成
- if isHaveVideo {
- self?.dealWithDataSuccess()
- }
- }
- // 只有图片
- if !isHaveVideo {
- isExportVideosSuccess = true
- BFLog(message: "所有相册视频导出成功")
- dealWithDataSuccess()
- }
- }
- }
- /// 处理所有数据完成
- /// - Returns: <#description#>
- func dealWithDataSuccess() {
- BFLog(message: "三组参数:\(isSynchroMusicInfoSuccess) \(isStuckPointDataSuccess) \(isExportVideosSuccess)")
- if !isSynchroMusicInfoSuccess || !isStuckPointDataSuccess || !isExportVideosSuccess {
- return
- }
- playeTimeRange = CMTimeRange(start: CMTimeMakeWithSeconds(stuckPointMusicData?.startTime ?? 0, preferredTimescale: BASE_FILTER_TIMESCALE), end: CMTimeMakeWithSeconds(stuckPointMusicData?.endTime ?? 0, preferredTimescale: BASE_FILTER_TIMESCALE))
- createPorjectData()
- settingPlayerView()
- }
- }
|