소스 검색

Merge pull request #422 from deltachat/fix_video_encoding

fix playback of attached videos
björn petersen 5 년 전
부모
커밋
c7c028b0e5

+ 4 - 0
deltachat-ios.xcodeproj/project.pbxproj

@@ -14,6 +14,7 @@
 		30260CA7238F02F700D8D52C /* MultilineTextFieldCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30260CA6238F02F700D8D52C /* MultilineTextFieldCell.swift */; };
 		302B84C6239676F0001C261F /* AvatarHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30AC265E237F1807002A943F /* AvatarHelper.swift */; };
 		302B84C72396770B001C261F /* RelayHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 302B84C42396627F001C261F /* RelayHelper.swift */; };
+		302B84CE2397F6CD001C261F /* URL+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 302B84CD2397F6CD001C261F /* URL+Extension.swift */; };
 		3040F45E234DFBC000FA34D5 /* Audio.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3040F45D234DFBC000FA34D5 /* Audio.swift */; };
 		3040F460234F419400FA34D5 /* BasicAudioController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3040F45F234F419300FA34D5 /* BasicAudioController.swift */; };
 		3040F462234F550300FA34D5 /* AudioPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3040F461234F550300FA34D5 /* AudioPlayerView.swift */; };
@@ -185,6 +186,7 @@
 		3022E6D322E876A100763272 /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/InfoPlist.strings; sourceTree = "<group>"; };
 		30260CA6238F02F700D8D52C /* MultilineTextFieldCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultilineTextFieldCell.swift; sourceTree = "<group>"; };
 		302B84C42396627F001C261F /* RelayHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayHelper.swift; sourceTree = "<group>"; };
+		302B84CD2397F6CD001C261F /* URL+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URL+Extension.swift"; sourceTree = "<group>"; };
 		3040F45D234DFBC000FA34D5 /* Audio.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Audio.swift; sourceTree = "<group>"; };
 		3040F45F234F419300FA34D5 /* BasicAudioController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BasicAudioController.swift; sourceTree = "<group>"; };
 		3040F461234F550300FA34D5 /* AudioPlayerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioPlayerView.swift; sourceTree = "<group>"; };
@@ -421,6 +423,7 @@
 				305961882346125000C80F33 /* CGRect+Extensions.swift */,
 				3059620D234614E700C80F33 /* DcContact+Extension.swift */,
 				3059620F2346154D00C80F33 /* String+Extension.swift */,
+				302B84CD2397F6CD001C261F /* URL+Extension.swift */,
 			);
 			path = Extensions;
 			sourceTree = "<group>";
@@ -1088,6 +1091,7 @@
 				AEE6EC412282DF5700EDC689 /* MailboxViewController.swift in Sources */,
 				AEE6EC482283045D00EDC689 /* EditSettingsController.swift in Sources */,
 				305961DF2346125100C80F33 /* MessageCellDelegate.swift in Sources */,
+				302B84CE2397F6CD001C261F /* URL+Extension.swift in Sources */,
 				305961CC2346125100C80F33 /* UIView+Extensions.swift in Sources */,
 				7A9FB1441FB061E2001FEA36 /* AppDelegate.swift in Sources */,
 				305961F52346125100C80F33 /* TypingIndicatorCell.swift in Sources */,

+ 1 - 1
deltachat-ios/Controller/ChatViewController.swift

@@ -789,7 +789,7 @@ extension ChatViewController: MessagesDataSource {
     private func sendVideo(url: NSURL) {
         DispatchQueue.global().async {
             let msg = DcMsg(viewType: DC_MSG_VIDEO)
-            msg.setFile(filepath: url.relativePath, mimeType: "video/mov")
+            msg.setFile(filepath: url.relativePath, mimeType: "video/mp4")
             msg.sendInChat(id: self.chatId)
         }
     }

+ 0 - 11
deltachat-ios/Extensions/Extensions.swift

@@ -1,17 +1,6 @@
 import UIKit
 import Foundation
 
-extension URL {
-    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
-        }
-    }
-}
-
 extension Dictionary {
     func percentEscaped() -> String {
         return map { key, value in

+ 65 - 0
deltachat-ios/Extensions/URL+Extension.swift

@@ -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
+                }
+            })
+         })
+    }
+}

+ 13 - 2
deltachat-ios/Helper/MediaPicker.swift

@@ -110,8 +110,19 @@ class MediaPicker: NSObject, UINavigationControllerDelegate, UIImagePickerContro
     }
 
     func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
-        if let videoUrl = info[UIImagePickerController.InfoKey.mediaURL] as? NSURL {
-            self.delegate?.onVideoSelected(url: videoUrl)
+        if let videoUrl = info[UIImagePickerController.InfoKey.mediaURL] as? URL {
+            videoUrl.convertToMp4(completionHandler: { url, error in
+                if let url = url {
+                    self.delegate?.onVideoSelected(url: (url as NSURL))
+                } else if let error = error {
+                    logger.error(error.localizedDescription)
+                    let alert = UIAlertController(title: String.localized("error"), message: nil, preferredStyle: .alert)
+                    alert.addAction(UIAlertAction(title: String.localized("ok"), style: .cancel, handler: { _ in
+                        self.navigationController.dismiss(animated: true, completion: nil)
+                    }))
+                    self.navigationController.present(alert, animated: true, completion: nil)
+                }
+            })
         } else if let imageUrl = info[UIImagePickerController.InfoKey.imageURL] as? NSURL {
             self.delegate?.onImageSelected(url: imageUrl)
         }