VideoPreviewItem.swift 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. // _____ _
  2. // |_ _| |_ _ _ ___ ___ _ __ __ _
  3. // | | | ' \| '_/ -_) -_) ' \/ _` |_
  4. // |_| |_||_|_| \___\___|_|_|_\__,_(_)
  5. //
  6. // Threema iOS Client
  7. // Copyright (c) 2020 Threema GmbH
  8. //
  9. // This program is free software: you can redistribute it and/or modify
  10. // it under the terms of the GNU Affero General Public License, version 3,
  11. // as published by the Free Software Foundation.
  12. //
  13. // This program is distributed in the hope that it will be useful,
  14. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. // GNU Affero General Public License for more details.
  17. //
  18. // You should have received a copy of the GNU Affero General Public License
  19. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  20. import Foundation
  21. import CocoaLumberjackSwift
  22. class VideoPreviewItem: MediaPreviewItem, MediaPreviewItemProtocol {
  23. var video: Data?
  24. var isConverting = false
  25. var isConverted = false
  26. var transcodeSema = DispatchSemaphore(value: 0)
  27. override func requestAsset() {
  28. let manager = PHImageManager()
  29. guard let originalAsset = self.originalAsset else {
  30. guard let itemUrl = self.itemUrl else {
  31. return
  32. }
  33. let asset = AVAsset(url: itemUrl)
  34. self.thumbnail = MediaConverter.getThumbnailForVideo(asset)
  35. self.thumbnailSemaphore.signal()
  36. self.semaphore.signal()
  37. return
  38. }
  39. let asset = originalAsset.originalAsset!
  40. if asset.mediaType == PHAssetMediaType.video {
  41. let options = PHVideoRequestOptions()
  42. options.version = .current
  43. options.isNetworkAccessAllowed = true
  44. manager.requestAVAsset(forVideo: asset, options: options, resultHandler: {
  45. (avasset, _, _) in
  46. self.thumbnail = MediaConverter.getThumbnailForVideo(avasset)
  47. self.thumbnailSemaphore.signal()
  48. if let avassetURL = avasset as? AVURLAsset {
  49. self.itemUrl = avassetURL.url
  50. self.semaphore.signal()
  51. }
  52. })
  53. }
  54. }
  55. override func getAccessiblityDescription() -> String? {
  56. guard let originalAsset = self.originalAsset else {
  57. let text = String(format: NSLocalizedString("video", comment: ""))
  58. return text
  59. }
  60. let asset = originalAsset.originalAsset!
  61. guard let date = asset.creationDate else {
  62. return nil
  63. }
  64. let datetime = DateFormatter.accessibilityDateTime(date)
  65. let text = String(format: NSLocalizedString("video_date", comment: ""),"\(String(describing: datetime))")
  66. return text
  67. }
  68. func convertVideo() {
  69. DispatchQueue.global(qos: .userInitiated).async {
  70. if !self.isConverted {
  71. if !self.isConverting {
  72. self.isConverting = true
  73. MediaConverter.convertVideoAsset(self.getItem()!, onCompletion: {
  74. (url) in
  75. self.video = try? Data(contentsOf: url!)
  76. self.itemUrl = url
  77. self.isConverted = true
  78. self.transcodeSema.signal()
  79. }, onError: {
  80. (error) in
  81. DDLogError("Could not convert video \(error.debugDescription)")
  82. })
  83. }
  84. self.transcodeSema.wait()
  85. self.transcodeSema.signal()
  86. }
  87. }
  88. }
  89. func getItem() -> URL? {
  90. self.convertVideo()
  91. return self.itemUrl
  92. }
  93. func getTranscodedItem() -> URL? {
  94. self.convertVideo()
  95. self.transcodeSema.wait()
  96. self.transcodeSema.signal()
  97. return self.itemUrl
  98. }
  99. func getItem() -> Data? {
  100. self.convertVideo()
  101. return self.video
  102. }
  103. func getItem() -> AVAsset? {
  104. if self.itemUrl == nil {
  105. self.semaphore.wait()
  106. self.semaphore.signal()
  107. }
  108. guard let url : URL = self.getItem() else {
  109. return nil
  110. }
  111. let asset = AVAsset(url: url)
  112. return asset
  113. }
  114. }