1
0
mirror of https://github.com/mastodon/mastodon-ios.git synced 2025-01-31 17:45:17 +01:00

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 import Nuke
extension AttachmentViewModel { extension AttachmentViewModel {
func compressVideo(url: URL) async throws -> URL { func compressVideo(url: URL) async throws -> URL? {
let urlAsset = AVURLAsset(url: url) let urlAsset = AVURLAsset(url: url)
guard let track = urlAsset.tracks(withMediaType: .video).first else {
return nil
}
let exporter = NextLevelSessionExporter(withAsset: urlAsset) let exporter = NextLevelSessionExporter(withAsset: urlAsset)
exporter.outputFileType = .mp4 exporter.outputFileType = .mp4
let isLandscape: Bool = { let preferredSize = try await preferredSizeFor(
guard let track = urlAsset.tracks(withMediaType: .video).first else { track: track,
return true maxLongestSide: 1280
} )
let size = track.naturalSize.applying(track.preferredTransform)
return abs(size.width) >= abs(size.height)
}()
let outputURL = try FileManager.default.createTemporaryFileURL( let outputURL = try FileManager.default.createTemporaryFileURL(
filename: UUID().uuidString, filename: UUID().uuidString,
@ -40,8 +41,8 @@ extension AttachmentViewModel {
] ]
exporter.videoOutputConfiguration = [ exporter.videoOutputConfiguration = [
AVVideoCodecKey: AVVideoCodecType.h264, AVVideoCodecKey: AVVideoCodecType.h264,
AVVideoWidthKey: NSNumber(integerLiteral: isLandscape ? 1280 : 720), AVVideoWidthKey: NSNumber(floatLiteral: preferredSize.width),
AVVideoHeightKey: NSNumber(integerLiteral: isLandscape ? 720 : 1280), AVVideoHeightKey: NSNumber(floatLiteral: preferredSize.height),
AVVideoScalingModeKey: AVVideoScalingModeResizeAspectFill, AVVideoScalingModeKey: AVVideoScalingModeResizeAspectFill,
AVVideoCompressionPropertiesKey: compressionDict AVVideoCompressionPropertiesKey: compressionDict
] ]
@ -61,6 +62,27 @@ extension AttachmentViewModel {
return outputURL 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 { private func exportVideo(by exporter: NextLevelSessionExporter) async throws -> URL {
guard let outputURL = exporter.outputURL else { guard let outputURL = exporter.outputURL else {
throw AppError.badRequest throw AppError.badRequest

View File

@ -145,7 +145,10 @@ final public class AttachmentViewModel: NSObject, ObservableObject, Identifiable
case .video(let fileURL, let mimeType): case .video(let fileURL, let mimeType):
self.output = output self.output = output
self.update(uploadState: .compressing) 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) output = .video(compressedFileURL, mimeType: mimeType)
try? FileManager.default.removeItem(at: fileURL) // remove old file try? FileManager.default.removeItem(at: fileURL) // remove old file
} }