0.AVCapture  <AVFoundation/AVFoundation.h>

媒体采集需要的几个对象:

1、AVCaptureDevice: 代表抽象的硬件设备(如前置摄像头,后置摄像头等)。

2、AVCaptureInput: 代表输入设备(可以是它的子类),它配置抽象硬件设备的ports。

3、AVCaptureOutput: 它代表输出数据,管理着输出到一个movie或者图像。

4、AVCaptureSession: 它是input和output的桥梁。它协调着input到output的数据传输。

关系:

有很多Device的input,也有很多数据类型的Output,都通过一个Capture Session来控制进行传输。也即:CaptureDevice适配AVCaptureInput,通过Session来输入到AVCaptureOutput中。这样也就达到了从设备到文件等持久化输入目的(如从相机设备采集图像到UIImage中)。

那么存在一个问题了:视频输入(input)就对应视频的输出(output),而音频输入就对应音频的输出,因而需要建立对应的Connections,来各自连接它们。而这样的连接对象,是由AVCaptureSession来持有的,这个对象叫AVCaptureConnection。

在一个AVCaptureConnection中,这里维持着对应的数据传输输入到数据输出的过程(detail过程)。这里,AVCaptureInput或其子类对象包含着各种input port,通过各种input port,我们的AVCaptureOutput可以获取相应的数据。

一个AVCaptureConnection可以控制input到output的数据传输。

1.Session及其使用模式

You use an instance to coordinate the flow of data from AV input devices to outputs. You add the capture devices and outputs you want to the session, then start data flow by sending the session a startRunning message, and stop recording by sending a stopRunning message.

AVCaptureSession *session = [AVCaptureSession alloc] init];

[session startRunning];

这里表明了,需要create一个session,然后发running消息给它,它会自动跑起来,把输入设备的东西,提交到输出设备中。

若想在一个已经使用上的session中(已经startRunning了)做更换新的device、删除旧的device等一系列的操作,那么就需要使用如下方法:

AVCaptureSession *session;

[session beginConfiguration];

// Remove an existing capture device.

// Add a new capture device.

// Reset the preset.

[session commitConfiguration];

当然,如果session的时候发生了异常,那么我们可以通过notification去observe相关的事件(可以在AVCaptureSession Class Reference中的Notifications中找到相应的情况),而session如果出现相应问题的时候,它会post出来,此时我们就可以处理了。

2.AVCaptureDevice,主要用来获取iPhone一些关于相机设备的属性。

InputDevice即是对硬件的抽象,一对一的。一个AVCaptureDevice对象,对应一个实际的硬件设备。

那么显然,我们可以通过AVCaptureDevice的类方法devices或devicesWithMediaType去获取全部或局部设备列表。(当然也可以检测相应的设备是否可以使用,这里注意有设备抢占问题,当前是否可用)

相机设备可以用下面的方法判断设备是否支持相关属性(property),比如对焦方式或者对焦状态Focus modes。

[currentDevice isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus];

1. 前置和后置摄像头

enum {

AVCaptureDevicePositionBack = 1,

AVCaptureDevicePositionFront = 2

};

typedef NSInteger AVCaptureDevicePosition;

2. 闪光灯开关

enum {

AVCaptureFlashModeOff = 0,

AVCaptureFlashModeOn = 1,

AVCaptureFlashModeAuto = 2

};

typedef NSInteger AVCaptureFlashMode;

3. 手电筒开关

enum {

AVCaptureTorchModelOff = 0,

AVCaptureTorchModelOn = 1,

AVCaptureTorchModeAuto = 2

};

typedef NSInteger AVCaptureTorchMode;

4. 焦距调整

enum {

AVCaptureFocusModelLocked = 0,

AVCaptureFocusModeAutoFocus = 1,

AVCaptureFocusModeContinousAutoFocus = 2

};

typedef NSInteger AVCaptureFocusMode;

5. 曝光量调节

