PublishNewVideoPhotoView.swift 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842
  1. //
  2. // PublishNewVideoPhotoView.swift
  3. // RainbowPlanet
  4. //
  5. // Created by 南鑫林 on 2019/9/3.
  6. // Copyright © 2019 RainbowPlanet. All rights reserved.
  7. //
  8. import UIKit
  9. // MARK: - 初始化/action
  10. class PublishNewVideoPhotoView: BaseView {
  11. /// 销毁View
  12. deinit {
  13. NXLLog("deinit")
  14. if observe != nil {
  15. NotificationCenter.default.removeObserver(observe!)
  16. }
  17. }
  18. weak var observe : NSObjectProtocol?
  19. /// 录制的时长
  20. var recorderDuration: CGFloat = 0.0
  21. /// 录制最大时长
  22. let maxDuration : CGFloat = 60.0
  23. /// 录制最小时长
  24. let minDuration : CGFloat = 3.0
  25. /// 滤镜选中的selected
  26. var selectedIndex : Int = 0
  27. /// 是否完成录制
  28. var isFinishRecorder : Bool = false
  29. /// 封面图路径
  30. var outCoverImagePathURL : URL?
  31. /// 添加View
  32. override func setupViews() {
  33. backgroundColor = UIColor.black
  34. addSubview(recorderPreview)
  35. addSubview(publishNewVideoPhotoSetView)
  36. addSubview(effectFilterBeautyView)
  37. addSubview(musicView)
  38. }
  39. /// 布局
  40. override func setupLayouts() {
  41. publishNewVideoPhotoSetView.snp.makeConstraints { (make) in
  42. make.edges.equalToSuperview()
  43. }
  44. }
  45. /// 设置数据
  46. override func setupData() {
  47. // 返回
  48. publishNewVideoPhotoSetView.closeButton.rx.tap.subscribe(onNext: { [weak self] (data) in
  49. self?.recorder?.stopPreview()
  50. let vc = UIViewController.topMost
  51. vc?.navigationController?.dismiss(animated: true, completion: nil)
  52. }).disposed(by: disposeBag)
  53. // 翻转
  54. publishNewVideoPhotoSetView.cameraFlipButton.rx.tap.subscribe(onNext: {[weak self] (data) in
  55. self?.setCameraFlip()
  56. }).disposed(by: disposeBag)
  57. // 滤镜
  58. publishNewVideoPhotoSetView.filterButton.rx.tap.subscribe(onNext: {[weak self] (data) in
  59. self?.effectFilterBeautyView.filterBeautyType = .filter
  60. self?.effectFilterBeautyViewisHidden(isHidden: false)
  61. }).disposed(by: disposeBag)
  62. // 美颜
  63. publishNewVideoPhotoSetView.beautyButton.rx.tap.subscribe(onNext: {[weak self] (data) in
  64. self?.effectFilterBeautyView.filterBeautyType = .beauty
  65. self?.effectFilterBeautyViewisHidden(isHidden: false)
  66. }).disposed(by: disposeBag)
  67. // 音乐
  68. publishNewVideoPhotoSetView.musicButton.rx.tap.subscribe(onNext: {[weak self] (data) in
  69. self?.musicViewisHidden(isHidden: false)
  70. }).disposed(by: disposeBag)
  71. // 闪光灯
  72. publishNewVideoPhotoSetView.flashButton.rx.tap.subscribe(onNext: {[weak self] (data) in
  73. if self?.recorder?.torchMode == .auto {
  74. self?.recorder?.switchTorch(with: AliyunIRecorderTorchMode.on)
  75. self?.publishNewVideoPhotoSetView.flashButton.setImage(kImage(name: "video_ico_flashlight"), for: UIControl.State.normal)
  76. } else if self?.recorder?.torchMode == .on {
  77. self?.recorder?.switchTorch(with: AliyunIRecorderTorchMode.off)
  78. self?.publishNewVideoPhotoSetView.flashButton.setImage(kImage(name: "video_ico_flashlight_close"), for: UIControl.State.normal)
  79. } else if self?.recorder?.torchMode == .off {
  80. self?.recorder?.switchTorch(with: AliyunIRecorderTorchMode.auto)
  81. self?.publishNewVideoPhotoSetView.flashButton.setImage(kImage(name: "video_ico_flashlight_auto"), for: UIControl.State.normal)
  82. }
  83. }).disposed(by: disposeBag)
  84. //录制/拍摄
  85. publishNewVideoPhotoSetView.recordButton.rx.tap.subscribe(onNext: { [weak self] (data) in
  86. // 开始录制/暂停录制
  87. if PublishNewViewModel.shared.publishNewRecorderType == .video {
  88. if (self?.publishNewVideoPhotoSetView.recordButton.isSelected)! { //暂停拍摄
  89. self?.stopTakeVideo()
  90. }else { //开始拍摄
  91. self?.startTakeVideo()
  92. }
  93. }
  94. // 拍照
  95. if PublishNewViewModel.shared.publishNewRecorderType == .photo {
  96. // 拍照
  97. self?.takePhoto()
  98. //切换按钮状态
  99. self?.publishNewVideoPhotoSetView.recordButton.isSelected = false
  100. }
  101. }).disposed(by: disposeBag)
  102. // 回删视频
  103. publishNewVideoPhotoSetView.deleteButton.rx.tap.subscribe(onNext: { [weak self] (data) in
  104. /// 回删视频
  105. self?.deleteVideo()
  106. }).disposed(by: disposeBag)
  107. // 完成录制
  108. publishNewVideoPhotoSetView.finishButton.rx.tap.subscribe(onNext: { [weak self] (data) in
  109. //完成录制的view
  110. self?.finishRecorderView()
  111. if self?.recorder?.isRecording ?? true {
  112. // 完成录制需要先掉用停止录制在走delegate
  113. self?.stopTakeVideo()
  114. }else {
  115. self?.finishTakeVideo()
  116. }
  117. }).disposed(by: disposeBag)
  118. // 左滑 滤镜 加 1
  119. publishNewVideoPhotoSetView.leftSwipeClosure = {
  120. [weak self] in
  121. self?.filterPlus()
  122. }
  123. // 右滑 滤镜 减 1
  124. publishNewVideoPhotoSetView.rightSwipeClosure = {
  125. [weak self] in
  126. self?.filterLess()
  127. }
  128. // 美颜等级设置
  129. effectFilterBeautyView.effectBeautyView.didSelectCloSure = {
  130. [weak self] beautifyValue in
  131. self?.recorder?.beautifyValue = beautifyValue
  132. }
  133. // 美颜滤镜设置
  134. effectFilterBeautyView.effectFilterView.didSelectCloSure = {
  135. [weak self] (index, aliyunEffectFilter) in
  136. self?.selectedIndex = index
  137. if index == 0 {
  138. self?.recorder?.deleteFilter()
  139. }else {
  140. self?.recorder?.apply(aliyunEffectFilter)
  141. }
  142. self?.showFilterNameLabel(aliyunEffectFilter: aliyunEffectFilter)
  143. }
  144. // 关闭音乐按钮
  145. musicView.closeButton.rx.tap.subscribe(onNext: { [weak self] (data) in
  146. PublishNewMusicView.publishNewMusicSelectedIndexPath = nil
  147. self?.musicViewisHidden(isHidden: true)
  148. }).disposed(by: disposeBag)
  149. // 不使用音乐按钮
  150. musicView.noUseMusicButton.rx.tap.subscribe(onNext: { [weak self] (data) in
  151. PublishNewMusicView.publishNewMusicSelectedIndexPath = nil
  152. PublishNewMusicView.publishNewMusicUseIndexPath = nil
  153. let effectMusic : AliyunEffectMusic? = nil
  154. self?.recorder?.apply(effectMusic)
  155. self?.musicViewisHidden(isHidden: true)
  156. }).disposed(by: disposeBag)
  157. // 使用音乐
  158. musicView.userMusicClosure = {
  159. [weak self] in
  160. if PublishNewMusicView.publishNewMusicUseURL?.path == nil {
  161. PublishNewMusicView.publishNewMusicUseIndexPath = nil
  162. self?.musicViewisHidden(isHidden: true)
  163. SwiftProgressHUD.shared().showText("使用音乐错误,请您重新选择!!!")
  164. }else {
  165. PublishNewMusicView.publishNewMusicSelectedIndexPath = nil
  166. self?.recorder?.apply(AliyunEffectMusic(file: PublishNewMusicView.publishNewMusicUseURL?.path))
  167. self?.musicViewisHidden(isHidden: true)
  168. }
  169. }
  170. // 左滑 滤镜 加 1
  171. recorderPreview.leftSwipeClosure = {
  172. [weak self] in
  173. self?.filterPlus()
  174. }
  175. // 右滑 滤镜 减 1
  176. recorderPreview.rightSwipeClosure = {
  177. [weak self] in
  178. self?.filterLess()
  179. }
  180. // 点击手势
  181. recorderPreview.tapClosure = {
  182. [weak self] in
  183. if self?.effectFilterBeautyView.alpha == 1 {
  184. // 隐藏滤镜
  185. self?.effectFilterBeautyViewisHidden(isHidden: true)
  186. }
  187. if self?.musicView.alpha == 1 {
  188. // 隐藏音乐
  189. self?.musicViewisHidden(isHidden: true)
  190. }
  191. }
  192. // 对于锁屏,来电,退后台等事件,需要进行特殊处理。
  193. //当进入Inactive状态前需要调
  194. observe = NotificationCenter.default.addObserver(forName: UIApplication.willResignActiveNotification, object: nil, queue: OperationQueue.main) {[weak self] (_) in
  195. if self?.recorder?.isRecording ?? true {
  196. self?.stopTakeVideo()
  197. }
  198. self?.recorder?.stopPreview()
  199. }
  200. // 当进入Active状态
  201. observe = NotificationCenter.default.addObserver(forName: UIApplication.didBecomeActiveNotification, object: nil, queue: OperationQueue.main) {[weak self] (_) in
  202. self?.recorder?.startPreview()
  203. }
  204. }
  205. /// SDK录制类
  206. lazy var recorder: AliyunIRecorder? = {
  207. let recorder = AliyunIRecorder.init(delegate: self, videoSize: CGSize(width: 720, height: 1280))
  208. // 预览View
  209. recorder?.preview = recorderPreview
  210. //创建文件夹路径
  211. let taskPathUrl =
  212. PathURLManager.projectDateFormatPath(dateFormat: "yyyyMM", parentURL:
  213. PathURLManager.projectVideosPath(parentURL:
  214. PathURLManager.projectResourcesPath(parentURL:
  215. PathURLManager.projectRecordssPath(parentURL:
  216. PathURLManager.projectDocumentPath()))))!
  217. //清除录制路径
  218. PathURLManager.clearPath(pathURL: taskPathUrl)
  219. // 设置文件夹路径
  220. recorder?.taskPath = taskPathUrl.path
  221. // 设置录制视频输出路径
  222. let outputPathURL =
  223. PathURLManager.projectPathExtensionMp4(parentURL:
  224. PathURLManager.projectFilePath(fileName:
  225. PathURLManager.randomString(), parentURL:
  226. PathURLManager.projectDateFormatPath(dateFormat: "yyyyMM", parentURL:
  227. PathURLManager.projectVideosPath(parentURL:
  228. PathURLManager.projectResourcesPath(parentURL:
  229. PathURLManager.projectRecordssPath(parentURL:
  230. PathURLManager.projectDocumentPath()))))))!
  231. // 设置录制视频封面输出路径
  232. outCoverImagePathURL =
  233. PathURLManager.projectPathExtensionPng(parentURL:
  234. PathURLManager.projectFilePath(fileName:
  235. PathURLManager.randomString(), parentURL:
  236. PathURLManager.projectDateFormatPath(dateFormat: "yyyyMM", parentURL:
  237. PathURLManager.projectPicturesPath(parentURL:
  238. PathURLManager.projectResourcesPath(parentURL:
  239. PathURLManager.projectRecordssPath(parentURL:
  240. PathURLManager.projectDocumentPath()))))))!
  241. // 设置录制视频输出路径
  242. recorder?.outputPath = outputPathURL.path
  243. //循环切换手电筒模式手电筒模式有三种,分别是off,on和auto。切换顺序:off —-> on —-> auto。默认值:off。
  244. recorder?.switchTorch(with: AliyunIRecorderTorchMode.off)
  245. // 美颜状态
  246. recorder?.beautifyStatus = true;
  247. // 设置美颜度 [0,100]
  248. recorder?.beautifyValue = 50
  249. // 前置摄像头采集分辨率 默认:AVCaptureSessionPreset1280x720
  250. recorder?.frontCaptureSessionPreset = AVCaptureSession.Preset.hd1280x720.rawValue
  251. // 后置摄像头采集分辨率 默认:AVCaptureSessionPreset1280x720
  252. recorder?.backCaptureSessionPreset = AVCaptureSession.Preset.hd1280x720.rawValue
  253. // 设置摄像头角度
  254. recorder?.cameraRotate = 0
  255. // 设置编码方式 0软编 1硬编
  256. recorder?.encodeMode = 0
  257. // 设置关键帧间隔
  258. recorder?.gop = 5
  259. // 设置关键帧间隔
  260. recorder?.recordFps = 25
  261. // 设置是否静音
  262. recorder?.mute = false
  263. // 设置视频质量 如果设置了bitrate参数,那么当前设置无效。
  264. recorder?.videoQuality = .hight
  265. // 设置输出视频码率(bps)
  266. recorder?.bitrate = 2000000
  267. // 设置采集视频格式
  268. recorder?.outputType = .type420f
  269. // 设置视频最大时长 默认8
  270. recorder?.clipManager.maxDuration = maxDuration
  271. // 设置视频最小时长 默认8
  272. recorder?.clipManager.minDuration = minDuration
  273. return recorder!
  274. }()
  275. /// 摄像头
  276. lazy var recorderPreview : PublishNewRecorderPreview = {
  277. let recorderPreview = PublishNewRecorderPreview(frame: kScreenBounds)
  278. return recorderPreview
  279. }()
  280. /// 所有按钮View
  281. lazy var publishNewVideoPhotoSetView: PublishNewVideoPhotoSetView = {
  282. let publishNewVideoPhotoSetView = PublishNewVideoPhotoSetView()
  283. return publishNewVideoPhotoSetView
  284. }()
  285. /// 滤镜跟美颜
  286. lazy var effectFilterBeautyView: PublishNewEffectFilterBeautyView = {
  287. let effectFilterBeautyView = PublishNewEffectFilterBeautyView(frame: CGRect(x: 0, y: kScreenHeight, width: kScreenWidth, height: 48 + 125 + kSafeTabBarHeight))
  288. return effectFilterBeautyView
  289. }()
  290. /// 音乐
  291. lazy var musicView : PublishNewMusicView = {
  292. let musicView = PublishNewMusicView(frame: CGRect(x: 0, y: kScreenHeight, width: kScreenWidth, height: kScreenHeight - kSafeStatusBarHeight))
  293. return musicView
  294. }()
  295. }
  296. // MARK: - 方法
  297. extension PublishNewVideoPhotoView {
  298. /// 开始拍视频
  299. func startTakeVideo() {
  300. self.recorder?.startRecording()
  301. DispatchQueue.main.async {
  302. [weak self] in
  303. // 回删按钮隐藏
  304. self?.deleteAlpha(alpha: 0)
  305. // 分段view隐藏
  306. self?.segmentedViewAlpha(alpha: 0)
  307. // 开始录制隐藏View
  308. self?.startTakeVideoHiddenView()
  309. }
  310. }
  311. /// 暂停拍视频
  312. func stopTakeVideo() {
  313. self.recorder?.stopRecording()
  314. }
  315. /// 开始录制隐藏View
  316. func startTakeVideoHiddenView() {
  317. publishNewVideoPhotoSetView.progressView.videoCount += 1
  318. publishNewVideoPhotoSetView.closeButton.isHidden = true
  319. publishNewVideoPhotoSetView.cameraFlipButton.isHidden = true
  320. publishNewVideoPhotoSetView.filterButton.isHidden = true
  321. publishNewVideoPhotoSetView.beautyButton.isHidden = true
  322. publishNewVideoPhotoSetView.musicButton.isHidden = true
  323. //切换按钮状态
  324. publishNewVideoPhotoSetView.recordButton.isSelected = !publishNewVideoPhotoSetView.recordButton.isSelected
  325. }
  326. /// 停止录制显示View
  327. func stopTakeVideoVideoHiddenView() {
  328. publishNewVideoPhotoSetView.closeButton.isHidden = false
  329. publishNewVideoPhotoSetView.cameraFlipButton.isHidden = false
  330. publishNewVideoPhotoSetView.filterButton.isHidden = false
  331. publishNewVideoPhotoSetView.beautyButton.isHidden = false
  332. publishNewVideoPhotoSetView.musicButton.isHidden = false
  333. //切换按钮状态
  334. publishNewVideoPhotoSetView.recordButton.isSelected = !publishNewVideoPhotoSetView.recordButton.isSelected
  335. }
  336. /// 完成拍视频
  337. func finishTakeVideo() {
  338. self.recorder?.finishRecording()
  339. }
  340. /// 拍照
  341. func takePhoto() {
  342. recorder?.takePhoto({(image, rawImage) in
  343. DispatchQueue.main.async {
  344. // 跳转到使用照片页面
  345. let publishConfirmPhotoNewVC = PublishConfirmPhotoNewViewController()
  346. publishConfirmPhotoNewVC.photoImg = image
  347. UIViewController.topMost?.navigationController?.pushViewController(publishConfirmPhotoNewVC, animated: true)
  348. }
  349. })
  350. }
  351. /// 回删视频
  352. func deleteVideo() {
  353. DispatchQueue.main.async {
  354. [weak self] in
  355. if self?.recorder?.clipManager?.partCount ?? 0 > 0 {
  356. AlertSheetView.alert(title: "是否删除上一片段?") { [weak self] (popupView, index, title) in
  357. let partCount = self?.recorder?.clipManager?.partCount
  358. // 删除最后一个视频片段
  359. self?.recorder?.clipManager?.deletePart()
  360. // 视频时长
  361. self?.recorderDuration = (self?.recorder?.clipManager?.duration)!
  362. // 完成按钮是否显示
  363. self?.finishAlpha()
  364. // 时间按钮是否显示
  365. self?.durationTimeAlpha()
  366. // 设置回删的进度View
  367. self?.publishNewVideoPhotoSetView.progressView.videoCount -= 1
  368. // 设置回删的进度View
  369. self?.setProgress()
  370. // 剩下最后一个片段视频
  371. if partCount == 1 {
  372. // 回删按钮是否隐藏
  373. self?.deleteAlpha(alpha: 0)
  374. // 分段view隐藏
  375. self?.segmentedViewAlpha(alpha: 1)
  376. }
  377. }
  378. }
  379. }
  380. }
  381. /// 回删按钮显示跟隐藏
  382. /// - Parameter alpha: 回删按钮显示跟隐藏
  383. func deleteAlpha(alpha:CGFloat) {
  384. DispatchQueue.main.async {
  385. [weak self] in
  386. self?.publishNewVideoPhotoSetView.deleteButton.alpha = alpha
  387. }
  388. }
  389. /// 完成按钮显示跟隐藏
  390. /// - Parameter alpha: 完成按钮显示跟隐藏
  391. func finishAlpha() {
  392. DispatchQueue.main.async {
  393. [weak self] in
  394. if (self?.recorderDuration)! >= 3.0 {
  395. if (self?.publishNewVideoPhotoSetView.finishButton.isHidden)! {
  396. self?.publishNewVideoPhotoSetView.finishButton.isHidden = false
  397. }
  398. }else {
  399. if !(self?.publishNewVideoPhotoSetView.finishButton.isHidden)! {
  400. self?.publishNewVideoPhotoSetView.finishButton.isHidden = true
  401. }
  402. }
  403. }
  404. }
  405. /// 时间label显示跟隐藏
  406. /// - Parameter alpha: 时间label显示跟隐藏
  407. func durationTimeAlpha() {
  408. DispatchQueue.main.async {
  409. [weak self] in
  410. if (self?.recorderDuration)! > 0.0 {
  411. if (self?.publishNewVideoPhotoSetView.durationTimeLabel.isHidden)! {
  412. self?.publishNewVideoPhotoSetView.durationTimeLabel.isHidden = false
  413. self?.publishNewVideoPhotoSetView.durationTimeDotLabel.isHidden = false
  414. }
  415. let d : Int = Int(self?.recorderDuration ?? 0)
  416. let m : Int = Int(d / 60)
  417. let s : Int = Int(d % 60)
  418. self?.publishNewVideoPhotoSetView.durationTimeLabel.text = String(format: "%02d:%02d", m,s)
  419. }else {
  420. if !(self?.publishNewVideoPhotoSetView.durationTimeLabel.isHidden)! {
  421. self?.publishNewVideoPhotoSetView.durationTimeLabel.isHidden = true
  422. self?.publishNewVideoPhotoSetView.durationTimeDotLabel.isHidden = true
  423. }
  424. }
  425. }
  426. }
  427. /// 设置时间进度
  428. func setProgress() {
  429. DispatchQueue.main.async {
  430. [weak self] in
  431. self?.publishNewVideoPhotoSetView.progressView.progress = self?.recorderDuration ?? 0
  432. }
  433. }
  434. /// 设置进度条是否显示
  435. ///
  436. /// - Parameter alpha: 透明度
  437. func setProgressViewAlpha(alpha:CGFloat,duration:TimeInterval) {
  438. UIView.animate(withDuration: duration) {
  439. [weak self] in
  440. self?.publishNewVideoPhotoSetView.progressView.alpha = alpha
  441. }
  442. // 更新关闭/闪光灯/音乐按钮的位置
  443. closeMakeConstraints(duration: duration)
  444. }
  445. /// 更新关闭/闪光灯/音乐按钮的位置
  446. ///
  447. /// - Parameter duration: 0.5s
  448. func closeMakeConstraints(duration:TimeInterval) {
  449. if PublishNewViewModel.shared.publishNewRecorderType == .video {
  450. publishNewVideoPhotoSetView.closeVideoUpMakeConstraints(duration: duration)
  451. // 设置闪光灯icon
  452. recorder?.switchTorch(with: AliyunIRecorderTorchMode.off)
  453. publishNewVideoPhotoSetView.flashButton.setImage(kImage(name: "video_ico_flashlight_close"), for: UIControl.State.normal)
  454. }else if PublishNewViewModel.shared.publishNewRecorderType == .photo {
  455. publishNewVideoPhotoSetView.closePhotoUpMakeConstraints(duration: duration)
  456. // 设置闪光灯icon
  457. recorder?.switchTorch(with: AliyunIRecorderTorchMode.auto)
  458. publishNewVideoPhotoSetView.flashButton.setImage(kImage(name: "video_ico_flashlight_auto"), for: UIControl.State.normal)
  459. }
  460. }
  461. /// 设置相机翻转
  462. func setCameraFlip() {
  463. let cameraPosition = recorder?.cameraPosition
  464. if cameraPosition == .front {
  465. UIView.transition(with: recorderPreview, duration: 0.5, options: UIView.AnimationOptions.transitionFlipFromLeft, animations: {
  466. [weak self] in
  467. self?.recorder?.switchCameraPosition()
  468. }, completion: { _ in})
  469. }else {
  470. UIView.transition(with: recorderPreview, duration: 0.5, options: UIView.AnimationOptions.transitionFlipFromRight, animations: {
  471. [weak self] in
  472. self?.recorder?.switchCameraPosition()
  473. }, completion: { _ in})
  474. }
  475. }
  476. /// 分段view显示
  477. /// - Parameter alpha: 透明度
  478. func segmentedViewAlpha(alpha:CGFloat) {
  479. UIView.animate(withDuration: 0.5) {
  480. PublishNewViewModel.shared.segmentedView?.alpha = alpha
  481. }
  482. }
  483. /// 滤镜美颜是否显示
  484. ///
  485. /// - Parameter isHidden: 是否隐藏
  486. func effectFilterBeautyViewisHidden(isHidden:Bool) {
  487. var offsetY : CGFloat = kScreenHeight
  488. if isHidden {
  489. offsetY = kScreenHeight
  490. if recorderDuration == 0 {
  491. segmentedViewAlpha(alpha:1)
  492. }else {
  493. segmentedViewAlpha(alpha:0)
  494. }
  495. // 移除点击手势
  496. recorderPreview.removetap()
  497. }else {
  498. offsetY = kScreenHeight-(48 + 125 + kSafeTabBarHeight)
  499. segmentedViewAlpha(alpha:0)
  500. // 添加点击手势
  501. recorderPreview.addTap()
  502. }
  503. UIView.animate(withDuration: 0.5) {
  504. [weak self] in
  505. self?.effectFilterBeautyView.frame = CGRect(x: 0, y: offsetY, width: kScreenWidth, height: 48 + 125 +
  506. kSafeTabBarHeight)
  507. if isHidden {
  508. self?.effectFilterBeautyView.alpha = 0
  509. self?.publishNewVideoPhotoSetView.alpha = 1
  510. }else {
  511. self?.effectFilterBeautyView.alpha = 1
  512. self?.publishNewVideoPhotoSetView.alpha = 0
  513. }
  514. }
  515. }
  516. //滤镜 减 1
  517. func filterLess() {
  518. if selectedIndex > 0 {
  519. selectedIndex = selectedIndex - 1
  520. }else {
  521. selectedIndex = (aliyunFiltersModel?.filters?.count ?? 1) - 1
  522. }
  523. //选中滤镜
  524. didSelectFilter()
  525. }
  526. //滤镜 加 1
  527. func filterPlus() {
  528. if selectedIndex < ((aliyunFiltersModel?.filters?.count ?? 0) - 1) {
  529. selectedIndex = selectedIndex + 1
  530. }else {
  531. selectedIndex = 0
  532. }
  533. //选中滤镜
  534. didSelectFilter()
  535. }
  536. /// 选中滤镜
  537. func didSelectFilter() {
  538. let indexPath = IndexPath(row: self.selectedIndex , section: 0)
  539. effectFilterBeautyView.effectFilterView.collectionView(effectFilterBeautyView.effectFilterView.collectionView, didSelectItemAt: indexPath)
  540. effectFilterBeautyView.effectFilterView.collectionView.selectItem(at: indexPath, animated: true, scrollPosition: UICollectionView.ScrollPosition.centeredHorizontally)
  541. }
  542. /// 滤镜名字显示
  543. ///
  544. /// - Parameter aliyunEffectFilter: 滤镜模型
  545. func showFilterNameLabel(aliyunEffectFilter:AliyunEffectFilter) {
  546. recorderPreview.filterNameLabel.alpha = 1
  547. recorderPreview.filterNameLabel.text = aliyunEffectFilter.name
  548. UIView.animate(withDuration: 2, animations: {
  549. [weak self] in
  550. self?.recorderPreview.filterNameLabel.alpha = 1
  551. }, completion: {
  552. [weak self] (finished) in
  553. UIView.animate(withDuration: 2, animations: {
  554. [weak self] in
  555. self?.recorderPreview.filterNameLabel.alpha = 0
  556. })
  557. })
  558. }
  559. /// 音乐是否显示
  560. ///
  561. /// - Parameter isHidden: 是否隐藏
  562. func musicViewisHidden(isHidden:Bool) {
  563. AliPlayerManager.shared.audioPlayer?.stop()
  564. recorder?.startPreview()
  565. var offsetY : CGFloat = kScreenHeight
  566. if isHidden {
  567. offsetY = kScreenHeight
  568. if recorderDuration == 0 {
  569. segmentedViewAlpha(alpha:1)
  570. }else {
  571. segmentedViewAlpha(alpha:0)
  572. }
  573. // 移除点击手势
  574. recorderPreview.removetap()
  575. musicView.listContainerView.reloadData()
  576. }else {
  577. offsetY = kSafeStatusBarHeight
  578. segmentedViewAlpha(alpha:0)
  579. // 添加点击手势
  580. recorderPreview.addTap()
  581. }
  582. UIView.animate(withDuration: 0.5, animations: {
  583. [weak self] in
  584. self?.musicView.frame = CGRect(x: 0, y: offsetY, width: kScreenWidth, height: kScreenHeight -
  585. kSafeStatusBarHeight)
  586. if isHidden {
  587. self?.musicView.alpha = 0
  588. self?.publishNewVideoPhotoSetView.alpha = 1
  589. }else {
  590. self?.musicView.alpha = 1
  591. self?.publishNewVideoPhotoSetView.alpha = 0
  592. }
  593. })
  594. }
  595. /// 结束录制回调/停止录制回调
  596. func stopRecorderShowHidden() {
  597. // 回删按钮透明度
  598. deleteAlpha(alpha:1)
  599. // 停止录制显示View
  600. DispatchQueue.main.async {
  601. [weak self] in
  602. self?.stopTakeVideoVideoHiddenView()
  603. }
  604. }
  605. /// 完成录制的View
  606. func finishRecorderView() {
  607. SwiftProgressHUD.shared().showWait("视频正在合成中...")
  608. isFinishRecorder = true
  609. }
  610. }
  611. // MARK: - 代理
  612. extension PublishNewVideoPhotoView : AliyunIRecorderDelegate {
  613. /// 授权代理
  614. /// - Parameter status: 收取状态
  615. func recorderDeviceAuthorization(_ status: AliyunIRecorderDeviceAuthor) {
  616. switch status {
  617. // 授权同意
  618. case .enabled:
  619. break
  620. // 音频授权被拒绝
  621. case .audioDenied:
  622. break
  623. // 视频授权被拒绝
  624. case .videoDenied:
  625. break
  626. default:
  627. break
  628. }
  629. }
  630. /**
  631. 摄像头返回的原始视频数据
  632. 开放出来的目的是用于做人脸识别
  633. @param sampleBuffer 视频数据
  634. */
  635. // func recorderOutputVideoRawSampleBuffer(_ sampleBuffer: CMSampleBuffer!)
  636. /**
  637. 返回原始的音频数据
  638. 用来做语音识别一类的业务
  639. @param sampleBuffer 音频数据
  640. */
  641. // func recorderOutputAudioRawSampleBuffer(_ sampleBuffer: CMSampleBuffer!)
  642. /**
  643. 用户自定义渲染
  644. @param sampleBuffer 原始视频数据
  645. @return 用户自渲染后的PixelBuffer
  646. */
  647. // optional func customRenderedPixelBuffer(withRawSampleBuffer sampleBuffer: CMSampleBuffer!) -> Unmanaged<CVPixelBuffer>!
  648. /**
  649. 用户自定义渲染
  650. 开放pixelBuffer和纹理id给用户自渲染 (仅支持BGRA格式)
  651. @param pixelBuffer 摄像头数据
  652. @param textureName 摄像头数据纹理
  653. @return 自定义渲染后的纹理id
  654. */
  655. // optional func recorderOutputVideoPixelBuffer(_ pixelBuffer: CVPixelBuffer!, textureName: Int) -> Int
  656. /**
  657. 用户自定义渲染接口
  658. @param srcTexture 原始视频帧纹理id
  659. @param size 原始视频帧纹理size
  660. @return 返回纹理id
  661. */
  662. // optional func customRender(_ srcTexture: Int32, size: CGSize) -> Int32
  663. /**
  664. 录制实时时长
  665. @param duration 录制时长
  666. */
  667. func recorderVideoDuration(_ duration: CGFloat) {
  668. // 录制时长
  669. recorderDuration = duration
  670. // 完成按钮是否显示
  671. finishAlpha()
  672. // 时间按钮是否显示
  673. durationTimeAlpha()
  674. // 时间进度
  675. setProgress()
  676. }
  677. /**
  678. 摄像头返回的原始视频纹理
  679. 摄像头数据格式为BGRA、YUV时都需实现
  680. @param textureName 原始纹理ID
  681. @return 处理后的纹理ID
  682. */
  683. // optional func recorderOutputVideoTextureName(_ textureName: Int, textureSize textureSie: CGSize) -> Int
  684. /**
  685. 摄像头返回的原始视频纹理
  686. 摄像头数据格式仅为YUV时须实现,反之不实现
  687. @param textureName 原始UV分量的纹理ID
  688. @return 处理后的纹理ID
  689. */
  690. // optional func recorderOutputVideoUVTextureName(_ textureName: Int) -> Int
  691. /**
  692. 开始预览回调
  693. */
  694. func recorderDidStartPreview() {
  695. }
  696. /**
  697. 停止录制回调
  698. */
  699. func recorderDidStopRecording() {
  700. //是否完成录制
  701. if isFinishRecorder { //完成 显示view也要完成视频合成
  702. finishTakeVideo()
  703. }else{ //没有完成只改变view显示
  704. stopRecorderShowHidden()
  705. }
  706. }
  707. /**
  708. 当录至最大时长时回调
  709. */
  710. func recorderDidStopWithMaxDuration() {
  711. finishRecorderView()
  712. finishTakeVideo()
  713. }
  714. /**
  715. 结束录制回调
  716. */
  717. func recorderDidFinishRecording() {
  718. SwiftProgressHUD.shared().hide()
  719. if isFinishRecorder { //完成 显示view也要完成视频合成
  720. stopRecorderShowHidden()
  721. }
  722. isFinishRecorder = false
  723. DispatchQueue.main.async {
  724. [weak self] in
  725. self?.publishNewVideoPhotoSetView.recordButton.isSelected = false
  726. let vc = PublishEditNewViewController()
  727. vc.taskPath = self?.recorder?.taskPath
  728. vc.outputPath = self?.recorder?.outputPath
  729. vc.outCoverImagePath = self?.outCoverImagePathURL?.path
  730. vc.popClosure = {
  731. [weak self] in
  732. self?.recorder?.startPreview()
  733. }
  734. UIViewController.topMost?.navigationController?.pushViewController(vc, animated: true)
  735. }
  736. }
  737. /**
  738. 录制异常
  739. @param error 异常
  740. */
  741. func recoderError(_ error: Error!) {
  742. NXLLog(error)
  743. SwiftProgressHUD.shared().showText("录制异常")
  744. }
  745. }