iOS视频流采集概述(AVCaptureSession)

需求:须要采集到视频帧数据从而能够进行一系列处理(如: 裁剪,旋转,美颜,特效....). 因此,必须采集到视频帧数据.


阅读前提:

  • 使用AVFoundation框架
  • 采集音视频帧数据

GitHub地址(附代码) : iOS视频流采集概述

简书地址 : iOS视频流采集概述

博客地址 : iOS视频流采集概述

掘金地址 : iOS视频流采集概述


注意:本文仅仅是原理性讲解,而实际相机的设置也是比较复杂,具体相机参数的设置请参考另外一篇 - iOS相机设置实战


Overview

AVCaptureSession:使用相机或麦克风实时采集音视频数据流.git

  • AVCaptureSession : 管理输入输出音视频流github

  • AVCaptureDevice : 相机硬件的接口,用于控制硬件特性,诸如镜头的位置(先后摄像头)、曝光、闪光灯等。算法

  • AVCaptureInput : 配置输入设备,提供来自设备的数据bash

  • AVCaptureOutput : 管理输出的结果(音视频数据流)session

  • AVCaptureConnection: 表示输入与输出的链接app

  • AVCaptureVideoPreviewLayer: 显示当前相机正在采集的情况框架

一个session能够配置多个输入输出async

1.AVCaptureSession

下图展现了向session中添加输入输出后的链接状况ide

2.AVCaptureConnection

受权

首先须要在Info.plist文件中添加键Privacy - Camera Usage Description以请求相机权限.post

注意: 若是不添加,程序crash,若是用户不给权限,则会显示全黑的相机画面.

1. 使用Capture Session管理数据流

AVCaptureSession *session = [[AVCaptureSession alloc] init];
// Add inputs and outputs.
[session startRunning];

复制代码

1.1. 使用preset配置分辨率,帧率

  • canSetSessionPreset:检查是否支持指定分辨率
  • setActiveVideoMinFrameDuration: 设置帧率最小值
  • setActiveVideoMaxFrameDuration: 设置帧率最大值

CMTimeMake: 分子为1,即每秒钟来多少帧.

  • 在低帧率下(帧率<=30)能够用以下方式设置
- (void)setCameraResolutionByPresetWithHeight:(int)height session:(AVCaptureSession *)session {
    [session beginConfiguration];
    session.sessionPreset = preset;
    [session commitConfiguration];
}

- (void)setCameraForLFRWithFrameRate:(int)frameRate {
    // Only for frame rate <= 30
    AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    [captureDevice lockForConfiguration:NULL];
    [captureDevice setActiveVideoMinFrameDuration:CMTimeMake(1, frameRate)];
    [captureDevice setActiveVideoMaxFrameDuration:CMTimeMake(1, frameRate)];
    [captureDevice unlockForConfiguration];
}
复制代码
  • 高帧率下设置分辨率(帧率>30)

若是须要对某一分辨率支持高帧率的设置,如50帧,60帧,120帧...,原先setActiveVideoMinFrameDurationsetActiveVideoMaxFrameDuration是没法作到的,Apple规定咱们须要使用新的方法设置帧率setActiveVideoMinFrameDurationsetActiveVideoMaxFrameDuration,而且该方法必须配合新的设置分辨率activeFormat的方法一块儿使用.

新的设置分辨率的方法activeFormatsessionPreset是互斥的,若是使用了一个, 另外一个会失效,建议直接使用高帧率的设置方法,废弃低帧率下设置方法,避免产生兼容问题。

Apple在更新方法后将原先分离的分辨率与帧率的设置方法合二为一,原先是单独设置相机分辨率与帧率,而如今则须要一块儿设置,即每一个分辨率有其对应支持的帧率范围,每一个帧率也有其支持的分辨率,须要咱们遍从来查询,因此原先统一的单独的设置分辨率与帧率的方法在高帧率模式下至关于弃用,能够根据项目需求选择,若是肯定项目不会支持高帧率(fps>30),可使用之前的方法,简单且有效.

