Solution without a large switch/case: https://developer.apple.com/forums/thread/705269?answerId=741570022#741570022
Post
Replies
Boosts
Views
Activity
I came across this solution as a recommended result, so thought to share my solution here, as well.
What you seem to be describing is equivalent to fitting an image inside its frame: image.contentMode = .scaleAspectFit
Here's the CGAffineTransform equivalent for an AVAssetTrack:
func scaleAspectFitTransform(for assetTrack: AVAssetTrack, into renderSize: CGSize) -> CGAffineTransform {
let naturalSize = assetTrack.naturalSize.applying(assetTrack.preferredTransform)
let absoluteSize = CGSize(width: abs(naturalSize.width),
height: abs(naturalSize.height))
let xFactor = renderSize.width / absoluteSize.width
let yFactor = renderSize.height / absoluteSize.height
let scaleFactor = min(xFactor, yFactor)
var output = assetTrack.preferredTransform.scaledBy(x: scaleFactor, y: scaleFactor)
output.tx = assetTrack.preferredTransform.tx * scaleFactor
output.ty = assetTrack.preferredTransform.ty * scaleFactor
let compressedSize = CGSize(width: absoluteSize.width * scaleFactor,
height: absoluteSize.height * scaleFactor)
let widthDiff = renderSize.width - compressedSize.width
let heightDiff = renderSize.height - compressedSize.height
let plainTranslation = CGAffineTransform.identity.translatedBy(x: widthDiff / 2,
y: heightDiff / 2)
return output.concatenating(plainTranslation)
Then, apply it to your layer instructions:
guard let sourceVideoTrack = sourceAVAsset.tracks(withMediaType: .video).first else { return }
let transform = scaleAspectFitTransform(for: sourceVideoTrack, into: renderSize)
var layerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: outputVideoTrack)
layerInstruction.setTransform(transform, at: .zero)
let compositionInstruction = AVMutableVideoCompositionInstruction()
compositionInstruction.timeRange = CMTimeRangeMake(start: .zero, duration: videoAsset.duration)
compositionInstruction.layerInstructions = [layerInstruction]
let videoComposition = AVMutableVideoComposition()
videoComposition.renderSize = renderSize
videoComposition.instructions = [compositionInstruction]