Record square video in iOS

I've been looking for some sample code on recording square video's (like Instagram) but didn't find a complete working solution. So after some digging around on Apple's Developer Portal and StackOverflow, I took the cow by the horns and made one myself.

The basic solution comes from StackOverflow, but the key part was missing and caused my movies to screw up. The important part which needed to be added was the rotation to portrait and the transform (as otherwise the rotation would move the video out of bounds).

Below's the complete code, starting from an existing movie on disk (filePath) up till writing out the square movie to disk (outputPath).

[objc] // output file NSString* docFolder = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; NSString* outputPath = [docFolder stringByAppendingPathComponent:@"output2.mov"]; if ([[NSFileManager defaultManager] fileExistsAtPath:outputPath]) [[NSFileManager defaultManager] removeItemAtPath:outputPath error:nil]; // input file AVAsset* asset = [AVAsset assetWithURL:[NSURL fileURLWithPath:filePath]]; AVMutableComposition *composition = [AVMutableComposition composition]; [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid]; // input clip AVAssetTrack *clipVideoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]; // make it square AVMutableVideoComposition* videoComposition = [AVMutableVideoComposition videoComposition]; videoComposition.renderSize = CGSizeMake(clipVideoTrack.naturalSize.height, clipVideoTrack.naturalSize.height); videoComposition.frameDuration = CMTimeMake(1, 30); AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction]; instruction.timeRange = CMTimeRangeMake(kCMTimeZero, CMTimeMakeWithSeconds(60, 30) ); // rotate to portrait AVMutableVideoCompositionLayerInstruction* transformer = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:clipVideoTrack]; CGAffineTransform t1 = CGAffineTransformMakeTranslation(clipVideoTrack.naturalSize.height, -(clipVideoTrack.naturalSize.width - clipVideoTrack.naturalSize.height) /2 ); CGAffineTransform t2 = CGAffineTransformRotate(t1, M_PI_2); CGAffineTransform finalTransform = t2; [transformer setTransform:finalTransform atTime:kCMTimeZero]; instruction.layerInstructions = [NSArray arrayWithObject:transformer]; videoComposition.instructions = [NSArray arrayWithObject: instruction]; // export exporter = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetHighestQuality] ; exporter.videoComposition = videoComposition; exporter.outputURL=[NSURL fileURLWithPath:outputPath]; exporter.outputFileType=AVFileTypeQuickTimeMovie; [exporter exportAsynchronouslyWithCompletionHandler:^(void){ NSLog(@"Exporting done!"); }]; [/objc]