2012-11-06 3 views
4

저는 avplayer를 회전하려고합니다.하지만 회전 할 때 처음부터 회전하고 있습니다. 언제든지 재생하려고하는데 회전하고 싶습니다. 사과 설명서를 사용하고 있습니다. there.Here에서 가져온이 코드 내 code.`AVFoundation 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, i.e, 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]; 
} 
+0

가 그래서 처음부터 시작? – evilgoldfish

+0

예.하지만 회전 모드로 계속 실행하고 싶습니다. – Ram

답변

13

입니다 프레임으로 비디오 프레임을 회전합니다이 방법

#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]; 

참고 : 만 AVPlayer를 들어있는 뷰의 변환 방법을 사용하여보기에 비디오를 회전하려면.

view.transform=CGAffineTransformMakeRotation(M_PI/2); 
+0

매력처럼 작동했습니다. 고마워요! – Anil

+0

이미 회전 한 비디오를 다시 회전하고 싶습니다. 하지만 그렇게하면 첫 번째 메서드 호출은 AVMutableComposition을 만듭니다. 그래서 AVURLAsset으로 변환했습니다. 그러나 나는 그것이 완성 블록 밖에서하고 있다고 생각한다. Cant가 그것을 다시 돌리는 것처럼 보입니다. 같은 메서드를 다시 호출하면 충돌이 발생합니다. – Anil

+0

Hello @Oleh, 라이브 스트리밍을 재생할 때이 기능을 사용할 수 있습니까? –

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? 

    // 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 

} 
1

스위프트 3/스위프트 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 
}