Fix #902: Uploaded video get's distorted because aspect ratio is not maintained (#958)

This commit is contained in:
Marcus Kida 2023-02-27 14:36:21 +01:00 committed by GitHub
parent 2a97ae1a40
commit a0b318ad7b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 38 additions and 13 deletions

View File

@ -13,19 +13,20 @@ import SessionExporter
import Nuke
extension AttachmentViewModel {
func compressVideo(url: URL) async throws -> URL {
func compressVideo(url: URL) async throws -> URL? {
let urlAsset = AVURLAsset(url: url)
guard let track = urlAsset.tracks(withMediaType: .video).first else {
return nil
}
let exporter = NextLevelSessionExporter(withAsset: urlAsset)
exporter.outputFileType = .mp4
let isLandscape: Bool = {
guard let track = urlAsset.tracks(withMediaType: .video).first else {
return true
}
let size = track.naturalSize.applying(track.preferredTransform)
return abs(size.width) >= abs(size.height)
}()
let preferredSize = try await preferredSizeFor(
track: track,
maxLongestSide: 1280
)
let outputURL = try FileManager.default.createTemporaryFileURL(
filename: UUID().uuidString,
@ -40,8 +41,8 @@ extension AttachmentViewModel {
]
exporter.videoOutputConfiguration = [
AVVideoCodecKey: AVVideoCodecType.h264,
AVVideoWidthKey: NSNumber(integerLiteral: isLandscape ? 1280 : 720),
AVVideoHeightKey: NSNumber(integerLiteral: isLandscape ? 720 : 1280),
AVVideoWidthKey: NSNumber(floatLiteral: preferredSize.width),
AVVideoHeightKey: NSNumber(floatLiteral: preferredSize.height),
AVVideoScalingModeKey: AVVideoScalingModeResizeAspectFill,
AVVideoCompressionPropertiesKey: compressionDict
]
@ -60,6 +61,27 @@ extension AttachmentViewModel {
return outputURL
}
private func preferredSizeFor(track: AVAssetTrack, maxLongestSide: CGFloat) async throws -> CGSize {
let trackSize = try await track.load(.naturalSize).applying(track.preferredTransform)
let actualSize = CGSize(width: abs(trackSize.width), height: abs(trackSize.height))
let isLandscape = actualSize.width >= actualSize.height
switch isLandscape {
case false: // portrait mode, needs height altered eventually
if actualSize.height > maxLongestSide {
// reduce height, keep aspect ratio
return CGSize(width: (maxLongestSide / (actualSize.height/actualSize.width)), height: maxLongestSide)
}
return actualSize
case true: // landscape mode, needs width altered eventually
if actualSize.width > maxLongestSide {
// reduce width, keep aspect ratio
return CGSize(width: maxLongestSide, height: (maxLongestSide * (actualSize.height/actualSize.width)))
}
return actualSize
}
}
private func exportVideo(by exporter: NextLevelSessionExporter) async throws -> URL {
guard let outputURL = exporter.outputURL else {

View File

@ -145,7 +145,10 @@ final public class AttachmentViewModel: NSObject, ObservableObject, Identifiable
case .video(let fileURL, let mimeType):
self.output = output
self.update(uploadState: .compressing)
let compressedFileURL = try await compressVideo(url: fileURL)
guard let compressedFileURL = try await compressVideo(url: fileURL) else {
assertionFailure("Unable to compress video")
return
}
output = .video(compressedFileURL, mimeType: mimeType)
try? FileManager.default.removeItem(at: fileURL) // remove old file
}