Square cropping and fixing the video orientation in iOS Square cropping and fixing the video orientation in iOS objective-c objective-c

Square cropping and fixing the video orientation in iOS


I suppose the source code come from this link ( project code included )

http://www.one-dreamer.com/cropping-video-square-like-vine-instagram-xcode/

You need first to know the REAL video orientation:

- (UIImageOrientation)getVideoOrientationFromAsset:(AVAsset *)asset{    AVAssetTrack *videoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];    CGSize size = [videoTrack naturalSize];    CGAffineTransform txf = [videoTrack preferredTransform];    if (size.width == txf.tx && size.height == txf.ty)        return UIImageOrientationLeft; //return UIInterfaceOrientationLandscapeLeft;    else if (txf.tx == 0 && txf.ty == 0)        return UIImageOrientationRight; //return UIInterfaceOrientationLandscapeRight;    else if (txf.tx == 0 && txf.ty == size.width)        return UIImageOrientationDown; //return UIInterfaceOrientationPortraitUpsideDown;    else        return UIImageOrientationUp;  //return UIInterfaceOrientationPortrait;}

I made that function in a way that it return the right orientation as if it was an image

Then, i modified the function to fix the right orientation, supporting any crop region not just a square, like this:

// apply the crop to passed video asset (set outputUrl to avoid the saving on disk ). Return the exporter session object- (AVAssetExportSession*)applyCropToVideoWithAsset:(AVAsset*)asset AtRect:(CGRect)cropRect OnTimeRange:(CMTimeRange)cropTimeRange ExportToUrl:(NSURL*)outputUrl ExistingExportSession:(AVAssetExportSession*)exporter WithCompletion:(void(^)(BOOL success, NSError* error, NSURL* videoUrl))completion{    //create an avassetrack with our asset    AVAssetTrack *clipVideoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];    //create a video composition and preset some settings    AVMutableVideoComposition* videoComposition = [AVMutableVideoComposition videoComposition];    videoComposition.frameDuration = CMTimeMake(1, 30);    CGFloat cropOffX = cropRect.origin.x;    CGFloat cropOffY = cropRect.origin.y;    CGFloat cropWidth = cropRect.size.width;    CGFloat cropHeight = cropRect.size.height;    videoComposition.renderSize = CGSizeMake(cropWidth, cropHeight);    //create a video instruction    AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];    instruction.timeRange = cropTimeRange;    AVMutableVideoCompositionLayerInstruction* transformer = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:clipVideoTrack];    UIImageOrientation videoOrientation = [self getVideoOrientationFromAsset:asset];    CGAffineTransform t1 = CGAffineTransformIdentity;    CGAffineTransform t2 = CGAffineTransformIdentity;    switch (videoOrientation) {        case UIImageOrientationUp:            t1 = CGAffineTransformMakeTranslation(clipVideoTrack.naturalSize.height - cropOffX, 0 - cropOffY );            t2 = CGAffineTransformRotate(t1, M_PI_2 );            break;        case UIImageOrientationDown:            t1 = CGAffineTransformMakeTranslation(0 - cropOffX, clipVideoTrack.naturalSize.width - cropOffY ); // not fixed width is the real height in upside down            t2 = CGAffineTransformRotate(t1, - M_PI_2 );            break;        case UIImageOrientationRight:            t1 = CGAffineTransformMakeTranslation(0 - cropOffX, 0 - cropOffY );            t2 = CGAffineTransformRotate(t1, 0 );            break;        case UIImageOrientationLeft:            t1 = CGAffineTransformMakeTranslation(clipVideoTrack.naturalSize.width - cropOffX, clipVideoTrack.naturalSize.height - cropOffY );            t2 = CGAffineTransformRotate(t1, M_PI  );            break;        default:            NSLog(@"no supported orientation has been found in this video");            break;    }    CGAffineTransform finalTransform = t2;    [transformer setTransform:finalTransform atTime:kCMTimeZero];    //add the transformer layer instructions, then add to video composition    instruction.layerInstructions = [NSArray arrayWithObject:transformer];    videoComposition.instructions = [NSArray arrayWithObject: instruction];    //Remove any prevouis videos at that path    [[NSFileManager defaultManager]  removeItemAtURL:outputUrl error:nil];    if (!exporter){        exporter = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetHighestQuality] ;    }    // assign all instruction for the video processing (in this case the transformation for cropping the video    exporter.videoComposition = videoComposition;    //exporter.outputFileType = AVFileTypeQuickTimeMovie;    if (outputUrl){        exporter.outputURL = outputUrl;        [exporter exportAsynchronouslyWithCompletionHandler:^{             switch ([exporter status]) {                 case AVAssetExportSessionStatusFailed:                     NSLog(@"crop Export failed: %@", [[exporter error] localizedDescription]);                     if (completion){                         dispatch_async(dispatch_get_main_queue(), ^{                             completion(NO,[exporter error],nil);                         });                         return;                     }                     break;                 case AVAssetExportSessionStatusCancelled:                     NSLog(@"crop Export canceled");                     if (completion){                         dispatch_async(dispatch_get_main_queue(), ^{                             completion(NO,nil,nil);                         });                         return;                     }                     break;                 default:                     break;            }            if (completion){                dispatch_async(dispatch_get_main_queue(), ^{                    completion(YES,nil,outputUrl);                });            }        }];    }    return exporter;}

