iOS 7 AVCaptureMetadataOutput delegate (QRCode scanner)

Ricardo RendonCepeda picture Ricardo RendonCepeda · Sep 25, 2013 · Viewed 13.8k times · Source

I'm trying to implement a QRCode scanner with the new iOS 7 features but my code isn't calling the main AVCaptureMetadataOutputObjectsDelegate method.

I've used the AVFoundation camera before and with my current implementation I've got the preview layer running without a problem. Even switching my output back to AVCaptureVideoDataOutput validates my session setup.

I'm using this NSHipster post as a guideline and here's my code so far:

Interface:

@import AVFoundation;

@interface QRCodeViewController () <AVCaptureMetadataOutputObjectsDelegate>

@property (strong, nonatomic) AVCaptureDevice* device;
@property (strong, nonatomic) AVCaptureDeviceInput* input;
@property (strong, nonatomic) AVCaptureMetadataOutput* output;
@property (strong, nonatomic) AVCaptureSession* session;
@property (strong, nonatomic) AVCaptureVideoPreviewLayer* preview;

@end

Setup:

- (void)setupCamera
{
    // Device
    self.device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

    // Input
    self.input = [AVCaptureDeviceInput deviceInputWithDevice:self.device error:nil];

    // Output
    self.output = [[AVCaptureMetadataOutput alloc] init];
    [self.output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];

    // Session
    self.session = [[AVCaptureSession alloc] init];
    [self.session addInput:self.input];
    [self.session addOutput:self.output];

    // Preview
    self.preview = [AVCaptureVideoPreviewLayer layerWithSession:self.session];
    self.preview.videoGravity = AVLayerVideoGravityResizeAspectFill;
    self.preview.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
    [self.view.layer insertSublayer:self.preview atIndex:0];

    // Start
    [self.session startRunning];
}

Delegate Method:

// DELEGATE METHOD NOT CALLED
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection
{
    NSLog(@"Metadata");
}

Any help is greatly appreciated!

Answer

Ned Zepplin picture Ned Zepplin · Sep 25, 2013

I am trying to figure this out myself. The documentation seems to say that if you don't set the type(s) you want in metadataObjectTypes, you won't get any calls. But my iPad Mini's back camera returns an empty array for availableMetadataObjectTypes. Let us know what you figure out.

Edit:

I just figured out that if you add the AVCaptureMetadataOutput object to the session, the availableMetadataObjectTypes gets filled in and you can add the barcode detector to it. Then the captureOutput delegate will get called, so like this:

AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc] init];
[output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
[session addOutput:output];
output.metadataObjectTypes = @[AVMetadataObjectTypeQRCode];