美文网首页
AVCaptureSession - 基于iOS自带框架实现二维

AVCaptureSession - 基于iOS自带框架实现二维

作者: Blunet | 来源:发表于2018-02-03 15:33 被阅读0次

    做项目的过程中,或许都遇到过扫码的需求,从最早通过zxin和zbar的解码库,自定义扫码界面完成基本的扫码需求。到近期因为公司项目对引用的三方库有严格的过审要求,从而想到基于AVFoundation框架的自定义扫码解析。这里做一个简单的小计。充当个备胎,以备不时之需。

    step 1:导入框架

    AVFoundation/AVFoundation.h/AVFoundation/AVCaptureDevice.h/AVFoundation/AVMediaFormat.h

    step2:加入代理AVCaptureMetadataOutputObjectsDelegate/AVCaptureVideoDataOutputSampleBufferDelegate

    step3:实例对象

    /** 设备 */

    @property (nonatomic, strong) AVCaptureDevice * device;

    /** 输入输出的中间桥梁 */

    @property (nonatomic, strong) AVCaptureSession * session;

    /** 相机图层 */

    @property (nonatomic, strong) AVCaptureVideoPreviewLayer * previewLayer;

    /** 扫描支持的编码格式的数组 */

    @property (nonatomic, strong) NSMutableArray * metadataObjectTypes;

    这里的metadataObjectTypes数组是为了区分二维码和条形码的不同解析

    /**

    * MARK:根据条码状态返回不同的解码数组

    */

    - (NSMutableArray * )setMetaDataOutPutWithBarcode :(BOOL)isBarcode{

        NSMutableArray *metadataOutput_Arr = [[NSMutableArray alloc]init];

        if (!isBarcode) {

            metadataOutput_Arr = [NSMutableArray arrayWithObjects:AVMetadataObjectTypeAztecCode, AVMetadataObjectTypePDF417Code, AVMetadataObjectTypeQRCode, nil];

            // >= iOS 8

            if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_7_1) {

                [metadataOutput_Arr addObjectsFromArray:@[ AVMetadataObjectTypeDataMatrixCode]];

            }

        }else{

            metadataOutput_Arr = [NSMutableArray arrayWithObjects:AVMetadataObjectTypeCode128Code, AVMetadataObjectTypeCode39Code, AVMetadataObjectTypeCode39Mod43Code, AVMetadataObjectTypeCode93Code, AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeUPCECode, nil];

            // >= iOS 8

            if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_7_1) {

                [metadataOutput_Arr addObjectsFromArray:@[AVMetadataObjectTypeInterleaved2of5Code, AVMetadataObjectTypeITF14Code]];

            }

        }

        return metadataOutput_Arr;

    }

    下面看看初始化

    /**

    *  扫描初始化

    */

    - (void)capture{

        //获取摄像设备

        self.device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

        //创建输入流

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

        //创建输出流

        self.metadataOutput = [[AVCaptureMetadataOutput alloc] init];

        {//规范化扫描有效范围

            CGFloat scanView_w = 0;

            CGFloat scanView_H = 0;

            if (self.isBarcode) {

                scanView_w = FTNScreenW-20*2;

                scanView_H = 156.0;

            }else{

                scanView_w = scanView_Width;

                scanView_H = scanView_Height;

            }

    //设置你需要解析的范围(确保范围在你自定义框的内部,避免未进扫描框就可以解析条码了)

            [self.metadataOutput setRectOfInterest:CGRectMake(((FTNScreenH-scanView_H)/2)/FTNScreenH, ((FTNScreenW-scanView_w)/2)/FTNScreenW, scanView_H/FTNScreenH, scanView_w/FTNScreenW)];

        }

        //设置代理 在主线程里刷新

        [self.metadataOutput setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];

        //创建视频输出流

        AVCaptureVideoDataOutput * videoDataOutput = [[AVCaptureVideoDataOutput alloc] init];

        //设置代理在子线程里刷新

        dispatch_queue_t queue = dispatch_queue_create("myQueue", NULL);

        [videoDataOutput setSampleBufferDelegate:self queue:queue];

        //设置像素格式

        videoDataOutput.videoSettings = [NSDictionary dictionaryWithObject:

                                        [NSNumber numberWithInt:kCVPixelFormatType_32BGRA] forKey:(id)kCVPixelBufferPixelFormatTypeKey];

        //高质量采集率

        self.session.sessionPreset = AVCaptureSessionPresetHigh;

        [self.session addInput:input];

        [self.session addOutput:self.metadataOutput];

        [self.session addOutput:videoDataOutput];

        self.previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:self.session];

        self.previewLayer.frame = CGRectMake(0, 0, FTNScreenW, FTNScreenH);

        self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;

        self.previewLayer.backgroundColor = [UIColor yellowColor].CGColor;

        [self.view.layer addSublayer:self.previewLayer];

        //设置扫描支持的编码格式(如下设置条形码和二维码兼容)

        //    metadataOutput.metadataObjectTypes = self.metadataObjectTypes;

        self.metadataOutput.metadataObjectTypes = [self setMetaDataOutPutWithBarcode:NO];

        //开始捕获

        [self.session startRunning];

        //自动调焦 (解决条形码扫描难)

        //先进行判断是否支持控制对焦

        if (self.device.isFocusPointOfInterestSupported) {

            NSError *error = nil;

            //对cameraDevice进行操作前,需要先锁定,防止其他线程访问

            [self.device lockForConfiguration:&error];

            [self.device setFocusMode:AVCaptureFocusModeContinuousAutoFocus];

            //操作完成后,记得进行unlock。

            [self.device unlockForConfiguration];

        }

        if (self.device.isExposurePointOfInterestSupported) {

            NSError *error = nil;

            //对cameraDevice进行操作前,需要先锁定,防止其他线程访问

            [self.device lockForConfiguration:&error];

            [self.device setExposureMode:AVCaptureExposureModeAutoExpose];

            //操作完成后,记得进行unlock。

            [self.device unlockForConfiguration];

        }

        if (self.device.isAutoFocusRangeRestrictionSupported) {

            NSError *error = nil;

            //对cameraDevice进行操作前,需要先锁定,防止其他线程访问

            [self.device lockForConfiguration:&error];

            [self.device setAutoFocusRangeRestriction:AVCaptureAutoFocusRangeRestrictionNear];

            //操作完成后,记得进行unlock。

            [self.device unlockForConfiguration];

        }

    }

    最后,扫描结果的返回方法

    - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection{

        if (metadataObjects.count > 0) {

            [self.session stopRunning];

            AVMetadataMachineReadableCodeObject * metadataObject = metadataObjects.firstObject;

            for (AVMetadataMachineReadableCodeObject * metadataObject in metadataObjects) {

                NSLog(@"-----jie guo ---- %@",metadataObject.stringValue);

            }

            self.returnScanBarCodeValue(metadataObject.stringValue);

        }

    }

    需要注意。扫码过程中可能会遇到很长的条形码。这时候可能会扫码解析很慢。解决办法一个是检查解析范围的合理性(setRectOfInterest),一个是设置相机对焦模式(setFocusMode)为连续自动对焦。再则可以将条码和二维码分开解析(设置metadataOutput.metadataObjectTypes = ??的不同解析模式)。

    相关文章

      网友评论

          本文标题:AVCaptureSession - 基于iOS自带框架实现二维

          本文链接:https://www.haomeiwen.com/subject/cdyuzxtx.html