Created
August 7, 2017 11:45
-
-
Save TheSwiftyCoder/70c25ef1da406124297884176179f354 to your computer and use it in GitHub Desktop.
Allows a UIImage to be placed full width and height of a video in Swift 3
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
func processVideoWithWatermark(video: AVURLAsset, watermark: UIImage, completion: @escaping (Bool) -> Void) { | |
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first | |
let outputPath = documentsURL?.appendingPathComponent("dfyVideo_\(Date().timeStamp).mov") // Needs random time | |
if FileManager.default.fileExists(atPath: video.url.absoluteString) { | |
do { | |
try FileManager.default.removeItem(atPath: video.url.absoluteString) | |
} | |
catch { | |
print ("Error deleting file") | |
} | |
} | |
// File to composit | |
let asset = AVAsset.init(url: video.url) | |
let composition = AVMutableComposition.init() | |
composition.addMutableTrack(withMediaType: AVMediaTypeVideo, preferredTrackID: kCMPersistentTrackID_Invalid) | |
let clipVideoTrack = asset.tracks(withMediaType: AVMediaTypeVideo)[0] | |
// Rotate to potrait | |
let transformer = AVMutableVideoCompositionLayerInstruction(assetTrack: clipVideoTrack) | |
var videoAssetOrientation_: UIImageOrientation = .up | |
var isVideoAssetPortrait_: Bool = false | |
let videoTransform:CGAffineTransform = clipVideoTrack.preferredTransform | |
if videoTransform.a == 0 && videoTransform.b == 1.0 && videoTransform.c == -1.0 && videoTransform.d == 0 { | |
videoAssetOrientation_ = .right | |
isVideoAssetPortrait_ = true | |
} | |
if videoTransform.a == 0 && videoTransform.b == -1.0 && videoTransform.c == 1.0 && videoTransform.d == 0 { | |
videoAssetOrientation_ = .left | |
isVideoAssetPortrait_ = true | |
} | |
if videoTransform.a == 1.0 && videoTransform.b == 0 && videoTransform.c == 0 && videoTransform.d == 1.0 { | |
videoAssetOrientation_ = .up | |
} | |
if videoTransform.a == -1.0 && videoTransform.b == 0 && videoTransform.c == 0 && videoTransform.d == -1.0 { | |
videoAssetOrientation_ = .down | |
} | |
transformer.setTransform(clipVideoTrack.preferredTransform, at: kCMTimeZero) | |
var naturalSize = CGSize() | |
if isVideoAssetPortrait_ { | |
naturalSize = CGSize(width: clipVideoTrack.naturalSize.height, height: clipVideoTrack.naturalSize.width) | |
} else { | |
naturalSize = clipVideoTrack.naturalSize | |
} | |
var renderWidth: CGFloat! | |
var renderHeight: CGFloat! | |
renderWidth = naturalSize.width | |
renderHeight = naturalSize.height | |
let parentlayer = CALayer() | |
let videoLayer = CALayer() | |
let watermarkLayer = CALayer() | |
watermarkLayer.contents = watermark.cgImage | |
watermarkLayer.opacity = 1.0 | |
parentlayer.frame = CGRect(x: 0, y: 0, width: renderWidth, height: renderHeight) | |
videoLayer.frame = CGRect(x: 0, y: 0, width: renderWidth, height: renderHeight) | |
watermarkLayer.frame = CGRect(x: 0, y: 0 ,width: renderWidth, height: renderHeight) | |
parentlayer.addSublayer(videoLayer) | |
parentlayer.addSublayer(watermarkLayer) | |
let videoComposition = AVMutableVideoComposition() | |
videoComposition.renderSize = CGSize(width: renderWidth, height: renderHeight) | |
videoComposition.frameDuration = CMTimeMake(1, 30) | |
videoComposition.renderScale = 1.0 | |
// Add watermark to video | |
videoComposition.animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayers: [videoLayer], in: parentlayer) | |
let instruction = AVMutableVideoCompositionInstruction() | |
instruction.timeRange = CMTimeRangeMake(kCMTimeZero, CMTimeMakeWithSeconds(60, 30)) | |
instruction.layerInstructions = [transformer] | |
videoComposition.instructions = [instruction] | |
let exporter = AVAssetExportSession.init(asset: asset, presetName: AVAssetExportPresetHighestQuality) | |
exporter?.outputFileType = AVFileTypeQuickTimeMovie | |
exporter?.outputURL = outputPath | |
exporter?.videoComposition = videoComposition | |
exporter?.exportAsynchronously() { handler -> Void in | |
if exporter?.status == .completed { | |
DispatchQueue.main.async(execute: { | |
self.saveVideoToUserLibrary(fileURL: outputPath!, savingCompletion: { (success, error) in | |
if success == true { | |
completion(true) | |
} else { | |
print("Saving error: \(error)") | |
completion(false) | |
} | |
}) | |
}) | |
return | |
} else if exporter?.status == .failed { | |
print("Export failed - \(String(describing: exporter?.error))") | |
} | |
completion(false) | |
return | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment