Я пытаюсь сделать видео из массива изображений и добавить к ним анимацию. Моя работа работает нормально на всех устройствах, кроме iphone 5s.
{
let composition = AVMutableComposition()
let track = self.asset?.tracks(withMediaType: AVMediaType.video)
let videoTrack:AVAssetTrack = track![0] as AVAssetTrack
let timerange = CMTimeRangeMake(kCMTimeZero,
(self.asset?.duration)!)
let compositionVideoTrack:AVMutableCompositionTrack = composition.addMutableTrack(withMediaType: AVMediaType.video, preferredTrackID: CMPersistentTrackID())!
do {
try compositionVideoTrack.insertTimeRange(timerange, of: videoTrack, at: kCMTimeZero)
compositionVideoTrack.preferredTransform = videoTrack.preferredTransform
} catch {
print(error)
}
//if your video has sound, you don’t need to check this
if self.audioIsEnabled {
let compositionAudioTrack:AVMutableCompositionTrack = composition.addMutableTrack(withMediaType: AVMediaType.audio, preferredTrackID: CMPersistentTrackID())!
for audioTrack in (self.asset?.tracks(withMediaType: AVMediaType.audio))! {
do {
try compositionAudioTrack.insertTimeRange(audioTrack.timeRange, of: audioTrack, at: kCMTimeZero)
} catch {
print(error)
}
}
}
let size = videoTrack.naturalSize
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)
//this is the animation part
var time = [0.00001, 4, 9, 12, 16] //I used this
var imgarray = self.selectedImageArray
parentlayer.removeFromSuperlayer()
for image in 0..<self.selectedImageArray.count {
let nextPhoto = imgarray[image]
let horizontalRatio = CGFloat(self.outputSize.width) / nextPhoto.size.width
let verticalRatio = CGFloat(self.outputSize.height) / nextPhoto.size.height
let aspectRatio = min(horizontalRatio, verticalRatio)
let newSize: CGSize = CGSize(width: nextPhoto.size.width * aspectRatio, height: nextPhoto.size.height * aspectRatio)
let x = newSize.width < self.outputSize.width ? (self.outputSize.width - newSize.width) / 2 : 0
let y = newSize.height < self.outputSize.height ? (self.outputSize.height - newSize.height) / 2 : 0
let blackLayer = CALayer()
blackLayer.removeAllAnimations()
//MARK:- Animations
///#1. left->right///
if(self.globalSelectedTransitionTag == 0){
if(image == 0){
blackLayer.frame = CGRect(x: -videoTrack.naturalSize.width, y: 0, width: videoTrack.naturalSize.width, height: videoTrack.naturalSize.height)
blackLayer.backgroundColor = UIColor.clear.cgColor
let imageLayer = CALayer()
imageLayer.frame = CGRect(x: x, y: y, width: newSize.width, height: newSize.height)
imageLayer.contents = imgarray[image].cgImage
blackLayer.addSublayer(imageLayer)
let animation = CABasicAnimation()
animation.keyPath = "position.x"
animation.fromValue = -videoTrack.naturalSize.width
animation.toValue = 5 * (videoTrack.naturalSize.width)
animation.duration = 10
animation.beginTime = CFTimeInterval(time[image])
animation.fillMode = kCAFillModeBoth
animation.isRemovedOnCompletion = true
//imageLayer.opacity = 0.5
blackLayer.add(animation, forKey: "opacity")
}else if(image == 1){
blackLayer.frame = CGRect(x: 2 * videoTrack.naturalSize.width, y: 0, width: videoTrack.naturalSize.width, height: videoTrack.naturalSize.height)
blackLayer.backgroundColor = UIColor.clear.cgColor
let imageLayer = CALayer()
imageLayer.frame = CGRect(x: x, y: y, width: newSize.width, height: newSize.height)
imageLayer.contents = imgarray[image].cgImage
blackLayer.addSublayer(imageLayer)
let animation = CABasicAnimation()
animation.keyPath = "position.x"
animation.fromValue = 2 * (videoTrack.naturalSize.width)
animation.toValue = -videoTrack.naturalSize.width
animation.duration = 10
animation.beginTime = CFTimeInterval(time[image])
animation.fillMode = kCAFillModeForwards
animation.isRemovedOnCompletion = true
// animation.speed = 0.7
blackLayer.add(animation, forKey: "basic")
}else if(image == 2){
blackLayer.frame = CGRect(x: 0, y: 2 * videoTrack.naturalSize.height, width: videoTrack.naturalSize.width, height: videoTrack.naturalSize.height)
blackLayer.backgroundColor = UIColor.clear.cgColor
let imageLayer = CALayer()
imageLayer.frame = CGRect(x: x, y: y, width: newSize.width, height: newSize.height)
imageLayer.contents = imgarray[image].cgImage
blackLayer.addSublayer(imageLayer)
let animation = CABasicAnimation()
animation.keyPath = "position.y"
animation.fromValue = 2 * videoTrack.naturalSize.height
animation.toValue = -videoTrack.naturalSize.height
animation.duration = 10
animation.beginTime = CFTimeInterval(time[image])
animation.fillMode = kCAFillModeForwards
animation.isRemovedOnCompletion = true
blackLayer.add(animation, forKey: "basic")
}else if(image == 3){
blackLayer.frame = CGRect(x: 0, y: -videoTrack.naturalSize.height, width: videoTrack.naturalSize.width, height: videoTrack.naturalSize.height)
blackLayer.backgroundColor = UIColor.clear.cgColor
let imageLayer = CALayer()
imageLayer.frame = CGRect(x: x, y: y, width: newSize.width, height: newSize.height)
imageLayer.contents = imgarray[image].cgImage
blackLayer.addSublayer(imageLayer)
let animation = CABasicAnimation()
animation.keyPath = "position.y"
animation.fromValue = -videoTrack.naturalSize.height
animation.toValue = 2 * videoTrack.naturalSize.height
animation.duration = 10
animation.beginTime = CFTimeInterval(time[image])
animation.fillMode = kCAFillModeForwards
animation.isRemovedOnCompletion = true
// animation.speed = 0.7
blackLayer.add(animation, forKey: "basic")
}else if(image == 4){
blackLayer.frame = CGRect(x: 0, y: -videoTrack.naturalSize.height, width: videoTrack.naturalSize.width, height: videoTrack.naturalSize.height)
blackLayer.backgroundColor = UIColor.clear.cgColor
let imageLayer = CALayer()
imageLayer.frame = CGRect(x: x, y: y, width: newSize.width, height: newSize.height)
imageLayer.contents = imgarray[image].cgImage
blackLayer.addSublayer(imageLayer)
let animation = CABasicAnimation()
animation.keyPath = "position.y"
animation.fromValue = 2 * videoTrack.naturalSize.height
animation.toValue = -videoTrack.naturalSize.height
animation.duration = 10
animation.beginTime = CFTimeInterval(time[image])
animation.fillMode = kCAFillModeForwards
animation.isRemovedOnCompletion = true
blackLayer.add(animation, forKey: "basic")
}
}else if(self.globalSelectedTransitionTag == 1){
blackLayer.frame = CGRect(x: 0, y: 0, width: videoTrack.naturalSize.width, height: videoTrack.naturalSize.height)
blackLayer.backgroundColor = UIColor.clear.cgColor
blackLayer.opacity = 0
let imageLayer = CALayer()
imageLayer.frame = CGRect(x: x, y: y, width: newSize.width, height: newSize.height)
imageLayer.contents = imgarray[image].cgImage
blackLayer.addSublayer(imageLayer)
let scaleAnimation = CAKeyframeAnimation(keyPath: "transform.scale")
if(image%2==0){
scaleAnimation.values = [0.9, 1.0, 0.9]
}else{
scaleAnimation.values = [1.0, 0.9, 1.0]
}
scaleAnimation.beginTime = CFTimeInterval(time[image])
scaleAnimation.duration = 10
scaleAnimation.isRemovedOnCompletion = false
blackLayer.add(scaleAnimation, forKey: "transform.scale")
let fadeInOutAnimation = CABasicAnimation(keyPath: "opacity")
fadeInOutAnimation.fromValue = 1
fadeInOutAnimation.toValue = 0.6
fadeInOutAnimation.duration = 10
fadeInOutAnimation.beginTime = CFTimeInterval(time[image])
fadeInOutAnimation.isRemovedOnCompletion = false
blackLayer.add(fadeInOutAnimation, forKey: "opacity")
}
//2.right->left
else if(self.globalSelectedTransitionTag == 2){
if(image == 0 || image == 2 || image == 4){
blackLayer.frame = CGRect(x: 0, y: -videoTrack.naturalSize.height, width: videoTrack.naturalSize.width, height: videoTrack.naturalSize.height)
blackLayer.backgroundColor = UIColor.clear.cgColor
let imageLayer = CALayer()
imageLayer.frame = CGRect(x: x, y: y, width: newSize.width, height: newSize.height)
imageLayer.contents = imgarray[image].cgImage
blackLayer.addSublayer(imageLayer)
let animation = CABasicAnimation()
animation.keyPath = "position.y"
animation.fromValue = 2*videoTrack.naturalSize.height
animation.toValue = -videoTrack.naturalSize.height
animation.duration = 3
animation.beginTime = CFTimeInterval(time[image])
animation.fillMode = kCAFillModeForwards
animation.isRemovedOnCompletion = false
// animation.speed = 0.7
blackLayer.add(animation, forKey: "basic")
}else{
blackLayer.frame = CGRect(x: 0, y: -videoTrack.naturalSize.height, width: videoTrack.naturalSize.width, height: videoTrack.naturalSize.height)
blackLayer.backgroundColor = UIColor.clear.cgColor
let imageLayer = CALayer()
imageLayer.frame = CGRect(x: x, y: y, width: newSize.width, height: newSize.height)
imageLayer.contents = imgarray[image].cgImage
blackLayer.addSublayer(imageLayer)
let animation = CABasicAnimation()
animation.keyPath = "position.y"
animation.fromValue = -videoTrack.naturalSize.height
animation.toValue = 2 * videoTrack.naturalSize.height
animation.duration = 3
animation.beginTime = CFTimeInterval(time[image])
animation.fillMode = kCAFillModeForwards
animation.isRemovedOnCompletion = false
blackLayer.add(animation, forKey: "basic")
}
}
}
parentlayer.addSublayer(blackLayer)
}
let layercomposition = AVMutableVideoComposition()
layercomposition.frameDuration = CMTimeMake(1, 30)
layercomposition.renderSize = size
if(fromBgImage||fromBgPattern||fromBgGradient||fromBgColor){
self.applyVideoEffects(to:layercomposition, size:size, andImage:globalBackgroundImage, andController:self, andsourceOverlay:"fromBgImage")
}else if(fromTextAction){
self.applyVideoEffects(to:layercomposition, size: size)
}
else{
layercomposition.animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayer: videolayer, in: parentlayer)
}
let instruction = AVMutableVideoCompositionInstruction()
instruction.timeRange = CMTimeRangeMake(kCMTimeZero, composition.duration)
let videotrack = composition.tracks(withMediaType: AVMediaType.video)[0] as AVAssetTrack
let layerinstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: videotrack)
instruction.layerInstructions = [layerinstruction]
layercomposition.instructions = [instruction]
if(fromTransition){
self.globalrVideoComposition = layercomposition
}
let videoName2 = String.init(format:"/Documents/%@.MP4",GlobalClass().randomString(length:4))
let animatedVideoURL = NSURL(fileURLWithPath:NSHomeDirectory() + videoName2)
self.removeFileAtURLIfExists(url: animatedVideoURL)
// AVAssetExportPresetHighestQuality
guard let assetExport = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetHighestQuality) else {return}
assetExport.videoComposition = self.globalrVideoComposition
assetExport.outputFileType = AVFileType.mp4
assetExport.outputURL = animatedVideoURL as URL
print("****** animatedVideoURL *****",animatedVideoURL)
assetExport.exportAsynchronously(completionHandler: {
switch assetExport.status{
case AVAssetExportSessionStatus.failed:
let errormsg = (String(describing: assetExport.error))
let alertController = UIAlertController(title:"Error", message:errormsg, preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .default, handler: nil)
alertController.addAction(defaultAction)
self.present(alertController, animated: true, completion: nil)
print("errormsg",errormsg)
case AVAssetExportSessionStatus.cancelled:
print("cancelled \(String(describing: assetExport.error))")
let alertController = UIAlertController(title:"Cancelled", message: (assetExport.error as! String), preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .default, handler: nil)
alertController.addAction(defaultAction)
print("The task is done,enjoy now!")
self.present(alertController, animated: true, completion: nil)
default:
print("Exported")
if(self.fromPlayVideo){
DispatchQueue.main.async {
self.globalVideoURL = animatedVideoURL;
self.playVideoInPlayer(animatedVideoURL: self.globalVideoURL as URL)
}
}else if(self.fromSave){
PHPhotoLibrary.shared().performChanges({
PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: animatedVideoURL as URL)
print("222222 animatedVideoURL",animatedVideoURL)
}) { saved, error in
DispatchQueue.main.async {
MBProgressHUD.hideAllHUDs(for: self.view, animated: true)
}
if saved {
let alertController = UIAlertController(title: "Video successfully saved", message: nil, preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .default, handler: nil)
alertController.addAction(defaultAction)
print("The task is done,enjoy now!")
self.present(alertController, animated: true, completion: nil)
}else{
}
}
}
}
})
}
После поиска в Google я обнаружил, что если яизмените предустановку exportsession на passthrough ... он также может работать на iphone 5s.
Но когда я изменяю предустановку на любую другую предустановку, кроме самого высокого качества, она не показывает анимацию на видео.
И, кроме того, это займет очень много времени в Highestquality.
Есть ли какой-нибудь способ, которым я могу делать видео с анимацией и с немного более быстрым также?
Любая помощь или предложение в этом направлении будетзаметно. Заранее спасибо!