I have been spending time trying to figure out how to crop and zoom a specific video based on user input from a scrollview.
Imagine we have a zoomable view (works for images and videos). This includes a scrollview and an av player layer. Users can zoom and pan around within the view which will be cropped later.
I am able to calculate the crop area and reposition the video within a mutable composition, however I can’t seem to “fit” the video within the render size without losing quality.
Below is the code I am currently using with a few screenshots.
let size = videoMutableTrack.naturalSize.applying(videoMutableTrack.preferredTransform)
var scaleRatioX = (renderSize.width / 2) / currentVideoView.contentSize.width
var scaleRatioY = (renderSize.height) / currentVideoView.contentSize.height
if (rotate) {
scaleRatioX = (renderSize.width) / currentVideoView.contentSize.width
scaleRatioY = (renderSize.height / 2) / currentVideoView.contentSize.height
}
let scale = CGAffineTransform(scaleX: scaleRatioX, y: scaleRatioY) // When using this scale, no zoom is applied.
let scale = CGAffineTransform(scaleX: scaleRatioX * (currentVideoView.zoomScale / 2), y: scaleRatioY * (currentVideoView.zoomScale / 2)) // When using this scale, zoom is applied (last screenshot)
let offsetX = -currentVideoView.contentOffset.x
let offsetY = -currentVideoView.contentOffset.y
let layerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: videoMutableTrack)
let move = CGAffineTransform(translationX: offsetX, y: offsetY)
layerInstruction.setTransform(move.concatenating(scale), at: .zero)
let mutableVideoComposition = AVMutableVideoComposition()
mutableVideoComposition.instructions = [compositionInstruction]
mutableVideoComposition.frameDuration = CMTimeMake(value: 1, timescale: Int32(highestFrameRate))
mutableVideoComposition.renderSize = renderSize
mutableVideoComposition.animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayer: videoLayer, in: outputLayer)