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")
}
})
}
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]