Reputation: 958
I want to add a Image over a video and in order to do so I follow this tutorial:
The code I implemented is this:
func addViewToVideo(fromVideoAt videoURL: URL, withView: UIView, completion: @escaping (URL?) -> Void) {
let imageTransformedFromView = withView.asImage()
let asset = AVURLAsset(url: videoURL)
let composition = AVMutableComposition()
guard let compositionTrack = composition.addMutableTrack(withMediaType: .video, preferredTrackID: kCMPersistentTrackID_Invalid), let assetTrack = asset.tracks(withMediaType: .video).first else{
print("Something is wrong with the asset")
completion(nil)
return
}
do{
let timeRange = CMTimeRange(start: .zero, duration: asset.duration)
try compositionTrack.insertTimeRange(timeRange, of: assetTrack, at: .zero)
if let audioAssetTrack = asset.tracks(withMediaType: .audio).first, let compositionAudioTrack = composition.addMutableTrack(withMediaType: .audio, preferredTrackID: kCMPersistentTrackID_Invalid){
try compositionAudioTrack.insertTimeRange(timeRange, of: audioAssetTrack, at: .zero)
}
}catch{
print(error)
completion(nil)
return
}
compositionTrack.preferredTransform = assetTrack.preferredTransform
let videoSize: CGSize
videoSize = CGSize(
width: assetTrack.naturalSize.height,
height: assetTrack.naturalSize.width)
let videoLayer = CALayer()
videoLayer.frame = CGRect(origin: .zero, size: videoSize)
let overlayLayer = CALayer()
overlayLayer.frame = CGRect(origin: .zero, size: videoSize)
addImage(imagePassed: imageTransformedFromView, to: overlayLayer, videoSize: videoSize)
let outputLayer = CALayer()
outputLayer.frame = CGRect(origin: .zero, size: videoSize)
outputLayer.addSublayer(videoLayer)
outputLayer.addSublayer(overlayLayer)
let videoComposition = AVMutableVideoComposition()
videoComposition.renderSize = videoSize
videoComposition.frameDuration = CMTime(value: 1, timescale: 30)
videoComposition.animationTool = AVVideoCompositionCoreAnimationTool(
postProcessingAsVideoLayer: videoLayer,
in: outputLayer)
let instruction = AVMutableVideoCompositionInstruction()
instruction.timeRange = CMTimeRange(start: .zero,duration: composition.duration)
videoComposition.instructions = [instruction]
let layerInstruction = compositionLayerInstruction(
for: compositionTrack,
assetTrack: assetTrack)
instruction.layerInstructions = [layerInstruction]
guard let export = AVAssetExportSession(
asset: composition,
presetName: AVAssetExportPreset1920x1080)
else {
print("Cannot create export session.")
completion(nil)
return
}
let videoName = UUID().uuidString
let exportURL = URL(fileURLWithPath: NSTemporaryDirectory())
.appendingPathComponent(videoName)
.appendingPathExtension("mov")
export.videoComposition = videoComposition
export.outputFileType = .mov
export.outputURL = exportURL
export.exportAsynchronously {
DispatchQueue.main.async {
switch export.status {
case .completed:
completion(exportURL)
default:
print("Something went wrong during export.")
print(export.error ?? "unknown error")
completion(nil)
break
}
}
}
}
func compositionLayerInstruction(for track: AVCompositionTrack, assetTrack: AVAssetTrack) -> AVMutableVideoCompositionLayerInstruction {
let instruction = AVMutableVideoCompositionLayerInstruction(assetTrack: track)
var transform = CGAffineTransform.identity
let assetSize = assetTrack.naturalSize
transform = CGAffineTransform(a: 0, b: 1, c: -1, d: 0, tx: assetSize.height, ty: 0)
instruction.setTransform(transform, at: .zero)
return instruction
}
It works pretty fine apart from the fact that when I pass a video from the front camera it doesn't mirror it.
I'm pretty sure the reason why it doesn't mirror it stays behind the CGAffineTransform
transformation.
To be honest I don't know how to work with the a,b,c,d,tx,ty
constructors, but how could I transform the video such that it seems it's mirrored?
Upvotes: 1
Views: 902