Search code examples
iphoneavfoundationswift4ios11

Overlap Multiple Videos in swift


I tried to convert an objective C code to swift 4, The code is adding video over another video http://www.theappguruz.com/blog/ios-overlap-multiple-videos this the objective-c Code I got this error : "(Error Domain=AVFoundationErrorDomain Code=-11841 "Operation Stopped" UserInfo={NSLocalizedFailureReason=The video could not be composed., NSLocalizedDescription=Operation Stopped, NSUnderlyingError=0x604000646cf0 {Error Domain=NSOSStatusErrorDomain Code=-17390 "(null)"}}) "

class func mergeVideos(firestUrl : URL , SecondUrl : URL ){

    let firstAssets = AVAsset(url: firestUrl)
    let secondAssets = AVAsset(url: SecondUrl)

    let mixComposition = AVMutableComposition()

    let firstTrack = mixComposition.addMutableTrack(withMediaType: .video, preferredTrackID: kCMPersistentTrackID_Invalid)
    let seconTrack = mixComposition.addMutableTrack(withMediaType: .video, preferredTrackID: kCMPersistentTrackID_Invalid)

    do{
  try   firstTrack?.insertTimeRange(CMTimeRangeMake(kCMTimeZero, firstAssets.duration), of: firstAssets.tracks(withMediaType: .video)[0], at: kCMTimeZero)
    try seconTrack?.insertTimeRange(CMTimeRangeMake(kCMTimeZero, secondAssets.duration), of: secondAssets.tracks(withMediaType: .video)[0], at: kCMTimeZero)


    }catch{


    }

    let mainInstraction = AVMutableVideoCompositionInstruction()

    mainInstraction.timeRange  = CMTimeRangeMake(kCMTimeZero, firstAssets.duration)

    let firstLayerInstraction = AVMutableVideoCompositionLayerInstruction(assetTrack: firstTrack!)
    let scale = CGAffineTransform(scaleX: 0.6, y: 0.6)
    let move = CGAffineTransform(translationX: 0, y: 0)
    let transform = scale.concatenating(move)
    firstLayerInstraction.setTransform(transform, at: kCMTimeZero)


    let secondLayerInstraction = AVMutableVideoCompositionLayerInstruction(assetTrack: seconTrack!)
    let secondScale = CGAffineTransform(scaleX: 0.9, y: 0.9)
    let secondMove = CGAffineTransform(translationX: 0, y: 0)
    let secondTransform = secondScale.concatenating(secondMove)
    secondLayerInstraction.setTransform(secondTransform, at: kCMTimeZero)

 let  mainCompositonInst = AVMutableVideoComposition()
    mainCompositonInst.instructions = [mainInstraction]
    mainCompositonInst.frameDuration = CMTimeMake(1, 30)
    mainCompositonInst.renderSize = CGSize(width:(firstTrack?.naturalSize.width)!, height:(firstTrack?.naturalSize.height)! )


  let saveUrl = URL(fileURLWithPath: NSHomeDirectory() + "/Documents/1.mp4")






   guard let assetExport = AVAssetExportSession(asset: mixComposition, presetName:AVAssetExportPresetHighestQuality) else {return}
    assetExport.videoComposition = mainCompositonInst
    assetExport.outputFileType = .mp4
    assetExport.outputURL = saveUrl
    assetExport.exportAsynchronously(completionHandler: {
        switch assetExport.status{
        case  AVAssetExportSessionStatus.failed:
            print("failed \(assetExport.error)")
        case AVAssetExportSessionStatus.cancelled:
            print("cancelled \(assetExport.error)")
        case AVAssetExportSessionStatus.completed:
            print("Completed")
        default:
            print("unknown")
        }
    })

}

Solution

  • I have the solution to my problem . I just need to add layerInstractions to AVMutableVideoCompositionInstruction properties and the code will work fine . this line of code will fix the problem :

        mainInstraction.layerInstructions = [firstLayerInstraction , secondLayerInstraction]