iosswiftswift2avfoundationavasset

How to fix my orientation issue with merging videos from front and back camera


I am merging multiply videos (implantation of pause button) and everything working fine except when merging video from the back camera with video from front camera then one of the videos comes turned upside down in the new video(merged video). My code:

let mixComposition = AVMutableComposition() 

let videoTrack = mixComposition.addMutableTrackWithMediaType(AVMediaTypeVideo, preferredTrackID: CMPersistentTrackID())
let trackAudio = mixComposition.addMutableTrackWithMediaType(AVMediaTypeAudio, preferredTrackID: CMPersistentTrackID())

var insertTime = kCMTimeZero
for var i = 0; i < currentAssets.count; i++ {
    let tracks = currentAssets[i].tracksWithMediaType(AVMediaTypeVideo)
    let audios = currentAssets[i].tracksWithMediaType(AVMediaTypeAudio)
                    
    let assetTrack:AVAssetTrack = tracks[0] as AVAssetTrack
    try videoTrack.insertTimeRange(CMTimeRangeMake(kCMTimeZero, currentAssets[i].duration), ofTrack: assetTrack, atTime: insertTime)
    let assetTrackAudio:AVAssetTrack = audios[0] as AVAssetTrack
    try trackAudio.insertTimeRange(CMTimeRangeMake(kCMTimeZero, currentAssets[i].duration), ofTrack: assetTrackAudio, atTime: insertTime)
    insertTime = CMTimeAdd(insertTime, currentAssets[i].duration)
}
videoTrack.preferredTransform = assetTrack.preferredTransform

let documentsURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory,inDomains: .UserDomainMask).last!
let mediaURL = documentsURL.URLByAppendingPathComponent(AppMediaFolder)
let savePath = mediaURL.URLByAppendingPathComponent("\(NSUUID().UUIDString).mp4").path!
        
self.createDirectoryIfExists(mediaURL)
let url = NSURL(fileURLWithPath: savePath)
        
currentAssets.removeAll()
currentAssets.append(AVAsset(URL: url))
        
//Create Exporter
let exporter = AVAssetExportSession(asset: mixComposition, presetName: AVAssetExportPresetHighestQuality)!
exporter.outputURL = url
exporter.outputFileType = AVFileTypeMPEG4
exporter.shouldOptimizeForNetworkUse = true
                

Solution

  • You need to be careful with the renderSize of your AVMutableVideoComposition and the transform of the AVMutableVideoCompositionLayerInstruction.

    To properly align them, you need to both translate and rotate the video with the correct degrees. To flip it upside down you need to rotate it by 180 degrees and translate it to the proper coordinates:

    ...
    videoComposition.renderSize = CGSizeMake(X, Y)
    ...
    let translate = CGAffineTransformMakeTranslation(X, Y);
    let rotate = CGAffineTransformRotate(translate, CGFloat(ANGLE_IN_RADIANS))
    ...    
    

    In my case, the renderSize and the translation are set to 1280 and 720 and the 180 degree rotation is basically M_PI in radians:

    let videoComposition = AVMutableVideoComposition()
    videoComposition.renderSize = CGSizeMake(1280, 720)
    videoComposition.frameDuration = CMTimeMake(1, 30)
    
    let videoInstruction = AVMutableVideoCompositionInstruction()
    instruction.timeRange = CMTimeRangeMake(kCMTimeZero, CMTimeMakeWithSeconds(180, 30))
    
    let transformInstruction:AVMutableVideoCompositionLayerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: clipVideoTrack)
    let translate = CGAffineTransformMakeTranslation(1280, 720);
    let rotate = CGAffineTransformRotate(translate, CGFloat(M_PI))
    
    transformInstruction.setTransform(rotate, atTime: kCMTimeZero)
    videoInstruction.layerInstructions = [transformInstruction]
    videoComposition.instructions = [videoInstruction]
    

    In the end, you will still need to add this videoComposition to your AVAssetExportSession for the transformations to take effect.