5

我正在尝试旋转 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];
}
4

3 回答 3

14

此方法将逐帧旋转您的视频:

#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 的视图的 transform 方法。

view.transform=CGAffineTransformMakeRotation(M_PI/2);
于 2013-01-24T12:15:29.723 回答
4

斯威夫特 5 版本

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: AVMediaType.video).count != 0 {
        assetVideoTrack = asset.tracks(withMediaType: AVMediaType.video)[0]
    }

    if asset.tracks(withMediaType: AVMediaType.audio).count != 0 {
        assetAudioTrack = asset.tracks(withMediaType: AVMediaType.audio)[0]
    }

    let insertionPoint = CMTime.invalid

    composition = AVMutableComposition()

    if assetVideoTrack != nil {

        let compositionVideoTrack: AVMutableCompositionTrack = (composition?.addMutableTrack(withMediaType: AVMediaType.video, preferredTrackID: kCMPersistentTrackID_Invalid))!
        let timeRange = CMTimeRangeMake(start: CMTime.zero, duration: asset.duration)

        try! compositionVideoTrack.insertTimeRange(timeRange, of: assetVideoTrack!, at: insertionPoint)

    }

    if assetAudioTrack != nil {

        let compositionAudioTrack: AVMutableCompositionTrack = (composition?.addMutableTrack(withMediaType: AVMediaType.audio, preferredTrackID: kCMPersistentTrackID_Invalid))!
        let timeRange = CMTimeRangeMake(start: CMTime.zero, duration: 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(value: 1, timescale: 30)

    instruction = AVMutableVideoCompositionInstruction()

    instruction?.timeRange = CMTimeRangeMake(start: CMTime.zero, duration: composition!.duration)

    layerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: (composition?.tracks[0])!)


    layerInstruction?.setTransform(t2!, at: CMTime.zero)

    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 = CMTime.zero

    player.replaceCurrentItem(with: playItem_)

    player.seek(to: time, toleranceBefore: CMTime.zero, toleranceAfter: CMTime.zero)

    let exportSession = AVAssetExportSession(asset: composition!, presetName: AVAssetExportPresetMediumQuality)

    exportSession?.outputURL = URL(string: String(format: "%@_rotated", url as CVarArg))
    exportSession?.outputFileType = AVFileType.mov
    exportSession?.videoComposition = videoComposition
    exportSession?.shouldOptimizeForNetworkUse = true
    exportSession?.timeRange = CMTimeRangeMake(start: CMTime.zero, duration: 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
}
于 2017-05-25T14:03:48.207 回答
4

非常感谢你,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

}
于 2015-09-15T04:09:47.170 回答