如何裁剪 AVCaptureMovieFileOutput 录制的视频?

How to crop a video recorded given by AVCaptureMovieFileOutput?

我制作了 CustomCamera,它可以全屏录制视频(通过将 AVCaptureVideoPreviewLayer 的 videoGravity 设置为 resizeAspectFill)并使用 AVCaptureMovieFileOutput 保存录制。录制效果很好,但是当我将录制的视频保存到图库中时,它无法全屏播放。它的顶部和底部有黑色条。因此,在录制时由于 resizeAspectFill 而全屏显示,但在导出视频后导出时没有任何转换,因此它以录制时的比例播放(我猜)。 下面是我尝试全屏导出视频的代码,但它不起作用。

func fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: Error?) {
if let err = error as NSError?, err.code != -11810 { //-11810 = recording stopped when timelimit reached
    print("Error recording movie: \(err)")
} else {
    let videoAsset: AVAsset = AVAsset( url: outputFileURL )
    guard let clipVideoTrack = videoAsset.tracks( withMediaType: AVMediaType.video ).first as AVAssetTrack? else {
        
        return
    }
    
    let videoComposition = AVMutableVideoComposition(propertiesOf: videoAsset)

    let instruction = AVMutableVideoCompositionInstruction()
    instruction.timeRange = clipVideoTrack.timeRange
    
     let transformer = AVMutableVideoCompositionLayerInstruction( assetTrack: clipVideoTrack)
    transformer.setTransform(videoPreviewLayer.affineTransform(), at: .zero) // This is the transform value of AVCaptureVideoPreviewLayer
    print("clipVideoTrack size: \(clipVideoTrack.naturalSize)")
    
    instruction.layerInstructions = [transformer]
    videoComposition.instructions = [instruction]
    
    let outputPath = "\(NSTemporaryDirectory())\(UUID().uuidString).mov"
    let croppedOutputFileUrl = URL(fileURLWithPath: outputPath)
    
    let exporter = AVAssetExportSession(asset: videoAsset, presetName: AVAssetExportPresetHighestQuality)!
    exporter.videoComposition = videoComposition
    exporter.outputURL = croppedOutputFileUrl
    exporter.outputFileType = .mov
    exporter.shouldOptimizeForNetworkUse = true
    exporter.canPerformMultiplePassesOverSourceMediaData = true
    
    exporter.exportAsynchronously( completionHandler: { () -> Void in
        if let error = exporter.error {
            print("Error in exporting: \(error)")
        }
        if exporter.status == .completed {
            print("exported successfully")
        }
        DispatchQueue.main.async(execute: {
            if let url = exporter.outputURL {
                print("exported file url: \(url)")
            } else {
            }
            
        })
    })
}
}

录制的视频尺寸取决于您的会话sessionPreset

captureSession.sessionPreset = AVCaptureSession.Preset.vga640x480 // and many others 

它与选择播放视频的当前宽高比无关

我发现使用 AVCaptureMovieFileOutput 很难更改录制视频的分辨率,并且裁剪带来了很多挑战。所以,最后我决定尝试一下 AVCaptureVideoDataOutput,它的效果非常好。我能够全屏录制视频,以及当 AVCaptureVideoDataOutput 生成最终视频时,它在视频录制过程中看起来完全一样。