ios - 使用 AVAsset/AVCaptureSession 时,方形视频方向不会从横向变为纵向

标签 ios objective-c avcapturesession avassetwriter avasset

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

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

最佳答案

我只是使用以下代码和步骤解决了该问题:

首先,我的设备方向是锁定的,我的应用程序仅支持纵向方向,所以我认为我只能纵向方向,但是我通过横向模式捕获视频,因此使用 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;
}

关于ios - 使用 AVAsset/AVCaptureSession 时,方形视频方向不会从横向变为纵向,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38912280/

相关文章:

ios - 是否可以使用 iOS Developer Enterprise Program 分发使用 beta SDK 构建的内部应用程序?

ios - 如何使用闪光灯在自定义相机上拍照?

ios - AVCaptureVideoDataOutput P3 色彩空间

ios - 为什么数据添加到 FireBase 数据库后自动删除?

ios - 当语言不存在时,本地化如何默认? [解释]

ios - iOS 上的本地主机

ios - 使用线程和核心数据时出错(objective-c)

objective-c - 在 UITableView 中插入新行的技术

objective-c - cocos2d绘制方法

iphone - iOS : camera orientation