使用AVAsset / AVCaptureSession,方形视频方向不会从横向更改为纵向

时间:2016-08-12 07:27:24

标签: ios objective-c avcapturesession avassetwriter avasset

我正在尝试使用AVCaptureSession创建一个方形视频并且我成功捕获了视频,但问题是,如果我的设备是纵向模式并且我捕获视频,那么它的Orientation记录正确但是如果我的设备是横向的我捕获视频我想将此视频方向更改为纵向。以下代码用于捕获后裁剪视频:

-(void)cropView:(NSURL*)outputfile
{
    AVAsset *asset = [AVAsset assetWithURL:outputfile];
    AVAssetTrack *clipVideoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
    AVMutableVideoComposition* videoComposition = [AVMutableVideoComposition videoComposition];
    videoComposition.frameDuration = CMTimeMake(1, 30);
    videoComposition.renderSize =CGSizeMake(clipVideoTrack.naturalSize.height, clipVideoTrack.naturalSize.height);


    AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
    instruction.timeRange = CMTimeRangeMake(kCMTimeZero, CMTimeMakeWithSeconds(60, 30));

    // rotate to portrait
    AVMutableVideoCompositionLayerInstruction* transformer = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:clipVideoTrack];
    CGAffineTransform t1 = CGAffineTransformMakeTranslation(clipVideoTrack.naturalSize.height, -(clipVideoTrack.naturalSize.width - clipVideoTrack.naturalSize.height) /2 );
    CGAffineTransform t2 = CGAffineTransformRotate(t1, M_PI_2);

    CGAffineTransform finalTransform = t2;
    [transformer setTransform:finalTransform atTime:kCMTimeZero];
    instruction.layerInstructions = [NSArray arrayWithObject:transformer];
    videoComposition.instructions = [NSArray arrayWithObject: instruction];


    NSString *outputPath = [NSString stringWithFormat:@"%@%@", NSTemporaryDirectory(), @"video.mp4"];
    NSURL *exportUrl = [NSURL fileURLWithPath:outputPath];

    [[NSFileManager defaultManager]  removeItemAtURL:exportUrl error:nil];


    //Export
    AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetHighestQuality] ;
    exporter.videoComposition = videoComposition;
    exporter.outputURL = exportUrl;
    exporter.outputFileType = AVFileTypeMPEG4;


    [exporter exportAsynchronouslyWithCompletionHandler:^
     {
         dispatch_async(dispatch_get_main_queue(), ^{
             //Call when finished
             [self exportDidFinish:exporter];
         });
     }];
}

1 个答案:

答案 0 :(得分:3)

我只是使用以下代码和步骤修复此问题:

首先我的设备方向是锁定,我的应用程序仅支持纵向方向,所以我认为我只获得纵向方向,但我通过横向模式捕获视频,因此使用Core-motion我使用以下代码获取设备方向

#import <CoreMotion/CoreMotion.h>

@interface ViewController ()
{
     AVCaptureVideoOrientation orientationLast, orientationAfterProcess;
  CMMotionManager *motionManager;
}

@implementation ViewController

- (void)initializeMotionManager{
    motionManager = [[CMMotionManager alloc] init];
    motionManager.accelerometerUpdateInterval = .2;
    motionManager.gyroUpdateInterval = .2;

    [motionManager startAccelerometerUpdatesToQueue:[NSOperationQueue currentQueue]
                                        withHandler:^(CMAccelerometerData  *accelerometerData, NSError *error) {
                                            if (!error) {
                                                [self outputAccelertionData:accelerometerData.acceleration];
                                            }
                                            else{
                                                NSLog(@"%@", error);
                                            }
                                        }];
}
- (void)outputAccelertionData:(CMAcceleration)acceleration{
    AVCaptureVideoOrientation orientationNew;

    if (acceleration.x >= 0.75) {
        orientationNew = AVCaptureVideoOrientationLandscapeLeft;
    }
    else if (acceleration.x <= -0.75) {
        orientationNew =AVCaptureVideoOrientationLandscapeRight;
    }
    else if (acceleration.y <= -0.75) {
        orientationNew =AVCaptureVideoOrientationPortrait;
    }
    else if (acceleration.y >= 0.75) {
        orientationNew =AVCaptureVideoOrientationPortraitUpsideDown;
    }
    else {
        // Consider same as last time
        return;
    }

    if (orientationNew == orientationLast)
        return;

    orientationLast = orientationNew;
}

因此基于设备轮换orientationLast更新设备方向。之后,当我点击录制视频按钮时,我设置了AVCaptureConnection方向。

AVCaptureConnection *CaptureConnection = [MovieFileOutput connectionWithMediaType:AVMediaTypeVideo];

    if ([CaptureConnection isVideoOrientationSupported])
    {
        [CaptureConnection setVideoOrientation:orientationLast];
    }

现在捕获视频后。裁剪时间我做了以下代码并且工作正常。

-(void)cropView:(NSURL*)outputfile
{
     AVAsset *asset = [AVAsset assetWithURL:outputfile];


    AVAssetTrack *clipVideoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
    AVMutableVideoComposition* videoComposition = [AVMutableVideoComposition videoComposition];
    videoComposition.frameDuration = CMTimeMake(1, 30);

    AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
    instruction.timeRange = CMTimeRangeMake(kCMTimeZero, CMTimeMakeWithSeconds(60, 30));

    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;

    videoComposition.renderSize = CGSizeMake(cropWidth, cropHeight);

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


    NSString *outputPath = [NSString stringWithFormat:@"%@%@", NSTemporaryDirectory(), @"video.mp4"];
    NSURL *exportUrl = [NSURL fileURLWithPath:outputPath];

    [[NSFileManager defaultManager]  removeItemAtURL:exportUrl error:nil];


    //Export
    AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetHighestQuality] ;
    exporter.videoComposition = videoComposition;
    exporter.outputURL = exportUrl;
    exporter.outputFileType = AVFileTypeMPEG4;


    [exporter exportAsynchronouslyWithCompletionHandler:^
     {
         dispatch_async(dispatch_get_main_queue(), ^{
             //Call when finished
             [self exportDidFinish:exporter];
         });
     }];

}

- (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;
}