注意: 使用activeFormat方法后,以前使用sessionPreset方法设置的分辨率将自动变为AVCaptureSessionPresetInputPriority,因此若是项目以前有用canSetSessionPreset比较的if语句也都将失效,建议若是项目必须支持高帧率则完全启用sessionPreset方法.

具体设置方法参考另外一篇文章:iOS相机设置实战

注意: 在将session配置为使用用于高分辨率静态拍摄的活动格式并将如下一个或多个操做应用于AVCaptureVideoDataOutput时,系统可能没法知足目标帧速率:缩放,方向更改,格式转换。

1.2. 更改相机设置

若是你须要在开启相机后进一步调节相机参数,在beginConfigurationcommitConfiguration中写入更改的代码.调用beginConfiguration后能够添加移除输入输出,更改分辨率,配置个别的输入输出属性,直到调用commitConfiguration全部的更改才会生效.

[session beginConfiguration];
// Remove an existing capture device.
// Add a new capture device.
// Reset the preset.
[session commitConfiguration];



复制代码

1.3. 监听Session状态

可使用通知监听相机当前状态,如开始,中止,意外中断等等...

  • 监听掉帧
- (void)captureOutput:(AVCaptureOutput *)output didDropSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
复制代码
  • 处理相机运行中忽然出错
[kTVUNotification addObserver:self selector:@selector(handleCameraRuntimeError)
                         name:AVCaptureSessionRuntimeErrorNotification
                       object:nil];
[kTVUNotification addObserver:self selector:@selector(handleCameraInterruptionEndedError)
                         name:AVCaptureSessionInterruptionEndedNotification
                       object:nil];
[kTVUNotification addObserver:self selector:@selector(handleCameraWasInterruptedError)
                         name:AVCaptureSessionWasInterruptedNotification
                       object:nil];
复制代码

2. AVCaptureDevice表示输入设备

2.1. 定义

AVCaptureDevice对象是关于相机硬件的接口,用于控制硬件特性,诸如镜头的位置、曝光、闪光灯等。

2.2. 获取设备

使用AVCaptureDevice的devicesdevicesWithMediaType:方法能够找到咱们须要的设备, 可用设备列表可能会发生变化, 如它们被别的应用使用,或一个新的输入设备接入(如耳机),经过注册AVCaptureDeviceWasConnectedNotification,AVCaptureDeviceWasDisconnectedNotification能够在设备变化时获得通知.

2.3. 设备特性

能够经过代码获取当前输入设备的位置(先后置摄像头)以及其余硬件相关信息.

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.4. 相机功能设置

不一样设备具备不一样的功能,若是须要能够开启对应的功能

NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
NSMutableArray *torchDevices = [[NSMutableArray alloc] init];
 
