我正在使用 AVFoundation 在视频上制作文字叠加和水印。我面临一些困难。我正在使用Image/Text overlay in video swift问题的代码。但我修改了它。当我调用功能 loadVideo 时,视频无法加载。我想不明白。这是我的代码
@IBAction func loadVideo(_ sender: Any) {
let path = Bundle.main.path(forResource: "SampleVideo", ofType:"mp4")
let fileURL = URL(fileURLWithPath: path!)
let composition = AVMutableComposition()
let vidAsset = AVURLAsset(url: fileURL as URL, options: nil)
// get video track
let vtrack = vidAsset.tracks(withMediaType: AVMediaTypeVideo)
let videoTrack:AVAssetTrack = vtrack[0]
_ = videoTrack.timeRange.duration
let vid_timerange = CMTimeRangeMake(kCMTimeZero, vidAsset.duration)
let compositionvideoTrack:AVMutableCompositionTrack = composition.addMutableTrack(withMediaType: AVMediaTypeVideo, preferredTrackID: CMPersistentTrackID())
do {
_ = try compositionvideoTrack.insertTimeRange(vid_timerange, of: videoTrack, at: kCMTimeZero)
} catch {
print("error")
}
compositionvideoTrack.preferredTransform = videoTrack.preferredTransform
// Watermark Effect
let size = videoTrack.naturalSize
let imglogo = UIImage(named: "iosIcon.png")
let imglayer = CALayer()
imglayer.contents = imglogo?.cgImage
imglayer.frame = CGRect(x: 5, y: 5, width: 100, height: 100)
imglayer.opacity = 0.6
// create text Layer
let titleLayer = CATextLayer()
titleLayer.backgroundColor = UIColor.white.cgColor
titleLayer.string = "Subtitle Overlay Text"
titleLayer.font = UIFont(name: "Helvetica", size: 28)
titleLayer.shadowOpacity = 0.5
titleLayer.alignmentMode = kCAAlignmentCenter
titleLayer.frame = CGRect(x: 0, y: 50, width: size.width, height: size.height / 6)
let videolayer = CALayer()
videolayer.frame = CGRect(x: 0, y: 0, width: size.width, height: size.height)
let parentlayer = CALayer()
parentlayer.frame = CGRect(x: 0, y: 0, width: size.width, height: size.height)
parentlayer.addSublayer(videolayer)
parentlayer.addSublayer(imglayer)
parentlayer.addSublayer(titleLayer)
let layercomposition = AVMutableVideoComposition()
layercomposition.frameDuration = CMTimeMake(1, 30)
layercomposition.renderSize = size
layercomposition.animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayer: videolayer, in: parentlayer)
// instruction for watermark
let instruction = AVMutableVideoCompositionInstruction()
instruction.timeRange = CMTimeRangeMake(kCMTimeZero, composition.duration)
let videotrack = composition.tracks(withMediaType: AVMediaTypeVideo)[0] as AVAssetTrack
let layerinstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: videotrack)
instruction.layerInstructions = NSArray(object: layerinstruction) as [AnyObject] as [AnyObject] as! [AVVideoCompositionLayerInstruction]
layercomposition.instructions = NSArray(object: instruction) as [AnyObject] as [AnyObject] as! [AVVideoCompositionInstructionProtocol]
// create new file to receive data
let dirPaths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let docsDir = dirPaths[0] as String
let movieFilePath = docsDir.appending("result.mov")
let movieDestinationUrl = URL(fileURLWithPath: movieFilePath)
//remove existing file
_ = try? FileManager().removeItem(at: movieDestinationUrl)
// use AVAssetExportSession to export video
guard let assetExport = AVAssetExportSession(asset: composition, presetName:AVAssetExportPresetHighestQuality) else {return}
assetExport.videoComposition = layercomposition
assetExport.outputFileType = AVFileTypeQuickTimeMovie
assetExport.outputURL = movieDestinationUrl
assetExport.exportAsynchronously(completionHandler: {
switch assetExport.status{
case AVAssetExportSessionStatus.failed:
print("failed \(assetExport.error)")
case AVAssetExportSessionStatus.cancelled:
print("cancelled \(assetExport.error)")
case AVAssetExportSessionStatus.completed:
print("Completed")
default:
print("unknown")
}
})
}
我做错了什么?将ExportAsset保存在文件目录中有什么问题吗?
答案 0 :(得分:1)
最后我决定回答我自己的问题。上面的代码运行没有失败,但在模拟器中导出需要一些时间。所以我将presetName: AVAssetExportPresetHighestQuality 更改为 AVAssetExportPresetMediumQuality 。在文档目录中导出视频文件时也有修改。上面的代码不会删除文档目录中的现有视频文件。因此,当我导出另一个视频时,它无法覆盖现有视频。所以我删除了该文件。以下是代码:
{{1}}
答案 1 :(得分:1)
创建layerInstuctions后,请尝试使用此代码而不是上面的内容。对于其他任何有问题的人,就像我一样。您应该能够将预设保留在 AVAssetExportPresetHighestQuality
instruction.layerInstructions = [layerinstruction]
layercomposition.instructions = [instruction]
let movieFilePath = NSTemporaryDirectory() + "result.mp4"
let movieDestinationUrl = URL(fileURLWithPath: movieFilePath)
// must delete existing temporary file from file directory, also use try catch
do {
try FileManager.default.removeItem(at: movieDestinationUrl as URL)
} catch _ as NSError {
print("Error")
}