enum {

AVCaptureExposureModeLocked = 0,

AVCaptureExposureModeAutoExpose = 1,

AVCaptureExposureModeContinuousAutoExposure = 2

};

typedef NSInteger AVCaptureExposureMode;

6. 白平衡

enum {

AVCaptureWhiteBalanceModeLocked = 0,

AVCaptureWhiteBalanceModeAutoWhiteBalance = 1,

AVCaptureWhiteBalanceModeContinuousAutoWhiteBalance = 2

};

typedef NSInteger AVCaptureWhiteBalanceMode;

3. CaptureInput的构建和添加到Session中的方法

创建并配置输入设备

AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

NSError *error = nil;

AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];

// 添加input到session的模式是(检查可否添加到session,然后根据情况添加或者不添加)

AVCaptureSession *captureSession = <#Get a capture session#>;

if ([captureSession canAddInput:input]) {

[captureSession addInput:input];

}

4.output的分类和使用

在ios中,分为MovieFile、VideoData、AudioData和StillImage几种output,使用方式类似,只是范围不同。另外,它们都继承于AVCaptureOutput。

第一个是输出成movie文件,第二个适用于逐个Frame的处理,第三个适用于声音采集,第四个是still image(静态图像<拍照>)相关。

他们的添加方式都是使用session的addOutput方法。

5.AVCaptureStillImageOutput 照片输出流对象

6. AVCaptureVideoPreviewLayer 预览图层,来显示照相机拍摄到的画面

#import "ViewController.h"

#import <AVFoundation/AVFoundation.h>

@interface ViewController ()

{

}

// AVCaptureSession对象来执行输入设备和输出设备之间的数据传递

@property (nonatomic, strong)AVCaptureSession *session;

// AVCaptureDeviceInput对象是输入流

@property (nonatomic, strong)AVCaptureDeviceInput *videoInput;

// 照片输出流对象

@property (nonatomic, strong)AVCaptureStillImageOutput *stillImageOutput;

// 预览图层,来显示照相机拍摄到的画面

@property (nonatomic, strong)AVCaptureVideoPreviewLayer *previewLayer;

// 切换前后镜头的按钮

@property (nonatomic, strong)UIButton *toggleButton;

// 拍照按钮

@property (nonatomic, strong)UIButton *shutterButton;

// 放置预览图层的View

@property (nonatomic, strong)UIView *cameraShowView;

// 用来展示拍照获取的照片

@property (nonatomic, strong)UIImageView *imageShowView;

@end

@implementation ViewController

- (id)init

{

self = [super init];

if (self) {

[self initialSession];

[self initCameraShowView];

[self initImageShowView];

[self initButton];

}

return self;

}

- (void)initialSession

{

self.session = [[AVCaptureSession alloc] init];

self.videoInput = [[AVCaptureDeviceInput alloc] initWithDevice:[self backCamera] error:nil];

self.stillImageOutput = [[AVCaptureStillImageOutput alloc] init];

// 这是输出流的设置参数AVVideoCodecJPEG参数表示以JPEG的图片格式输出图片

NSDictionary *outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys:AVVideoCodecJPEG,AVVideoCodecKey, nil];

[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];

}

}

- (void)initCameraShowView

{

self.cameraShowView = [[UIView alloc] initWithFrame:self.view.frame];

[self.view addSubview:self.cameraShowView];

}

- (void)initImageShowView

{

self.imageShowView = [[UIImageView alloc] initWithFrame:CGRectMake(0, self.view.frame.size.height -200, 200, 200)];

self.imageShowView.contentMode = UIViewContentModeScaleToFill;

self.imageShowView.backgroundColor = [UIColor whiteColor];

[self.view addSubview:self.imageShowView];

}

- (void)initButton