for (AVCaptureDevice *device in devices) {
    [if ([device hasTorch] &&
         [device supportsAVCaptureSessionPreset:AVCaptureSessionPreset640x480]) {
        [torchDevices addObject:device];
    }
}
复制代码

注意:在设置相机属性前,老是先经过API查询当前设备是否支持该功能,再进行相应处理

  • 聚焦模式-Focus Modes
    • AVCaptureFocusModeLocked: 设置一个固定的聚焦点
    • AVCaptureFocusModeAutoFocus: 首次自动对焦而后锁定一个聚焦点
    • AVCaptureFocusModeContinuousAutoFocus: 指当场景改变,相机会自动从新对焦到画面的中心点
isFocusModeSupported: 查询设备是否支持.
adjustingFocus: 判断一个设备是否正在改变对焦点
复制代码

使用focusPointOfInterestSupported测试设备是否支持设置对焦点,若是支持,使用focusPointOfInterest设置聚焦点,{0,0}表明画面左上角坐标,{1,1}表明右下角坐标.

if ([currentDevice isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus]) {
    CGPoint autofocusPoint = CGPointMake(0.5f, 0.5f);
    [currentDevice setFocusPointOfInterest:autofocusPoint];
    [currentDevice setFocusMode:AVCaptureFocusModeContinuousAutoFocus];
}

复制代码
  • 曝光模式-Exposure Modes
    • AVCaptureExposureModeContinuousAutoExposure: 自动调节曝光模式
    • AVCaptureExposureModeLocked: 固定的曝光模式
isExposureModeSupported:是否支持某个曝光模式
adjustingExposure:判断一个设备是否正在改变曝光值
复制代码
if ([currentDevice isExposureModeSupported:AVCaptureExposureModeContinuousAutoExposure]) {
    CGPoint exposurePoint = CGPointMake(0.5f, 0.5f);
    [currentDevice setExposurePointOfInterest:exposurePoint];
    [currentDevice setExposureMode:AVCaptureExposureModeContinuousAutoExposure];
}

复制代码
  • 闪光灯模式-Flash Modes
    • AVCaptureFlashModeOff: 永不开启
    • AVCaptureFlashModeOn: 老是开启
    • AVCaptureFlashModeAuto: 自动开启,根据光线判断
hasFlash:是否有闪光灯
isFlashModeSupported:是否支持闪光灯模式
复制代码
  • 手电筒模式-Torch Mode
    • AVCaptureTorchModeOff
    • AVCaptureTorchModeOn
    • AVCaptureTorchModeAuto
hasTorch: 是否有手电筒
isTorchModeSupported: 是否支持手电筒模式
复制代码

手电筒只有在相机开启时才能打开

  • 视频稳定性-Video Stabilization
    • videoStabilizationEnabled
    • enablesVideoStabilizationWhenAvailable

该功能默认是关闭的,画面稳定功能依赖于设备特定的硬件,而且不是全部格式的元数据与分辨率都支持此功能.

开启该功能可能形成画面延迟

  • 白平衡-White Balance
    • AVCaptureWhiteBalanceModeLocked
    • AVCaptureWhiteBalanceModeContinuousAutoWhiteBalance
isWhiteBalanceModeSupported: 是否支持白平衡模式
adjustingWhiteBalance: 是否正在调整白平衡
复制代码

相机为了适应不一样类型的光照条件须要补偿。这意味着在冷光线的条件下,传感器应该加强红色部分,而在暖光线下加强蓝色部分。在 iPhone 相机中,设备会自动决定合适的补光,但有时也会被场景的颜色所混淆失效。幸运地是,iOS 8 能够里手动控制白平衡。

自动模式工做方式和对焦、曝光的方式同样,可是没有“感兴趣的点”,整张图像都会被归入考虑范围。在手动模式,咱们能够经过开尔文所表示的温度来调节色温和色彩。典型的色温值在 2000-3000K (相似蜡烛或灯泡的暖光源) 到 8000K (纯净的蓝色天空) 之间。色彩范围从最小的 -150 (偏绿) 到 150 (偏品红)。

  • 设置设备方向
    • AVCaptureConnectionsupportsVideoOrientation:
AVCaptureConnection *captureConnection = <#A capture connection#>;
if ([captureConnection isVideoOrientationSupported])
{
    AVCaptureVideoOrientation orientation = AVCaptureVideoOrientationLandscapeLeft;
    [captureConnection setVideoOrientation:orientation];
}
复制代码
  • 配置设备

使用锁配置相机属性,lockForConfiguration:,为了不在你修改它时其余应用程序可能对它作更改.

if ([device isFocusModeSupported:AVCaptureFocusModeLocked]) {
    NSError *error = nil;
    if ([device lockForConfiguration:&error]) {
        device.focusMode = AVCaptureFocusModeLocked;
        [device unlockForConfiguration];
    }
    else {
        // Respond to the failure as appropriate.
复制代码
  • 切换设备
AVCaptureSession *session = <#A capture session#>;
[session beginConfiguration];
 
[session removeInput:frontFacingCameraDeviceInput];
[session addInput:backFacingCameraDeviceInput];
 
[session commitConfiguration];
复制代码

3. 配置Capture Inputs添加到Session中

一个AVCaptureInput表明一种或多种媒体数据,好比,输入设备能够同时提供视频和音频数据.每种媒体流表明一个AVCaptureInputPort对象.使用AVCaptureConnection能够将AVCaptureInputPort与AVCaptureOutput链接起来.

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.
}


复制代码

4. 使用Capture Outputs从Session中获取输出流

AVCaptureOutput: 从session中获取输出流.

  • AVCaptureMovieFileOutput: 将数据写入文件
  • AVCaptureVideoDataOutput: 将视频数据以回调形式输出视频帧
  • AVCaptureAudioDataOutput: 将音频数据以回调形式输出音频帧
  • AVCaptureStillImageOutput: 捕捉静态图片
addOutput: 添加输出
canAddOutput: 是否能添加

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.
}

复制代码

4.1. AVCaptureMovieFileOutput

4.1.1. 写入文件

AVCaptureMovieFileOutput: 使用此类做为输出.能够配置录制最长时间,文件大小以及禁止在磁盘空间不足时继续录制等等.

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#>;
复制代码
4.1.2. 开始录制

你须要提供一个文件保存地址的URL以及代理去监听状态,这个代理是AVCaptureFileOutputRecordingDelegate, 必须实现captureOutput:didFinishRecordingToOutputFileAtURL:fromConnections:error:代理方法

URL不能是已经存在的文件,由于没法重写.

AVCaptureMovieFileOutput *aMovieFileOutput = <#Get a movie file output#>;
NSURL *fileURL = <#A file URL that identifies the output location#>;
[aMovieFileOutput startRecordingToOutputFileURL:fileURL recordingDelegate:<#The delegate#>];
复制代码
4.1.3. 确保文件写入成功

经过代理方法能够检查是否写入成功

须要检查AVErrorRecordingSuccessfullyFinishedKey的值,由于可能写入没有错误,但因为磁盘内存不足致使最终写入失败.

写入失败的缘由

  • 磁盘内存不足(AVErrorDiskFull)
  • 录制设备失去链接(AVErrorDeviceWasDisconnected)
  • session意外中断(AVErrorSessionWasInterrupted)
- (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...
复制代码
4.1.4. 添加Metadata到文件

能够在任意时间设置输出文件的metadata信息,即便正在录制.

AVCaptureMovieFileOutput *aMovieFileOutput = <#Get a movie file output#>;
NSArray *existingMetadataArray = aMovieFileOutput.metadata;
NSMutableArray *newMetadataArray = nil;
if (existingMetadataArray) {
    newMetadataArray = [existingMetadataArray mutableCopy];
}
else {
    newMetadataArray = [[NSMutableArray alloc] init];
}
 
AVMutableMetadataItem *item = [[AVMutableMetadataItem alloc] init];
item.keySpace = AVMetadataKeySpaceCommon;
item.key = AVMetadataCommonKeyLocation;
 
CLLocation *location - <#The location to set#>;
item.value = [NSString stringWithFormat:@"%+08.4lf%+09.4lf/"
    location.coordinate.latitude, location.coordinate.longitude];
 
[newMetadataArray addObject:item];
 
aMovieFileOutput.metadata = newMetadataArray;

复制代码

4.2 AVCaptureVideoDataOutput

4.2.1. 获取视频帧数据

AVCaptureVideoDataOutput对象能够经过代理(setSampleBufferDelegate:queue:)获取实时的视频帧数据.同时须要指定一个接受视频帧的串行队列.

必须使用串行队列,由于要保证视频帧是按顺序传输给代理方法

captureOutput:didOutputSampleBuffer:fromConnection:代理方法中接受视频帧,每一个视频帧被存放在CMSampleBufferRef引用对象中, 默认这些buffers以相机最有效的格式发出,咱们也能够经过videoSettings指定输出相机的格式.须要将要指定的格式设置为kCVPixelBufferPixelFormatTypeKey的value,使用availableVideoCodecTypes能够查询当前支持的相机格式.

AVCaptureVideoDataOutput *videoDataOutput = [AVCaptureVideoDataOutput new];
NSDictionary *newSettings =
                @{ (NSString *)kCVPixelBufferPixelFormatTypeKey : @(kCVPixelFormatType_32BGRA) };
videoDataOutput.videoSettings = newSettings;
 
 // discard if the data output queue is blocked (as we process the still image
[videoDataOutput setAlwaysDiscardsLateVideoFrames:YES];)
 
// create a serial dispatch queue used for the sample buffer delegate as well as when a still image is captured
// a serial dispatch queue must be used to guarantee that video frames will be delivered in order
// see the header doc for setSampleBufferDelegate:queue: for more information
videoDataOutputQueue = dispatch_queue_create("VideoDataOutputQueue", DISPATCH_QUEUE_SERIAL);
[videoDataOutput setSampleBufferDelegate:self queue:videoDataOutputQueue];
 
AVCaptureSession *captureSession = <#The Capture Session#>;
 
if ( [captureSession canAddOutput:videoDataOutput] )
     [captureSession addOutput:videoDataOutput];
 

复制代码
4.3. AVCaptureStillImageOutput

若是要使用附带metadata元数据的静止图像,须要使用AVCaptureStillImageOutput.

  • 像素与编码格式

使用availableImageDataCVPixelFormatTypes, availableImageDataCodecTypes获取当前支持的格式,以便于查询是否支持你想要设置的格式.

AVCaptureStillImageOutput *stillImageOutput = [[AVCaptureStillImageOutput alloc] init];
NSDictionary *outputSettings = @{ AVVideoCodecKey : AVVideoCodecJPEG};
[stillImageOutput setOutputSettings:outputSettings];
复制代码
  • 采集图像

向output发送一条captureStillImageAsynchronouslyFromConnection:completionHandler:消息以采集一张图像.

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; }
}

