利用AVFoundation实现二维码扫描

2016-07-15  本文已影响0人  LeeTrombone

主要涉及的类:

AVCaptureDevice代表了物理捕获设备如:摄像机。用于配置等底层硬件设置相机的自动对焦模式。

AVCaptureDeviceInput是AVCaptureInput的子类,可以作为输入捕获会话,用AVCaptureDevice实例初始化。

AVCaptureSession管理输入(AVCaptureInput)和输出(AVCaptureOutput)流,包含开启和停止会话方法。

AVCaptureMetadataOutput是AVCaptureOutput的子类,处理输出捕获会话。捕获的对象传递给一个委托实线AVCaptureMetadataOutputObjectsDelegate协议。协议方法在指定的派发队列(dispatch queue)上执行。

AVCaptureVideoPreviewLayer是CALayer的一个子类,显示捕获到的相机输出流。

实现的基本流程如下:

1.首先获取流媒体信息我们需要用到AVCaptureSession对象来管理输入流和输出流;

2.然后利用AVCaptureVideoPreviewLayer对象来显示信息。

二维码扫描流程图.jpg

下面开始上代码了...

1.导入AVFoundation Framework的头文件,并添加AVCaptureSession和AVCaptureVideoPreviewLayer的属性

#import "QRCodeScanViewController.h"
#import <AVFoundation/AVFoundation.h>

@interface QRCodeScanViewController () <AVCaptureMetadataOutputObjectsDelegate>

@property (nonatomic, strong) AVCaptureSession *captureSession;
@property (nonatomic, strong) AVCaptureVideoPreviewLayer *previewLayer;
// 闪关灯开启关闭标志
@property (nonatomic, assign) BOOL isLightOn;
@end

2.创建会话,读取输入流

// 开始扫描
- (BOOL)startScan {
    // 获取手机硬件设备
    AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    // 初始化输入流
    NSError *error = nil;
    AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:&error];
    if (!input) {
        NSLog(@"%@",[error localizedDescription]);
        return NO;
    }
    // 创建会话
    _captureSession = [[AVCaptureSession alloc] init];
    // 添加输入流
    [_captureSession addInput:input];
    // 初始化输出流
    AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc] init];
    // 添加输出流
    [_captureSession addOutput:output];
    // 创建dispatch queue
    dispatch_queue_t queue = dispatch_queue_create(kQRCodeScanQueueName, DISPATCH_QUEUE_CONCURRENT);
    //扫描的结果苹果是通过代理的方式区回调,所以outPut需要添加代理,并且因为扫描是耗时的工作,所以把它放到子线程里面
    [output setMetadataObjectsDelegate:self queue:queue];
    // 设置支持二维码和条形码扫描
    [output setMetadataObjectTypes:@[AVMetadataObjectTypeQRCode]];
    // 创建输出对象
    _previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_captureSession];
    [_previewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
    _previewLayer.frame = self.view.bounds;
    [self.view.layer insertSublayer:_previewLayer atIndex:0];
    // 开始会话
    [_captureSession startRunning];
    return YES;
}

3.结束扫描

// 结束扫描
- (void)stopScan {
    // 停止会话
    [_captureSession stopRunning];
    _captureSession = nil;
}

4.获取扫描结果并处理

#pragma mark -- AVCaptureMetadataOutputObjectsDelegate
// 扫描结果的代理回调方法
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
    if (metadataObjects != nil && metadataObjects.count > 0) {
        // 扫描到之后,停止扫描
        [self stopScan];
        // 获取结果并对其进行处理
        AVMetadataMachineReadableCodeObject *object = metadataObjects.firstObject;
        if ([[object type] isEqualToString:AVMetadataObjectTypeQRCode]) {
            NSString *result = object.stringValue;
            // 处理result
            NSLog(@"%@",result);
        } else {
            NSLog(@"不是二维码");
        }
    }
}

5.通常在扫描的时候会有开启闪光灯的功能,也是通过AVCaptureDevice来实现的。添加isLightOn属性,设置初始值为NO,并添加开关闪光灯的按钮

// 开启和关闭闪光灯
- (IBAction)didClickedLightUpButton:(UIButton *)sender {
    AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    //判断手机是否有闪光灯
    if ([device hasTorch]) {
        //呼叫手机操作系统,控制手机硬件
        NSError *error = nil;
        [device lockForConfiguration:&error];
        if (self.isLightOn == NO) {
            [device setTorchMode:AVCaptureTorchModeOn];
            self.isLightOn = YES;
        } else {
            [device setTorchMode:AVCaptureTorchModeOff];
            self.isLightOn = NO;
        }
        //结束对硬件的控制,跟上面的lockForConfiguration是配对的API
        [device unlockForConfiguration];
    }
}

最后附上github地址:https://github.com/chocklee/QRCodeScan

上一篇下一篇

猜你喜欢

热点阅读