如何在AVFoundation中裁剪显示视频局部?代码异常求助
AVFoundation视频裁剪不符合预期的排查思路
针对你提供的代码,从以下几个方向逐一排查:
Core Image与UIKit坐标系不匹配
CICrop的inputRectangle参数遵循Core Image坐标系(原点在左下角),而你直接使用的是UIKit坐标系(原点在左上角),这会导致裁剪区域位置完全颠倒。先把UIKit风格的裁剪矩形转换为Core Image坐标系:guard let videoTrack = item.asset.tracks(withMediaType: .video).first else { return } let videoNaturalSize = videoTrack.naturalSize // 转换坐标系 let ciCropRect = CGRect( x: cropRect.origin.x, y: videoNaturalSize.height - cropRect.origin.y - cropRect.height, width: cropRect.width, height: cropRect.height ) // 用转换后的rect创建CIVector cropFilter.setValue(CIVector(cgRect: ciCropRect), forKey: "inputRectangle")裁剪区域超出视频实际分辨率
你使用了固定的cropRect数值,但如果视频的实际分辨率和你预期不符(比如视频是1920x1080,你按1280x720设置坐标),会导致裁剪区域偏移或无效。先获取视频的真实尺寸:guard let videoTrack = item.asset.tracks(withMediaType: .video).first else { return } let naturalSize = videoTrack.naturalSize let transform = videoTrack.preferredTransform // 修正旋转后的实际显示尺寸 let actualVideoSize = CGSize( width: naturalSize.width * abs(transform.a), height: naturalSize.height * abs(transform.d) ) // 检查cropRect是否在有效范围内 guard cropRect.origin.x + cropRect.width <= actualVideoSize.width, cropRect.origin.y + cropRect.height <= actualVideoSize.height else { // 裁剪区域超出视频范围,调整或报错 return }视频旋转导致的变换错误
如果视频带有旋转属性(比如竖屏拍摄的视频),preferredTransform会改变视频的显示方向,此时直接平移裁剪后的图像会出现错位。可以结合视频的transform调整最终输出:// 获取视频的旋转角度对应的变换 let videoTransform = videoTrack.preferredTransform // 先做裁剪平移,再应用视频原变换 let finalImage = imageAtOrigin.transformed(by: videoTransform) request.finish(with: finalImage, context: nil)Asset未加载完成就创建合成
直接通过URL创建AVPlayerItem时,asset可能还未完成加载,导致获取的track信息错误。改成异步加载asset的tracks后再创建视频合成:let asset = AVAsset(url: nextVideoItem.url) asset.loadValuesAsynchronously(forKeys: ["tracks"]) { DispatchQueue.main.async { guard asset.statusOfValue(forKey: "tracks", error: nil) == .loaded else { // 加载失败处理 return } let item = AVPlayerItem(asset: asset) // 在这里创建cropComposition并设置给item let cropRect = CGRect(x: 200, y: 200, width: 300, height: 300) let cropComposition = AVMutableVideoComposition(asset: asset, applyingCIFiltersWithHandler: { request in // 裁剪逻辑... }) cropComposition.renderSize = cropRect.size item.videoComposition = cropComposition self.player.replaceCurrentItem(with: item) self.player.play() } }验证CIFilter输出结果
在request.finish前,临时渲染裁剪后的图像,确认滤镜处理是否符合预期:let context = CIContext() if let outputImage = cropFilter.outputImage, let cgImage = context.createCGImage(outputImage, from: outputImage.extent) { let testImage = UIImage(cgImage: cgImage) print("裁剪后图像尺寸:\(testImage.size)") // 可以把testImage显示到临时UIImageView中直观查看 }
内容的提问来源于stack exchange,提问作者NFC.cool
相关产品推荐
相关产品推荐