[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. 展现预览图

若是相机的session已经开始工做,咱们能够为用户建立一个预览图展现当前相机采集的情况(即就像系统相机拍摄视频时的预览界面)

5.1. Video Preview

  • AVCaptureVideoPreviewLayer: 展现相机预览状况,CALayer的子类.
  • 使用AVCaptureVideoDataOutput能够将像素层呈现给用户

a video preview layer保持对它关联session的强引用,为了确保在图层尝试显示视频时不会被释放

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];
复制代码

preview layer是CALayer的子类,所以它具备CALayer的行为,你能够对这一图层执行转换,旋转等操做.

5.1.1. 视频重力感应模式
  • AVLayerVideoGravityResizeAspect: 保持分辨率的原始尺寸,即横纵比,未填充的屏幕区域会有黑条
  • AVLayerVideoGravityResizeAspectFill: 保持横纵比,铺满屏幕时能够牺牲部分像素
  • AVLayerVideoGravityResize: 拉伸视频以充满屏幕,图像会失真
5.1.2. 点击聚焦

实现带有预览层的对焦时,必须考虑预览层的预览方向和重力以及镜像预览的可能性.

5.2. 显示Audio Levels

注意:通常采集音频不使用AVCaptureSession, 而是用更底层的AudioQueue, AudioUnit, 如需帮助请参考另外一篇文章: 音频采集

