-
-
Save krin-san/f00553bcb0c27298c4d3b33c73cd1a90 to your computer and use it in GitHub Desktop.
Crop video to square with a specified side respecting the original video orientation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@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