Date
Jul. 27th, 2024
 
2024年 6月 22日

Post: iOS : 自定义相机实例 Demo

iOS : 自定义相机实例 Demo

Published 12:09 Sep 22, 2015.

Created by @ezra. Categorized in #Programming, and tagged as #iOS.

Source format: Markdown

Table of Content

本文介绍一个简单的自定义相机实例 Demo。

如我前面文章所说,首先需要包含 AVFoundation.framework,并导入头文件:

#import <AVFoundation/AVFoundation.h>

添加必要的属性:

// 处理输入输出设备的数据流动
@property (nonatomic, strong) AVCaptureSession *captureSession;
// 输入设备
@property (nonatomic, strong) AVCaptureDeviceInput *captureInput;
// 输出设备,本例输出静止图像
@property (nonatomic, strong) AVCaptureStillImageOutput *stillImageOutput;
// 预览层
@property (nonatomic, strong) AVCaptureVideoPreviewLayer *previewLayer;

创建必要的控件(略)并为控件添加属性:

// 放置 预览层 的视图
@property (nonatomic, weak) UIView *cameraShowView;
// 切换前后摄像头的按钮
@property (nonatomic, weak) UIButton *toggleButton;
// 拍照按钮
@property (nonatomic, weak) UIButton *shutterButton;
// 切换闪光灯模式的按钮
@property (nonatomic, weak) UIButton *flashButton;

对输入输出设备等进行初始化:

#pragma mark - 初始化
- (void)initialSession {
    // 初始化 session 和设备
    self.captureSession = [[AVCaptureSession alloc] init];
    self.captureInput = [[AVCaptureDeviceInput alloc] initWithDevice:[self backCamera] error:nil];
    // [self backCamera] 为自定义方法,参见下文
    self.stillImageOutput = [[AVCaptureStillImageOutput alloc] init];

    // 输出配置
    NSDictionary *outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys:AVVideoCodecJPEG, AVVideoCodecKey, nil];
    [self.stillImageOutput setOutputSettings:outputSettings];

    // 添加设备
    if ([self.captureSession canAddInput:self.captureInput]) {
        [self.captureSession addInput:self.captureInput];
    }
    if ([self.captureSession canAddOutput:self.stillImageOutput]) {
        [self.captureSession addOutput:self.stillImageOutput];
    }

    // 拿到设备
    AVCaptureDevice *device = self.captureInput.device;
    // 修改前注意要锁定设备
    if ([device lockForConfiguration:nil]) {
    // 对焦模式
        if ([device isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus]) {
            [device setFocusMode:AVCaptureFocusModeContinuousAutoFocus];
        } else if ([device isFocusModeSupported:AVCaptureFocusModeAutoFocus]) {
            [device setFocusMode:AVCaptureFocusModeAutoFocus];
        }
        // 曝光模式
//        if ([device isExposureModeSupported:AVCaptureExposureModeAutoExpose]) {
//            [device setExposureMode:AVCaptureExposureModeAutoExpose];
//        }
        // 闪光灯模式
        if ([device hasFlash]) {
            [device setFlashMode:AVCaptureFlashModeAuto];
            [device setTorchMode:AVCaptureTorchModeAuto];
        }
        // 修改后解锁设备
        [device unlockForConfiguration];
    }
}

配置预览层:

#pragma mark - 配置预览层
- (void)setUpCameraLayer {
//    if (_cameraAvaible == NO) return;

    if (self.previewLayer == nil) {
        self.previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.captureSession];
        CALayer * viewLayer = [self.cameraShowView layer];
        [viewLayer setMasksToBounds:YES];
        [self.previewLayer setFrame:[UIScreen mainScreen].bounds];
        [self.previewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
        [viewLayer insertSublayer:self.previewLayer below:[[viewLayer sublayers] objectAtIndex:0]];
    }
}

在合适的地方,例如 viewDidLoad 中调用初始化和配置预览层的方法:

// 初始化
[self initialSession];
// 配置预览层
[self setUpCameraLayer];

控制器视图显示后摄像头开始摄取图像:

// 开始
if (self.captureSession) {
   [self.captureSession startRunning];
}

控制器视图消失后摄像头停止摄取图像:

- (void) viewDidDisappear:(BOOL)animated {
    [super viewDidDisappear: animated];
    // 结束
    if (self.captureSession) {
        [self.captureSession stopRunning];
    }
}

获取摄像头:

#pragma mark - 获得前置
- (AVCaptureDevice *)frontCamera {
    return [self cameraWithPosition:AVCaptureDevicePositionFront];
}

#pragma mark - 获得后置
- (AVCaptureDevice *)backCamera {
    return [self cameraWithPosition:AVCaptureDevicePositionBack];
}

#pragma mark - 获得摄像头
- (AVCaptureDevice *)cameraWithPosition:(AVCaptureDevicePosition)position {
    NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
    for (AVCaptureDevice *device in devices) {
        if ([device position] == position) {
            return device;
        }
    }
    return nil;
}

切换摄像头:

#pragma mark - 切换摄像头
- (void)toggleCamera {
    NSUInteger cameraCount = [[AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo] count];
    if (cameraCount > 1) {
        NSError *error;
        AVCaptureDeviceInput *newVideoInput;
        AVCaptureDevicePosition position = [[self.captureInput device] position];

        if (position == AVCaptureDevicePositionBack)
            newVideoInput = [[AVCaptureDeviceInput alloc] initWithDevice:[self frontCamera] error:&error];
        else if (position == AVCaptureDevicePositionFront)
            newVideoInput = [[AVCaptureDeviceInput alloc] initWithDevice:[self backCamera] error:&error];
        else
            return;

        if (newVideoInput != nil) {
            [self.captureSession beginConfiguration];
            [self.captureSession removeInput:self.captureInput];
            if ([self.captureSession canAddInput:newVideoInput]) {
                [self.captureSession addInput:newVideoInput];
                [self setCaptureInput:newVideoInput];
            } else {
                [self.captureSession addInput:self.captureInput];
            }
            [self.captureSession commitConfiguration];
        } else if (error) {
            [self showOpoosAlertViewWithContentText:[NSString stringWithFormat:@"%@", error] durationTime:2.0];
        }
    }
}

捕获图像拍摄照片:

#pragma mark - 拍照
- (void)shutterCamera {
    AVCaptureConnection * videoConnection = [self.stillImageOutput connectionWithMediaType:AVMediaTypeVideo];
    if (!videoConnection) {
        [self showOpoosAlertViewWithContentText:@"拍摄失败" durationTime:2.0];
        return;
    }

    // 捕获图像
    [self.stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
        if (imageDataSampleBuffer == NULL) {
            return;
        }
        NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
        UIImage *image = [UIImage imageWithData:imageData];
        // 处理图像...
    }];
}

好了,一个简单的自定义相机就完成了。

Pinned Message
HOTODOGO
I'm looking for a SOFTWARE PROJECT DIRECTOR / SOFTWARE R&D DIRECTOR position in a fresh and dynamic company. I would like to gain the right experience and extend my skills while working in great teams and big projects.
Feel free to contact me.
For more information, please view online résumé or download PDF
本人正在寻求任职 软件项目经理 / 软件技术经理 岗位的机会, 希望加⼊某个新鲜⽽充满活⼒的公司。
如有意向请随时 与我联系
更多信息请 查阅在线简历下载 PDF