You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS Swift实现无画质损失的视频裁剪与缩放

问题描述

我正尝试基于ScrollView的用户输入,实现特定视频的裁剪与缩放功能。现有一个支持图片和视频的可缩放视图,包含ScrollView和AVPlayerLayer,用户可在视图内缩放、平移,后续将进行裁剪。我已能计算裁剪区域并在AVMutableComposition中重新定位视频,但无法在不损失画质的情况下让视频适配渲染尺寸。我希望截图2填充截图3的渲染尺寸,同时呈现截图1的效果。注:请忽略截图画质,为上传至SO我将其转为了JPEG格式。

当前实现代码

if let videoMutableTrack = composition.addMutableTrack(withMediaType: .video, preferredTrackID: kCMPersistentTrackID_Invalid) {
        do {
            try videoMutableTrack.insertTimeRange(CMTimeRangeMake(start: .zero, duration: fileAsset.duration), of: videoTrack, at: .zero)
        }
        catch {
            print(error)
            self.setErrorInfo(error)
            completionHandler(nil)
            return
        }
        
        if (fileAsset.duration > maxDuration) {
            maxDuration = fileAsset.duration
        }
        
        let size = videoMutableTrack.naturalSize.applying(videoMutableTrack.preferredTransform)
        
        var scaleRatioX = (renderSize.width / 2) / size.width
        var scaleRatioY = (renderSize.height) / size.height
        if (rotate) {
            scaleRatioX = (renderSize.width) / size.width
            scaleRatioY = (renderSize.height / 2) / size.height
        }
        
        var scale = CGAffineTransform(scaleX: scaleRatioX, y: scaleRatioY)
        
        let offsetX = -currentVideoView.contentOffset.x
        let offsetY = -currentVideoView.contentOffset.y
        
        let layerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: videoMutableTrack)
        if (videoFile.fileId == 1) {
            var move = CGAffineTransform(translationX: 0, y: 0)
            
            if (shouldUseDefaultScaling(currentVideoView)) {
                scale = CGAffineTransform(scaleX: scaleRatioX * (currentVideoView.zoomScale / 2), y: scaleRatioY * (currentVideoView.zoomScale / 2))
                move = CGAffineTransform(translationX: offsetX, y: offsetY)
            }
            
            layerInstruction.setTransform(move.concatenating(scale), at: .zero)
        }
        else {
            var move = CGAffineTransform(translationX: size.width, y: 0)
            if (rotate) {
                move = CGAffineTransform(translationX: 0, y: size.height)
            }
            
            if (shouldUseDefaultScaling(currentVideoView)) {
                scale = CGAffineTransform(scaleX: scaleRatioX * currentVideoView.zoomScale, y: scaleRatioY * currentVideoView.zoomScale)
                move = CGAffineTransform(translationX: offsetX, y: offsetY)
            }
            
            layerInstruction.setTransform(move.concatenating(scale), at: .zero)
        }
        
        compositionInstruction.layerInstructions.append(layerInstruction)
    }

let currentFrameRate = Int(roundf((videoTrack.nominalFrameRate)))
    highestFrameRate = (currentFrameRate > highestFrameRate) ? currentFrameRate : highestFrameRate
    
    compositionInstruction.timeRange = CMTimeRangeMake(start: .zero, duration: maxDuration)
    
    let videoLayer = CALayer()
    videoLayer.frame = CGRect(origin: .zero, size: renderSize)
    
    let mutableVideoComposition = AVMutableVideoComposition()
    mutableVideoComposition.instructions = [compositionInstruction]
    mutableVideoComposition.frameDuration = CMTimeMake(value: 1, timescale: Int32(highestFrameRate))
    mutableVideoComposition.renderSize = renderSize
    mutableVideoComposition.animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayer: videoLayer, in: outputLayer)

相关截图

  • 用户选择视频/照片:User Picks Videos/Photos
  • 裁剪后(无缩放):Cropped - No Zoom
  • 裁剪后(已缩放):Cropped - Zooming

内容的提问来源于stack exchange,提问作者Joe Ginley

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 06:04:57