{

self.shutterButton = [UIButton buttonWithType:UIButtonTypeSystem];

self.shutterButton.frame = CGRectMake(10, 30, 60, 30);

self.shutterButton.backgroundColor = [UIColor cyanColor];

[self.shutterButton setTitle:@"拍照" forState:UIControlStateNormal];

[self.shutterButton addTarget:self action:@selector(shutterCamera)forControlEvents:UIControlEventTouchUpInside];

[self.view addSubview:self.shutterButton];

self.toggleButton = [UIButton buttonWithType:UIButtonTypeSystem];

self.toggleButton.frame = CGRectMake(80, 30, 60, 30);

self.toggleButton.backgroundColor = [UIColor cyanColor];

[self.toggleButton setTitle:@"切换摄像头" forState:UIControlStateNormal];

[self.toggleButton addTarget:self action:@selector(toggleCamera)forControlEvents:UIControlEventTouchUpInside];

[self.view addSubview:self.toggleButton];

}

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

- (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];

}

- (void)viewDidLoad {

[super viewDidLoad];

// Do any additional setup after loading the view, typically from a nib.

}

- (void)viewWillAppear:(BOOL)animated

{

[super viewWillAppear:animated];

[self setUpCameraLayer];

}

- (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];

}

}

- (void)setUpCameraLayer

{

if (self.previewLayer == nil) {

self.previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.session];

UIView * view = self.cameraShowView;

CALayer * viewLayer = [view layer];

// UIView的clipsToBounds属性和CALayer的setMasksToBounds属性表达的意思是一致的,决定子视图的显示范围。当取值为YES的时候,剪裁超出父视图范围的子视图部分,当取值为NO时,不剪裁子视图。

[viewLayer setMasksToBounds:YES];

CGRect bounds = [view bounds];

[self.previewLayer setFrame:bounds];

[self.previewLayer setVideoGravity:AVLayerVideoGravityResizeAspect];

[viewLayer addSublayer:self.previewLayer];

}

}

// 这是拍照按钮的方法

- (void)shutterCamera

{

AVCaptureConnection *videoConnection = [self.stillImageOutputconnectionWithMediaType:AVMediaTypeVideo];

if (!videoConnection) {

return;

}

[self.stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnectioncompletionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {

if (imageDataSampleBuffer == NULL) {

return;

}

NSData *imageData = [AVCaptureStillImageOutputjpegStillImageNSDataRepresentation:imageDataSampleBuffer];

UIImage *image = [UIImage imageWithData:imageData];

NSLog(@"image size = %@", NSStringFromCGSize(image.size));

self.imageShowView.image = image;

}];

}

// 这是切换镜头的按钮方法

- (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.videoInput = newVideoInput;

} else {

[self.session addInput:self.videoInput];

}

[self.session commitConfiguration];

} else if (error) {

NSLog(@"toggle carema failed, error = %@", error);

}

}

}

- (void)didReceiveMemoryWarning {

[super didReceiveMemoryWarning];

// Dispose of any resources that can be recreated.

}

@end

