使用AVCaptureSession拍照、摄像、载图
原文链接 https://gaoxiaosong.github.io/2014/08/11/custom-avcapturesession.html
注:以下为加速网络访问所做的原文缓存,经过重新格式化,可能存在格式方面的问题,或偶有遗漏信息,请以原文为准。
概要示意图:
详细示意图:
1、建立Session
1.1 声明Session
AVCaptureSession *session = [[AVCaptureSession alloc] init];
// Add inputs and outputs.
[session startRunning];
1.2 设置采集的质量
if ([session canSetSessionPreset:AVCaptureSessionPreset1280x720]) {
session.sessionPreset = AVCaptureSessionPreset1280x720;
}
else {
// Handle the failure.
}
1.3 重新设置Session
[session beginConfiguration];
// Remove an existing capture device.
// Add a new capture device.
// Reset the preset.
[session commitConfiguration];
2、添加Input
2.1 配置一个Device(查找前后摄像头)
NSArray *devices = [AVCaptureDevice devices];
for (AVCaptureDevice *device in devices) {
NSLog(@"Device name: %@", [device localizedName]);
if ([device hasMediaType:AVMediaTypeVideo]) {
if ([device position] == AVCaptureDevicePositionBack) {
NSLog(@"Device position : back");
}
else {
NSLog(@"Device position : front");
}
}
}
2.2 设备的前后切换
AVCaptureSession *session = <#A capture session#>;
[session beginConfiguration];
[session removeInput:frontFacingCameraDeviceInput];
[session addInput:backFacingCameraDeviceInput];
[session commitConfiguration];
2.3 添加输入设备到当前Session
NSError *error;
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];
if (!input) {
// Handle the error appropriately.
}
AVCaptureSession *captureSession = <#Get a capture session#>;
AVCaptureDeviceInput *captureDeviceInput = <#Get a capture device input#>;
if ([captureSession canAddInput:captureDeviceInput]) {
[captureSession addInput:captureDeviceInput];
}
else {
// Handle the failure.
}
3、添加输出设备到Session
- AVCaptureMovieFileOutput:输出一个 视频文件。
- AVCaptureVideoDataOutput:可以采集数据从指定的视频中。
- AVCaptureAudioDataOutput:采集音频。
- AVCaptureStillImageOutput:采集静态图片。
3.1 添加一个Output到Session
AVCaptureSession *captureSession = <#Get a capture session#>;
AVCaptureMovieFileOutput *movieOutput = <#Create and configure a movie output#>;
if ([captureSession canAddOutput:movieOutput]) {
[captureSession addOutput:movieOutput];
}
else {
// Handle the failure.
}
3.2 保存视频到文件
3.2.1 声明一个输出
AVCaptureMovieFileOutput *aMovieFileOutput = [[AVCaptureMovieFileOutput alloc] init];
CMTime maxDuration = <#Create a CMTime to represent the maximum duration#>;
aMovieFileOutput.maxRecordedDuration = maxDuration;
aMovieFileOutput.minFreeDiskSpaceLimit = <#An appropriate minimum given the quality of the movie format and the duration#>;
3.2.2 配置写到指定的文件
AVCaptureMovieFileOutput *aMovieFileOutput = <#Get a movie file output#>;
NSURL *fileURL = <#A file URL that identifies the output location#>;
[aMovieFileOutput startRecordingToOutputFileURL:fileURL recordingDelegate:<#The delegate#>];
3.2.3 确定文件是否写成功
captureOutput:didFinishRecordingToOutputFileAtURL:fromConnections:error: 实现这个方法
(void)captureOutput:(AVCaptureFileOutput *)captureOutput
didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL
fromConnections:(NSArray *)connections
error:(NSError *)error {
BOOL recordedSuccessfully = YES;
if ([error code] != noErr) {
// A problem occurred: Find out if the recording was successful.
id value = [[error userInfo] objectForKey:AVErrorRecordingSuccessfullyFinishedKey];
if (value) {
recordedSuccessfully = [value boolValue];
}
}
// Continue as appropriate...
3.3 对采集载图
3.3.1 设置采集图片的像素格式
说实话下面这段的像素格式我也似懂非懂, 感觉是不是像素的对像素的质量会有一些影响
You can use the videoSettings property to specify a custom output format. The video settings property is a dictionary; currently, the only supported key is kCVPixelBufferPixelFormatTypeKey. The recommended pixel format choices for iPhone 4 are kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange or kCVPixelFormatType_32BGRA; for iPhone 3G the recommended pixel format choices are kCVPixelFormatType_422YpCbCr8 or kCVPixelFormatType_32BGRA. Both Core Graphics and OpenGL work well with the BGRA format:
// Create a VideoDataOutput and add it to the session
AVCaptureVideoDataOutput *output = [[[AVCaptureVideoDataOutput alloc] init] autorelease];
[session addOutput:output];
// Configure your output.
dispatch_queue_t queue = dispatch_queue_create("myQueue", NULL);
[output setSampleBufferDelegate:self queue:queue];
dispatch_release(queue);
// Specify the pixel format
output.videoSettings = [NSDictionary dictionaryWithObject: [NSNumber numberWithInt:kCVPixelFormatType_32BGRA] forKey:(id)kCVPixelBufferPixelFormatTypeKey];
3.3.2 采集静态图片
AVCaptureStillImageOutput这个类可以采集静态图片。
Pixel and Encoding Formats
Different devices support different image formats:
可以自己指定想要捕捉的格式,下面就可以指定捕捉一个JPEG的图片:
AVCaptureStillImageOutput *stillImageOutput = [[AVCaptureStillImageOutput alloc] init];
NSDictionary *outputSettings = @{ AVVideoCodecKey : AVVideoCodecJPEG};
[stillImageOutput setOutputSettings:outputSettings];
如果使用JPEG图片格式,就不应该再指定其它的压缩了,output会自动压缩,这个压缩会使用硬件加速。而我们要使用这个图片数据时。可以使用jpegStillImageNSDataRepresentation:这个方法来获取相应的NSData,这个方法不会做重复压缩的动作。
4、捕捉图片
当想捕捉图片的时候,给output发送一个captureStillImageAsynchronouslyFromConnection:completionHandler:消息。第一个参数是捕捉需要用到的连接,需要查找哪一个input设备的端口是收集视频的:
AVCaptureConnection *videoConnection = nil;
for (AVCaptureConnection *connection in stillImageOutput.connections) {
for (AVCaptureInputPort *port in [connection inputPorts]) {
if ([[port mediaType] isEqual:AVMediaTypeVideo]) {
videoConnection = connection;
break;
}
}
if (videoConnection) { break; }
}
第二个参数是一个block,返回的参数中imageSampleBuffer是一个CMSampleBuffer,包含了图像的数据。imageSampleBuffer中可能含有metadata,例如Exif dictionary,或者一个附件。
[stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler:
^(CMSampleBufferRef imageSampleBuffer, NSError *error) {
CFDictionaryRef exifAttachments =
CMGetAttachment(imageSampleBuffer, kCGImagePropertyExifDictionary, NULL);
if (exifAttachments) {
// Do something with the attachments.
}
// Continue as appropriate.
}];
5、为用户显示当前的录制状态
5.1 录制预览
AVCaptureSession *captureSession = <#Get a capture session#>;
CALayer *viewLayer = <#Get a layer from the view in which you want to present the preview#>;
AVCaptureVideoPreviewLayer *captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:captureSession];
[viewLayer addSublayer:captureVideoPreviewLayer];
Video Gravity Modes
The preview layer supports three gravity modes that you set using videoGravity:
- AVLayerVideoGravityResizeAspect: This preserves the aspect ratio, leaving black bars where the video does not fill the available screen area.
- AVLayerVideoGravityResizeAspectFill: This preserves the aspect ratio, but fills the available screen area, cropping the video when necessary.
- AVLayerVideoGravityResize: This simply stretches the video to fill the available screen area, even if doing so distorts the image.
6、结束捕捉
- (void)stopVideoCapture:(id)arg
{
// 停止摄像头捕抓
if (self->avCaptureSession) {
[self->avCaptureSession stopRunning];
self->avCaptureSession = nil;
[labelStatesetText:@"Video capture stopped"];
}
}