ios: converting video to mp4 and making quality lower (#3597)
* ios: converting video to mp4 and making quality lower Lower quality allows to play that videos on Android as well * update export settings --------- Co-authored-by: Avently <avently@local> Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
This commit is contained in:
parent
4d5aefa82c
commit
dded56d8b8
@ -104,7 +104,7 @@ struct ComposeState {
|
|||||||
|
|
||||||
var sendEnabled: Bool {
|
var sendEnabled: Bool {
|
||||||
switch preview {
|
switch preview {
|
||||||
case .mediaPreviews: return true
|
case let .mediaPreviews(media): return !media.isEmpty
|
||||||
case .voicePreview: return voiceMessageRecordingState == .finished
|
case .voicePreview: return voiceMessageRecordingState == .finished
|
||||||
case .filePreview: return true
|
case .filePreview: return true
|
||||||
default: return !message.isEmpty || liveMessage != nil
|
default: return !message.isEmpty || liveMessage != nil
|
||||||
@ -384,7 +384,7 @@ struct ComposeView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.sheet(isPresented: $showMediaPicker) {
|
.sheet(isPresented: $showMediaPicker) {
|
||||||
LibraryMediaListPicker(addMedia: addMediaContent, selectionLimit: 10) { itemsSelected in
|
LibraryMediaListPicker(addMedia: addMediaContent, selectionLimit: 10, finishedPreprocessing: finishedPreprocessingMediaContent) { itemsSelected in
|
||||||
await MainActor.run {
|
await MainActor.run {
|
||||||
showMediaPicker = false
|
showMediaPicker = false
|
||||||
if itemsSelected {
|
if itemsSelected {
|
||||||
@ -503,6 +503,15 @@ struct ComposeView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// When error occurs while converting video, remove media preview
|
||||||
|
private func finishedPreprocessingMediaContent() {
|
||||||
|
if case let .mediaPreviews(media) = composeState.preview, media.isEmpty {
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
composeState = composeState.copy(preview: .noPreview)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private var maxFileSize: Int64 {
|
private var maxFileSize: Int64 {
|
||||||
getMaxFileSize(.xftp)
|
getMaxFileSize(.xftp)
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@ struct LibraryMediaListPicker: UIViewControllerRepresentable {
|
|||||||
typealias UIViewControllerType = PHPickerViewController
|
typealias UIViewControllerType = PHPickerViewController
|
||||||
var addMedia: (_ content: UploadContent) async -> Void
|
var addMedia: (_ content: UploadContent) async -> Void
|
||||||
var selectionLimit: Int
|
var selectionLimit: Int
|
||||||
|
var finishedPreprocessing: () -> Void = {}
|
||||||
var didFinishPicking: (_ didSelectItems: Bool) async -> Void
|
var didFinishPicking: (_ didSelectItems: Bool) async -> Void
|
||||||
|
|
||||||
class Coordinator: PHPickerViewControllerDelegate {
|
class Coordinator: PHPickerViewControllerDelegate {
|
||||||
@ -50,6 +51,7 @@ struct LibraryMediaListPicker: UIViewControllerRepresentable {
|
|||||||
for r in results {
|
for r in results {
|
||||||
await loadItem(r.itemProvider)
|
await loadItem(r.itemProvider)
|
||||||
}
|
}
|
||||||
|
parent.finishedPreprocessing()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,21 +105,27 @@ struct LibraryMediaListPicker: UIViewControllerRepresentable {
|
|||||||
await withCheckedContinuation { cont in
|
await withCheckedContinuation { cont in
|
||||||
loadFileURL(p, type: UTType.movie) { url in
|
loadFileURL(p, type: UTType.movie) { url in
|
||||||
if let url = url {
|
if let url = url {
|
||||||
let tempUrl = URL(fileURLWithPath: generateNewFileName(getTempFilesDirectory().path + "/" + "video", url.pathExtension, fullPath: true))
|
let tempUrl = URL(fileURLWithPath: generateNewFileName(getTempFilesDirectory().path + "/" + "rawvideo", url.pathExtension, fullPath: true))
|
||||||
|
let convertedVideoUrl = URL(fileURLWithPath: generateNewFileName(getTempFilesDirectory().path + "/" + "video", "mp4", fullPath: true))
|
||||||
do {
|
do {
|
||||||
// logger.debug("LibraryMediaListPicker copyItem \(url) to \(tempUrl)")
|
// logger.debug("LibraryMediaListPicker copyItem \(url) to \(tempUrl)")
|
||||||
try FileManager.default.copyItem(at: url, to: tempUrl)
|
try FileManager.default.copyItem(at: url, to: tempUrl)
|
||||||
DispatchQueue.main.async {
|
|
||||||
_ = ChatModel.shared.filesToDelete.insert(tempUrl)
|
|
||||||
}
|
|
||||||
let video = UploadContent.loadVideoFromURL(url: tempUrl)
|
|
||||||
cont.resume(returning: video)
|
|
||||||
return
|
|
||||||
} catch let err {
|
} catch let err {
|
||||||
logger.error("LibraryMediaListPicker copyItem error: \(err.localizedDescription)")
|
logger.error("LibraryMediaListPicker copyItem error: \(err.localizedDescription)")
|
||||||
|
return cont.resume(returning: nil)
|
||||||
|
}
|
||||||
|
Task {
|
||||||
|
let success = await makeVideoQualityLower(tempUrl, outputUrl: convertedVideoUrl)
|
||||||
|
try? FileManager.default.removeItem(at: tempUrl)
|
||||||
|
if success {
|
||||||
|
_ = ChatModel.shared.filesToDelete.insert(convertedVideoUrl)
|
||||||
|
let video = UploadContent.loadVideoFromURL(url: convertedVideoUrl)
|
||||||
|
return cont.resume(returning: video)
|
||||||
|
}
|
||||||
|
try? FileManager.default.removeItem(at: convertedVideoUrl)
|
||||||
|
cont.resume(returning: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cont.resume(returning: nil)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -143,7 +151,7 @@ struct LibraryMediaListPicker: UIViewControllerRepresentable {
|
|||||||
config.filter = .any(of: [.images, .videos])
|
config.filter = .any(of: [.images, .videos])
|
||||||
config.selectionLimit = selectionLimit
|
config.selectionLimit = selectionLimit
|
||||||
config.selection = .ordered
|
config.selection = .ordered
|
||||||
//config.preferredAssetRepresentationMode = .current
|
config.preferredAssetRepresentationMode = .current
|
||||||
let controller = PHPickerViewController(configuration: config)
|
let controller = PHPickerViewController(configuration: config)
|
||||||
controller.delegate = context.coordinator
|
controller.delegate = context.coordinator
|
||||||
return controller
|
return controller
|
||||||
|
26
apps/ios/Shared/Views/Helpers/VideoUtils.swift
Normal file
26
apps/ios/Shared/Views/Helpers/VideoUtils.swift
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
//
|
||||||
|
// VideoUtils.swift
|
||||||
|
// SimpleX (iOS)
|
||||||
|
//
|
||||||
|
// Created by Avently on 25.12.2023.
|
||||||
|
// Copyright © 2023 SimpleX Chat. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import AVFoundation
|
||||||
|
import Foundation
|
||||||
|
import SimpleXChat
|
||||||
|
|
||||||
|
func makeVideoQualityLower(_ input: URL, outputUrl: URL) async -> Bool {
|
||||||
|
let asset: AVURLAsset = AVURLAsset(url: input, options: nil)
|
||||||
|
if let s = AVAssetExportSession(asset: asset, presetName: AVAssetExportPreset640x480) {
|
||||||
|
s.outputURL = outputUrl
|
||||||
|
s.outputFileType = .mp4
|
||||||
|
s.metadataItemFilter = AVMetadataItemFilter.forSharing()
|
||||||
|
await s.export()
|
||||||
|
if let err = s.error {
|
||||||
|
logger.error("Failed to export video with error: \(err)")
|
||||||
|
}
|
||||||
|
return s.status == .completed
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
@ -188,6 +188,7 @@
|
|||||||
64D0C2C629FAC1EC00B38D5F /* AddContactLearnMore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64D0C2C529FAC1EC00B38D5F /* AddContactLearnMore.swift */; };
|
64D0C2C629FAC1EC00B38D5F /* AddContactLearnMore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64D0C2C529FAC1EC00B38D5F /* AddContactLearnMore.swift */; };
|
||||||
64E972072881BB22008DBC02 /* CIGroupInvitationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64E972062881BB22008DBC02 /* CIGroupInvitationView.swift */; };
|
64E972072881BB22008DBC02 /* CIGroupInvitationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64E972062881BB22008DBC02 /* CIGroupInvitationView.swift */; };
|
||||||
64F1CC3B28B39D8600CD1FB1 /* IncognitoHelp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64F1CC3A28B39D8600CD1FB1 /* IncognitoHelp.swift */; };
|
64F1CC3B28B39D8600CD1FB1 /* IncognitoHelp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64F1CC3A28B39D8600CD1FB1 /* IncognitoHelp.swift */; };
|
||||||
|
8C05382E2B39887E006436DC /* VideoUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C05382D2B39887E006436DC /* VideoUtils.swift */; };
|
||||||
D7197A1829AE89660055C05A /* WebRTC in Frameworks */ = {isa = PBXBuildFile; productRef = D7197A1729AE89660055C05A /* WebRTC */; };
|
D7197A1829AE89660055C05A /* WebRTC in Frameworks */ = {isa = PBXBuildFile; productRef = D7197A1729AE89660055C05A /* WebRTC */; };
|
||||||
D72A9088294BD7A70047C86D /* NativeTextEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D72A9087294BD7A70047C86D /* NativeTextEditor.swift */; };
|
D72A9088294BD7A70047C86D /* NativeTextEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D72A9087294BD7A70047C86D /* NativeTextEditor.swift */; };
|
||||||
D741547829AF89AF0022400A /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D741547729AF89AF0022400A /* StoreKit.framework */; };
|
D741547829AF89AF0022400A /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D741547729AF89AF0022400A /* StoreKit.framework */; };
|
||||||
@ -476,6 +477,7 @@
|
|||||||
64DAE1502809D9F5000DA960 /* FileUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileUtils.swift; sourceTree = "<group>"; };
|
64DAE1502809D9F5000DA960 /* FileUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileUtils.swift; sourceTree = "<group>"; };
|
||||||
64E972062881BB22008DBC02 /* CIGroupInvitationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIGroupInvitationView.swift; sourceTree = "<group>"; };
|
64E972062881BB22008DBC02 /* CIGroupInvitationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIGroupInvitationView.swift; sourceTree = "<group>"; };
|
||||||
64F1CC3A28B39D8600CD1FB1 /* IncognitoHelp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IncognitoHelp.swift; sourceTree = "<group>"; };
|
64F1CC3A28B39D8600CD1FB1 /* IncognitoHelp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IncognitoHelp.swift; sourceTree = "<group>"; };
|
||||||
|
8C05382D2B39887E006436DC /* VideoUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoUtils.swift; sourceTree = "<group>"; };
|
||||||
D72A9087294BD7A70047C86D /* NativeTextEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NativeTextEditor.swift; sourceTree = "<group>"; };
|
D72A9087294BD7A70047C86D /* NativeTextEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NativeTextEditor.swift; sourceTree = "<group>"; };
|
||||||
D741547729AF89AF0022400A /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.1.sdk/System/Library/Frameworks/StoreKit.framework; sourceTree = DEVELOPER_DIR; };
|
D741547729AF89AF0022400A /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.1.sdk/System/Library/Frameworks/StoreKit.framework; sourceTree = DEVELOPER_DIR; };
|
||||||
D741547929AF90B00022400A /* PushKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PushKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.1.sdk/System/Library/Frameworks/PushKit.framework; sourceTree = DEVELOPER_DIR; };
|
D741547929AF90B00022400A /* PushKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PushKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.1.sdk/System/Library/Frameworks/PushKit.framework; sourceTree = DEVELOPER_DIR; };
|
||||||
@ -642,6 +644,7 @@
|
|||||||
64466DCB29FFE3E800E3D48D /* MailView.swift */,
|
64466DCB29FFE3E800E3D48D /* MailView.swift */,
|
||||||
64C3B0202A0D359700E19930 /* CustomTimePicker.swift */,
|
64C3B0202A0D359700E19930 /* CustomTimePicker.swift */,
|
||||||
5CEBD7452A5C0A8F00665FE2 /* KeyboardPadding.swift */,
|
5CEBD7452A5C0A8F00665FE2 /* KeyboardPadding.swift */,
|
||||||
|
8C05382D2B39887E006436DC /* VideoUtils.swift */,
|
||||||
);
|
);
|
||||||
path = Helpers;
|
path = Helpers;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -1212,6 +1215,7 @@
|
|||||||
5CCD403727A5F9A200368C90 /* ScanToConnectView.swift in Sources */,
|
5CCD403727A5F9A200368C90 /* ScanToConnectView.swift in Sources */,
|
||||||
5CFA59D12864782E00863A68 /* ChatArchiveView.swift in Sources */,
|
5CFA59D12864782E00863A68 /* ChatArchiveView.swift in Sources */,
|
||||||
649BCDA22805D6EF00C3A862 /* CIImageView.swift in Sources */,
|
649BCDA22805D6EF00C3A862 /* CIImageView.swift in Sources */,
|
||||||
|
8C05382E2B39887E006436DC /* VideoUtils.swift in Sources */,
|
||||||
5CADE79C292131E900072E13 /* ContactPreferencesView.swift in Sources */,
|
5CADE79C292131E900072E13 /* ContactPreferencesView.swift in Sources */,
|
||||||
5CB346E52868AA7F001FD2EF /* SuspendChat.swift in Sources */,
|
5CB346E52868AA7F001FD2EF /* SuspendChat.swift in Sources */,
|
||||||
5C9C2DA52894777E00CC63B1 /* GroupProfileView.swift in Sources */,
|
5C9C2DA52894777E00CC63B1 /* GroupProfileView.swift in Sources */,
|
||||||
|
Loading…
Reference in New Issue
Block a user