AVCaptureSession旋转

3
我正在尝试以正确的方式创建UIImage应用程序。我的大部分代码都是从Apple示例中提取的...
@interface CameraManager () <AVCaptureVideoDataOutputSampleBufferDelegate>

@property (nonatomic, strong) CIContext *context;
@property (nonatomic, strong) AVCaptureDevice *rearCamera;

@end

@implementation CameraManager

- (id)init {
    if ((self = [super init])) {

        self.context = [CIContext contextWithOptions:nil];
        [self setupCamera];
        [self addStillImageOutput];
    }
    return self;
}

- (void)setupCamera
{
    self.session = [[AVCaptureSession alloc] init];
    [self.session beginConfiguration];

    [self.session setSessionPreset:AVCaptureSessionPresetPhoto];

    NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
    self.rearCamera = nil;
    for (AVCaptureDevice *device in devices) {
        if (device.position == AVCaptureDevicePositionBack) {
            self.rearCamera = device;
            break;
        }
    }

    NSError *error = nil;
    AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:self.rearCamera error:&error];
    [self.session addInput:input];

    AVCaptureVideoDataOutput *dataOutput = [[AVCaptureVideoDataOutput alloc] init];
    [dataOutput setAlwaysDiscardsLateVideoFrames:YES];

    NSDictionary *options = @{(id)kCVPixelBufferPixelFormatTypeKey : @(kCVPixelFormatType_32BGRA)};
    [dataOutput setVideoSettings:options];

    [dataOutput setSampleBufferDelegate:self queue:dispatch_get_main_queue()];

    [self.session addOutput:dataOutput];
    [self.session commitConfiguration];
}

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
{
    // grab the pixel buffer
    CVPixelBufferRef pixelBuffer = (CVPixelBufferRef) CMSampleBufferGetImageBuffer(sampleBuffer);

    // create a CIImage from it, rotate it and zero the origin
    CIImage *image = [CIImage imageWithCVPixelBuffer:pixelBuffer];
    if ([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeLeft) {
        image = [image imageByApplyingTransform:CGAffineTransformMakeRotation(M_PI)];
    }
    CGPoint origin = [image extent].origin;
    image = [image imageByApplyingTransform:CGAffineTransformMakeTranslation(-origin.x, -origin.y)];

    // set it as the contents of the UIImageView
    CGImageRef cgImage = [self.context createCGImage:image fromRect:[image extent]];
    UIImage *uiImage = [UIImage imageWithCGImage:cgImage];

    [[NSNotificationCenter defaultCenter] postNotificationName:@"image" object:uiImage];

    CGImageRelease(cgImage);
}

- (void)addStillImageOutput
{
    [self setStillImageOutput:[[AVCaptureStillImageOutput alloc] init]];
    NSDictionary *outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys:AVVideoCodecJPEG,AVVideoCodecKey,nil];
    [[self stillImageOutput] setOutputSettings:outputSettings];

    AVCaptureConnection *videoConnection = nil;
    for (AVCaptureConnection *connection in [self.stillImageOutput connections]) {
        for (AVCaptureInputPort *port in [connection inputPorts]) {
            if ([[port mediaType] isEqual:AVMediaTypeVideo] ) {
                videoConnection = connection;
                break;
            }
        }
        if (videoConnection) {
            break;
        }
    }

    [[self session] addOutput:[self stillImageOutput]];
}

- (void)captureStillImage
{
    AVCaptureConnection *videoConnection = nil;
    for (AVCaptureConnection *connection in [[self stillImageOutput] connections]) {
        for (AVCaptureInputPort *port in [connection inputPorts]) {
            if ([[port mediaType] isEqual:AVMediaTypeVideo]) {
                videoConnection = connection;
                break;
            }
        }
        if (videoConnection) {
            break;
        }
    }

    NSLog(@"about to request a capture from: %@", [self stillImageOutput]);
    [[self stillImageOutput] captureStillImageAsynchronouslyFromConnection:videoConnection
                                                         completionHandler:^(CMSampleBufferRef imageSampleBuffer, NSError *error) {
                                                             CFDictionaryRef exifAttachments = CMGetAttachment(imageSampleBuffer, kCGImagePropertyExifDictionary, NULL);
                                                             if (exifAttachments) {
                                                                 NSLog(@"attachements: %@", exifAttachments);
                                                             } else {
                                                                 NSLog(@"no attachments");
                                                             }
                                                             NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];
                                                             UIImage *image = [[UIImage alloc] initWithData:imageData];

                                                             [[NSNotificationCenter defaultCenter] postNotificationName:kImageCapturedSuccessfully object:image];
                                                         }];
}

这是我的相机管理器类代码。
我使用OutputSampleBufferDelegate来显示相机的预览(由于各种原因)。
我使用会话输出来“拍照”。
方法captureStillImage是我想要修复的部分。
拍摄的照片在设备处于LandscapeLeft方向时拍摄(界面也是LandscapeLeft)。
预览都以正确的方式显示,exif数据也以正确的方式显示宽度和高度(X = 3264,Y = 2448)。
但是当我显示UIImage时,它逆时针旋转90度。图像的纵横比正确(即一切看起来都很好,圆形仍然是圆形),只是旋转了。
我找到了几个声称可以解决此问题的类别。
我还发现了几个StackOverflow帖子,带有声称可以解决此问题的答案。
但是这些都没有起作用。
有谁知道如何将这个东西旋转到正确的位置?
3个回答

4
在调用captureStillImageAsynchronouslyFromConnection之前,我通常会添加以下代码:
if ([videoConnection isVideoOrientationSupported]) {
    [videoConnection setVideoOrientation:[UIDevice currentDevice].orientation];
}

请注意,您必须调用-beginGeneratingDeviceOrientationNotifications,否则将返回UIDeviceOrientationUnknown(0)。还要注意,您不能在请求方向之前立即调用-beginGeneratingDeviceOrientationNotifications,您必须在某些时间之前调用它(例如在viewWillAppear或其他地方)。 - prewett

1
也许你应该在captureStillImageAsynchronouslyFromConnection完成块中接收图像数据后尝试设置图像方向:
UIImage *image = [[UIImage alloc] initWithData:imageData];
image = [[UIImage alloc] initWithCGImage:image.CGImage scale:1.0f orientation:UIImageOrientationDown];

0

方向问题出现在前置摄像头上,因此请检查设备类型并生成新图像,这样肯定可以解决方向问题:

-(void)capture:(void(^)(UIImage *))handler{

AVCaptureConnection *videoConnection = nil;
for (AVCaptureConnection *connection in self.stillImageOutput.connections)
{
    for (AVCaptureInputPort *port in [connection inputPorts])
    {
        if ([[port mediaType] isEqual:AVMediaTypeVideo] )
        {
            videoConnection = connection;
            break;
        }
    }
    if (videoConnection) { break; }
}

[self.stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler: ^(CMSampleBufferRef imageSampleBuffer, NSError *error) {

    if (imageSampleBuffer != NULL) {
        NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];
        **UIImage *capturedImage = [UIImage imageWithData:imageData];
        if (self.captureDevice == [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo][1]) {
            capturedImage = [[UIImage alloc] initWithCGImage:capturedImage.CGImage scale:1.0f orientation:UIImageOrientationLeftMirrored];
        }**

        handler(capturedImage);
    }
}];
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接