如何裁剪 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 生成最终视频时,它在视频录制过程中看起来完全一样。
我制作了 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 生成最终视频时,它在视频录制过程中看起来完全一样。