|
@@ -0,0 +1,65 @@
|
|
|
+import Foundation
|
|
|
+import AVKit
|
|
|
+
|
|
|
+extension URL {
|
|
|
+ enum ConversionError: Error {
|
|
|
+ case runtimeError(String)
|
|
|
+ }
|
|
|
+
|
|
|
+ public var queryParameters: [String: String]? {
|
|
|
+ guard
|
|
|
+ let components = URLComponents(url: self, resolvingAgainstBaseURL: true),
|
|
|
+ let queryItems = components.queryItems else { return nil }
|
|
|
+ return queryItems.reduce(into: [String: String]()) { result, item in
|
|
|
+ result[item.name] = item.value
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public func convertToMp4(completionHandler: ((URL?, Error?) -> Void)?) {
|
|
|
+ let avAsset = AVURLAsset(url: self, options: nil)
|
|
|
+ AVAssetExportSession.determineCompatibility(ofExportPreset: AVAssetExportPresetPassthrough,
|
|
|
+ with: avAsset,
|
|
|
+ outputFileType: .mp4,
|
|
|
+ completionHandler: { (isCompatible) in
|
|
|
+ if !isCompatible {
|
|
|
+ completionHandler?(nil, ConversionError.runtimeError("File has incompatible file format for mp4 conversion"))
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ guard let exportSession = AVAssetExportSession(asset: avAsset, presetName: AVAssetExportPresetPassthrough) else {
|
|
|
+ completionHandler?(nil, ConversionError.runtimeError("Could not initiate AVAssertExportSession"))
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ let filename = self.deletingPathExtension().lastPathComponent.replacingOccurrences(of: ".", with: "-").appending(".mp4")
|
|
|
+ let outputURL = FileManager.default.temporaryDirectory.appendingPathComponent(filename)
|
|
|
+
|
|
|
+ if FileManager.default.fileExists(atPath: outputURL.path) {
|
|
|
+ do {
|
|
|
+ try FileManager.default.removeItem(at: outputURL)
|
|
|
+ } catch {
|
|
|
+ completionHandler?(nil, error)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ exportSession.outputURL = outputURL
|
|
|
+ exportSession.outputFileType = AVFileType.mp4
|
|
|
+ exportSession.shouldOptimizeForNetworkUse = true
|
|
|
+ let start = CMTimeMakeWithSeconds(0.0, preferredTimescale: 0)
|
|
|
+ let range = CMTimeRangeMake(start: start, duration: avAsset.duration)
|
|
|
+ exportSession.timeRange = range
|
|
|
+
|
|
|
+ exportSession.exportAsynchronously(completionHandler: {() -> Void in
|
|
|
+ switch exportSession.status {
|
|
|
+ case .failed:
|
|
|
+ completionHandler?(nil, exportSession.error)
|
|
|
+ case .cancelled:
|
|
|
+ completionHandler?(nil, nil)
|
|
|
+ case .completed:
|
|
|
+ completionHandler?(exportSession.outputURL, nil)
|
|
|
+ default: break
|
|
|
+ }
|
|
|
+ })
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|