从 av 基础框架工作为 ios 开发自定义相机应用程序时,Camara 预览显示不正确?

Posted

技术标签:

【中文标题】从 av 基础框架工作为 ios 开发自定义相机应用程序时,Camara 预览显示不正确?【英文标题】:Camara preview not displayed in correct when developing a custom camera application for ios from av foundation frame work? 【发布时间】:2014-01-15 05:24:43 【问题描述】:

我正在使用 xcode 5 为 ios 7 开发一个自定义相机应用程序。我有一个视图控制器如下的类

    #import "ADMSImageUploader.h"
#import "ADMSViewController.h"

@interface ADMSImageUploader ()

@end

@implementation ADMSImageUploader

AVCaptureVideoPreviewLayer *captureVideoPreviewLayer;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil

    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) 
        // Custom initialization
    
    return self;


- (void)viewDidLoad

    [super viewDidLoad];
    // Do any additional setup after loading the view.
    FrontCamera = NO;
    [self initializeCamera];



- (void)didReceiveMemoryWarning

    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.

- (void)viewDidAppear:(BOOL)animated 




//AVCaptureSession to show live video feed in view
- (void) initializeCamera 
    session = [[AVCaptureSession alloc] init];
    session.sessionPreset = AVCaptureSessionPresetPhoto;

    captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:session];
    [self.imagePreview.layer setMasksToBounds:YES];

    //    CGSize landscapeSize;
    //    landscapeSize.width = self.imagePreview.bounds.size.width;
    //    landscapeSize.height = self.view.bounds.size.width;

    //CGRect rect=[[UIScreen mainScreen]bounds];

    captureVideoPreviewLayer.frame = CGRectMake(0.0, 0.0, self.imagePreview.frame.size.width, self.imagePreview.frame.size.height);
    connection = captureVideoPreviewLayer.connection;
    orientation = AVCaptureVideoOrientationLandscapeRight;
    //connection.videoOrientation = AVCaptureVideoOrientationLandscapeRight;
    [captureVideoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];

//    if ([[UIDevice currentDevice] orientation] == UIInterfaceOrientationPortrait ) 
//        captureVideoPreviewLayer.frame = CGRectMake(0.0, 0.0, self.imagePreview.frame.size.width, self.imagePreview.frame.size.height);
//        connection = captureVideoPreviewLayer.connection;
//        orientation = AVCaptureVideoOrientationPortrait;
//        //connection.videoOrientation = AVCaptureVideoOrientationLandscapeRight;
//        [captureVideoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
//        
//    else
//        captureVideoPreviewLayer.frame = CGRectMake(0.0, 0.0, self.imagePreview.frame.size.width, self.imagePreview.frame.size.height);
//        connection = captureVideoPreviewLayer.connection;
//        orientation = AVCaptureVideoOrientationLandscapeRight;
//        //connection.videoOrientation = AVCaptureVideoOrientationLandscapeRight;
//        [captureVideoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
//
//    

    [self.imagePreview.layer addSublayer:captureVideoPreviewLayer];


    NSArray *devices = [AVCaptureDevice devices];
    AVCaptureDevice *frontCamera;
    AVCaptureDevice *backCamera;

    for (AVCaptureDevice *device in devices) 

        NSLog(@"Device name: %@", [device localizedName]);

        if ([device hasMediaType:AVMediaTypeVideo]) 

            if ([device position] == AVCaptureDevicePositionBack) 
                NSLog(@"Device position : back");
                backCamera = device;
            
            else 
                NSLog(@"Device position : front");
                frontCamera = device;
            
        
        else
            if (!([device position] == AVCaptureDevicePositionBack)) 
                UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Cannot take photos using rear camera"
                                                                message:@"Your device doesnot support this feature."
                                                               delegate:nil
                                                      cancelButtonTitle:@"OK"
                                                      otherButtonTitles:nil];
                [alert show];

            
        
    

    if (!FrontCamera) 
        NSError *error = nil;
        AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:backCamera error:&error];
        if (!input) 
            NSLog(@"ERROR: trying to open camera: %@", error);
        
        [session addInput:input];
    

    if (FrontCamera) 
        NSError *error = nil;
        AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:frontCamera error:&error];
        if (!input) 
            NSLog(@"ERROR: trying to open camera: %@", error);
        
        [session addInput:input];
    

    _stillImageOutput = [[AVCaptureStillImageOutput alloc] init];
    NSDictionary *outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys: AVVideoCodecJPEG, AVVideoCodecKey, nil];
    [_stillImageOutput setOutputSettings:outputSettings];

    [session addOutput:_stillImageOutput];

    [session startRunning];


- (BOOL)shouldAutorotate
     return YES;
    


//-(void)openCamera:(NSString *)dealerId:(NSString *)inventoryId
//
//    
//
- (void)viewWillAppear:(BOOL)animated

    [self.navigationController setNavigationBarHidden:YES animated:animated];
    [super viewWillAppear:animated];
    _uploadButtonBehaviour.hidden = YES;
    _discardButtonBehaviour.hidden = YES;


- (void)viewWillDisappear:(BOOL)animated

    [self.navigationController setNavigationBarHidden:NO animated:animated];
    [super viewWillDisappear:animated];


- (NSUInteger)supportedInterfaceOrientations;

    return UIInterfaceOrientationMaskLandscape;



- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation;


        captureVideoPreviewLayer.frame = CGRectMake(0.0, 0.0,self.imagePreview.frame.size.width,self.imagePreview.frame.size.height);
        [captureVideoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
        connection = captureVideoPreviewLayer.connection;
        [captureVideoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];

        //  connection.videoOrientation = AVCaptureVideoOrientationLandscapeRight;

        [connection setVideoOrientation:AVCaptureVideoOrientationLandscapeRight];




-(UIInterfaceOrientation)preferredInterfaceOrientationForPresentation

    return UIInterfaceOrientationLandscapeRight;


- (IBAction)captureButton:(id)sender 


- (IBAction)exitButton:(id)sender 
    [self.navigationController popToRootViewControllerAnimated:YES];


- (IBAction)uploadButton:(id)sender 


- (IBAction)discardButton:(id)sender 

@end

我只想在景观模式下启动这个视图控制器。我正在使用导航控制器转到不同的视图控制器。

当我以前的视图控制器处于垂直方向时,相机预览如下

当我将 ios 设备旋转到横向时,会显示以下相机预览。这里的问题是预览图像被拉伸了。

当我以前的视图控制器处于水平方向时,相机预览如下。相机预览出现倒置。 。我请求你在这个问题上帮助我。

【问题讨论】:

【参考方案1】:

我曾经遇到过同样的问题。我通过检测设备方向使用CGAffineTransformMakeScale 手动旋转捕获的图像来解决这个问题。

if ([[UIDevice currentDevice] orientation] == UIDeviceOrientationLandscapeRight) 
    CIImage *c = [[CIImage alloc] initWithImage:imageFromCamera];
    c = [c imageByApplyingTransform:CGAffineTransformTranslate(CGAffineTransformMakeScale(-1, -1), 0, c.extent.size.height)];
    imageFromCamera = [UIImage imageWithCGImage:[[CIContext contextWithOptions:nil] createCGImage:c fromRect:c.extent]];

如果旋转不正确,请更改 CGAffineTransformMakeScale 的值。

【讨论】:

【参考方案2】:
//AVCaptureSession to show live video feed in view
- (void) initializeCamera

    session = [[AVCaptureSession alloc] init];
    if ([session canSetSessionPreset:AVCaptureSessionPresetPhoto]) 
        session.sessionPreset = AVCaptureSessionPresetPhoto;
        devicesArray = [AVCaptureDevice devices];
        for (AVCaptureDevice *device in devicesArray)
            if ([device hasMediaType:AVMediaTypeVideo])
                if ([device position] == AVCaptureDevicePositionBack)
                    NSLog(@"Device name: %@", [device localizedName]);
                    NSLog(@"Device position : back");
                    backCamera = device;
                    backCameraCheck = YES;
                
            
        
        if (backCameraCheck) 
            NSError *error = nil;
            inputDevice = [AVCaptureDeviceInput deviceInputWithDevice:backCamera error:&error];
            if (!inputDevice)
                NSLog(@"ERROR: trying to open camera: %@", error);
            else
                [session addInput:inputDevice];
            
        else
            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Cannot take photos using rear camera"
                                                            message:@"Your device doesnot support this feature."
                                                           delegate:nil
                                                  cancelButtonTitle:@"OK"
                                                otherButtonTitles:nil];
            [alert show];
        
        output = [[AVCaptureVideoDataOutput alloc] init];
        [session addOutput:output];
        captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:session];
        [captureVideoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
        connection = [output connectionWithMediaType:AVMediaTypeVideo];
        connection = captureVideoPreviewLayer.connection;
        if ([[UIDevice currentDevice] orientation] == UIInterfaceOrientationPortrait ) 
            captureVideoPreviewLayer.frame = CGRectMake(0.0, 0.0, self.imagePreview.frame.size.width, self.imagePreview.frame.size.height);
            if ([connection isVideoOrientationSupported])
                orientation = AVCaptureVideoOrientationPortrait;
                [connection setVideoOrientation:orientation];
            
        else
            NSLog(@"view width = %f %f", self.imagePreview.frame.size.width, self.imagePreview.frame.size.height);
            captureVideoPreviewLayer.frame = CGRectMake(0.0, 0.0, self.imagePreview.frame.size.height,self.imagePreview.frame.size.width);
            if ([connection isVideoOrientationSupported])
                orientation = AVCaptureVideoOrientationLandscapeRight;
                [connection setVideoOrientation:orientation];
            
        
        [self.imagePreview.layer setMasksToBounds:YES];
        [self.imagePreview.layer addSublayer:captureVideoPreviewLayer];


        _stillImageOutput = [[AVCaptureStillImageOutput alloc] init];
        NSDictionary *outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys: AVVideoCodecJPEG, AVVideoCodecKey, nil];
        [_stillImageOutput setOutputSettings:outputSettings];
        [session addOutput:_stillImageOutput];
        [session startRunning];
    else 
        // Handle the failure.
    

【讨论】:

以上是关于从 av 基础框架工作为 ios 开发自定义相机应用程序时,Camara 预览显示不正确?的主要内容,如果未能解决你的问题,请参考以下文章

Android Camera2 教程 · 第一章 · 概览

iOS开发笔记17:自定义相机拍照

iOS自定义相机界面

如何使用自定义相机 API 制作圆形框架布局并捕获圆形图像?

如何使用按钮实现自定义相机?

自定义相机安卓