12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066 |
- //
- // PQStuckPointEditerController.swift
- // PQSpeed
- //
- // Created by ak on 2021/4/26.
- // Copyright © 2021 BytesFlow. All rights reserved.
- // 功能:卡点音乐编辑界面
- import BFAnalyzeKit
- import BFCommonKit
- import BFUIKit
- import BFMediaKit
- import Foundation
- import ObjectMapper
- import Photos
- import RealmSwift
- import UIKit
- class PQStuckPointEditerController: BFBaseViewController {
- // 是否导出视频成功
- 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()
- // 首帧图片
- var firstFrameImage: UIImage? {
- didSet {
- if firstFrameImage != nil {
- playerView.layer.contents = firstFrameImage?.cgImage
- }
- }
- }
- // add by ak 是否是再创作模式
- var isReCreate: Bool = false
- public var reCreateVideoData: PQReCreateModel? // 再创作数据
- // 最后一个选择的模式 BTN 用于还原选中状态
- var lastEditModelBtn: UIButton?
- // add by ak 最大、最小速度 有固定值和自定义,当快慢速下两个值都有效,当跳跃卡点只有maxSpeed有效
- // 快慢速模式的 速度设置,快/慢速
- var modelSpeed_maxSpeed: Float = 1.0
- var modelSpeed_minSpeed: Float = 1.0
- // 跳跃模式的速度
- var modelPoint_speed: Float = 1.0
- // 快慢速最后一次选择的速度位置
- var lastSpeedSelectIndex: Int = 0
- // 跳跃卡点最后一次选择的速度位置
- var lastJumpSpeedSelectIndex: Int = 0
- // 循环次数设置最后一次选择的位置
- var lastCyclesSelectIndex: Int = -1
- // 当前选择的玩法模式
- var currentCreateStickersModel: createStickersModel = .createStickersModelSpeed
- // 最终使用的卡点数据
- var finallyStuckPoints: Array = Array<Float>.init()
- var finallyStuckPointsInt64: Array = Array<Int64>.init()
- // 最终使用的音频时长
- var finallyUserAudioTime: Float = 0.0
- // 注意推荐时间位置和后面最近的卡点时间与0.3的关系
- // 保存丢卡点处理后的卡点信息推荐开始到最后倒数第二个
- // 经过档位处理后的卡点信息
- var stuckPointsTemp: Array = Array<Float>.init()
- var stuckPointsTempInt64: Array = Array<Int64>.init()
- // 是否点击了下一步去合成
- var isClickNextBtn: 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: BFConfig.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 playerView = PQGPUImagePlayerView(frame: .zero)
- playerView.backgroundColor = BFConfig.shared.styleBackGroundColor
- playerView.isShowLine = false
- playerView.showGaussianBlur = true
- playerView.pause()
- playerView.renderViewOnClickHandle = { [weak self] in
- self?.musicEditBGView.pausePlayer()
- }
- playerView.playerEmptyView.isHidden = true
- return playerView
- }()
- /// 节奏选择视图
- lazy var sustomSwitchView: PQCustomSwitchView = {
- let sustomSwitchView = PQCustomSwitchView(frame: CGRect(x: 16, y: 0, width: 180, height: 30), titles: ["慢节奏", "适中", "快节奏"], defaultIndex: stuckPointMusicData?.speed ?? 2)
- sustomSwitchView.switchChangeHandle = { [weak self] sender in
- // 改变速率,.只有快慢速且非只有图片素材时自动+1处理
- self?.stuckPointMusicData?.speed = sender.tag
- self?.musicEditBGView.pausePlayer()
- self?.projectModel.sData?.getBGMSession()?.sectionTimeline?.audioTrack?.audioTrackMaterials.first?.bgmInfo?.rhythmMusicSpeed = sender.tag
- // 播放前先暂停
- // self?.playerView.stop()
- // 开始播放
- self?.settingPlayerView()
- // 下面都是统计
- if self?.currentCreateStickersModel == .createStickersModelPoint {
- BFEventTrackAdaptor.baseReportUpload(businessType: .bt_buttonClick, objectType: .ot_shanyinApp_musicVideoPreview_selectMusicVideoRhythm, pageSource: .sp_stuck_previewSyncedUp, commonParams: commonParams())
- } else if self?.currentCreateStickersModel == .createStickersModelSpeed {
- BFEventTrackAdaptor.baseReportUpload(businessType: .bt_buttonClick, objectType: .ot_shanyinApp_musicVideoPreview_selectSpeedRhythm, pageSource: .sp_stuck_previewSyncedUp, commonParams: commonParams())
- } else if self?.currentCreateStickersModel == .createStickersModelOnlyMusic {
- BFEventTrackAdaptor.baseReportUpload(businessType: .bt_buttonClick, objectType: .ot_shanyinApp_musicVideoPreview_selectMusicVideoRepeatRhythm, pageSource: .sp_stuck_previewSyncedUp, commonParams: commonParams())
- }
- }
- return sustomSwitchView
- }()
- /// 裁剪视图
- lazy var stuckPointCuttingView: PQStuckPointCuttingView = {
- let stuckPointCuttingView = PQStuckPointCuttingView(frame: CGRect(x: 0, y: optionlineView.frame.minY - 85 - 28, width: view.frame.width, height: 80), duration: CGFloat(Float(stuckPointMusicData?.duration ?? "0") ?? 0), suggestRhythmStartTime: CGFloat(stuckPointMusicData?.suggestRhythmStartTime ?? 0))
- /// 裁剪进度回调
- stuckPointCuttingView.videoDidBeginDrag = { [weak self] in
- BFLog(message: "开始划动")
- self?.playerView.pause()
- }
- /// 播放进度回调
- 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(1, message: "拖拽结束返回--type = \(type),startTime = \(startTime),endTime = \(endTime),progress = \(progress)")
- self?.playerView.pause()
- self?.musicEditBGView.pausePlayer()
- // 修改最新值
- 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))
- self?.dealParameter(model: self?.currentCreateStickersModel ?? .createStickersModelSpeed)
- if (self?.finallyStuckPoints.count ?? 0) < 1 {
- BFLog(message: "finallyStuckPoints data is error!!!!")
- return
- }
- DispatchQueue.global().async { // 并行、异步
- let beginTime = Date()
- 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)), model: self?.currentCreateStickersModel ?? .createStickersModelSpeed)
- DispatchQueue.main.async { // 串行、异步
- self?.playerView.mStickers = self?.mStickers
- BFLog(message: "endTime is endTimeendTime \(Date().timeIntervalSince(beginTime))")
- self?.playerView.play(pauseFirstFrame: false, playeTimeRange: self!.playeTimeRange)
- // 更新一下时间条的UI总时间 及数据
- self?.stuckPointCuttingView.videoDuration = CGFloat(self?.finallyUserAudioTime ?? 0)
- self?.stuckPointCuttingView.stuckPointStartTime = CGFloat(CMTimeGetSeconds(self?.playeTimeRange.start ?? .zero))
- self?.stuckPointCuttingView.stuckPointEndTime = CGFloat(CMTimeGetSeconds(self?.playeTimeRange.end ?? .zero))
- self?.stuckPointCuttingView.tatalTimeLabel.text = "\(Float64(CMTimeGetSeconds(self?.playeTimeRange.end ?? .zero) - CMTimeGetSeconds(self?.playeTimeRange.start ?? .zero)).formatDurationToHMS())"
- }
- }
- }
- }
- return stuckPointCuttingView
- }()
- /// 卡点模式标题
- lazy var pointEditRemindLab: UILabel = {
- let pointEditRemindLab = UILabel()
- pointEditRemindLab.backgroundColor = .clear
- pointEditRemindLab.textAlignment = .left
- pointEditRemindLab.font = UIFont.boldSystemFont(ofSize: 14)
- pointEditRemindLab.textColor = BFConfig.shared.styleTitleColor
- pointEditRemindLab.text = "卡点模式"
- return pointEditRemindLab
- }()
- /// 卡点模式标题
- lazy var speedTitleLab: UILabel = {
- let speedTitleLab = UILabel()
- speedTitleLab.backgroundColor = .clear
- speedTitleLab.textAlignment = .left
- speedTitleLab.font = UIFont.boldSystemFont(ofSize: 14)
- speedTitleLab.textColor = BFConfig.shared.styleTitleColor
- speedTitleLab.text = "节奏变化"
- return speedTitleLab
- }()
- /// 卡点模式下方操作区背景
- lazy var pointEditBGView: UIView = {
- let pointEditBGView = UIView()
- pointEditBGView.backgroundColor = .clear
- return pointEditBGView
- }()
- /// 下方音乐编辑操作区背景
- lazy var musicEditBGView: PQSelecteMusicView = {
- let musicEditBGView = PQSelecteMusicView()
- musicEditBGView.backgroundColor = .clear
- musicEditBGView.isUserInteractionEnabled = true
- musicEditBGView.isHidden = true
- musicEditBGView.musicSearchBtn.addTarget(self, action: #selector(musicSearchBtnClick(sender:)), for: .touchUpInside)
- musicEditBGView.didSelectItemHandle = { [weak self] status in
- if status == .isSelected {
- if self?.playerView.status != .playing {
- self?.playerView.RenderViewOnclick()
- }
- } else {
- self?.playerView.pause()
- }
- }
- musicEditBGView.btnClickHandle = { [weak self] _, bgmData in
- // 使用音乐
- self?.userstuckPointMusic(musicData: bgmData as? PQVoiceModel)
- }
- return musicEditBGView
- }()
- // 卡点编辑 btn
- lazy var pointEditerBtn: UIButton = {
- let pointEdterBtn = UIButton(type: .custom)
- pointEdterBtn.setImage(UIImage.moduleImage(named: "pointEditerBtn_n", moduleName: "BFStuckPointKit", isAssets: false), for: .normal)
- pointEdterBtn.setImage(UIImage.moduleImage(named: "pointEditerBtn_h", moduleName: "BFStuckPointKit", isAssets: false)?.withRenderingMode(.alwaysTemplate), for: .selected)
- pointEdterBtn.tintColor = UIColor.hexColor(hexadecimal: BFConfig.shared.styleColor.rawValue)
- pointEdterBtn.addTarget(self, action: #selector(pointEditerBtnClick(sender:)), for: .touchUpInside)
- pointEdterBtn.isSelected = true
- pointEdterBtn.adjustsImageWhenHighlighted = false
- return pointEdterBtn
- }()
- // 音乐编辑 btn
- lazy var musicEditerBtn: UIButton = {
- let musicEditerBtn = UIButton(type: .custom)
- musicEditerBtn.setImage(UIImage.moduleImage(named: "musicEditerBtn_n", moduleName: "BFStuckPointKit", isAssets: false), for: .normal)
- musicEditerBtn.setImage(UIImage.moduleImage(named: "musicEditerBtn_h", moduleName: "BFStuckPointKit", isAssets: false)?.withRenderingMode(.alwaysTemplate), for: .selected)
- musicEditerBtn.tintColor = UIColor.hexColor(hexadecimal: BFConfig.shared.styleColor.rawValue)
- musicEditerBtn.addTarget(self, action: #selector(musicEditerBtnClick(sender:)), for: .touchUpInside)
- musicEditerBtn.adjustsImageWhenHighlighted = false
- return musicEditerBtn
- }()
- // 快慢速卡点模式 btn
- lazy var speedStuckBtn: UIButton = {
- let speedStuckBtn = UIButton(type: .custom)
- speedStuckBtn.addTarget(self, action: #selector(editModelClick1(sender:)), for: .touchUpInside)
- speedStuckBtn.setTitle("快慢速卡点", for: .normal)
- speedStuckBtn.titleLabel?.font = UIFont.systemFont(ofSize: 13, weight: .regular)
- jumpPointBtn.backgroundColor = BFConfig.shared.pointEditNamalBackgroundColor
- speedStuckBtn.setTitleColor(UIColor.hexColor(hexadecimal: BFConfig.shared.styleColor.rawValue), for: .selected)
- speedStuckBtn.setTitleColor(UIColor.hexColor(hexadecimal: "#959595"), for: .normal)
- speedStuckBtn.addCorner(corner: 5)
- speedStuckBtn.imagePosition(at: .top, space: 8)
- speedStuckBtn.tag = 1
- speedStuckBtn.adjustsImageWhenHighlighted = false
- speedStuckBtn.setImage(UIImage.moduleImage(named: BFConfig.shared.speedStuckBtnImage_N, moduleName: "BFStuckPointKit", isAssets: false), for: .normal)
- speedStuckBtn.setImage(UIImage.moduleImage(named: BFConfig.shared.speedStuckBtnImage_H, moduleName: "BFStuckPointKit", isAssets: false), for: .selected)
- return speedStuckBtn
- }()
- // //
- // lazy var speedStuckBtnGif: UIImageView = {
- // let speedStuckBtnGif = UIImageView()
- // speedStuckBtnGif.kf.setImage(with: URL(fileURLWithPath: currentBundlePath()!.path(forResource: "speedstuck_h", ofType: "gif")!))
- // speedStuckBtnGif.isHidden = true
- // return speedStuckBtnGif
- //
- // }()
- // 跳转卡点模式 btn
- lazy var jumpPointBtn: UIButton = {
- let jumpPointBtn = UIButton(type: .custom)
- jumpPointBtn.setTitle("跳跃卡点", for: .normal)
- jumpPointBtn.titleLabel?.font = UIFont.systemFont(ofSize: 13, weight: .regular)
- jumpPointBtn.backgroundColor = BFConfig.shared.pointEditNamalBackgroundColor
- jumpPointBtn.setTitleColor(UIColor.hexColor(hexadecimal: BFConfig.shared.styleColor.rawValue), for: .selected)
- jumpPointBtn.setTitleColor(UIColor.hexColor(hexadecimal: "#959595"), for: .normal)
- jumpPointBtn.imagePosition(at: .top, space: 8)
- jumpPointBtn.addCorner(corner: 5)
- jumpPointBtn.tag = 2
- jumpPointBtn.addTarget(self, action: #selector(editModelClick1(sender:)), for: .touchUpInside)
- jumpPointBtn.adjustsImageWhenHighlighted = false
- jumpPointBtn.setImage(UIImage.moduleImage(named: BFConfig.shared.jumpPointBtnImage_N, moduleName: "BFStuckPointKit", isAssets: false), for: .normal)
- jumpPointBtn.setImage(UIImage.moduleImage(named: BFConfig.shared.jumpPointBtnImage_H, moduleName: "BFStuckPointKit", isAssets: false), for: .selected)
- return jumpPointBtn
- }()
- // lazy var jumpPointBtnGif: UIImageView = {
- // let jumpPointBtnGif = UIImageView()
- // jumpPointBtnGif.kf.setImage(with: URL(fileURLWithPath: currentBundlePath()!.path(forResource: "jumpPoint_n", ofType: "gif")!))
- // jumpPointBtnGif.isHidden = true
- // return jumpPointBtnGif
- //
- // }()
- // 仅配乐模式 btn
- lazy var onlyMusicBtn: UIButton = {
- let onlyMusicBtn = UIButton(type: .custom)
- onlyMusicBtn.setTitle("仅配乐", for: .normal)
- onlyMusicBtn.titleLabel?.font = UIFont.systemFont(ofSize: 13, weight: .regular)
- onlyMusicBtn.backgroundColor = BFConfig.shared.pointEditNamalBackgroundColor
- onlyMusicBtn.setTitleColor(UIColor.hexColor(hexadecimal: BFConfig.shared.styleColor.rawValue), for: .selected)
- onlyMusicBtn.setTitleColor(UIColor.hexColor(hexadecimal: "#959595"), for: .normal)
- onlyMusicBtn.addCorner(corner: 5)
- onlyMusicBtn.tag = 3
- onlyMusicBtn.addTarget(self, action: #selector(editModelClick1(sender:)), for: .touchUpInside)
- onlyMusicBtn.adjustsImageWhenHighlighted = false
- onlyMusicBtn.setImage(UIImage.moduleImage(named: BFConfig.shared.onlyMusicBtnImage_N, moduleName: "BFStuckPointKit", isAssets: false), for: .normal)
- onlyMusicBtn.setImage(UIImage.moduleImage(named: BFConfig.shared.onlyMusicBtnImage_H, moduleName: "BFStuckPointKit", isAssets: false), for: .selected)
- return onlyMusicBtn
- }()
- // 操作面板上的分割线
- lazy var optionlineView: UIView = {
- let optionlineView = UIView()
- optionlineView.backgroundColor = BFConfig.shared.pointEditNamalBackgroundColor
- return optionlineView
- }()
- // 固定速度 UI
- lazy var speedSettingView: PQSpeedSettingView = {
- let speedSetView = PQSpeedSettingView()
- speedSetView.backgroundColor = .clear
- speedSetView.selectSpeedCallBack = { [weak self] maxSpeed, minSpeed, selectIndex, isSettingPlayer in
- BFLog(message: "固定maxSpeed is\(maxSpeed) minSpeed \(minSpeed)")
- self?.musicEditBGView.pausePlayer()
- if maxSpeed == -1.0, minSpeed == -1.0 {
- self?.customSpeedSettingView.isHidden = false
- self?.customSpeedSettingView.viewType = self?.speedSettingView.viewType ?? 2
- } else {
- if maxSpeed != 0.0 {
- // 更新最后一次选择的位置恢复时使用
- if self?.speedSettingView.viewType == 1 {
- self?.lastSpeedSelectIndex = selectIndex
- self?.modelSpeed_maxSpeed = maxSpeed
- self?.modelSpeed_minSpeed = minSpeed
- } else if self?.speedSettingView.viewType == 2 {
- self?.lastJumpSpeedSelectIndex = selectIndex
- self?.modelPoint_speed = maxSpeed
- } else {
- self?.lastCyclesSelectIndex = selectIndex
- }
- } else {
- BFLog(message: "设置速度无效")
- }
- }
- if isSettingPlayer {
- self?.settingPlayerView()
- }
- }
- return speedSetView
- }()
- // 自定义速度
- lazy var customSpeedSettingView: PQCustomSpeedSettingView = {
- let customSpeedSetView = PQCustomSpeedSettingView(frame: CGRect(x: 0, y: cScreenHeigth - 354, width: cScreenWidth, height: 354))
- customSpeedSetView.isHidden = true
- customSpeedSetView.selectSpeedCallBack = { [weak self, weak customSpeedSetView] maxSpeed, minSpeed, isJumpSpeedModel, isCancle in
- if !isCancle {
- BFLog(message: "自定义速度maxSpeed is\(maxSpeed) minSpeed \(minSpeed) \(isJumpSpeedModel)")
- self?.musicEditBGView.pausePlayer()
- // 自定定义的更新一下最后的选择位置
- if self?.speedSettingView.viewType == 1 {
- self?.lastSpeedSelectIndex = -1
- self?.modelSpeed_maxSpeed = maxSpeed
- self?.modelSpeed_minSpeed = minSpeed
- } else if self?.speedSettingView.viewType == 2 {
- self?.lastJumpSpeedSelectIndex = -1
- self?.modelPoint_speed = maxSpeed
- } else {
- self?.lastCyclesSelectIndex = Int(maxSpeed - 1)
- }
- self?.settingPlayerView()
- // 确认后 选中自定义
- self?.speedSettingView.selectCustom()
- } else {
- // 取消后恢复上一次选择的位置
- if self?.speedSettingView.viewType == 1 {
- self?.speedSettingView.setSelectItem(index: self?.lastSpeedSelectIndex ?? 0, isSettingPlayer: false)
- } else if self?.speedSettingView.viewType == 2 {
- self?.speedSettingView.setSelectItem(index: self?.lastJumpSpeedSelectIndex ?? 0, isSettingPlayer: false)
- } else {
- self?.speedSettingView.setSelectItem(index: self?.lastCyclesSelectIndex ?? 0, isSettingPlayer: false)
- }
- customSpeedSetView?.isHidden = true
- }
- }
- return customSpeedSetView
- }()
- /// 音乐标题
- 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 = BFConfig.shared.styleTitleColor
- musicImageView.image = UIImage.moduleImage(named: "stuckPoint_reCreate_music", moduleName: "BFStuckPointKit", 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
- 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 = BFConfig.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
- }()
- @objc func willEnterForeground() {
- BFLog(message: "进入到前台")
- if navigationController?.topViewController == self {
- if projectModel.sData!.sections.count > 0 {
- settingPlayerView()
- } else {
- prepareMeta()
- }
- }
- }
- @objc func enterBackground() {
- BFLog(message: "进入到后台")
- // 取消导出
- if navigationController?.topViewController == self {
- playerView.pause()
- }
- }
- override func backBtnClick() {
- super.backBtnClick()
- // playerView.pause()
- // 点击上报:返回按钮
- BFEventTrackAdaptor.baseReportUpload(businessType: .bt_buttonClick, objectType: .ot_click_back, pageSource: .sp_stuck_previewSyncedUp, commonParams: commonParams())
- }
- // 使用选择音乐 调用情况:1,操作面板直接选择 ,2 搜索界面点击使用
- func userstuckPointMusic(musicData: PQVoiceModel?) {
- // 1,音乐面板点击了使用
- stuckPointMusicData = musicData
- // 2,同步最新音乐数据
- synchroMusicInfoData(resetSelectIndex: false)
- // 3,更新音乐标题UI
- 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
- if nameWidth < cDefaultMargin * 4 {
- musicNameLab.text = " \(stuckPointMusicData?.musicName ?? "") "
- } else {
- musicNameLab.text = " \(stuckPointMusicData?.musicName ?? "") "
- }
- // 更新一下节奏的 UI
- sustomSwitchView.selectOneBtn(Index: stuckPointMusicData?.speed ?? 2)
- }
- // 点击搜索音乐
- @objc func musicSearchBtnClick(sender _: UIButton) {
- let searchVC = PQEditMusicSearchController()
- searchVC.btnClickHandle = { [weak self] _, bgmData in
- // 使用音乐
- BFLog(message: "搜索音乐点击了使用")
- self?.musicEditBGView.insertSearchMusic(model: bgmData as! PQVoiceModel)
- self?.userstuckPointMusic(musicData: bgmData as? PQVoiceModel)
- }
- let navigationController: UINavigationController = UINavigationController(rootViewController: searchVC)
- navigationController.modalPresentationStyle = .fullScreen
- present(navigationController, animated: true, completion: nil)
- }
- // 卡点编辑
- @objc func pointEditerBtnClick(sender: UIButton) {
- if sender.isSelected { return }
- sender.isSelected = !sender.isSelected
- musicEditerBtn.isSelected = false
- pointEditBGView.isHidden = false
- musicEditBGView.isHidden = true
- BFEventTrackAdaptor.baseReportUpload(businessType: .bt_buttonClick, objectType: .ot_shanyinApp_musicVideoPreview_videoTab, pageSource: .sp_shanyinApp_main, commonParams: commonParams())
- }
- // 音乐编辑
- @objc func musicEditerBtnClick(sender: UIButton) {
- if sender.isSelected { return }
- sender.isSelected = !sender.isSelected
- pointEditerBtn.isSelected = false
- pointEditBGView.isHidden = true
- musicEditBGView.showData()
- BFEventTrackAdaptor.baseReportUpload(businessType: .bt_buttonClick, objectType: .ot_shanyinApp_musicVideoPreview_musicTab, pageSource: .sp_shanyinApp_main, commonParams: commonParams())
- }
- @objc func editModelClick1(sender: UIButton) {
- editModelClick(sender: sender)
- }
- // 三种模式修改
- @objc func editModelClick(sender: UIButton, reportLog: Bool = true) {
- // if sender.isSelected {
- // BFLog(message: "已经是选中状态")
- // return “”
- // }
- musicEditBGView.pausePlayer()
- sharedImageProcessingContext.framebufferCache.purgeAllUnassignedFramebuffers()
- if sender == jumpPointBtn, selectedTotalDuration < 6, selectedDataCount != selectedImageDataCount, reCreateVideoData == nil {
- cShowHUB(superView: view, msg: "素材时长需要大于6秒才\n可选择“跳跃卡点”模式")
- return
- }
- lastEditModelBtn?.isSelected = false
- // 设置取消选中的背景色
- lastEditModelBtn?.backgroundColor = BFConfig.shared.pointEditNamalBackgroundColor
- sender.isSelected = !sender.isSelected
- lastEditModelBtn = sender
- // 设置选中的背景色
- let styleColor = UIColor.hexColor(hexadecimal: BFConfig.shared.styleColor.rawValue)
- lastEditModelBtn?.backgroundColor = UIColor(red: styleColor.rgbaf[0], green: styleColor.rgbaf[1], blue: styleColor.rgbaf[2], alpha: 0.15)
- BFLog(message: "sender tag is \(sender.tag)")
- // 2素材全是图片的时候三个模式都显示循环设置 UI
- if selectedDataCount == selectedImageDataCount {
- speedSettingView.viewType = 3
- customSpeedSettingView.viewType = speedSettingView.viewType
- speedSettingView.snp.remakeConstraints { make in
- make.left.equalToSuperview().offset(16)
- make.right.equalToSuperview()
- make.top.equalTo(onlyMusicBtn.snp.bottom).offset(10)
- make.height.equalTo(30)
- }
- speedSettingView.isHidden = false
- speedTitleLab.isHidden = false
- sustomSwitchView.isHidden = false
- if lastCyclesSelectIndex != -1 {
- speedSettingView.setSelectItem(index: lastCyclesSelectIndex, isSettingPlayer: false)
- }
- } else {
- // 1 ui 调整
- if sender.tag == 1 || sender.tag == 2 {
- speedSettingView.viewType = sender.tag
- customSpeedSettingView.viewType = speedSettingView.viewType
- speedSettingView.snp.remakeConstraints { make in
- make.left.equalToSuperview().offset(16)
- make.right.equalToSuperview()
- make.top.equalTo(onlyMusicBtn.snp.bottom).offset(10)
- make.height.equalTo(sender.tag == 1 ? 44 : 30)
- }
- speedSettingView.isHidden = false
- speedTitleLab.isHidden = false
- sustomSwitchView.isHidden = false
- if sender.tag == 1 { // 快慢速
- speedSettingView.setSelectItem(index: lastSpeedSelectIndex, isSettingPlayer: false, setDisable: (selectedTotalDuration < 6 && selectedDataCount != selectedImageDataCount) ? true : false)
- } else if sender.tag == 2 { // 跳跃卡点
- speedSettingView.setSelectItem(index: lastJumpSpeedSelectIndex, isSettingPlayer: false)
- }
- } else {
- speedTitleLab.isHidden = true
- speedSettingView.isHidden = true
- sustomSwitchView.isHidden = true
- }
- }
- // 3 设置 btn 不同显示状态
- var speedStuckBtnGifName = ""
- var jumpPointBtnGifName = ""
- if sender.tag == 1 { // 快慢速
- speedStuckBtnGifName = "speedstuck_h_pq"
- jumpPointBtnGifName = "jumpPoint_n_pq"
- currentCreateStickersModel = .createStickersModelSpeed
- if reportLog {
- BFEventTrackAdaptor.baseReportUpload(businessType: .bt_buttonClick, objectType: .ot_shanyinApp_musicVideoPreview_selectPatternSpeed, pageSource: .sp_shanyinApp_main, commonParams: commonParams())
- }
- } else if sender.tag == 2 { // 跳跃卡点
- speedStuckBtnGifName = "speedstuck_n_pq"
- jumpPointBtnGifName = "jumpPoint_h_pq"
- currentCreateStickersModel = .createStickersModelPoint
- if reportLog {
- BFEventTrackAdaptor.baseReportUpload(businessType: .bt_buttonClick, objectType: .ot_shanyinApp_musicVideoPreview_selectPatternMusicVideo, pageSource: .sp_shanyinApp_main, commonParams: commonParams())
- }
- } else if sender.tag == 3 { // 仅音乐
- speedStuckBtnGifName = "speedstuck_n_pq"
- jumpPointBtnGifName = "jumpPoint_n_pq"
- currentCreateStickersModel = .createStickersModelOnlyMusic
- if reportLog {
- BFEventTrackAdaptor.baseReportUpload(businessType: .bt_buttonClick, objectType: .ot_shanyinApp_musicVideoPreview_selectPatternBgm, pageSource: .sp_shanyinApp_main, commonParams: commonParams())
- }
- }
- settingPlayerView()
- }
- override func viewWillAppear(_ animated: Bool) {
- super.viewWillAppear(animated)
- lineView?.isHidden = true
- DispatchQueue.main.async {
- UIApplication.shared.isIdleTimerDisabled = true
- }
- musicNameLab.move()
- PQNotification.addObserver(self, selector: #selector(enterBackground), name: UIApplication.didEnterBackgroundNotification, object: nil)
- PQNotification.addObserver(self, selector: #selector(willEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil)
- // 从分享返回后从重初始化播放器
- if isClickNextBtn {
- isClickNextBtn = false
- settingPlayerView()
- }
- }
- override func viewWillDisappear(_ animated: Bool) {
- super.viewWillDisappear(animated)
- DispatchQueue.main.async {
- UIApplication.shared.isIdleTimerDisabled = false
- }
- musicNameLab.stop()
- playerView.stop()
- musicEditBGView.pausePlayer()
- PQNotification.removeObserver(self)
- synchroMarskView.removeMarskView()
- }
- override func viewDidLoad() {
- super.viewDidLoad()
- leftButton(image: nil, tintColor: BFConfig.shared.styleTitleColor)
- navHeadImageView?.addSubview(nextBtn)
- navHeadImageView?.addSubview(musicNameView)
- // 添加子视图
- addSubViews()
- prepareMeta()
- // 曝光上报:预览页面曝光上报
- BFEventTrackAdaptor.baseReportUpload(businessType: .bt_windowView, objectType: .ot_view_previewSyncedUp, pageSource: .sp_stuck_previewSyncedUp, commonParams: commonParams())
- // 从选择的素材中 第一个素材设置封面
- if selectedPhotoData != nil, selectedPhotoData!.count > 0 {
- let photo = selectedPhotoData!.first!
- let option = PHImageRequestOptions()
- option.isNetworkAccessAllowed = true // 允许下载iCloud的图片
- option.resizeMode = .none
- option.deliveryMode = .highQualityFormat
- PHImageManager.default().requestImage(for: photo, targetSize: CGSize(width: 1920, height: 1920), contentMode: .aspectFill, options: option) { [weak self] image, _ in
- // image就是图片
- if image != nil {
- self?.firstFrameImage = image
- }
- }
- }
- }
- override func viewDidLayoutSubviews() {
- super.viewDidLayoutSubviews()
- playerView.resetCanvasFrame(frame: coculationPlayViewRect())
- }
- func prepareMeta() {
- // 导出相册视频
- exportPhotoData()
- // 同步音乐数据
- synchroMusicInfoData()
- // 插入选择的音乐信息
- musicEditBGView.firstInsertVoiceModel = stuckPointMusicData!
- }
- /// 添加子视图
- /// - Returns: <#description#>
- func addSubViews() {
- if (stuckPointMusicData?.rhythmSdata.count ?? 0) <= 0 {
- return
- }
- view.addSubview(playerView)
- view.addSubview(pointEditBGView)
- view.addSubview(musicEditBGView)
- view.addSubview(optionlineView)
- view.addSubview(pointEditerBtn)
- view.addSubview(musicEditerBtn)
- view.addSubview(customSpeedSettingView)
- // 卡点
- pointEditBGView.addSubview(pointEditRemindLab)
- pointEditBGView.addSubview(speedTitleLab)
- pointEditBGView.addSubview(speedStuckBtn)
- pointEditBGView.addSubview(jumpPointBtn)
- pointEditBGView.addSubview(onlyMusicBtn)
- pointEditBGView.addSubview(speedSettingView)
- pointEditBGView.addSubview(sustomSwitchView)
- // 音乐
- musicEditBGView.addSubview(stuckPointCuttingView)
- pointEditerBtn.snp.makeConstraints { make in
- make.left.equalToSuperview().offset(100)
- make.bottom.equalToSuperview().offset(-(14 + cAKSafeAreaHeight))
- make.height.equalTo(24)
- make.width.equalTo(24)
- }
- musicEditerBtn.snp.makeConstraints { make in
- make.right.equalToSuperview().offset(-100)
- make.top.equalTo(pointEditerBtn.snp.top)
- make.height.equalTo(24)
- make.width.equalTo(24)
- }
- pointEditBGView.snp.makeConstraints { make in
- make.left.right.equalTo(view)
- make.bottom.equalTo(pointEditerBtn.snp.top).offset(-7)
- make.height.equalTo(290)
- }
- musicEditBGView.snp.makeConstraints { make in
- make.left.right.equalToSuperview()
- make.bottom.equalTo(pointEditerBtn.snp.top).offset(-7)
- make.height.equalTo(290)
- }
- optionlineView.snp.makeConstraints { make in
- make.left.right.equalToSuperview()
- make.bottom.equalTo(pointEditBGView.snp.bottom).offset(-1)
- make.height.equalTo(1)
- }
- stuckPointCuttingView.snp.makeConstraints { make in
- make.left.right.equalToSuperview()
- make.bottom.equalTo(musicEditBGView.snp.bottom).offset(-1)
- make.height.equalTo(85)
- }
- pointEditRemindLab.snp.makeConstraints { make in
- make.left.equalToSuperview().offset(16)
- make.top.equalToSuperview().offset(16)
- make.height.equalTo(20)
- make.width.equalTo(80)
- }
- speedStuckBtn.snp.makeConstraints { make in
- make.left.equalToSuperview().offset(16)
- make.top.equalTo(pointEditRemindLab.snp.bottom).offset(8)
- make.height.equalTo(80)
- make.width.equalTo(80)
- }
- jumpPointBtn.snp.makeConstraints { make in
- make.left.equalTo(speedStuckBtn.snp.right).offset(10)
- make.top.equalTo(speedStuckBtn.snp.top)
- make.height.equalTo(80)
- make.width.equalTo(80)
- }
- onlyMusicBtn.snp.makeConstraints { make in
- make.left.equalTo(jumpPointBtn.snp.right).offset(10)
- make.top.equalTo(speedStuckBtn.snp.top)
- make.height.equalTo(80)
- make.width.equalTo(64)
- }
- // 重新设置三个模式 btn 图片和title的位置
- speedStuckBtn.titleEdgeInsets = UIEdgeInsets(top: 0, left: -(speedStuckBtn.imageView?.frame.size.width ?? 0), bottom: -(speedStuckBtn.imageView?.frame.size.height ?? 0), right: 0)
- speedStuckBtn.imageEdgeInsets = UIEdgeInsets(top: -(speedStuckBtn.titleLabel?.intrinsicContentSize.height ?? 0), left: 0, bottom: 0, right: -(speedStuckBtn.titleLabel?.intrinsicContentSize.width ?? 0))
- jumpPointBtn.titleEdgeInsets = UIEdgeInsets(top: 0, left: -(jumpPointBtn.imageView?.frame.size.width ?? 0), bottom: -(jumpPointBtn.imageView?.frame.size.height ?? 0), right: 0)
- jumpPointBtn.imageEdgeInsets = UIEdgeInsets(top: -(jumpPointBtn.titleLabel?.intrinsicContentSize.height ?? 0), left: 0, bottom: 0, right: -(jumpPointBtn.titleLabel?.intrinsicContentSize.width ?? 0))
- onlyMusicBtn.titleEdgeInsets = UIEdgeInsets(top: 0, left: -(onlyMusicBtn.imageView?.frame.size.width ?? 0), bottom: -(onlyMusicBtn.imageView?.frame.size.height ?? 0), right: 0)
- onlyMusicBtn.imageEdgeInsets = UIEdgeInsets(top: -(onlyMusicBtn.titleLabel?.intrinsicContentSize.height ?? 0), left: 0, bottom: 0, right: -(onlyMusicBtn.titleLabel?.intrinsicContentSize.width ?? 0))
- speedSettingView.snp.makeConstraints { make in
- make.left.equalToSuperview().offset(16)
- make.right.equalToSuperview()
- make.top.equalTo(onlyMusicBtn.snp.bottom).offset(10)
- make.height.equalTo(44)
- }
- speedTitleLab.snp.makeConstraints { make in
- make.left.equalToSuperview().offset(16)
- make.top.equalToSuperview().offset(190)
- make.height.equalTo(20)
- make.width.equalTo(80)
- }
- sustomSwitchView.snp.makeConstraints { make in
- make.left.equalToSuperview().offset(16)
- make.top.equalTo(speedTitleLab.snp.bottom).offset(8)
- make.height.equalTo(30)
- make.width.equalTo(180)
- }
- }
- @objc func nextBtnClick(sender _: UIButton) {
- BFLog(message: "去发布")
- isClickNextBtn = true
- 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, currentCreateStickersModel, modelSpeed_maxSpeed, modelSpeed_minSpeed, Float(finallyStuckPoints.last ?? 0) - Float(finallyStuckPoints.first ?? 0), getClipAudioRange(), playeTimeRange)
- } else {
- if finallyStuckPoints.count == 0 {
- cShowHUB(superView: nil, msg: "无卡点信息,返回重新选择音乐")
- return
- }
- let videoExporter = PQStuckPointPublicController()
- videoExporter.rhythmMode = currentCreateStickersModel
- videoExporter.syncedUpVideoSpeedMin = modelSpeed_maxSpeed
- videoExporter.syncedUpVideoSpeedMax = modelSpeed_minSpeed
- videoExporter.isReCreate = isReCreate
- videoExporter.selectedTotalDuration = selectedTotalDuration
- videoExporter.selectedDataCount = selectedDataCount
- videoExporter.selectedImageDataCount = selectedImageDataCount
- videoExporter.finallyUserAudioTime = Float(finallyStuckPoints.last ?? 0) - Float(finallyStuckPoints.first ?? 0)
- videoExporter.clipAudioRange = getClipAudioRange()
- videoExporter.playeTimeRange = playeTimeRange
- videoExporter.mStickers = mStickers
- videoExporter.audioMixModel = stuckPointMusicData
- videoExporter.coverImage = selectedMetarialData?.first?.coverImageUI ?? UIImage()
- videoExporter.editProjectModel = tempModel
- navigationController?.pushViewController(videoExporter, animated: true)
- }
- // 点击上报:去合成
- BFEventTrackAdaptor.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], commonParams: commonParams())
- }
- override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
- super.touchesBegan(touches, with: event)
- if touches.first?.view != customSpeedSettingView {
- if !customSpeedSettingView.isHidden {
- customSpeedSettingView.isHidden = true
- }
- }
- }
- // 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,添加选择的视觉素材
- if projectModel.sData?.sections.count == 0 {
- 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(model)
- }
- projectModel.sData?.sections.append(section)
- }
- // 2,添加背景音乐
- projectModel.sData?.addBGM(audioMix: stuckPointMusicData!)
- }
- // 计算拼接音乐的开始和结束点
- func getClipAudioRange() -> CMTimeRange {
- // 设置音乐的拼接范围,开始:推荐的卡点 结束:点到的倒数第二位
- if stuckPointMusicData!.rhythmSdata.count > 0, stuckPointMusicData?.rhythmSdata[0].pointTimes.count ?? 0 > 2 {
- let lastSecondPoint = Float(stuckPointMusicData!.rhythmSdata[0].pointTimes[stuckPointMusicData!.rhythmSdata[0].pointTimes.count - 2]) / Float(BASE_FILTER_TIMESCALE)
- let clipAudioRange =
- CMTimeRange(start: CMTime(value: CMTimeValue(Float(stuckPointMusicData?.startTime ?? 0) * Float(BASE_FILTER_TIMESCALE)), timescale: BASE_FILTER_TIMESCALE), end: CMTime(value: CMTimeValue(Float(lastSecondPoint) * Float(BASE_FILTER_TIMESCALE)), timescale: BASE_FILTER_TIMESCALE))
- return clipAudioRange
- }
- return CMTimeRange(start: CMTime(value: 0, timescale: 1), duration: CMTime(value: 1, timescale: 1))
- }
- // 设置播放器
- func coculationPlayViewRect() -> CGRect {
- let playerShowHeight = pointEditBGView.frame.minY - (navHeadImageView?.frame.maxY ?? 0)
- var showRect: CGRect = CGRect(x: (cScreenWidth - playerShowHeight) / 2, y: 0, width: playerShowHeight, height: playerShowHeight)
- if firstFrameImage != nil {
- let w = firstFrameImage!.size.width
- let h = firstFrameImage!.size.height
- let ratioMaterial: Float = Float(w / max(h, 1))
- if ratioMaterial > 1 {
- // 横屏
- let tempPlayerHeight = min(cScreenWidth * CGFloat(h / w), playerShowHeight)
- showRect = CGRect(x: (cScreenWidth - tempPlayerHeight * CGFloat(ratioMaterial)) / 2, y: (playerShowHeight - tempPlayerHeight) / 2, width: tempPlayerHeight * CGFloat(ratioMaterial), height: tempPlayerHeight)
- } else {
- // 竖屏
- let playerViewWidth = (CGFloat(w) / CGFloat(h)) * playerShowHeight
- showRect = CGRect(x: (cScreenWidth - playerViewWidth) / 2, y: 0, width: playerViewWidth, height: 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
- }
- }
- if showRect.size.width != 0, showRect.size.height != 0 {
- if Int(showRect.height) % 2 != 0 {
- showRect.size.height = showRect.size.height + 1.0
- }
- if Int(showRect.width) % 2 != 0 {
- showRect.size.width = showRect.size.width + 1.0
- }
- }
- showRect.origin.y = (playerShowHeight - showRect.size.height) / 2.0 + (navHeadImageView?.frame.maxY ?? 0)
- return showRect
- }
- func settingPlayerView() {
- stuckPointCuttingView.resetDefaultsColor()
- synchroMarskView.show()
- // 1,设置播放器的显示区域 和画布大小
- // - 按第一个素材尺寸自适应
- playerView.pause()
- 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)
- }
- if videoSize.width.isNaN || videoSize.height.isNaN {
- BFLog(1, message: "宽高无效NaN")
- return
- }
- let maxValue = max(videoSize.width, videoSize.height)
- 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)
- let beginTime = Date()
- dealParameter(model: currentCreateStickersModel)
- // 更新裁剪时间条的的ui数据
- stuckPointCuttingView.videoDuration = max(CGFloat(finallyUserAudioTime), CGFloat(finallyStuckPoints.last!))
- let counn = (stuckPointMusicData?.rhythmSdata[0].pointTimes.count)! - 2
- let suggestRhythmStartTime = CGFloat(stuckPointMusicData?.suggestRhythmStartTime ?? 0)
- let suggestRhythmEndTime = max(suggestRhythmStartTime, CGFloat(stuckPointMusicData?.rhythmSdata[0].pointTimes[max(counn, 0)] ?? 0) / CGFloat(BASE_FILTER_TIMESCALE))
- stuckPointCuttingView.updateEndTime(
- startTime: CGFloat(CMTimeGetSeconds(playeTimeRange.start)),
- endTime: CGFloat(CMTimeGetSeconds(playeTimeRange.end)),
- suggestRhythmStartTime: suggestRhythmStartTime,
- suggestRhythmEndTime: suggestRhythmEndTime
- )
- // 2,创建滤镜
- DispatchQueue.global().async {
- 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)), model: self.currentCreateStickersModel)
- DispatchQueue.main.async { // 串行、异步
- self.playerView.mStickers = self.mStickers
- BFLog(message: "createStickers tiskskskskme \(Date().timeIntervalSince(beginTime))")
- // 3,设置音频
- let audioPath = self.stuckPointMusicData?.localPath ?? ""
- BFLog(message: "初始化音频播放器的音频地址为:\(audioPath)")
- self.playerView.stop()
- // 这里的测试这个音乐播放有问题
- // self.playerView.updateAsset(URL(fileURLWithPath: "63930549652d74e477141e3b79c8d29a9ef8af81625053214516.mp3", relativeTo:Bundle.main.resourceURL!), videoComposition: nil, audioMixModel: nil)
- self.playerView.updateAsset(URL(fileURLWithPath: documensDirectory + audioPath), videoComposition: nil, audioMixModel: nil, originMusicDuration: self.finallyUserAudioTime, clipAudioRange: self.getClipAudioRange(), isUsedAVPlayer: true)
- // 4, 设置播放器的输出画布大小
- self.playerView.movie?.mShowVidoSize = CGSize(width: CGFloat(self.projectModel.sData?.videoMetaData?.videoWidth ?? 0), height: CGFloat(self.projectModel.sData?.videoMetaData?.videoHeight ?? 0))
- // 传给movie 音频的原始卡点
- let fir = Int64(self.stuckPointsTemp.first ?? 0)
- let endd = Int64(self.stuckPointsTemp.last ?? 0)
- self.playerView.movie?.orginStuckRange = CMTimeRange(start: CMTime(value: Int64(fir) * Int64(BASE_FILTER_TIMESCALE), timescale: BASE_FILTER_TIMESCALE), end: CMTime(value: Int64(endd) * Int64(BASE_FILTER_TIMESCALE), timescale: BASE_FILTER_TIMESCALE))
- // 5,开始播放
- self.playerView.isLoop = false
- self.playerView.showProgressLab = true
- // 初始化音频的开始和结束时间
- BFLog(message: "播放的器 开始\(String(describing: CMTimeGetSeconds(self.playeTimeRange.start))) 结束 \(String(describing: CMTimeGetSeconds(self.playeTimeRange.end)))")
- let end3: TimeInterval = Date().timeIntervalSince1970
- self.playerView.play(pauseFirstFrame: false, playeTimeRange: CMTimeRange(start: self.playeTimeRange.start, end: self.playeTimeRange.end))
- self.stuckPointCuttingView.updateProgress(progress: 0)
- self.synchroMarskView.removeMarskView()
- let end4: TimeInterval = Date().timeIntervalSince1970
- BFLog(message: " playerView.play tiskskskskme \(end4 - end3)")
- // 6,进度回调
- self.playerView.progress = { [weak self] currentTime, tatolTime, percent in
- if percent == 1 {
- self?.stuckPointCuttingView.resetDefaultsColor(clearData: false)
- sharedImageProcessingContext.framebufferCache.purgeAllUnassignedFramebuffers()
- return
- }
- if CMTimeGetSeconds(self?.playeTimeRange.duration ?? .zero) <= 0.0 {
- BFLog(message: "时长错误!!!!")
- return
- }
- // 更新进度
- let progress = (currentTime - CMTimeGetSeconds(self?.playeTimeRange.start ?? .zero)) / CMTimeGetSeconds(self?.playeTimeRange.duration ?? .zero)
- BFLog(message: "\(currentTime) \(tatolTime) 显示播放器进度为: \(progress)")
- self?.stuckPointCuttingView.updateProgress(progress: CGFloat(progress))
- }
- }
- }
- }
- deinit {
- musicNameLab.stop()
- // playerView.pause()
- // 取消所有的导出
- PQSingletoMemoryUtil.shared.allExportSession.forEach { _, exportSession in
- exportSession.cancelExport()
- }
- self.synchroMarskView.removeMarskView()
- sharedImageProcessingContext.framebufferCache.purgeAllUnassignedFramebuffers()
- BFLog(1, message: "卡点视频预览界面release")
- }
- }
- // 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 - 1) - selectedImageDataCount
- // 所有视频总时长
- var videoTotalDuration: Float64 = 0.0
- for video in section.sectionTimeline!.visionTrack!.getEnableVisionTrackMaterials(type: "video") {
- // MARK: SanW-2021.11.15-不再导出到沙盒,直接使用本地相册地址
- let asset: AVURLAsset = AVURLAsset(url: URL(fileURLWithPath: video.locationPath), options: nil)
- // 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 {
- // MARK: SanW-2021.11.15-不再导出到沙盒,直接使用本地相册地址
- let asset: AVURLAsset = AVURLAsset(url: URL(fileURLWithPath: sticker.locationPath), options: nil)
- // 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 {
- // deep copy sticker model 防止只有一个对象
- let deepCopySticker: PQEditVisionTrackMaterialsModel? = sticker.copy() as? PQEditVisionTrackMaterialsModel
- // 设置循环模式和适配模式
- 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)
- }
- }
- // kongduan = clipNumTep
- return stickers
- }
- // 更新 playeTimeRange & finallyUserAudioTime
- func updateTimeInfomation() {
- // 四,背景音乐时长处理)计算最后使用的音频时长, 如果不用拼接音频时长度是卡点的倒数第二位时间
- let asset = AVURLAsset(url: URL(fileURLWithPath: documensDirectory + (stuckPointMusicData?.localPath ?? "")), options: nil)
- // 原推荐卡点的倒数第二位时间
- let lastSecondPoint = Float(stuckPointMusicData!.rhythmSdata[0].pointTimes[stuckPointMusicData!.rhythmSdata[0].pointTimes.count - 2]) / Float(BASE_FILTER_TIMESCALE)
- finallyUserAudioTime = Float(lastSecondPoint)
- if (finallyStuckPoints.last ?? 0) > Float(CMTimeGetSeconds(asset.duration)) {
- finallyUserAudioTime = Float(finallyStuckPoints.last ?? 0) + (Float(CMTimeGetSeconds(asset.duration)) - Float(lastSecondPoint))
- }
- playeTimeRange = CMTimeRange(start: CMTime(value: CMTimeValue(Float64(finallyStuckPoints.first ?? 0) * Float64(BASE_FILTER_TIMESCALE)), timescale: BASE_FILTER_TIMESCALE), end: CMTime(value: CMTimeValue(Float64(finallyStuckPoints.last ?? 0) * Float64(BASE_FILTER_TIMESCALE)), timescale: BASE_FILTER_TIMESCALE))
- for (index, usePoint) in finallyStuckPoints.enumerated() {
- BFLog(message: "测试人员最后使用的卡点信息 \(index) : \(usePoint)")
- }
- BFLog(message: "计算后给播放器使用的开始:\(CMTimeGetSeconds(playeTimeRange.start)) 结束时间\(CMTimeGetSeconds(playeTimeRange.end)) 播放总时长:\(CMTimeGetSeconds(playeTimeRange.end) - CMTimeGetSeconds(playeTimeRange.start))")
- }
- /// 创建sticker
- /// - Parameters:
- /// - sections: 项目所有段落数据信息
- /// - inputSize: 画布大小
- /// - Returns: filters 数据 播放器可直接使用
- func createStickers(sections: List<PQEditSectionModel>, inputSize _: CGSize = .zero, model: createStickersModel = .createStickersModelPoint) -> [PQEditVisionTrackMaterialsModel] {
- // 推荐卡点数
- let beginDecoderTime: TimeInterval = Date().timeIntervalSince1970
- // 保存滤镜对象数据
- var stickers: Array = Array<PQEditVisionTrackMaterialsModel>.init()
- for section in sections {
- if section.sectionType == "normal" {
- // 第一种情况:全是图片,三种模式都进行图片回环播放
- if section.sectionTimeline!.visionTrack!.getEnableVisionTrackMaterials(type: "video").count == 0, section.sectionTimeline!.visionTrack!.getEnableVisionTrackMaterials(type: "image").count > 0 {
- for (index, _) in finallyStuckPoints.enumerated() {
- let sticker: PQEditVisionTrackMaterialsModel = section.sectionTimeline!.visionTrack!.getEnableVisionTrackMaterials()[index % section.sectionTimeline!.visionTrack!.getEnableVisionTrackMaterials().count]
- BFLog(message: "stickerlocationPath sticker : \(sticker.locationPath)")
- //
- let deepCopySticker: PQEditVisionTrackMaterialsModel? = sticker.copy() as? PQEditVisionTrackMaterialsModel
- if deepCopySticker!.type == StickerType.IMAGE.rawValue {
- if index + 1 < finallyStuckPoints.count {
- deepCopySticker!.timelineIn = Float64(String(format: "%.6f", finallyStuckPoints[index])) ?? 0.0
- deepCopySticker!.timelineOut = Float64(String(format: "%.6f", finallyStuckPoints[index + 1])) ?? 0.0
- if deepCopySticker != nil {
- deepCopySticker?.generateDefaultValues()
- stickers.append(deepCopySticker!)
- BFLog(1, message: "测试人员index is 纯图片 timelineOut:\(deepCopySticker!.timelineIn) timelineOut :\(deepCopySticker!.timelineOut)")
- }
- }
- }
- }
- } else { // 第二种情况:视频 + 图片情况、视频要分段+图片按卡点时长创建
- if model == .createStickersModelPoint { // 跳跃卡点
- // 第二种情况:有视频要进行分割
- let clipFilters = clipVideoMerage(section: section, stuckPoints: finallyStuckPoints)
- // 数据不一致时要对数据进行二次处理,不是最好方案
- if clipFilters.count > finallyStuckPoints.count - 1 {
- clipPoint(clipNum: clipFilters.count - finallyStuckPoints.count, oldPoints: finallyStuckPoints)
- } else if clipFilters.count < finallyStuckPoints.count - 1 {
- while clipFilters.count < finallyStuckPoints.count - 1 {
- finallyStuckPoints.removeLast()
- }
- }
- // 更新最终使用值
- updateTimeInfomation()
- // stikcer段数比clipFilters 数 大于 1才是正确的
- BFLog(message: "stikcer count is\(clipFilters.count) finallyStuckPoints count is\(finallyStuckPoints.count)")
- for (index, point) in finallyStuckPoints.enumerated() {
- BFLog(message: "aaaaaindexindeindexxindexindexindex \(index) \(point)")
- if index + 1 < finallyStuckPoints.count, index < clipFilters.count {
- BFLog(message: "bbbbbindexindeindexxindexindexindex \(index) \(point)")
- let sticker: PQEditVisionTrackMaterialsModel = clipFilters[index]
- if sticker.type == StickerType.IMAGE.rawValue {
- BFLog(message: "当前是image filter !!!!!")
- }
- sticker.timelineIn = Float64(String(format: "%.6f", finallyStuckPoints[index])) ?? 0.0
- sticker.timelineOut = Float64(String(format: "%.6f", finallyStuckPoints[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
- }
- print("跳跃卡点测试人员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 if model == .createStickersModelOnlyMusic || model == .createStickersModelSpeed { // 仅音乐 和 快慢速卡点
- BFLog(message: "stuckPoints count is \(finallyStuckPoints.count)")
- for sticker in section.sectionTimeline!.visionTrack!.getEnableVisionTrackMaterials() {
- if sticker.type == StickerType.VIDEO.rawValue {
- // MARK: SanW-2021.11.15-不再导出到沙盒,直接使用本地相册地址
- let asset: AVURLAsset = AVURLAsset(url: URL(fileURLWithPath: sticker.locationPath), options: nil)
- // let asset: AVURLAsset = AVURLAsset(url: URL(fileURLWithPath: documensDirectory + sticker.locationPath), options: nil)
- BFLog(message: "单个视频\(sticker.locationPath)时长::\(CMTimeGetSeconds(asset.duration)) ,clipNum is:\(sticker.clipCount)")
- var lastOutTime: Float64 = 0.0
- for _ in 1 ... sticker.clipCount {
- // deep copy sticker model 防止只有一个对象
- let deepCopyStickerDecoderTime: TimeInterval = Date().timeIntervalSince1970
- let deepCopySticker: PQEditVisionTrackMaterialsModel? = sticker.copy() as? PQEditVisionTrackMaterialsModel
- BFLog(message: "生成stickers 总时长为 aaa\(Date().timeIntervalSince1970 - deepCopyStickerDecoderTime)")
- // 设置循环模式和适配模式
- deepCopySticker?.generateDefaultValues()
- deepCopySticker?.materialDurationFit?.fitType = adapterMode.staticFrame.rawValue
- // 当前分段的速度
- var tempSpeed: Float = 1.0
- if model == .createStickersModelSpeed {
- tempSpeed = (stickers.count % 2) == 0 ? modelSpeed_maxSpeed : modelSpeed_minSpeed
- }
- if stickers.count + 1 < finallyStuckPoints.count {
- deepCopySticker?.speedRate = tempSpeed
- // 定义临时使用的变量
- // 素材显示的开始时间和结束时间
- let tempTimelineIn: Float64 = Float64(String(format: "%.6f", finallyStuckPoints[stickers.count])) ?? 0.0
- let timelineOut: Float64 = Float64(String(format: "%.6f", finallyStuckPoints[stickers.count + 1])) ?? 0.0
- // 素材分割的开始时间和结束时间
- let tempModel_In = lastOutTime
- var tempOut = lastOutTime + Float64(tempSpeed) * (timelineOut - tempTimelineIn)
- // 处理最后一点视频素材不够卡点时长 e.g. 0.3 卡点时长0.5
- if tempOut > CMTimeGetSeconds(asset.duration) {
- // 最后一点素材时长
- let lastAssetDuration = CMTimeGetSeconds(asset.duration) - lastOutTime
- let pointDuration = timelineOut - tempTimelineIn
- // 要适应到卡点内要使用的C速度
- let needSpeed = lastAssetDuration / pointDuration
- // 当前卡点段为快速 快速都用 C 速处理
- BFLog(message: "最后一点视频素材不够卡点时长要做变速C处理 差\(tempOut - CMTimeGetSeconds(asset.duration)) \(needSpeed)")
- deepCopySticker?.speedRate = Float(needSpeed)
- tempOut = CMTimeGetSeconds(asset.duration)
- if needSpeed == 0 {
- BFLog(message: "needSpeed is 0 出现在时长和卡点正好相等")
- continue
- }
- }
- deepCopySticker?.model_in = tempModel_In
- deepCopySticker?.out = tempOut
- deepCopySticker?.timelineIn = tempTimelineIn
- deepCopySticker?.timelineOut = timelineOut
- lastOutTime = deepCopySticker?.out ?? 0
- }
- BFLog(message: "测试人员创建 sticker crilp is in 视频 \(String(format: "%.6f", deepCopySticker?.model_in ?? 0)) out \(String(format: "%.6f", deepCopySticker?.out ?? 0)) ,分段素材时长:\(String(format: "%.6f", (deepCopySticker?.out ?? 0) - (deepCopySticker?.model_in ?? 0))) ,分段显示时长:\(String(format: "%.6f", (deepCopySticker?.timelineOut ?? 0) - (deepCopySticker?.timelineIn ?? 0))), 视频素材原时长\(CMTimeGetSeconds(asset.duration)) clipNum \(sticker.clipCount) timelineIN: \(String(format: "%.6f", deepCopySticker?.timelineIn ?? 0)) timelineOUT:\(String(format: "%.6f", deepCopySticker?.timelineOut ?? 0)) speedRate:\(deepCopySticker?.speedRate ?? 0.0)")
- if deepCopySticker != nil {
- if deepCopySticker?.timelineIn == 0 {
- BFLog(message: "timelineIn data is error!!!")
- }
- stickers.append(deepCopySticker!)
- }
- }
- } else if sticker.type == StickerType.IMAGE.rawValue {
- if stickers.count + 1 >= finallyStuckPoints.count {
- BFLog(message: "数据出现错误!!!查正") // 155.318253
- break
- }
- sticker.generateDefaultValues()
- sticker.timelineIn = Float64(String(format: "%.6f", finallyStuckPoints[stickers.count])) ?? 0.0
- sticker.timelineOut = Float64(String(format: "%.6f", finallyStuckPoints[stickers.count + 1])) ?? 0.0
- stickers.append(sticker)
- BFLog(message: "测试人员创建 sticker crilp is in 图片 \(String(format: "%.6f", sticker.model_in)) out \(String(format: "%.6f", sticker.out)) ,分段素材时长:\(String(format: "%.6f", sticker.out - sticker.model_in)) ,分段显示时长:\(String(format: "%.6f", sticker.timelineOut - sticker.timelineIn)), timelineIN: \(String(format: "%.6f", sticker.timelineIn)) timelineOUT:\(String(format: "%.6f", sticker.timelineOut)) speedRate:\(sticker.speedRate)")
- }
- }
- }
- }
- }
- }
- BFLog(message: "生成stickers 总时长为:\(Date().timeIntervalSince1970 - beginDecoderTime)")
- return stickers
- }
- /// 根据档位取最后使用的卡点数据
- /// - Parameter seed: 档位速度
- /// - Returns: 最后使用的卡点
- func getUsedStuckPoint(seed: Int) -> [Float] {
- if !(stuckPointMusicData!.rhythmSdata.count > 0 && stuckPointMusicData!.rhythmSdata[0].pointTimes.count > 1) {
- return []
- }
- // 推荐卡点数
- var stuckPoints: Array = Array<Float>.init()
- var pointsTemp = Array<Float>.init()
- //
- // 最后一个卡点时间(原推荐卡点的倒数第二位时间)
- let lastPoint = stuckPointMusicData!.rhythmSdata[0].pointTimes[stuckPointMusicData!.rhythmSdata[0].pointTimes.count - 2]
- for (index, dunshu) in stuckPointMusicData!.rhythmSdata[0].pointTimes.enumerated() {
- if dunshu >= Int64((stuckPointMusicData?.startTime ?? 0) * Float64(BASE_FILTER_TIMESCALE)), dunshu < lastPoint {
- let savePointStr = String(format: "%.6f", Float(dunshu) / Float(BASE_FILTER_TIMESCALE))
- BFLog(message: "原所有卡点数:\(index) \(savePointStr)")
- pointsTemp.append(Float(savePointStr) ?? 0.0)
- }
- }
- /*
- 一,快慢速模式下取卡点 2 3 4
- 二,跳跃卡点模式下根据不同速度 取卡点 1,2,3
- 快节奏为选中区域的所有点位,即0,1,2,3,4 5 6 7 8 9 10 ……
- 适中为每两个点位取一个,即0,2,4,6……
- 慢节奏为每三个点位取一个,即0,3,6,9……
- */
- // 不丢
- if seed == 1 {
- stuckPoints = pointsTemp
- } else {
- // 根据档位要丢
- for (index, point) in pointsTemp.enumerated() {
- if index % seed == 0 {
- stuckPoints.append(point)
- }
- }
- }
- // for point in stuckPoints {
- // BFLog(message: "没有 start end 计算后的卡点数\(point)")
- // }
- // 若音乐起点至第一个卡点点位之间时长t0<0.3时,此段时长与下一个点位时长合并,故第一段卡点部分时长为t0+d
- while (stuckPoints.first ?? 0.0) - Float(stuckPointMusicData?.startTime ?? 0) < 0.3 {
- if stuckPoints.first != nil {
- stuckPoints.removeFirst()
- }
- }
- stuckPoints.insert(Float(stuckPointMusicData?.startTime ?? 0), at: 0)
- // for point in stuckPoints {
- // BFLog(message: "有 start end 计算后的卡点数\(point)")
- // }
- BFLog(message: "处理节奏后 stuckPoints count is \(stuckPoints.count) seed \(seed), start time:\(stuckPoints.first ?? 0.0),end time:\(stuckPoints.last ?? 0.0) 总时长为:\((stuckPoints.last ?? 0.0) - (stuckPoints.first ?? 0.0))")
- return stuckPoints
- }
- func clipPoint(clipNum: Int, oldPoints: [Float]) {
- BFLog(message: "拼接卡点数:\(clipNum)")
- if clipNum < 0 || oldPoints.count < 2 {
- BFLog(message: "clipNum is error!!!! \(clipNum)")
- return
- }
- // 如果是第一次拼接先补第0位
- if finallyStuckPoints.count == 0 {
- finallyStuckPoints.append(stuckPointsTemp.first ?? 0.0)
- }
- for i in finallyStuckPoints.count ... clipNum + finallyStuckPoints.count {
- if (i % (oldPoints.count - 1)) != 1 {
- let value = String(format: "%.6f", finallyStuckPoints[i - 1] + oldPoints[((i - 1) % (oldPoints.count - 1)) + 1] - oldPoints[((i - 2) % (oldPoints.count - 1)) + 1])
- finallyStuckPoints.append(Float(value) ?? 0.0)
- } else {
- let value = String(format: "%.6f", finallyStuckPoints[i - 1] + oldPoints[1] - oldPoints[0])
- finallyStuckPoints.append(Float(value) ?? 0.0)
- }
- }
- }
- /// 根据不同模式model, maxSpeed ,minSpeed, self?.stuckPointMusicData?.speed 档位,生成音乐时长和最终使用的卡点信息
- func dealParameter(model: createStickersModel) {
- // 清空上一次使用的卡点数据
- finallyStuckPoints.removeAll()
- // 已经取到的视频素材总长度,用于和原视频素材时长做对比,不够多加一个点
- var useAssestDuration: Float = 0.0
- switch model {
- case .createStickersModelPoint: // 跳跃卡点
- stuckPointsTemp = getUsedStuckPoint(seed: stuckPointMusicData?.speed ?? 0)
- // 要拼接的段数
- var clipNum: Int = 0
- var i: Int = 0
- // L/(n+1) L -原视觉素材总时长 n-抛留倍数 lastJumpSpeedSelectIndex 是位置 对应的值要+1
- // 根据公式计划出的总时长
- let jumpTime = Float(selectedTotalDuration) / Float(modelPoint_speed + 1)
- // 只有图片素材时会为0
- if jumpTime > 0 {
- while useAssestDuration < Float(jumpTime) {
- // 回环从头取\
- if i + 1 >= stuckPointsTemp.count {
- i = 0
- }
- // 快速段
- let LA = (stuckPointsTemp[i + 1] - stuckPointsTemp[i])
- useAssestDuration = useAssestDuration + Float(LA)
- i = i + 1
- clipNum = clipNum + 1
- }
- // 拼接要使用的卡点信息
- clipPoint(clipNum: clipNum, oldPoints: stuckPointsTemp)
- }
- case .createStickersModelSpeed, .createStickersModelOnlyMusic: // 快慢速
- // 快慢速 (2:快节奏,3:适中,4:慢节奏)
- var tempMaxSpeed: Float = 1
- var tempMinSpeed: Float = 1
- if model == .createStickersModelSpeed {
- // 改变速率,.只有快慢速且非只有图片素材时自动+1处理
- if model == .createStickersModelSpeed, selectedDataCount != selectedImageDataCount {
- stuckPointsTemp = getUsedStuckPoint(seed: (stuckPointMusicData?.speed ?? 0) + 1)
- } else {
- stuckPointsTemp = getUsedStuckPoint(seed: stuckPointMusicData?.speed ?? 0)
- }
- tempMaxSpeed = modelSpeed_maxSpeed
- tempMinSpeed = modelSpeed_minSpeed
- } else {
- stuckPointsTemp = getUsedStuckPoint(seed: stuckPointMusicData?.speed ?? 0)
- }
- /*
- - A-视频中的快速片段
- - B-视频中的慢速片段
- - d-在一档下音乐每个点位时长
- - n-不同音乐档位对应的d倍数,快节奏时,n=1;适中时,n=3;慢节奏时,n=5
- - L-原视觉素材时长
- - x-视频在A片段的播放倍速
- - y-视频在B片段的播放倍速
- */
- // LA=x*n*d,LB=y*n*d (n=1/3/5) 注:视频经过快慢速处理后的总时长约=L*2/(x+y)
- BFLog(message: "Ax快速为:\(tempMaxSpeed) By慢速为:\(tempMinSpeed) 档位 N为:\(stuckPointMusicData?.speed ?? 0) 使用的卡点总数:\(stuckPointsTemp.count)")
- // 使用新方法取使用的卡点数据
- for section in projectModel.sData?.sections ?? List() {
- if section.sectionType == "normal" {
- for sticker in section.sectionTimeline!.visionTrack!.getEnableVisionTrackMaterials() {
- if sticker.type == StickerType.VIDEO.rawValue {
- // MARK: SanW-2021.11.15-不再导出到沙盒,直接使用本地相册地址
- let asset: AVURLAsset = AVURLAsset(url: URL(fileURLWithPath: sticker.locationPath), options: nil)
- // let asset: AVURLAsset = AVURLAsset(url: URL(fileURLWithPath: documensDirectory + sticker.locationPath), options: nil)
- let assetDuration = Float(CMTimeGetSeconds(asset.duration))
- BFLog(message: "输入素材时长 \(assetDuration)")
- if finallyStuckPoints.count == 0 {
- finallyStuckPoints.append(stuckPointsTemp[0])
- }
- var j = finallyStuckPoints.count
- // 添加卡点的段数 用于判断当前卡点是快/慢速
- var pointCount: Int = 1
- // 已经取到的视频素材总长度,用于和原视频素材时长做对比,不够多加一个卡点
- var useAssestDurationTemp: Float = 0.0
- while useAssestDurationTemp < assetDuration {
- // 当前段的应该使用的速度 A/B
- let useSpeed = (pointCount % 2 != 0) ? tempMaxSpeed : tempMinSpeed
- // 计算卡点
- // 要添加的卡点数值
- var sub: Float = 0.0
- if stuckPointsTemp.count > 2 {
- if ((j - 1) % (stuckPointsTemp.count - 1)) != 0 {
- sub = stuckPointsTemp[((j - 1) % (stuckPointsTemp.count - 1)) + 1] - stuckPointsTemp[(j - 1) % (stuckPointsTemp.count - 1)]
- } else {
- sub = stuckPointsTemp[1] - stuckPointsTemp[0]
- }
- finallyStuckPoints.append(finallyStuckPoints[j - 1] + sub)
- j += 1
- }
- useAssestDurationTemp += sub * useSpeed
- if useAssestDurationTemp > assetDuration {
- useAssestDurationTemp -= sub * useSpeed
- break
- }
- pointCount += 1
- BFLog(2, message: "finallyStuckPoints last ;\((finallyStuckPoints.last ?? 0.0) - (finallyStuckPoints.first ?? 0.0)), tmp:\(useAssestDurationTemp)")
- }
- // 2拼接要使用的卡点信息
- sticker.clipCount = pointCount
- if stuckPointsTemp.count < 1 {
- // todo 和产品沟通提示
- BFLog(message: "卡点数据有错误!!!")
- return
- }
- BFLog(message: "finallyStuckPoints\(finallyStuckPoints)")
- // 3,多补一个卡点 做 C级 速处理,要根据条件不满足 要删除最后一位,
- if useAssestDurationTemp < assetDuration {
- /*
- // 下一个卡的的速度性质快、慢,e.g. sticker.clipCount = 5时 tempSpeed 应该是慢速。下面计算正确。
- var tempSpeed: Float = 1.0
- if model == .createStickersModelSpeed {
- tempSpeed = (sticker.clipCount) % 2 != 0 ? modelSpeed_maxSpeed : modelSpeed_minSpeed
- }
- // 最后一点素材时长
- let lastAssetDuration = Float(CMTimeGetSeconds(asset.duration)) - useAssestDurationTemp
- let lastPointIndex = (sticker.clipCount % stuckPointsTemp.count)
- // 两个卡点
- let a: Float = stuckPointsTemp[lastPointIndex]
- var b: Float = 0.0
- if lastPointIndex + 1 < stuckPointsTemp.count {
- b = stuckPointsTemp[lastPointIndex + 1]
- let pointDuration = b - a
- // 要适应到卡点内要使用的C速度
- let needSpeed = lastAssetDuration / pointDuration
- // 当前卡点段为快速
- if tempSpeed >= 1 {
- // if needSpeed < 0.4 * tempSpeed {
- // BFLog(message: "条件不满足不用补位 删除多加的一位")
- // finallyStuckPoints.removeLast()
- // }
- } else { // 当前卡点段为慢速
- if needSpeed >= 0.4 * tempSpeed && needSpeed >= 0.2 {
- // 查找使用的最后一个卡点在原数组中的位置
- } else {
- BFLog(message: "条件不满足不用补位 删除多加的一位")
- finallyStuckPoints.removeLast()
- }
- }
- }
- */
- } else {
- // 出现在第一个卡点X 倍速 > 原素材
- finallyStuckPoints.removeLast()
- }
- }
- }
- }
- }
- }
- // 拼接图片所使用的时长.选择一组图片 按图片数量计算卡点的总时长
- if selectedImageDataCount > 0 {
- clipPoint(clipNum: selectedImageDataCount - 1, oldPoints: stuckPointsTemp)
- }
- // 全是图片时数组里放着的一定都是图片的使用的卡点
- // 定义一次循环的总时长
- var oneSelectImageDuration: Float = 0.0
- if selectedDataCount == selectedImageDataCount {
- oneSelectImageDuration = (finallyStuckPoints.last ?? 0) - (finallyStuckPoints.first ?? 0)
- }
- // 3)素材全是图片处理
- if selectedDataCount == selectedImageDataCount {
- // lastCyclesSelectIndex != -1 已经设置过循环次数 应该是手动设置的值
- if lastCyclesSelectIndex != -1 {
- // 纯图片时 已经默认添加一次循环 所以要用lastCyclesSelectIndex - 1
- if lastCyclesSelectIndex != 0 {
- clipPoint(clipNum: selectedImageDataCount * lastCyclesSelectIndex - 1, oldPoints: stuckPointsTemp)
- }
- } else {
- if oneSelectImageDuration < 10 {
- lastCyclesSelectIndex = 0
- while oneSelectImageDuration < 10 {
- // 不够10S 时 一次加图片数量的卡点数
- clipPoint(clipNum: selectedImageDataCount - 1, oldPoints: stuckPointsTemp)
- oneSelectImageDuration = Float((finallyStuckPoints.last ?? 0) - (finallyStuckPoints.first ?? 0))
- lastCyclesSelectIndex = lastCyclesSelectIndex + 1
- }
- speedSettingView.setSelectItem(index: lastCyclesSelectIndex, isSettingPlayer: false, enableInsert: true)
- } else {
- lastCyclesSelectIndex = 0
- }
- }
- }
- if finallyStuckPoints.count < 2 {
- cShowHUB(superView: nil, msg: "视频资源导入失败,请重新选择!!")
- exportResourceFailed()
- return
- }
- // 设置速度选择的位置
- if speedSettingView.viewType == 1 {
- speedSettingView.setSelectItem(index: lastSpeedSelectIndex, isSettingPlayer: false)
- } else if speedSettingView.viewType == 2 {
- speedSettingView.setSelectItem(index: lastJumpSpeedSelectIndex, isSettingPlayer: false)
- } else if speedSettingView.viewType == 3 {
- if lastCyclesSelectIndex != -1 {
- speedSettingView.setSelectItem(index: lastCyclesSelectIndex, isSettingPlayer: false)
- } else {
- speedSettingView.setSelectItem(index: 0, isSettingPlayer: false)
- }
- }
- updateTimeInfomation()
- }
- }
- // MARK: - 同步/下载素材相关
- /// 同步/下载素材相关
- extension PQStuckPointEditerController {
- /// 同步音乐相关数据
- /// - Returns: <#description#>
- func synchroMusicInfoData(resetSelectIndex: Bool = true) {
- if (stuckPointMusicData?.rhythmSdata.count ?? 0) <= 0 {
- synchroMarskView.show()
- 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?.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(resetSelectIndex: resetSelectIndex)
- }
- self?.synchroMarskView.removeMarskView()
- }
- } else {
- self?.isSynchroMusicInfoSuccess = true
- // 处理所有数据完成
- self?.dealWithDataSuccess(resetSelectIndex: resetSelectIndex)
- }
- // 添加子视图
- self?.addSubViews()
- } else {
- self?.synchroMarskView.removeMarskView()
- cShowHUB(superView: nil, msg: "音乐信息加载失败,请重新选择音乐")
- self?.navigationController?.popViewController(animated: true)
- }
- }
- } else if stuckPointMusicData?.localPath == nil || (stuckPointMusicData?.localPath?.count ?? 0) > 0 {
- synchroMarskView.show()
- 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(resetSelectIndex: resetSelectIndex)
- } else {
- self?.synchroMarskView.removeMarskView()
- cShowHUB(superView: nil, msg: "音乐信息加载失败,请重新选择音乐")
- // BFUploadRemindView.showUploadRemindView(title: nil, attributedTitle: NSAttributedString(string: "加载音乐失败,请重新选择音乐"), summary: "", confirmTitle: nil) { [weak self] _, _ in
- self?.navigationController?.popViewController(animated: true)
- }
- }
- } else {
- isStuckPointDataSuccess = true
- // 处理所有数据完成
- dealWithDataSuccess(resetSelectIndex: resetSelectIndex)
- }
- }
- /// 导出相册数据
- /// - Returns: <#description#>
- func exportPhotoData() {
- // 取消所有的导出
- PQSingletoMemoryUtil.shared.allExportSession.forEach { _, exportSession in
- exportSession.cancelExport()
- }
- var isHaveVideo: Bool = false
- var failedExprot: 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
- })
- // MARK: SanW-2021.11.15-不在导出到沙盒,直接用本地地址
- tempPhoto?.locationPath = fileName.replacingOccurrences(of: "file://", with: "")
- dispatchGroup.leave()
- // 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)")
- // }
- // }
- // let curr = Date()
- // let assetResources = PHAssetResource.assetResources(for: photo.asset!)
- // if let rsc = assetResources.first(where: { res in
- // res.type == .video || res.type == .pairedVideo
- // }) {
- // PHAssetResourceManager.default().writeData(for: rsc, toFile: URL(fileURLWithPath: outFilePath), options: nil) { error in
- // if error == nil {
- // BFLog(message: "导出视频相exportAsynchronously \(String(describing: outFilePath)) \(Date().timeIntervalSince(curr))")
- // tempPhoto?.locationPath = outFilePath.replacingOccurrences(of: documensDirectory, with: "")
- // }else{
- // failedExprot = true
- // BFLog(message: "导出视频相exportAsynchro faile")
- // }
- // dispatchGroup.leave()
- // }
- //
- // }else {
- // BFLog(message: "导出视频相exportAsynchro faile")
- // dispatchGroup.leave()
- // }
- // }
- }
- }
- }
- }
- dispatchGroup.notify(queue: DispatchQueue.main) { [weak self] in
- if failedExprot {
- cShowHUB(superView: nil, msg: "视频导入失败,请返回重试")
- self?.exportResourceFailed()
- return
- }
- self?.isExportVideosSuccess = true
- BFLog(message: "所有相册视频导出成功")
- // 处理所有数据完成
- if isHaveVideo {
- self?.dealWithDataSuccess()
- }
- }
- // 只有图片
- if !isHaveVideo {
- isExportVideosSuccess = true
- BFLog(message: "所有相册视频导出成功")
- dealWithDataSuccess()
- }
- }
- }
- func exportResourceFailed() {
- DispatchQueue.main.async {
- self.synchroMarskView.removeMarskView()
- self.navigationController?.popViewController(animated: true)
- }
- }
- /// 处理所有数据完成
- /// - Returns: <#description#>
- /// resetSelectIndex : 是否重置用户选择的速度设置,在编辑界面切换音乐时不重置
- func dealWithDataSuccess(resetSelectIndex: Bool = true) {
- BFLog(message: "三组参数:\(isSynchroMusicInfoSuccess) \(isStuckPointDataSuccess) \(isExportVideosSuccess)")
- if !isSynchroMusicInfoSuccess || !isStuckPointDataSuccess || !isExportVideosSuccess {
- return
- }
- createPorjectData()
- BFLog(1, message: "界面编辑界面时参数 选择素材时长:\(selectedTotalDuration) 选择素材总数:\(selectedDataCount) 选择图片总数\(selectedImageDataCount) 再创建类型:\(String(describing: reCreateVideoData?.rhythmMode))")
- if resetSelectIndex {
- // 1 生成默认参数值
- /*
- - 当素材总时长∈[0-6)s 时,提示推荐仅配乐模式 or 快慢速模式
- - 当素材总时长∈[6-80)s 时,卡点抛留倍数为1x
- - 当素材总时长∈[80,120)s 时,卡点抛留倍数为2x
- - 当素材总时长∈[120,160)s 时,卡点抛留倍数为3x
- - 当素材总时长∈[160,200)s 时,卡点抛留倍数为4x
- - 当素材总时长∈[200,240)s 时,卡点抛留倍数为5x
- - 当素材总时长∈[240,∞)s 时,卡点抛留倍数为5x
- */
- // 1.1) 生成跳跃卡点的默认值
- if selectedTotalDuration >= 6 && selectedTotalDuration < 80 {
- lastJumpSpeedSelectIndex = 0
- } else if selectedTotalDuration >= 80 && selectedTotalDuration < 120 {
- lastJumpSpeedSelectIndex = 1
- } else if selectedTotalDuration >= 120 && selectedTotalDuration < 160 {
- lastJumpSpeedSelectIndex = 2
- } else if selectedTotalDuration >= 160 && selectedTotalDuration < 200 {
- lastJumpSpeedSelectIndex = 3
- } else if (selectedTotalDuration >= 200 && selectedTotalDuration < 240) || selectedTotalDuration >= 240 {
- lastJumpSpeedSelectIndex = 4
- }
- /* 默认进入快慢速模式
- - 当素材总时长∈[120,144]s 时,快慢速处理方式:快速为 6x,慢速为 1.2x,效果是快&快
- - 当素材总时长∈[70,120)s 时,快慢速处理方式:快速为5x,慢速为 1x,效果是快&正常
- - 当素材总时长∈[56,70)s 时,快慢速处理方式:快速为3x,慢速为 0.5x,效果是快&慢
- - 当素材总时长∈[17.5,56)s 时,快慢速处理方式:快速为 2.4x,慢速为 0.4x,效果是快&慢
- - 当素材总时长∈[10.5,17.5)s 时,快慢速处理方式:快速为 1.8x,慢速为 0.3x,效果是快&慢
- - 当素材总时长∈(0,10.5)s 时,快慢速处理方式:快速为 1x,慢速为 0.2x,效果是正常&慢
- */
- // 1.2)生成快慢速的默认值
- if selectedTotalDuration >= 120 && selectedTotalDuration <= 144 || selectedTotalDuration > 144 {
- lastSpeedSelectIndex = 5
- } else if selectedTotalDuration >= 70, selectedTotalDuration < 120 {
- lastSpeedSelectIndex = 4
- } else if selectedTotalDuration >= 56, selectedTotalDuration < 70 {
- lastSpeedSelectIndex = 3
- } else if selectedTotalDuration >= 17.5, selectedTotalDuration < 56 {
- lastSpeedSelectIndex = 2
- } else if selectedTotalDuration >= 10.5, selectedTotalDuration < 17.5 {
- lastSpeedSelectIndex = 1
- } else if selectedTotalDuration > 0, selectedTotalDuration < 10.5 {
- lastSpeedSelectIndex = 0
- }
- // 如果是再创作进来的按原视频的模式
- if reCreateVideoData != nil {
- BFLog(message: "是再创作进来的 \(reCreateVideoData!.rhythmMode)")
- switch reCreateVideoData!.rhythmMode {
- case 1:
- editModelClick(sender: jumpPointBtn, reportLog: false)
- case 2:
- editModelClick(sender: speedStuckBtn, reportLog: false)
- case 3:
- editModelClick(sender: onlyMusicBtn, reportLog: false)
- default: break
- }
- return
- }
- // 跳跃卡点不可用
- if selectedTotalDuration < 6, selectedDataCount != selectedImageDataCount {
- let styleColor = UIColor.hexColor(hexadecimal: BFConfig.shared.styleColor.rawValue)
- jumpPointBtn.setTitleColor(UIColor(red: styleColor.rgbaf[0], green: styleColor.rgbaf[1], blue: styleColor.rgbaf[2], alpha: 0.3), for: .selected)
- let pointEditNamalBackgroundColor = BFConfig.shared.pointEditNamalBackgroundColor
- jumpPointBtn.backgroundColor = UIColor(red: pointEditNamalBackgroundColor.rgbaf[0], green: pointEditNamalBackgroundColor.rgbaf[1], blue: pointEditNamalBackgroundColor.rgbaf[2], alpha: 0.3)
- }
- /*
- 文档规则 https://w42nne6hzg.feishu.cn/docs/doccnQZm1uCfkU4QtJb5fLxYk4d#
- */
- // 2,根据所选择所有素材时长进入默认模式
- // 全是图片
- if selectedDataCount == selectedImageDataCount {
- BFLog(message: "全是图片 \(selectedDataCount) \(selectedImageDataCount)")
- // 默认进入跳跃卡点模式
- editModelClick(sender: jumpPointBtn, reportLog: false)
- } else {
- // 默认进入快慢速模式
- if selectedTotalDuration > 0, selectedTotalDuration <= 144 {
- editModelClick(sender: speedStuckBtn, reportLog: false)
- } else {
- // 默认进入跳跃卡点模式
- editModelClick(sender: jumpPointBtn, reportLog: false)
- }
- }
- } else {
- editModelClick(sender: lastEditModelBtn ?? jumpPointBtn, reportLog: false)
- }
- }
- }
|