Skip to content

Instantly share code, notes, and snippets.

@zrxq
Created March 27, 2014 20:08
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 8 You must be signed in to fork a gist
  • Save zrxq/9817265 to your computer and use it in GitHub Desktop.
Save zrxq/9817265 to your computer and use it in GitHub Desktop.
Crop video to square with a specified side respecting the original video orientation
@import MobileCoreServices;
@import AVFoundation;
@import AssetsLibrary;
// ...
- (void)cropVideoAtURL:(NSURL *)videoURL toSquareWithSide:(CGFloat)sideLength completion:(void(^)(NSURL *resultURL, NSError *error))completionHander {
/* asset */
AVAsset *asset = [AVAsset assetWithURL:videoURL];
AVAssetTrack *assetVideoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] lastObject];
/* sizes/scales/offsets */
CGSize originalSize = assetVideoTrack.naturalSize;
CGFloat scale;
if (originalSize.width < originalSize.height) {
scale = sideLength / originalSize.width;
} else {
scale = sideLength / originalSize.height;
}
CGSize scaledSize = CGSizeMake(originalSize.width * scale, originalSize.height * scale);
CGPoint topLeft = CGPointMake(sideLength * .5 - scaledSize.width * .5, sideLength * .5 - scaledSize.height * .5);
/* Layer instruction */
AVMutableVideoCompositionLayerInstruction *layerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:assetVideoTrack];
CGAffineTransform orientationTransform = assetVideoTrack.preferredTransform;
/* fix the orientation transform */
if (orientationTransform.tx == originalSize.width || orientationTransform.tx == originalSize.height) {
orientationTransform.tx = sideLength;
}
if (orientationTransform.ty == originalSize.width || orientationTransform.ty == originalSize.height) {
orientationTransform.ty = sideLength;
}
/* -- */
CGAffineTransform transform = CGAffineTransformConcat(CGAffineTransformConcat(CGAffineTransformMakeScale(scale, scale), CGAffineTransformMakeTranslation(topLeft.x, topLeft.y)), orientationTransform);
[layerInstruction setTransform:transform atTime:kCMTimeZero];
/* Instruction */
AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
instruction.layerInstructions = @[layerInstruction];
instruction.timeRange = assetVideoTrack.timeRange;
/* Video composition */
AVMutableVideoComposition *videoComposition = [AVMutableVideoComposition videoComposition];
videoComposition.renderSize = CGSizeMake(sideLength, sideLength);
videoComposition.renderScale = 1.0;
videoComposition.frameDuration = CMTimeMake(1, 30);
videoComposition.instructions = @[instruction];
/* Export */
AVAssetExportSession *export = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPreset1280x720];
export.videoComposition = videoComposition;
export.outputURL = [NSURL fileURLWithPath:[[NSTemporaryDirectory() stringByAppendingPathComponent:[NSUUID new].UUIDString] stringByAppendingPathExtension:@"MOV"]];
export.outputFileType = AVFileTypeQuickTimeMovie;
export.shouldOptimizeForNetworkUse = YES;
[export exportAsynchronouslyWithCompletionHandler:^{
dispatch_async(dispatch_get_main_queue(), ^{
if (export.status == AVAssetExportSessionStatusCompleted) {
completionHander(export.outputURL, nil);
} else {
completionHander(nil, export.error);
}
});
}];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment