AVFoundation AVPlayer旋转

我想旋转avplayer,但是当我旋转它,它是从一开始就旋转,我想旋转,而我在任何时候玩它,它应该从那里旋转。我使用苹果文件,这个代码是从那里这是我的代码

-(void)performWithAsset:(AVAsset*)asset { AVMutableVideoCompositionInstruction *instruction = nil; AVMutableVideoCompositionLayerInstruction *layerInstruction = nil; CGAffineTransform t1; CGAffineTransform t2; AVAssetTrack *assetVideoTrack = nil; AVAssetTrack *assetAudioTrack = nil; // Check if the asset contains video and audio tracks if ([[asset tracksWithMediaType:AVMediaTypeVideo] count] != 0) { assetVideoTrack = [asset tracksWithMediaType:AVMediaTypeVideo][0]; } if ([[asset tracksWithMediaType:AVMediaTypeAudio] count] != 0) { assetAudioTrack = [asset tracksWithMediaType:AVMediaTypeAudio][0]; } CMTime insertionPoint = kCMTimeInvalid; NSError *error = nil; // Step 1 // Create a composition with the given asset and insert audio and video tracks into it from the asset if (!self.mutableComposition) { // Check whether a composition has already been created, ie, some other tool has already been applied // Create a new composition self.mutableComposition = [AVMutableComposition composition]; // Insert the video and audio tracks from AVAsset if (assetVideoTrack != nil) { AVMutableCompositionTrack *compositionVideoTrack = [self.mutableComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid]; [compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, [asset duration]) ofTrack:assetVideoTrack atTime:insertionPoint error:&error]; } if (assetAudioTrack != nil) { AVMutableCompositionTrack *compositionAudioTrack = [self.mutableComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid]; [compositionAudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, [asset duration]) ofTrack:assetAudioTrack atTime:insertionPoint error:&error]; } } // Step 2 // Translate the composition to compensate the movement caused by rotation (since rotation would cause it to move out of frame) t1 = CGAffineTransformMakeTranslation(assetVideoTrack.naturalSize.height, 0.0); // Rotate transformation t2 = CGAffineTransformRotate(t1, degreesToRadians(90.0)); // Step 3 // Set the appropriate render sizes and rotational transforms if (!self.mutableVideoComposition) { // Create a new video composition self.mutableVideoComposition = [AVMutableVideoComposition videoComposition]; self.mutableVideoComposition.renderSize = CGSizeMake(assetVideoTrack.naturalSize.height,assetVideoTrack.naturalSize.width); self.mutableVideoComposition.frameDuration = CMTimeMake(1, 30); // The rotate transform is set on a layer instruction instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction]; instruction.timeRange = CMTimeRangeMake(kCMTimeZero, [self.mutableComposition duration]); layerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:(self.mutableComposition.tracks)[0]]; [layerInstruction setTransform:t2 atTime:kCMTimeZero]; } else { self.mutableVideoComposition.renderSize = CGSizeMake(self.mutableVideoComposition.renderSize.height, self.mutableVideoComposition.renderSize.width); // Extract the existing layer instruction on the mutableVideoComposition instruction = (self.mutableVideoComposition.instructions)[0]; layerInstruction = (instruction.layerInstructions)[0]; // Check if a transform already exists on this layer instruction, this is done to add the current transform on top of previous edits CGAffineTransform existingTransform; if (![layerInstruction getTransformRampForTime:[self.mutableComposition duration] startTransform:&existingTransform endTransform:NULL timeRange:NULL]) { [layerInstruction setTransform:t2 atTime:kCMTimeZero]; } else { // Note: the point of origin for rotation is the upper left corner of the composition, t3 is to compensate for origin CGAffineTransform t3 = CGAffineTransformMakeTranslation(-1*assetVideoTrack.naturalSize.height/2, 0.0); CGAffineTransform newTransform = CGAffineTransformConcat(existingTransform, CGAffineTransformConcat(t2, t3)); [layerInstruction setTransform:newTransform atTime:kCMTimeZero]; } } // Step 4 enter code here // Add the transform instructions to the video composition instruction.layerInstructions = @[layerInstruction]; self.mutableVideoComposition.instructions = @[instruction]; // Step 5 // Notify AVSEViewController about rotation operation completion [[NSNotificationCenter defaultCenter] postNotificationName:AVSEEditCommandCompletionNotification object:self]; } 

这种方法将逐帧旋转你的video:

 #define degreesToRadians(x) (M_PI * x / 180.0) #define radiansToDegrees(x) (180.0 * x / M_PI) //NSURL *url = [[NSBundle mainBundle] URLForResource:nameOfVideo withExtension:@"MOV"]; -(AVPlayer*)rotateVideoPlayer:(AVPlayer*)player withDegrees:(float)degrees{ NSURL* url = [(AVURLAsset *)player.currentItem.asset URL]; AVMutableComposition *composition; AVMutableVideoComposition *videoComposition; AVMutableVideoCompositionInstruction * instruction; AVURLAsset* asset = [[AVURLAsset alloc] initWithURL:url options:nil]; AVMutableVideoCompositionLayerInstruction *layerInstruction = nil; CGAffineTransform t1; CGAffineTransform t2; AVAssetTrack *assetVideoTrack = nil; AVAssetTrack *assetAudioTrack = nil; // Check if the asset contains video and audio tracks if ([[asset tracksWithMediaType:AVMediaTypeVideo] count] != 0) { assetVideoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]; } if ([[asset tracksWithMediaType:AVMediaTypeAudio] count] != 0) { assetAudioTrack = [[asset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0]; } CMTime insertionPoint = kCMTimeInvalid; NSError *error = nil; // Step 1 // Create a new composition composition = [AVMutableComposition composition]; // Insert the video and audio tracks from AVAsset if (assetVideoTrack != nil) { AVMutableCompositionTrack *compositionVideoTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid]; [compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, [asset duration]) ofTrack:assetVideoTrack atTime:insertionPoint error:&error]; } if (assetAudioTrack != nil) { AVMutableCompositionTrack *compositionAudioTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid]; [compositionAudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, [asset duration]) ofTrack:assetAudioTrack atTime:insertionPoint error:&error]; } // Step 2 // Calculate position and size of render video after rotating float width=assetVideoTrack.naturalSize.width; float height=assetVideoTrack.naturalSize.height; float toDiagonal=sqrt(width*width+height*height); float toDiagonalAngle=radiansToDegrees(acosf(width/toDiagonal)); float toDiagonalAngle2=90-radiansToDegrees(acosf(width/toDiagonal)); float toDiagonalAngleComple; float toDiagonalAngleComple2; float finalHeight; float finalWidth; if(degrees>=0&&degrees<=90){ toDiagonalAngleComple=toDiagonalAngle+degrees; toDiagonalAngleComple2=toDiagonalAngle2+degrees; finalHeight=ABS(toDiagonal*sinf(degreesToRadians(toDiagonalAngleComple))); finalWidth=ABS(toDiagonal*sinf(degreesToRadians(toDiagonalAngleComple2))); t1 = CGAffineTransformMakeTranslation(height*sinf(degreesToRadians(degrees)), 0.0); } else if(degrees>90&&degrees<=180){ float degrees2 = degrees-90; toDiagonalAngleComple=toDiagonalAngle+degrees2; toDiagonalAngleComple2=toDiagonalAngle2+degrees2; finalHeight=ABS(toDiagonal*sinf(degreesToRadians(toDiagonalAngleComple2))); finalWidth=ABS(toDiagonal*sinf(degreesToRadians(toDiagonalAngleComple))); t1 = CGAffineTransformMakeTranslation(width*sinf(degreesToRadians(degrees2))+height*cosf(degreesToRadians(degrees2)), height*sinf(degreesToRadians(degrees2))); } else if(degrees>=-90&&degrees<0){ float degrees2 = degrees-90; float degreesabs = ABS(degrees); toDiagonalAngleComple=toDiagonalAngle+degrees2; toDiagonalAngleComple2=toDiagonalAngle2+degrees2; finalHeight=ABS(toDiagonal*sinf(degreesToRadians(toDiagonalAngleComple2))); finalWidth=ABS(toDiagonal*sinf(degreesToRadians(toDiagonalAngleComple))); t1 = CGAffineTransformMakeTranslation(0, width*sinf(degreesToRadians(degreesabs))); } else if(degrees>=-180&&degrees<-90){ float degreesabs = ABS(degrees); float degreesplus = degreesabs-90; toDiagonalAngleComple=toDiagonalAngle+degrees; toDiagonalAngleComple2=toDiagonalAngle2+degrees; finalHeight=ABS(toDiagonal*sinf(degreesToRadians(toDiagonalAngleComple))); finalWidth=ABS(toDiagonal*sinf(degreesToRadians(toDiagonalAngleComple2))); t1 = CGAffineTransformMakeTranslation(width*sinf(degreesToRadians(degreesplus)), height*sinf(degreesToRadians(degreesplus))+width*cosf(degreesToRadians(degreesplus))); } // Rotate transformation t2 = CGAffineTransformRotate(t1, degreesToRadians(degrees)); // Step 3 // Set the appropriate render sizes and rotational transforms // Create a new video composition videoComposition = [AVMutableVideoComposition videoComposition]; videoComposition.renderSize = CGSizeMake(finalWidth,finalHeight); videoComposition.frameDuration = CMTimeMake(1, 30); // The rotate transform is set on a layer instruction instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction]; instruction.timeRange = CMTimeRangeMake(kCMTimeZero, [composition duration]); layerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:[composition.tracks objectAtIndex:0]]; [layerInstruction setTransform:t2 atTime:kCMTimeZero]; // Step 4 // Add the transform instructions to the video composition instruction.layerInstructions = [NSArray arrayWithObject:layerInstruction]; videoComposition.instructions = [NSArray arrayWithObject:instruction]; AVPlayerItem *playerItem_ = [[AVPlayerItem alloc] initWithAsset:composition]; playerItem_.videoComposition = videoComposition; CMTime time; time=kCMTimeZero; [player replaceCurrentItemWithPlayerItem:playerItem_]; [player seekToTime:time toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero]; //Export rotated video to the file AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:composition presetName:AVAssetExportPresetMediumQuality] ; exportSession.outputURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@_rotated",url]]; exportSession.outputFileType = AVFileTypeQuickTimeMovie; exportSession.videoComposition = videoComposition; exportSession.shouldOptimizeForNetworkUse = YES; exportSession.timeRange = CMTimeRangeMake(kCMTimeZero, asset.duration); [exportSession exportAsynchronouslyWithCompletionHandler:^{ NSLog(@"Video exported"); }]; return player; } 

如何使用它:

例如

 //Creating AVPlayer and adding it to the view NSURL *path = [[NSBundle mainBundle] URLForResource:@"1" withExtension:@"MOV"]; AVURLAsset* asset = [[AVURLAsset alloc] initWithURL:path options:nil]; AVPlayerItem * item = [[AVPlayerItem alloc] initWithAsset:asset]; AVPlayer *player = [[AVPlayer alloc] initWithPlayerItem:item]; AVPlayerLayer * avPlayerLayer=[AVPlayerLayer playerLayerWithPlayer:player]; avPlayerLayer.frame = CGRectMake(20, 20, 250, 250); [self.view.layer addSublayer:avPlayerLayer]; [player play]; //Rotate video of AVPlayer and export it player = [self rotateVideoPlayer:player withDegrees:-45.0]; 

注意:如果您只想在视图上旋转video,请使用包含avplayer的视图的变换方法。

 view.transform=CGAffineTransformMakeRotation(M_PI/2); 

非常感谢Oleh Kudinov,你太棒了!

以下是如果有人需要它的迅速版本。

  func rotateVideoPlayer(player: AVPlayer, degrees: CGFloat) -> AVPlayer? { let urlAsset = player.currentItem?.asset as! AVURLAsset let url = urlAsset.URL var composition: AVMutableComposition? var videoComposition: AVMutableVideoComposition? var instruction: AVMutableVideoCompositionInstruction? let asset = AVURLAsset(URL: url) var layerInstruction: AVMutableVideoCompositionLayerInstruction? var t1: CGAffineTransform? var t2: CGAffineTransform? var assetVideoTrack: AVAssetTrack? var assetAudioTrack: AVAssetTrack? // Check if the asset contains video and audio tracks if asset.tracksWithMediaType(AVMediaTypeVideo).count != 0 { assetVideoTrack = asset.tracksWithMediaType(AVMediaTypeVideo)[0] } if asset.tracksWithMediaType(AVMediaTypeAudio).count != 0 { assetAudioTrack = asset.tracksWithMediaType(AVMediaTypeAudio)[0] } let insertionPoint = kCMTimeInvalid // Step 1 // Create a new composition composition = AVMutableComposition() // Insert a new composition if assetVideoTrack != nil { let compositionVideoTrack: AVMutableCompositionTrack = (composition?.addMutableTrackWithMediaType(AVMediaTypeVideo, preferredTrackID: kCMPersistentTrackID_Invalid))! let timeRange = CMTimeRangeMake(kCMTimeZero, asset.duration) try! compositionVideoTrack.insertTimeRange(timeRange, ofTrack: assetVideoTrack!, atTime: insertionPoint) } if assetAudioTrack != nil { let compositionAudioTrack: AVMutableCompositionTrack = (composition?.addMutableTrackWithMediaType(AVMediaTypeAudio, preferredTrackID: kCMPersistentTrackID_Invalid))! let timeRange = CMTimeRangeMake(kCMTimeZero, asset.duration) try! compositionAudioTrack.insertTimeRange(timeRange, ofTrack: assetAudioTrack!, atTime: insertionPoint) } // Step 2 // Calculate position and size of render video after rotating let width = Float((assetVideoTrack?.naturalSize.width)!) let height = Float((assetVideoTrack?.naturalSize.height)!) let toDiagonal = Float(sqrt(width * width + height * height)) let toDiagonalAngle = Float(radiansToDegrees(acosf(width/toDiagonal))) let toDiagonalAngle2 = Float(90 - radiansToDegrees(acosf(width/toDiagonal))) var toDiagonalAngleComple: Float var toDiagonalAngleComple2: Float var finalHeight: Float = 0 var finalWidth: Float = 0 if degrees >= 0 && degrees <= 90 { toDiagonalAngleComple = toDiagonalAngle + Float(degrees) toDiagonalAngleComple2 = toDiagonalAngle2 + Float(degrees) let sinfValue = sinf(degreesToRadians(toDiagonalAngleComple)) let sinfValue2 = sinf(degreesToRadians(toDiagonalAngleComple2)) finalHeight = abs(toDiagonal * sinfValue) finalWidth = abs(toDiagonal * sinfValue2) let side1 = height * sinf(degreesToRadians(Float(degrees))) let side2 = 0.0 t1 = CGAffineTransformMakeTranslation(CGFloat(side1), CGFloat(side2)) } else if degrees > 90 && degrees <= 180 { let degrees2 = Float(degrees - 90) toDiagonalAngleComple = toDiagonalAngle + degrees2 toDiagonalAngleComple2 = toDiagonalAngle2 + degrees2 let sinfValue = sinf(degreesToRadians(toDiagonalAngleComple2)) let sinfValue2 = sinf(degreesToRadians(toDiagonalAngleComple)) finalHeight = abs(toDiagonal * sinfValue) finalWidth = abs(toDiagonal * sinfValue2) let side1 = width * sinf(degreesToRadians(degrees2)) + height * cosf(degreesToRadians(degrees2)) let side2 = height * sinf(degreesToRadians(degrees2)) t1 = CGAffineTransformMakeTranslation(CGFloat(side1), CGFloat(side2)) } else if degrees >= -90 && degrees < 0 { let degrees2 = Float(degrees - 90) let degrees2abs = Float(abs(degrees)) toDiagonalAngleComple = toDiagonalAngle + degrees2 toDiagonalAngleComple2 = toDiagonalAngle2 + degrees2 let sinfValue = sinf(degreesToRadians(toDiagonalAngleComple2)) let sinfValue2 = sinf(degreesToRadians(toDiagonalAngleComple)) finalHeight = abs(toDiagonal * sinfValue) finalWidth = abs(toDiagonal * sinfValue2) let side1 = 0 let side2 = width * sinf(degreesToRadians(degreesabs)) t1 = CGAffineTransformMakeTranslation(CGFloat(side1), CGFloat(side2)) } else if degrees >= -180 && degrees < -90 { let degreesabs = Float(abs(degrees)) let degreesPlus = degreesabs - 90 toDiagonalAngleComple = toDiagonalAngle + Float(degrees) toDiagonalAngleComple2 = toDiagonalAngle2 + Float(degrees) let sinfValue = sinf(degreesToRadians(toDiagonalAngleComple)) let sinfValue2 = sinf(degreesToRadians(toDiagonalAngleComple2)) finalHeight = abs(toDiagonal * sinfValue) finalWidth = abs(toDiagonal * sinfValue2) let side1 = width * sinf(degreesToRadians(degreesPlus)) let side2 = height * sinf(degreesToRadians(degreesPlus)) + width * cosf(degreesToRadians(degreesPlus)) t1 = CGAffineTransformMakeTranslation(CGFloat(side1), CGFloat(side2)) } // Rotate transformation t2 = CGAffineTransformRotate(t1!, CGFloat(degreesToRadians(Float(degrees)))) // // Step 3 // // Set the appropriate render sizes and rotational transforms // // Create a new video composition // videoComposition = AVMutableComposition videoComposition = AVMutableVideoComposition() videoComposition?.renderSize = CGSizeMake(CGFloat(finalWidth), CGFloat(finalHeight)) videoComposition?.frameDuration = CMTimeMake(1, 30) // The rotate transform is set on a layer instruction instruction = AVMutableVideoCompositionInstruction() instruction?.timeRange = CMTimeRangeMake(kCMTimeZero, composition!.duration) // // + videoCompositionLayerInstructionWithAssetTrack: // Returns a new mutable video composition layer instruction for the given track. // // Swift // convenience init(assetTrack track: AVAssetTrack) // // Objective-C // + (instancetype)videoCompositionLayerInstructionWithAssetTrack:(AVAssetTrack *)track // objectiv-c: // layerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:[composition.tracks objectAtIndex:0]]; // Swift layerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: (composition?.tracks[0])!) layerInstruction?.setTransform(t2!, atTime: kCMTimeZero) // // Step 4 // // Add the transfor instructions to the video composition instruction?.layerInstructions = NSArray(object: layerInstruction!) as! [AVVideoCompositionLayerInstruction] videoComposition?.instructions = NSArray(object: instruction!) as! [AVVideoCompositionInstructionProtocol] let playItem_ = AVPlayerItem(asset: composition!) playItem_.videoComposition = videoComposition var time: CMTime! time = kCMTimeZero player.replaceCurrentItemWithPlayerItem(playItem_) player.seekToTime(time, toleranceBefore: kCMTimeZero, toleranceAfter: kCMTimeZero) // Export rotated video to the file let exportSession = AVAssetExportSession(asset: composition!, presetName: AVAssetExportPresetMediumQuality) exportSession?.outputURL = NSURL(string: String(format: "%@_rotated", url)) exportSession?.outputFileType = AVFileTypeQuickTimeMovie exportSession?.videoComposition = videoComposition exportSession?.shouldOptimizeForNetworkUse = true exportSession?.timeRange = CMTimeRangeMake(kCMTimeZero, asset.duration) exportSession?.exportAsynchronouslyWithCompletionHandler({ () -> Void in print("Video exported") }) return player } 

Swift 3 / Swift 4版本

 func rotateVideoPlayer(player: AVPlayer, degrees: CGFloat) -> AVPlayer? { let urlAsset = player.currentItem?.asset as! AVURLAsset let url = urlAsset.url var composition: AVMutableComposition? var videoComposition: AVMutableVideoComposition? var instruction: AVMutableVideoCompositionInstruction? let asset = AVURLAsset(url: url) var layerInstruction: AVMutableVideoCompositionLayerInstruction? var t1: CGAffineTransform? var t2: CGAffineTransform? var assetVideoTrack: AVAssetTrack? var assetAudioTrack: AVAssetTrack? if asset.tracks(withMediaType: AVMediaTypeVideo).count != 0 { assetVideoTrack = asset.tracks(withMediaType: AVMediaTypeVideo)[0] } if asset.tracks(withMediaType: AVMediaTypeAudio).count != 0 { assetAudioTrack = asset.tracks(withMediaType: AVMediaTypeAudio)[0] } let insertionPoint = kCMTimeInvalid composition = AVMutableComposition() if assetVideoTrack != nil { let compositionVideoTrack: AVMutableCompositionTrack = (composition?.addMutableTrack(withMediaType: AVMediaTypeVideo, preferredTrackID: kCMPersistentTrackID_Invalid))! let timeRange = CMTimeRangeMake(kCMTimeZero, asset.duration) try! compositionVideoTrack.insertTimeRange(timeRange, of: assetVideoTrack!, at: insertionPoint) } if assetAudioTrack != nil { let compositionAudioTrack: AVMutableCompositionTrack = (composition?.addMutableTrack(withMediaType: AVMediaTypeAudio, preferredTrackID: kCMPersistentTrackID_Invalid))! let timeRange = CMTimeRangeMake(kCMTimeZero, asset.duration) try! compositionAudioTrack.insertTimeRange(timeRange, of: assetAudioTrack!, at: insertionPoint) } let width = Float((assetVideoTrack?.naturalSize.width)!) let height = Float((assetVideoTrack?.naturalSize.height)!) let toDiagonal = Float(sqrt(width * width + height * height)) let toDiagonalAngle = Float(radiansToDegrees(acosf(width/toDiagonal))) let toDiagonalAngle2 = Float(90 - radiansToDegrees(acosf(width/toDiagonal))) var toDiagonalAngleComple: Float var toDiagonalAngleComple2: Float var finalHeight: Float = 0 var finalWidth: Float = 0 if degrees >= 0 && degrees <= 90 { toDiagonalAngleComple = toDiagonalAngle + Float(degrees) toDiagonalAngleComple2 = toDiagonalAngle2 + Float(degrees) let sinfValue = sinf(degreesToRadians(toDiagonalAngleComple)) let sinfValue2 = sinf(degreesToRadians(toDiagonalAngleComple2)) finalHeight = abs(toDiagonal * sinfValue) finalWidth = abs(toDiagonal * sinfValue2) let side1 = height * sinf(degreesToRadians(Float(degrees))) let side2 = 0.0 t1 = CGAffineTransform(translationX: CGFloat(side1), y: CGFloat(side2)) } else if degrees > 90 && degrees <= 180 { let degrees2 = Float(degrees - 90) toDiagonalAngleComple = toDiagonalAngle + degrees2 toDiagonalAngleComple2 = toDiagonalAngle2 + degrees2 let sinfValue = sinf(degreesToRadians(toDiagonalAngleComple2)) let sinfValue2 = sinf(degreesToRadians(toDiagonalAngleComple)) finalHeight = abs(toDiagonal * sinfValue) finalWidth = abs(toDiagonal * sinfValue2) let side1 = width * sinf(degreesToRadians(degrees2)) + height * cosf(degreesToRadians(degrees2)) let side2 = height * sinf(degreesToRadians(degrees2)) t1 = CGAffineTransform(translationX: CGFloat(side1), y: CGFloat(side2)) } else if degrees >= -90 && degrees < 0 { let degrees2 = Float(degrees - 90) let degrees2abs = Float(abs(degrees)) toDiagonalAngleComple = toDiagonalAngle + degrees2 toDiagonalAngleComple2 = toDiagonalAngle2 + degrees2 let sinfValue = sinf(degreesToRadians(toDiagonalAngleComple2)) let sinfValue2 = sinf(degreesToRadians(toDiagonalAngleComple)) finalHeight = abs(toDiagonal * sinfValue) finalWidth = abs(toDiagonal * sinfValue2) let side1 = 0 let side2 = width * sinf(degreesToRadians(degrees2abs)) t1 = CGAffineTransform(translationX: CGFloat(side1), y: CGFloat(side2)) } else if degrees >= -180 && degrees < -90 { let degreesabs = Float(abs(degrees)) let degreesPlus = degreesabs - 90 toDiagonalAngleComple = toDiagonalAngle + Float(degrees) toDiagonalAngleComple2 = toDiagonalAngle2 + Float(degrees) let sinfValue = sinf(degreesToRadians(toDiagonalAngleComple)) let sinfValue2 = sinf(degreesToRadians(toDiagonalAngleComple2)) finalHeight = abs(toDiagonal * sinfValue) finalWidth = abs(toDiagonal * sinfValue2) let side1 = width * sinf(degreesToRadians(degreesPlus)) let side2 = height * sinf(degreesToRadians(degreesPlus)) + width * cosf(degreesToRadians(degreesPlus)) t1 = CGAffineTransform(translationX: CGFloat(side1), y: CGFloat(side2)) } t2 = t1!.rotated(by: CGFloat(degreesToRadians(Float(degrees)))) videoComposition = AVMutableVideoComposition() videoComposition?.renderSize = CGSize(width: CGFloat(finalWidth), height: CGFloat(finalHeight)) videoComposition?.frameDuration = CMTimeMake(1, 30) instruction = AVMutableVideoCompositionInstruction() instruction?.timeRange = CMTimeRangeMake(kCMTimeZero, composition!.duration) layerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: (composition?.tracks[0])!) layerInstruction?.setTransform(t2!, at: kCMTimeZero) instruction?.layerInstructions = NSArray(object: layerInstruction!) as! [AVVideoCompositionLayerInstruction] videoComposition?.instructions = NSArray(object: instruction!) as! [AVVideoCompositionInstructionProtocol] let playItem_ = AVPlayerItem(asset: composition!) playItem_.videoComposition = videoComposition var time: CMTime! time = kCMTimeZero player.replaceCurrentItem(with: playItem_) player.seek(to: time, toleranceBefore: kCMTimeZero, toleranceAfter: kCMTimeZero) let exportSession = AVAssetExportSession(asset: composition!, presetName: AVAssetExportPresetMediumQuality) exportSession?.outputURL = URL(string: String(format: "%@_rotated", url as CVarArg)) exportSession?.outputFileType = AVFileTypeQuickTimeMovie exportSession?.videoComposition = videoComposition exportSession?.shouldOptimizeForNetworkUse = true exportSession?.timeRange = CMTimeRangeMake(kCMTimeZero, asset.duration) exportSession?.exportAsynchronously(completionHandler: { () -> Void in print("Video exported") }) return player } func degreesToRadians(_ input: Float) -> Float { let float: Float = 180 return Float(input) * .pi / float } func radiansToDegrees(_ input: Float) -> Float { return Float(input) * 180 / .pi }