使用AVCaptureAudioChannel对象监视捕获链接中音频通道的平均功率和峰值功率级别.音频级不支持KVO,所以必须常常轮询更新级别,以便更新用户界面(例如,每秒10次)。

AVCaptureAudioDataOutput *audioDataOutput = <#Get the audio data output#>;
NSArray *connections = audioDataOutput.connections;
if ([connections count] > 0) {
    // There should be only one connection to an AVCaptureAudioDataOutput.
    AVCaptureConnection *connection = [connections objectAtIndex:0];
 
    NSArray *audioChannels = connection.audioChannels;
 
    for (AVCaptureAudioChannel *channel in audioChannels) {
        float avg = channel.averagePowerLevel;
        float peak = channel.peakHoldLevel;
        // Update the level meter user interface.
    }
}

复制代码

6. 总结

下面将介绍如何采集视频帧并将其转换为UIImage对象.

6.1. 流程

  • 建立AVCaptureSession对象管理输入输出流
  • 建立AVCaptureDevice对象管理当前硬件支持的全部设备,能够遍历找到咱们须要的设备
  • 建立AVCaptureDeviceInput对象表示具体的的输入端的硬件设备
  • 建立AVCaptureVideoDataOutput对象管理输出视频帧
  • 实现AVCaptureVideoDataOutput代理方法以产生视频帧
  • 将视频帧从CMSampleBuffer格式转为UIImage格式

