iPhone SDK. is it possible to rotate videos in AVplayer using AVURLlAsset / AVMutableComposition?

3k views Asked by At

I have a simple video editing view that uses AVPlayer. I create a AVMutableComposition using one or several AVURLAsset. All works fine but the videos are always rotated 90 degrees. i.e. if the source video was taken in portrait mode. AVPlayer shows it in landscape mode and vice versa. I have gone through the documentation and "goolgled" it to death and can't find a solution. MAybe I'm looking in the wrong places.

Can anyone help?

Thanks in Advance;

Jean-Pierre

2

There are 2 answers

0
flainez On

Without having the code to examine, it is difficult to know what is going on... But most probably, your issue is caused because you are losing the value of your preferredTransform property.

All AVAssetTrack objects have a preferredTransform property that is used to specify if videos should be rotated or not. If you are creating new AVMutableAssetTrack objects, you might need to set the value of that property so the video stays in the intended orientation.

0
Abhinav Singh On

to my understanding you have some orientation issues like Portrait video is in landscape mode, and sometimes videos are turned upside down.This is due to the default AVAsset orientation. All movie and image files recorded using the default iPhone camera application have the video frame set to landscape, and so the media is saved in landscape mode. AVAsset has a preferredTransform property that contains the media orientation information, and this is applied to a media file whenever you view it using the Photos app or QuickTime. You can correct this easily by applying the necessary transforms to your AVAsset objects. But as your two video files can have different orientations, you’ll need to use two separate AVMutableCompositionTrack instances instead of one(assume) as you originally did. Create two AVMutableCompositionTrack video tracks Since you now have two separate AVMutableCompositionTrack instances, you need to apply an AVMutableVideoCompositionLayerInstruction to each track in order to fix the orientation. So add the following code

    //  Create AVMutableVideoCompositionInstruction
AVMutableVideoCompositionInstruction *mainInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
mainInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, CMTimeAdd(firstAsset.duration, secondAsset.duration));
// Create an AVMutableVideoCompositionLayerInstruction for the first track
AVMutableVideoCompositionLayerInstruction *firstlayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:firstTrack];
AVAssetTrack *firstAssetTrack = [[firstAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
UIImageOrientation firstAssetOrientation_  = UIImageOrientationUp;
BOOL isFirstAssetPortrait_  = NO;
CGAffineTransform firstTransform = firstAssetTrack.preferredTransform;
if (firstTransform.a == 0 && firstTransform.b == 1.0 && firstTransform.c == -1.0 && firstTransform.d == 0) {
    firstAssetOrientation_ = UIImageOrientationRight; 
    isFirstAssetPortrait_ = YES;
}
if (firstTransform.a == 0 && firstTransform.b == -1.0 && firstTransform.c == 1.0 && firstTransform.d == 0) {
    firstAssetOrientation_ =  UIImageOrientationLeft; 
    isFirstAssetPortrait_ = YES;
}
if (firstTransform.a == 1.0 && firstTransform.b == 0 && firstTransform.c == 0 && firstTransform.d == 1.0) {
    firstAssetOrientation_ =  UIImageOrientationUp;
}
if (firstTransform.a == -1.0 && firstTransform.b == 0 && firstTransform.c == 0 && firstTransform.d == -1.0) {
    firstAssetOrientation_ = UIImageOrientationDown;
}
[firstlayerInstruction setTransform:firstAsset.preferredTransform atTime:kCMTimeZero];
[firstlayerInstruction setOpacity:0.0 atTime:firstAsset.duration];
//  Create an AVMutableVideoCompositionLayerInstruction for the second track
AVMutableVideoCompositionLayerInstruction *secondlayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:secondTrack];
AVAssetTrack *secondAssetTrack = [[secondAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
UIImageOrientation secondAssetOrientation_  = UIImageOrientationUp;
BOOL isSecondAssetPortrait_  = NO;
CGAffineTransform secondTransform = secondAssetTrack.preferredTransform;
if (secondTransform.a == 0 && secondTransform.b == 1.0 && secondTransform.c == -1.0 && secondTransform.d == 0) {
    secondAssetOrientation_= UIImageOrientationRight; 
    isSecondAssetPortrait_ = YES;
}
if (secondTransform.a == 0 && secondTransform.b == -1.0 && secondTransform.c == 1.0 && secondTransform.d == 0) {
    secondAssetOrientation_ =  UIImageOrientationLeft; 
    isSecondAssetPortrait_ = YES;
}
if (secondTransform.a == 1.0 && secondTransform.b == 0 && secondTransform.c == 0 && secondTransform.d == 1.0) {
    secondAssetOrientation_ =  UIImageOrientationUp;
}
if (secondTransform.a == -1.0 && secondTransform.b == 0 && secondTransform.c == 0 && secondTransform.d == -1.0) {
    secondAssetOrientation_ = UIImageOrientationDown;
}
[secondlayerInstruction setTransform:secondAsset.preferredTransform atTime:firstAsset.duration];
}

finally add instructions,It’s just the orientation fix applied to the second track.

    mainInstruction.layerInstructions = [NSArray arrayWithObjects:firstlayerInstruction, secondlayerInstruction,nil];
AVMutableVideoComposition *mainCompositionInst = [AVMutableVideoComposition videoComposition];
mainCompositionInst.instructions = [NSArray arrayWithObject:mainInstruction];
mainCompositionInst.frameDuration = CMTimeMake(1, 30);

CGSize naturalSizeFirst, naturalSizeSecond;
if(isFirstAssetPortrait_){
    naturalSizeFirst = CGSizeMake(FirstAssetTrack.naturalSize.height, FirstAssetTrack.naturalSize.width);
} else {
    naturalSizeFirst = FirstAssetTrack.naturalSize;
}
if(isSecondAssetPortrait_){
    naturalSizeSecond = CGSizeMake(SecondAssetTrack.naturalSize.height, SecondAssetTrack.naturalSize.width);
} else {
    naturalSizeSecond = SecondAssetTrack.naturalSize;
}

float renderWidth, renderHeight;
if(naturalSizeFirst.width > naturalSizeSecond.width) {
    renderWidth = naturalSizeFirst.width;
} else {
    renderWidth = naturalSizeSecond.width;
}
if(naturalSizeFirst.height > naturalSizeSecond.height) {
    renderHeight = naturalSizeFirst.height;
} else {
    renderHeight = naturalSizeSecond.height;
}
MainCompositionInst.renderSize = CGSizeMake(renderWidth, renderHeight);

hope this helps