BFRecordItemModel.swift 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. //
  2. // BFRecordItemModel.swift
  3. // BFRecordScreenKit
  4. //
  5. // Created by 胡志强 on 2021/12/6.
  6. //
  7. import BFCommonKit
  8. import BFMediaKit
  9. import Foundation
  10. import Photos
  11. struct SplitRecordRange {
  12. var isRecord: Bool = false
  13. var range: CMTimeRange
  14. var index: Int
  15. }
  16. public class BFRecordItemModel: NSObject {
  17. // var baseMaterial : AVURLAsset?
  18. var localPath: String?
  19. var materialDuraion: Double = 0.0
  20. var fetchCoverImg: ((UIImage) -> Void)?
  21. var fetchAVUrlAsset: ((AVURLAsset) -> Void)?
  22. var fetchPlayItem: ((AVPlayerItem) -> Void)?
  23. var dealedDurationRanges = [SplitRecordRange]() // 录音切割的时间区间,合成导出时计算
  24. public var voiceStickers = [PQVoiceModel]() //
  25. public var videoStickers = [PQEditVisionTrackMaterialsModel]() // 合成导出时计算
  26. public var imageStickers = [PQEditVisionTrackMaterialsModel]() //
  27. public var titleStickers = [PQEditSubTitleModel]() // 字幕贴纸
  28. public var coverImg: UIImage? // 封面图
  29. public var playItem: AVPlayerItem? // 视频playerItem
  30. public var videoAsset: AVURLAsset? // 视频Asset
  31. public var mediaType: StickerType? // 素材类型
  32. public var progress: Double = 0 // 更新进度
  33. public var index = 0 // 素材index
  34. public var width = 0 // 素材宽
  35. public var height = 0 // 素材高
  36. func initOriginData(phasset: PHAsset) {
  37. width = phasset.pixelWidth
  38. height = phasset.pixelHeight
  39. if phasset.mediaType == .image {
  40. mediaType = .IMAGE
  41. } else if phasset.mediaType == .video {
  42. mediaType = .VIDEO
  43. }
  44. fetchCoverImage(phasset)
  45. fetchPlayItem(phasset)
  46. fetchAVUrlAsset(phasset)
  47. }
  48. func fetchCoverImage(_ phasset: PHAsset) {
  49. let option = PHImageRequestOptions()
  50. option.isNetworkAccessAllowed = true // 允许下载iCloud的图片
  51. option.resizeMode = .fast
  52. option.deliveryMode = .highQualityFormat
  53. PHImageManager.default().requestImage(for: phasset,
  54. targetSize: CGSize(width: width, height: height),
  55. contentMode: .aspectFit,
  56. options: option) { [weak self] image, _ in
  57. // 设置首帧/封面
  58. if image != nil {
  59. self?.coverImg = image
  60. self?.fetchCoverImg?(image!)
  61. }
  62. }
  63. }
  64. func fetchPlayItem(_ phasset: PHAsset) {
  65. let options = PHVideoRequestOptions()
  66. options.isNetworkAccessAllowed = true
  67. options.deliveryMode = .automatic
  68. if phasset.mediaType == .image {
  69. } else if phasset.mediaType == .video {
  70. PHImageManager.default().requestPlayerItem(forVideo: phasset, options: options, resultHandler: { [weak self] playerItem, _ in
  71. guard let item = playerItem else {
  72. cShowHUB(superView: nil, msg: "视频获取失败:\(self?.index ?? 0)")
  73. return
  74. }
  75. self?.playItem = item
  76. self?.fetchPlayItem?(item)
  77. })
  78. }
  79. }
  80. func fetchAVUrlAsset(_ phasset: PHAsset) {
  81. let options = PHVideoRequestOptions()
  82. options.isNetworkAccessAllowed = true
  83. options.deliveryMode = .automatic
  84. PHCachingImageManager().requestAVAsset(forVideo: phasset, options: options, resultHandler: { [weak self] (asset: AVAsset?, _: AVAudioMix?, _) in
  85. if let videoAsset = asset as? AVURLAsset {
  86. self?.materialDuraion = videoAsset.duration.seconds
  87. self?.localPath = (videoAsset.url.absoluteString.removingPercentEncoding)?.replacingOccurrences(of: "file://", with: "")
  88. self?.videoAsset = videoAsset
  89. self?.fetchAVUrlAsset?(videoAsset)
  90. }
  91. })
  92. }
  93. func generationTimeRanges(needSort _: Bool = false) {
  94. dealedDurationRanges.removeAll()
  95. var start: Double = 0
  96. var list: [PQVoiceModel]
  97. list = voiceStickers.sorted { model1, model2 in
  98. model1.startTime < model2.startTime
  99. }
  100. for model in list {
  101. if model.startTime > start {
  102. //
  103. let range = CMTimeRange(start: CMTime(seconds: start, preferredTimescale: 100), duration: CMTime(seconds: model.startTime - start, preferredTimescale: 100))
  104. dealedDurationRanges.append(SplitRecordRange(isRecord: false, range: range, index: -1))
  105. }
  106. let ind = voiceStickers.firstIndex(of: model)
  107. let range = CMTimeRange(start: CMTime(seconds: model.startTime, preferredTimescale: 100), end: CMTime(seconds: model.endTime, preferredTimescale: 100))
  108. dealedDurationRanges.append(SplitRecordRange(isRecord: true, range: range, index: ind ?? -1))
  109. start = model.endTime
  110. }
  111. if start < materialDuraion {
  112. let range = CMTimeRange(start: CMTime(seconds: start, preferredTimescale: 100), end: CMTime(seconds: materialDuraion, preferredTimescale: 100))
  113. dealedDurationRanges.append(SplitRecordRange(isRecord: false, range: range, index: -1))
  114. }
  115. }
  116. }