下面是简单流程实现

  • 建立并配置session对象
AVCaptureSession *session = [[AVCaptureSession alloc] init];
session.sessionPreset = AVCaptureSessionPresetMedium;

复制代码
  • 建立并配置设备的输入端
AVCaptureDevice *device =
        [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
 
NSError *error = nil;
AVCaptureDeviceInput *input =
        [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];
if (!input) {
    // Handle the error appropriately.
}
[session addInput:input];

复制代码
  • 建立并配置输出端

经过配置AVCaptureVideoDataOutput对象(如视频帧的格式, 帧率),以产生未压缩的原始数据.

AVCaptureVideoDataOutput *output = [[AVCaptureVideoDataOutput alloc] init];
[session addOutput:output];
output.videoSettings =
                @{ (NSString *)kCVPixelBufferPixelFormatTypeKey : @(kCVPixelFormatType_32BGRA) };
output.minFrameDuration = CMTimeMake(1, 15);

dispatch_queue_t queue = dispatch_queue_create("MyQueue", NULL);
[output setSampleBufferDelegate:self queue:queue];
dispatch_release(queue);

复制代码
  • 实现代理方法
- (void)captureOutput:(AVCaptureOutput *)captureOutput
         didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
         fromConnection:(AVCaptureConnection *)connection {
 
    UIImage *image = imageFromSampleBuffer(sampleBuffer);
    // Add your code here that uses the image.
}
复制代码
  • 开始/中止录制

配置完capture session以后,确保应用程序拥有权限.

NSString *mediaType = AVMediaTypeVideo;
 
[AVCaptureDevice requestAccessForMediaType:mediaType completionHandler:^(BOOL granted) {
    if (granted)
    {
        //Granted access to mediaType
        [self setDeviceAuthorized:YES];
    }
    else
    {
        //Not granted access to mediaType
        dispatch_async(dispatch_get_main_queue(), ^{
        [[[UIAlertView alloc] initWithTitle:@"AVCam!"
                                    message:@"AVCam doesn't have permission to use Camera, please change privacy settings"
                                   delegate:self
                          cancelButtonTitle:@"OK"
                          otherButtonTitles:nil] show];
                [self setDeviceAuthorized:NO];
        });
    }
}];

[session startRunning];
[session stopRunning];
复制代码

注意: startRunning是一个同步的方法,它可能会花一些时间,所以可能阻塞线程(能够在同步队列中执行避免主线程阻塞).

7. 补充

iOS7.0 介绍了高帧率视频采集,咱们须要使用AVCaptureDeviceFormat类,该类具备返回支持的图像类型,帧率,缩放比例,是否支持稳定性等等.

  • 支持720p, 60帧,同时保证视频稳定性
  • 兼容音频的倍速播放
  • 编辑支持可变组合中的缩放编辑 (Editing has full support for scaled edits in mutable compositions.)
  • 导出能够支持可变帧率的60fps或者将其转为较低帧率如30fps

7.1. 播放

AVPlayer的一个实例经过设置setRate:方法值自动管理大部分播放速度。该值用做播放速度的乘数。值为1.0会致使正常播放,0.5以半速播放,5.0播放比正常播放快5倍,依此类推。

AVPlayerItem对象支持audioTimePitchAlgorithm属性。此属性容许您指定在使用“时间间距算法设置”常量以各类帧速率播放影片时播放音频的方式。

7.2. 编辑

使用AVMutableComposition对象完成编辑操做

7.3. 导出

使用AVAssetExportSession导出60fps的视频文件

  • AVAssetExportPresetPassthrough: 避免从新编码视频。它将媒体的部分标记为部分60 fps,部分减速或部分加速.
  • frameDuration: 使用恒定帧速率导出以得到最大的播放兼容性,可使用audioTimePitchAlgorithm指定时间.

7.4. 录制

使用AVCaptureMovieFileOutput自动支持高帧率的录制,它将自动选择正确的H264的音高与比特率.若是须要对录制作一些额外操做,须要用到AVAssetWriter.

assetWriterInput.expectsMediaDataInRealTime=YES;
复制代码
相关文章
相关标签/搜索