Search code examples
iosswiftavfoundation

I want to merge video with image but after merging it's showing black screen


I have taken one video URL from backend and I want to marge with image. So I have added VideoLayer, ImageLayer on ParentLayer called AnimationLayer.

After Merge Video and images, it seems 1 black screen.

How can I resolve this bug?

 func MergeVideo1(_ vidioUrlString: String?, with img: UIImage?, With VideoName : String)
    {
        
        guard let videoUrl = URL(string: vidioUrlString ?? "") else { return  }
        
        let videoUrlAsset = AVURLAsset(url: videoUrl, options: nil)
        
        // Setup `mutableComposition` from the existing video
        let mutableComposition = AVMutableComposition()
        let videoAssetTrack = videoUrlAsset.tracks(withMediaType: AVMediaType.video).first!
        
        let videoCompositionTrack = mutableComposition.addMutableTrack(withMediaType: AVMediaType.video, preferredTrackID: kCMPersistentTrackID_Invalid)
        videoCompositionTrack!.preferredTransform = videoAssetTrack.preferredTransform
   
        try! videoCompositionTrack!.insertTimeRange(CMTimeRange(start:CMTime.zero, duration:videoAssetTrack.timeRange.duration), of: videoAssetTrack, at: CMTime.zero)
        let audioAssetTrack = videoUrlAsset.tracks(withMediaType: AVMediaType.audio).first!
        let audioCompositionTrack = mutableComposition.addMutableTrack(withMediaType: AVMediaType.audio, preferredTrackID: kCMPersistentTrackID_Invalid)
        try! audioCompositionTrack!.insertTimeRange(CMTimeRange(start: CMTime.zero, duration:audioAssetTrack.timeRange.duration), of: audioAssetTrack , at: CMTime.zero)
        
        // Create a `videoComposition` to represent the `foregroundImage`
        let videoSize: CGSize = videoCompositionTrack!.naturalSize
        let frame = CGRect(x: 0.0, y: 0.0, width: videoSize.width, height: videoSize.height)
        
        
           
         let imgLogoMix = UIImage(named: "icn_RandomDownload")
        //Logo
        let imageLayer_LOGO = CALayer()
        imageLayer_LOGO.contents = imgLogoMix.cgImage
        imageLayer_LOGO.frame = frame
        
        
        //Frame
        let imageLayer = CALayer()
        imageLayer.contents = img?.cgImage
        imageLayer.frame = frame
        
        let videoLayer = CALayer()
        videoLayer.frame = frame
        
        let animationLayer = CALayer()
        animationLayer.frame = frame
        
        animationLayer.addSublayer(videoLayer)
        animationLayer.addSublayer(imageLayer)
        animationLayer.addSublayer(imageLayer_LOGO)
        
        imageLayer.bringToFront()
        imageLayer_LOGO.bringToFront()

        
        
        let videoComposition = AVMutableVideoComposition(propertiesOf: (videoCompositionTrack?.asset!)!)
      
      
        videoComposition.animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayer: videoLayer, in: animationLayer)
        
        
        let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
        let DirPath = paths[0].appendingPathComponent("CREATE_IMAGE")
        //finalPath = DirPath.path +  "/myVideo.mp4"
        
        finalPath = DirPath.path +  "/\(VideoName).mp4"
        
        if FileManager.default.fileExists(atPath: finalPath) {
            do {
                try FileManager.default.removeItem(atPath: finalPath)
            } catch {
            }
        }
        
        let exportSession = AVAssetExportSession( asset: mutableComposition, presetName: AVAssetExportPresetHighestQuality)!
        exportSession.videoComposition = videoComposition
        //  exportSession.outputURL = destinationFilePath
        exportSession.outputURL = URL(fileURLWithPath: finalPath)
        exportSession.outputFileType = AVFileType.mp4
    
        
        
        exportSession.exportAsynchronously(completionHandler: {
            switch exportSession.status {
            case AVAssetExportSession.Status.failed:
                print("failed")
                SKActivityHUD.DismissHUD()
                print(exportSession.error ?? "unknown error")
            case AVAssetExportSession.Status.cancelled:
                print("cancelled")
                SKActivityHUD.DismissHUD()
                print(exportSession.error ?? "unknown error")
            default:
                print("Movie complete")
                // SKActivityHUD.DismissHUD()
              
            }
        })
    }

Edited above code with

let videoComposition = AVMutableVideoComposition()
        videoComposition.frameDuration = CMTimeMake(value: 1, timescale: Int32(videoCompositionTrack?.nominalFrameRate ?? 300))
  videoComposition.renderSize = videoSize
 videoComposition.animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayer: videoLayer, in: animationLayer)
 let instruction = AVMutableVideoCompositionInstruction()
 instruction.timeRange = CMTimeRangeMake(start: CMTime.zero, duration: mutableComposition.duration)
 let videotrack = mutableComposition.tracks(withMediaType: AVMediaType.video)[0] as AVAssetTrack
let layerinstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: videotrack)
instruction.layerInstructions = NSArray(object: layerinstruction) as [AnyObject] as! [AVVideoCompositionLayerInstruction]
videoComposition.instructions = [instruction]

Solution

  • Above code just replaced with

      let videoComposition = AVMutableVideoComposition()
        videoComposition.frameDuration = CMTimeMake(value: 1, timescale: Int32(videoCompositionTrack?.nominalFrameRate ?? 300))
        videoComposition.renderSize = videoSize
        videoComposition.animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayer: videoLayer, in: animationLayer)
    
      
        let instruction = AVMutableVideoCompositionInstruction()
        instruction.timeRange = CMTimeRangeMake(start: CMTime.zero, duration: mutableComposition.duration)
        let videotrack = mutableComposition.tracks(withMediaType: AVMediaType.video)[0] as AVAssetTrack
        let layerinstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: videotrack)
        let rgb = CGColorSpaceCreateDeviceRGB()
        let myColor : [CGFloat] = [1.0, 1.0, 1.0, 1.0] //white
        let ref = CGColor(colorSpace: rgb, components: myColor)
        instruction.backgroundColor = ref
        instruction.layerInstructions = NSArray(object: layerinstruction) as [AnyObject] as! [AVVideoCompositionLayerInstruction]
        videoComposition.instructions = [instruction]