2012-04-07 11 views
5

Quiero capturar imágenes en instancias específicas, por ejemplo, cuando se presiona un botón; pero no quiero mostrar ninguna pantalla de vista previa de video. Supongo que captureStillImageAsynchronouslyFromConnection es lo que necesito usar para este escenario. Actualmente, puedo capturar imagen si muestro una vista previa de video. Sin embargo, si quito el código para mostrar la vista previa, la aplicación se bloquea con el siguiente resultado:Cómo capturar imágenes sin mostrar vista previa en iOS

2012-04-07 11: 25: 54.898 imCapWOPreview [748: 707] *** Terminación de aplicación debido a excepción no detectada 'NSInvalidArgumentException', razón: '*** - [AVCaptureStillImageOutput captureStillImageAsynchronouslyFromConnection: completionHandler:] - conexión inactiva/inválida pasada.' *** En primer tiro pila de llamadas: (0x336ee8bf 0x301e21e5 0x3697c35d 0x34187 0x33648435 0x31094985 0x310949eb 0x310949a7 0x310946f5 0x3109502d 0x3109350f 0x31092f01 0x310794ed 0x31078d2d 0x37db7df3 0x336c2553 0x336c24f5 0x336c1343 0x336444dd 0x336443a5 0x37db6fcd 0x310a7743 0x33887 0x3382c) terminar la llamada lanzar una excepción (LLDB)

Así que aquí es mi aplicación:

BIDViewController.h:

#import <UIKit/UIKit.h> 
#import <AVFoundation/AVFoundation.h> 

@interface BIDViewController : UIViewController 
{ 
    AVCaptureStillImageOutput *stillImageOutput; 
} 
@property (strong, nonatomic) IBOutlet UIView *videoPreview; 
- (IBAction)doCap:(id)sender; 

@end 

El personal pertinente dentro BIDViewController.m:

#import "BIDViewController.h" 

@interface BIDViewController() 

@end 

@implementation BIDViewController 
@synthesize capturedIm; 
@synthesize videoPreview; 

- (void)viewDidLoad 
{ 
[super viewDidLoad]; 
[self setupAVCapture]; 
} 

- (BOOL)setupAVCapture 
{ 
NSError *error = nil; 

AVCaptureSession *session = [AVCaptureSession new]; 
[session setSessionPreset:AVCaptureSessionPresetHigh]; 

/* 
AVCaptureVideoPreviewLayer *captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:session]; 
captureVideoPreviewLayer.frame = self.videoPreview.bounds; 
[self.videoPreview.layer addSublayer:captureVideoPreviewLayer];  
*/ 

// Select a video device, make an input 
AVCaptureDevice *backCamera = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; 
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:backCamera error:&error]; 
if (error) 
    return NO; 
if ([session canAddInput:input]) 
    [session addInput:input]; 

// Make a still image output 
stillImageOutput = [AVCaptureStillImageOutput new]; 
NSDictionary *outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys: AVVideoCodecJPEG, AVVideoCodecKey, nil]; 
[stillImageOutput setOutputSettings:outputSettings];  
if ([session canAddOutput:stillImageOutput]) 
    [session addOutput:stillImageOutput]; 

[session startRunning]; 

return YES; 
} 

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

[stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnection 
    completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *__strong error) { 
     // Do something with the captured image 
    }]; 

} 

Con el código anterior, si doCap se llama, entonces se produce el accidente. Por otro lado, si quito los siguientes comentarios en función setupAVCapture

/* 
AVCaptureVideoPreviewLayer *captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:session]; 
captureVideoPreviewLayer.frame = self.videoPreview.bounds; 
[self.videoPreview.layer addSublayer:captureVideoPreviewLayer];  
*/ 

entonces funciona sin ningún problema.

En resumen, mi pregunta es, ¿cómo puedo capturar imágenes en instancias controladas sin mostrar vista previa?

+0

manera más simple sería 'self.videoPreview.hidden = SÍ;' – Felix

+0

el código funciona en mi iphone 4S – Felix

+0

@ phix23 ocultar el videoPrevista también funcionó para mí ... Entonces la siguiente pregunta es; ¿Hay una penalización de rendimiento con este enfoque? es decir, ¿se ha gastado el procesamiento redundante para enviar datos de vista previa de video a una capa oculta? –

Respuesta

8

Uso el siguiente código para capturar desde la cámara frontal (si está disponible) o usando la cámara posterior. Funciona bien en mi iPhone 4S.

-(void)viewDidLoad{ 

    AVCaptureSession *session = [[AVCaptureSession alloc] init]; 
    session.sessionPreset = AVCaptureSessionPresetMedium; 

    AVCaptureDevice *device = [self frontFacingCameraIfAvailable]; 

    NSError *error = nil; 
    AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error]; 
    if (!input) { 
     // Handle the error appropriately. 
     NSLog(@"ERROR: trying to open camera: %@", error); 
    } 
    [session addInput:input]; 

//stillImageOutput is a global variable in .h file: "AVCaptureStillImageOutput *stillImageOutput;" 
    stillImageOutput = [[AVCaptureStillImageOutput alloc] init]; 
    NSDictionary *outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys: AVVideoCodecJPEG, AVVideoCodecKey, nil]; 
    [stillImageOutput setOutputSettings:outputSettings]; 

    [session addOutput:stillImageOutput]; 

    [session startRunning]; 
} 

-(AVCaptureDevice *)frontFacingCameraIfAvailable{ 

    NSArray *videoDevices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; 
    AVCaptureDevice *captureDevice = nil; 

    for (AVCaptureDevice *device in videoDevices){ 

     if (device.position == AVCaptureDevicePositionFront){ 

      captureDevice = device; 
      break; 
     } 
    } 

    // couldn't find one on the front, so just get the default video device. 
    if (!captureDevice){ 

     captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; 
    } 

    return captureDevice; 
} 

-(IBAction)captureNow{ 

    AVCaptureConnection *videoConnection = nil; 
    for (AVCaptureConnection *connection in 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: %@", stillImageOutput); 
    [stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler: ^(CMSampleBufferRef imageSampleBuffer, NSError *error){ 

     CFDictionaryRef exifAttachments = CMGetAttachment(imageSampleBuffer, kCGImagePropertyExifDictionary, NULL); 
     if (exifAttachments){ 

      // Do something with the attachments if you want to. 
      NSLog(@"attachements: %@", exifAttachments); 
     } 
     else 
      NSLog(@"no attachments"); 

     NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer]; 
     UIImage *image = [[UIImage alloc] initWithData:imageData]; 

     self.vImage.image = image; 
    }]; 
} 
+0

Funciona muy bien. Gracias ! –

+1

obtengo un error en stillImageOutput.connections está vacío o contiene 0 objetos. ¿qué está mal? –

+0

Esta es una buena solución. Pero la pantalla se queda en blanco por un segundo después de que ocurra un chasquido para obtener la imagen. En la aplicación SnapChat no es así. ¿Cómo puedo obtener el comportamiento como en la aplicación SnapChat? – Satyam

1

Bueno, yo estaba frente a un problema similar donde el captureStillImageAsynchronouslyFromConnection:stillImageConnection fue lanzar una excepción que la connection pasado no es válido. Más tarde, descubrí que cuando hice properties para la sesión y stillImageOutPut para retener los valores, se resolvió el problema.

Cuestiones relacionadas