AVFoundation自定义拍照的更多相关文章

  1. 用AVFoundation自定义相机拍照

    自定义拍照或者录视频的功能,就需要用到AVFoundation框架,目前我只用到了拍照,所以记录下自定义拍照用法,视频用法等用上了再补充,应该是大同小异 demo在这里:https://github. ...

  2. iOS开发--AVFoundation自定义相机

    首先导入一个头文件 #import <AVFoundation/AVFoundation.h> 由于后面我们需要将拍摄好的照片写入系统相册中,所以我们在这里还需要导入一个相册需要的头文件 ...

  3. 摄像头(4)用Camera和SurfaceView自定义拍照程序

    定制拍照程序的基本步骤 1,打开照相机:Camera.open 这是独占方式打开的 2,创建SurfaceView对象 多缓冲,多线程view 3,添加回调事件监听器(SurfaceHolder.ad ...

  4. android自定义拍照

    调用系统相机,然后在自己的surfaceview上预览,拍照,不废话,直接上源码 package com.example.customecamera; import java.io.File; imp ...

  5. AVFoundation自定义录制视频

    #import <AVFoundation/AVFoundation.h> #import <AssetsLibrary/AssetsLibrary.h> @interface ...

  6. iOS自定义拍照框拍照&裁剪(一)

    卡片机时代 很重要的一点是,相机本身是没有方向概念的,它不理解拍摄的内容,只会以相机自己的坐标系去保存数据,下图展示了相机对"F"进行四个角度拍摄时返回的图片数据. 最初的卡片机时 ...

  7. AVFoundation-视频录制以及拍照

    一般如果UI和UE在设计时只要求功能,对相机界面没什么要求的话,个人觉得调用系统相机(UIImagePickerController)就可以满足我们的需求比如照相或者录制视频,但是考虑界面美观性,有时 ...

  8. iOS开发笔记17:自定义相机拍照

    之前用AVFoundation自定义相机做了拍照与视频相关的东西,为什么要自定义呢?主要是提供更个性化的交互设计,符合app主题,对于视频来说,也便于提供更多丰富有趣的功能.前段时间整理了下拍照部分的 ...

  9. Android—实现自定义相机倒计时拍照

    这篇博客为大家介绍Android自定义相机,并且实现倒计时拍照功能 首先自定义拍照会用到SurfaceView控件显示照片的预览区域,以下是布局文件: 两个TextView是用来显示提示信息和倒计时的 ...

随机推荐

  1. C# winform项目中ListView控件使用CheckBoxes属性实现单选功能

    C# winform项目中ListView控件使用CheckBoxes属性实现单选功能 在做项目时需要使用ListView控件的CheckBoxes属性显示,还要在点击行时自动选中CheckBoxes ...

  2. eclipse中的Java项目导出成为一个可以直接双击运行的jar文件

    1. 选择要到处JAR文件的工程,右键选择“Export” 2. 选择“Java-->Runnable JAR file”,点击“Next”: 3. 在“Launch configuration ...

  3. 利用 UltraEdit 重新排版 XML 结构数据

    我们在工作常碰到这种情况,通讯数据或文件数据是以 XML 结构形式保存的,但通常 XML 结构比较混乱,不易分析.现在我们利用 UltraEdit32对该类型数据做 Reformat,具体操作如下: ...

  4. 说说 bash 的 if 语句

    说说 bash 的 if 语句 在开始先给大家列出几个术语,不做解释,不懂的可以参考其它资料. 术语和符号: 退出状态码 $? [...] (中括号,方括号) [[...]] (双中括号,双方括号) ...

  5. python3 UnicodeEncodeError: 'gbk' codec can't encode character '\uff70' in position 75267: illegal multibyte sequence

    当你爬出想要的数据了,却发现中文是乱码的时候?请你计算下你内心的阴影面积 ! 菊个栗子: #!/usr/bin/env python3# -*- coding: utf-8 -*-import ioi ...

  6. 安卓作为udp服务器,PC作为客户端,仅监听

    安卓客户端作为udp服务器,监听其他客户端的数据,测试已成功 本次实验所用数据: 安卓作为服务器: 端口:8888            IP:192.168.1.104 电脑作为客户端: 端口:50 ...

  7. java 文件操作 读取字节级数据(读取)

    package com.swust; import java.io.*; /* * 功能:按照双精度浮点型.整型.布尔型.字符型.和字符串型的顺序从名为sample.dat文件读取数据 * 分析:用F ...

  8. 使用T4模板生成POCO类

    为什么叫T4?因为简写为4个T. T4(Text Template Transformation Toolkit)是微软官方在VisualStudio 2008中开始使用的代码生成引擎.在 Visua ...

  9. JS打开摄像头并截图上传

    直入正题,JS打开摄像头并截图上传至后端的一个完整步骤 1. 打开摄像头主要用到getUserMedia方法,然后将获取到的媒体流置入video标签 2. 截取图片主要用到canvas绘图,使用dra ...

  10. UE4 RHI与Render模块简解

    UE4中的RHI指的是Render hardware interface,作用像Ogre里的RenderSystem,针对Dx11,Dx12,Opengl等等平台抽象出相同的接口,我们能方便能使用相同 ...