Reputation: 648
I am using AVFoundation for making text overlay and watermark on a video. I am facing some difficulties. I am using Image/Text overlay in video swift question's code. But I modified it. When I call function loadVideo, video does not load. I cannot figure it out. Here is my code
@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")
}
})
}
What I am doing wrong? is something wrong with saving ExportAsset in file directory?
Upvotes: 3
Views: 934
Reputation: 857
After creating the layerInstuctions try this code instead of whats above. for anyone else having trouble with this like I was. And you should be able to keep the preset at 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")
}
Upvotes: 1
Reputation: 648
At last I decide to answer my own question. Above code is running without failing but in simulator it takes some time to export. So I changed the presetName:AVAssetExportPresetHighestQuality to AVAssetExportPresetMediumQuality. There is also a modification in exporting video file in documents directory. Above code does not remove existing video file in documents directory. So when I export another video it cannot override the existing video. So I remove the file. Below is the code:
let dirPaths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let docsDir: AnyObject = dirPaths[0] as AnyObject
let movieFilePath = docsDir.appending("result.mp4")
let movieDestinationUrl = NSURL(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")
}
Upvotes: 1