Базовая анимация не работает на iphone 5s, а предустановленная экспозиция Highestquality очень медленная в swift 4 - PullRequest
0 голосов
/ 01 марта 2019

Я пытаюсь сделать видео из массива изображений и добавить к ним анимацию. Моя работа работает нормально на всех устройствах, кроме 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.

Есть ли какой-нибудь способ, которым я могу делать видео с анимацией и с немного более быстрым также?

Любая помощь или предложение в этом направлении будетзаметно. Заранее спасибо!

...