2012-04-07 7 views
5

Ich möchte Bilder an bestimmten Instanzen erfassen, zum Beispiel, wenn eine Taste gedrückt wird; aber ich möchte keine Videovorschau anzeigen. Ich denke captureStillImageAsynchronouslyFromConnection ist, was ich für dieses Szenario verwenden muss. Momentan kann ich Bilder aufnehmen, wenn ich eine Videovorschau zeige. Allerdings, wenn ich den Code entfernen Sie die Vorschau zu zeigen, die App stürzt mit der folgenden Ausgabe:So erfassen Sie ein Bild ohne Vorschau in iOS

2012-04-07 11: 25: 54,898 imCapWOPreview [748: 707] *** Abschluss App aufgrund Uncaught-Ausnahme 'NSInvalidArgumentException', Grund: '*** - [AVCaptureStillImageOutput captureStillImageAsynchronouslyFromConnection: completionHandler:] - Inaktive/ungültige Verbindung bestanden.' *** Erstschlingen Aufrufliste: (0x336ee8bf 0x301e21e5 0x3697c35d 0x34187 0x33648435 0x310949eb 0x310949a7 0x31094985 0x310946f5 0x3109502d 0x3109350f 0x31092f01 0x310794ed 0x31078d2d 0x37db7df3 0x336c2553 0x336c24f5 0x336c1343 0x336444dd 0x336443a5 0x37db6fcd 0x310a7743 0x33887 0x3382c) Beenden genannt Auslösen einer Ausnahme (LLDB)

So, hier ist meine Implementierung:

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 

Relevante Mitarbeiter innerhalb 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 
    }]; 

} 

Mit dem obigen Code, wenn doCap genannt wird, dann tritt der Absturz. Auf der anderen Seite, wenn ich die folgenden Kommentare in der SetupAVCapture-Funktion

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

entfernen, dann funktioniert es ohne jedes Problem.

Zusammengefasst lautet meine Frage: Wie kann ich Bilder in kontrollierten Instanzen erfassen, ohne die Vorschau anzuzeigen?

+0

einfachste Art wäre 'self.videoPreview.hidden = YES;' – Felix

+0

der Code funktioniert auf meinem iPhone 4S – Felix

+0

@ phix23 Verstecken der videoPreview arbeitete auch für mich ... Dann ist die nächste Frage; Gibt es bei diesem Ansatz eine Leistungseinbuße? h. es wird eine redundante Verarbeitung zum Senden von Video-Vorschaudaten an eine verborgene Schicht benötigt? –

Antwort

8

Ich verwende den folgenden Code für die Aufnahme von der Frontkamera (falls verfügbar) oder die Verwendung der Rückkamera. Funktioniert gut auf meinem 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

Funktioniert gut. Vielen Dank ! –

+1

Ich bekomme einen Fehler bei stillImageOutput.connections ist leer oder enthält 0 Objekte. Was ist falsch? –

+0

Das ist eine wirklich gute Lösung. Aber der Bildschirm wird für eine Sekunde leer, nachdem Snap das Bild erhalten hat. In der SnapChat App ist das nicht so. Wie kann ich das Verhalten wie in SnapChat App bekommen? – Satyam

1

Nun, ich war ein ähnliches Problem konfrontiert, wo durch die captureStillImageAsynchronouslyFromConnection:stillImageConnection eine Ausnahme anhob, dass die übergebene connection ungültig ist. Später fand ich heraus, dass das Problem behoben wurde, wenn ich properties für die Sitzung und stillImageOutPut Werte beibehalten.