Tested in all recorded video orientation (Up,Down,Lanscape R, Landscape L) in both normal and front camera cases. I tested it on iPhone 5S (iOS 8.1), iPhone 6 Plus (iOS 8.1)

Hope it helps


This is my code to create a vine-like video from a video on disk. This is written in swift:

static let MaxDuration: CMTimeValue = 12class func compressVideoAsset(_ asset: AVAsset, output: URL, completion: @escaping (_ data: Data?) -> Void){    let session = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetMediumQuality)!    session.videoComposition = self.squareVideoCompositionForAsset(asset)    session.outputURL = output    session.outputFileType = AVFileTypeMPEG4    session.shouldOptimizeForNetworkUse = true    session.canPerformMultiplePassesOverSourceMediaData = true    let duration = CMTimeValue(CGFloat(asset.duration.value) / CGFloat(asset.duration.timescale) * 30)    session.timeRange = CMTimeRange(start: kCMTimeZero, duration: CMTime(value: min(duration, VideoCompressor.MaxDuration * 30), timescale: 30))    session.exportAsynchronously(completionHandler: { () -> Void in        let data = try? Data(contentsOf: output)        DispatchQueue.main.async(execute: { () -> Void in            completion(data)        })    })}private class func squareVideoCompositionForAsset(_ asset: AVAsset) -> AVVideoComposition{    let track = asset.tracks(withMediaType: AVMediaTypeVideo)[0]    let length = min(track.naturalSize.width, track.naturalSize.height)    var transform = track.preferredTransform    let size = track.naturalSize    let scale: CGFloat = (transform.a == -1 && transform.b == 0 && transform.c == 0 && transform.d == -1) ? -1 : 1 // check for inversion    transform = transform.translatedBy(x: scale * -(size.width - length) / 2, y: scale * -(size.height - length) / 2)    let transformer = AVMutableVideoCompositionLayerInstruction(assetTrack: track)    transformer.setTransform(transform, at: kCMTimeZero)    let instruction = AVMutableVideoCompositionInstruction()    instruction.timeRange = CMTimeRange(start: kCMTimeZero, duration: kCMTimePositiveInfinity)    instruction.layerInstructions = [transformer]    let composition = AVMutableVideoComposition()    composition.frameDuration = CMTime(value: 1, timescale: 30)    composition.renderSize = CGSize(width: length, height: length)    composition.instructions = [instruction]    return composition}


I know this question is old but some people may still be wondering why some of the videos from the camera roll zoom in after they're cropped. I faced this problem and realized that the cropRect I was using as a frame was not scaled for the different aspect ratios of the video. To fix this problem I simply added the code below to crop the very top of the video into a square. If you want to change the position just change the y value but make sure to scale it according to the video. Luca Iaco provided some great code to get started with. I appreciate it!

CGSize videoSize = [[[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] naturalSize];float scaleFactor;if (videoSize.width > videoSize.height) {    scaleFactor = videoSize.height/320;}else if (videoSize.width == videoSize.height){    scaleFactor = videoSize.height/320;}else{    scaleFactor = videoSize.width/320;}CGFloat cropOffX = 0;CGFloat cropOffY = 0;CGFloat cropWidth = 320 *scaleFactor;CGFloat cropHeight = 320 *scaleFactor;