Date
Nov. 6th, 2024
 
2024年 10月 6日

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
The Founder and CEO of Infeca Technology.
Developer, Designer, Blogger.
Big fan of Apple, Love of colour.
Feel free to contact me.
反曲点科技创始人和首席执行官。
开发、设计与写作皆为所长。
热爱苹果、钟情色彩。
随时恭候 垂询