关于iOS调用摄像机来获取照片,通常我们都会调用UIImagePickerController来调用系统提供的相机来拍照,这个控件非常好 用。但是有时UIImagePickerController控件无法满足我们的需求,例如我们需要更加复杂的OverlayerView,这时候我们就 要自己构造一个摄像机控件了。

这需要使用AVFoundation.framework这个framework里面的组件了,所以我们先要导入这个头文件,另外还需要的组件官方文档是这么说的:

● An instance of AVCaptureDevice to represent the input device, such as a camera or microphone
● An instance of a concrete subclass of AVCaptureInput to configure the ports from the input device
● An instance of a concrete subclass of AVCaptureOutput to manage the output to a movie file or still image
● An instance of AVCaptureSession to coordinate the data flow from the input to the output

这里我只构造了一个具有拍照功能的照相机,至于录影和录音功能这里就不加说明了。

总结下来,我们需要以下的对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@property (nonatomic, strong)       AVCaptureSession            * session;
//AVCaptureSession对象来执行输入设备和输出设备之间的数据传递
@property (nonatomic, strong)       AVCaptureDeviceInput        * videoInput;
//AVCaptureDeviceInput对象是输入流
@property (nonatomic, strong)       AVCaptureStillImageOutput   * stillImageOutput;
//照片输出流对象,当然我的照相机只有拍照功能,所以只需要这个对象就够了
@property (nonatomic, strong)       AVCaptureVideoPreviewLayer  * previewLayer;
//预览图层,来显示照相机拍摄到的画面
@property (nonatomic, strong)       UIBarButtonItem             * toggleButton;
//切换前后镜头的按钮
@property (nonatomic, strong)       UIButton                    * shutterButton;
//拍照按钮
@property (nonatomic, strong)       UIView                      * cameraShowView;
//放置预览图层的View

我的习惯是在init方法执行的时候创建这些对象,然后在viewWillAppear方法里加载预览图层。现在就让我们看一下代码就清楚了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- (void) initialSession
{
    //这个方法的执行我放在init方法里了
    self.session = [[AVCaptureSession alloc] init];
    self.videoInput = [[AVCaptureDeviceInput alloc] initWithDevice:[self frontCamera] error:nil];
    //[self fronCamera]方法会返回一个AVCaptureDevice对象,因为我初始化时是采用前摄像头,所以这么写,具体的实现方法后面会介绍
    self.stillImageOutput = [[AVCaptureStillImageOutput alloc] init];
    NSDictionary * outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys:AVVideoCodecJPEG,AVVideoCodecKey, nil];
    //这是输出流的设置参数AVVideoCodecJPEG参数表示以JPEG的图片格式输出图片
    [self.stillImageOutput setOutputSettings:outputSettings];
     
    if ([self.session canAddInput:self.videoInput]) {
        [self.session addInput:self.videoInput];
    }
    if ([self.session canAddOutput:self.stillImageOutput]) {
        [self.session addOutput:self.stillImageOutput];
    }
     
}

这是获取前后摄像头对象的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- (AVCaptureDevice *)cameraWithPosition:(AVCaptureDevicePosition) position {
    NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
    for (AVCaptureDevice *device in devices) {
        if ([device position] == position) {
            return device;
        }
    }
    return nil;
}
 
 
- (AVCaptureDevice *)frontCamera {
    return [self cameraWithPosition:AVCaptureDevicePositionFront];
}
 
- (AVCaptureDevice *)backCamera {
    return [self cameraWithPosition:AVCaptureDevicePositionBack];
}

接下来在viewWillAppear方法里执行加载预览图层的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- (void) setUpCameraLayer
{
    if (_cameraAvaible == NO) return;
     
    if (self.previewLayer == nil) {
        self.previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.session];
        UIView * view = self.cameraShowView;
        CALayer * viewLayer = [view layer];
        [viewLayer setMasksToBounds:YES];
         
        CGRect bounds = [view bounds];
        [self.previewLayer setFrame:bounds];
        [self.previewLayer setVideoGravity:AVLayerVideoGravityResizeAspect];
         
        [viewLayer insertSublayer:self.previewLayer below:[[viewLayer sublayers] objectAtIndex:0]];
         
    }
}

注意以下的方法,在viewDidAppear和viewDidDisappear方法中启动和关闭session

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- (void) viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    if (self.session) {
        [self.session startRunning];
    }
}
 
- (void) viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear: animated];
    if (self.session) {
        [self.session stopRunning];
    }
}

接着我们就来实现切换前后镜头的按钮,按钮的创建我就不多说了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
- (void)toggleCamera {
    NSUInteger cameraCount = [[AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo] count];
    if (cameraCount > 1) {
        NSError *error;
        AVCaptureDeviceInput *newVideoInput;
        AVCaptureDevicePosition position = [[_videoInput 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.session beginConfiguration];
            [self.session removeInput:self.videoInput];
            if ([self.session canAddInput:newVideoInput]) {
                [self.session addInput:newVideoInput];
                [self setVideoInput:newVideoInput];
            } else {
                [self.session addInput:self.videoInput];
            }
            [self.session commitConfiguration];
        } else if (error) {
            NSLog(@"toggle carema failed, error = %@", error);
        }
    }
}

这是切换镜头的按钮方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- (void) shutterCamera
{
    AVCaptureConnection * videoConnection = [self.stillImageOutput connectionWithMediaType:AVMediaTypeVideo];
    if (!videoConnection) {
        NSLog(@"take photo failed!");
        return;
    }
     
    [self.stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
        if (imageDataSampleBuffer == NULL) {
            return;
        }
        NSData * imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
        UIImage * image = [UIImage imageWithData:imageData];
        NSLog(@"image size = %@",NSStringFromCGSize(image.size));
    }];
}

这是拍照按钮的方法

这样自定义照相机的简单功能就完成了,如果你想要再添加其他复杂的功能,可以参考一下下面这篇文章,希望对你们有所帮助。

http://course.gdou.com/blog/Blog.pzs/archive/2011/12/14/10882.html

最新文章

  1. [LeetCode] Walls and Gates 墙和门
  2. 给DOM生成的元素添加事件
  3. 浅谈大型web系统架构
  4. 使用Owin中间件搭建OAuth2.0认证授权服务器
  5. codeforces A. The Wall 解题报告
  6. spark streaming中使用checkpoint
  7. Beyond Compare
  8. 一些用于数据整理的excel函数
  9. IOS快速集成下拉上拉刷新
  10. 利用css3动画和border来实现圆形进度条
  11. jenkins 重新设置 管理员密码
  12. Apache + PHP in Windows XP (to add SQLite)
  13. mysql HA-keepalived
  14. PHP填补数字前后的0
  15. PHP全栈学习笔记12
  16. ASP.NET MVC权限控制思路
  17. mongodb聚合命令
  18. CentOS7+CDH5.14.0安装全流程记录,图文详解全程实测-6CM安装前环境检查
  19. Linux下怎样搜索文件
  20. numpy函数:[1]shape用法

热门文章

  1. 10.2(java学习笔记)JDBC事务简述
  2. js常用功能总结
  3. fidder模拟post提交到PHP遇到的问题
  4. XAMPP安装与多虚拟目录地址设置
  5. Session集中式管理
  6. 使用ab.exe监测100个并发/100次请求情况下同步/异步访问数据库的性能差异
  7. SpringMvc(注解)上传文件的简单例子
  8. 通过案例对SparkStreaming透彻理解三板斧之三
  9. vue2 router-link to
  10. Required MultipartFile parameter 'file' is not present error