OC之AVCaptureSession

AVCaptureSession 继承自NSObject,是AVFoundation的核心类;用于管理捕获对象AVCaptureInput的视频和音频的输入,协调捕获的输出AVCaptureOutput

AVCaptureSession内部流程.png

1、管理输入和输出

属性或方法 描述
@property(nonatomic, readonly) NSArray<__kindof AVCaptureInput *> *inputs 数据流的输入管理AVCaptureInput对象集;
- (BOOL)canAddInput:(AVCaptureInput *)input 返回一个布尔值,该值指示给定的输入是否可以添加到会话中。
- (void)addInput:(AVCaptureInput *)input 向会话添加给定的输入。如果canAddInput:返回true,则使用此方法向会话添加输入;canAddInput:返回false,则该方法在调用时抛出异常。
- (void)removeInput:(AVCaptureInput *)input 删除一个给定的输入;可以在会话运行时调用此方法。
@property(nonatomic, readonly) NSArray<__kindof AVCaptureOutput *> *outputs 数据流的输出管理AVCaptureOutput对象
- (BOOL)canAddOutput:(AVCaptureOutput *)output 返回一个布尔值,该值指示给定的输出是否可以添加到会话中。
- (void)addOutput:(AVCaptureOutput *)output 向会话添加给定的输出;如果canAddOutput:返回true,则使用此方法向会话添加输出;canAddOutput:返回false,则该方法在调用时抛出异常。
- (void)removeOutput:(AVCaptureOutput *)output 删除一个给定的输出;可以在会话运行时调用此方法。

要执行实时或脱机捕获,需要实例化AVCaptureSession对象并添加适当的输入(如AVCaptureDeviceInput)和输出(如AVCaptureMovieFileOutput)。下面的代码片段说明了如何配置捕获设备来记录视频:

 dispatch_queue_t serialQueue = dispatch_queue_create("com.demo.gcdqueue.recordVideo", DISPATCH_QUEUE_SERIAL);
 AVCaptureSession *captureSession = [[AVCaptureSession alloc] init];
 AVCaptureDevice *videoCaptureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
 NSError *error = nil;
 AVCaptureDeviceInput *videoInput = [AVCaptureDeviceInput deviceInputWithDevice:videoCaptureDevice error:&error];
 AVCaptureMovieFileOutput *videoOutput = [[AVCaptureMovieFileOutput alloc] init];
 if ([captureSession canAddInput:videoInput]) {
    [captureSession addInput:videoInput];
 }
 else {
    //处理失败
 }

 if ([captureSession canAddOutput:videoOutput]){
    [captureSession addOutput:videoOutput];
 }
 else {
    //处理失败
 }

2、管理运行状态

属性、方法或通知 描述
- (void)startRunning 告诉AVCaptureSession实例开始运行。此方法用于启动从输入到连接到AVCaptureSession实例(即接收者)的输出的数据流。此方法是同步的,会阻塞,直到接收器完全开始运行或无法开始运行为止。如果在此过程中发生错误,且AVCaptureSession未能开始运行,将收到AVCaptureSessionRuntimeErrorNotification通知。
- (void)stopRunning 告诉AVCaptureSession实例停止运行。此方法用于停止从输入到连接到AVCaptureSession实例(即接收方)的输出的数据流。这个方法是同步的,会阻塞直到接收器完全停止运行。
@property(nonatomic, readonly, getter=isRunning) BOOL running 指示接收器是否正在运行;可以使用KVO来观察这个属性的值。
@property(nonatomic, readonly, getter=isInterrupted) BOOL interrupted 指示接收器是否被中断。可以使用KVO来观察这个属性的值。
AVCaptureSessionRuntimeErrorNotification 在捕获会话中发生错误时发送;使用键AVCaptureSessionErrorKey从通知的用户信息字典中检索底层错误。
AVCaptureSessionDidStartRunningNotification AVCaptureSession实例开始运行时发送通知
AVCaptureSessionDidStopRunningNotification AVCaptureSession实例停止时发送通知
AVCaptureSessionWasInterruptedNotification AVCaptureSession实例被中断时发送通知。可以使用AVCaptureSessionInterruptionReasonKey键检索关于中断原因的信息,这个键的值是一个包含AVCaptureSessionInterruptionReason值的NSNumber对象。还可以使用AVCaptureSessionInterruptionSystemPressureStateKey键检索导致捕获会话中断的系统压力因素信息,如果AVCaptureSession实例由于系统压力而中断,则该通知的userInfo字典包含这个键,它的相应值是AVCaptureSystemPressureState对象,提供关于系统压力级别的详细信息以及导致中断的因素。
AVCaptureSessionInterruptionEndedNotification AVCaptureSession实例的中断结束时发送通知

可以调用startRunning来启动从输入到输出的数据流,调用stopRunning来停止流。

dispatch_queue_t serialQueue = dispatch_queue_create("com.demo.gcdqueue.recordVideo", DISPATCH_QUEUE_SERIAL);
dispatch_async(serialQueue, ^{
    
    //开始运行session
    if (captureSession.running == NO){
        [captureSession startRunning];
    }
    
    //停止session
    if (captureSession.running){
        [captureSession stopRunning];
    }
});

注意:startRunning方法是一个耗时操作,它会阻塞当前线程直到启动会话完毕;因此应该在串行队列上执行会话设置,这样主队列就不会阻塞(这会使UI保持响应)。可以参见Apple Demo 示例

3、更改配置

方法 描述
- (void)beginConfiguration 指示要原子化地进行的一组配置更改的开始
- (void)commitConfiguration 提交一组配置更改

可以使用-beginConfiguration-commitConfiguration将正在运行的会话上的多个配置操作批处理为原子更新。在调用-beginConfiguration之后,例如,可以添加或删除输出,更改sessionPreset,或配置单个捕获输入或输出属性。在调用-commitConfiguration之前,实际上不会进行任何更改,在此阶段,它们将一起应用。

    dispatch_async(serialQueue, ^{
        
        [captureSession beginConfiguration];
        NSError *error = nil;
        AVCaptureDevice *audioCaptureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
        AVCaptureDeviceInput *audioInput = [AVCaptureDeviceInput deviceInputWithDevice:audioCaptureDevice error:&error];
        if ([captureSession canAddInput:audioInput]) {
            [captureSession addInput:audioInput];
        }
        else{
            //处理失败
        }

        [captureSession commitConfiguration];
    });

4、预设管理会话

属性或方法 描述
@property(nonatomic, copy) AVCaptureSessionPreset sessionPreset 一个常数值,指示输出的质量级别或比特率;默认值是 AVCaptureSessionPresetHigh。可以在会话运行时设置此值;如果-canSetSessionPreset:返回YES,则能设置此值。
- (BOOL)canSetSessionPreset:(AVCaptureSessionPreset)preset 返回一个布尔值,该值指示AVCaptureSession实例是否可以使用给定的预设值。

使用AVCaptureSessionPreset属性定义捕获设置预置的常量。

typedef NSString * AVCaptureSessionPreset

AVF_EXPORT AVCaptureSessionPreset const AVCaptureSessionPresetPhoto NS_AVAILABLE(10_7, 4_0) __TVOS_PROHIBITED __WATCHOS_PROHIBITED;
AVF_EXPORT AVCaptureSessionPreset const AVCaptureSessionPresetHigh NS_AVAILABLE(10_7, 4_0) __TVOS_PROHIBITED __WATCHOS_PROHIBITED;
AVF_EXPORT AVCaptureSessionPreset const AVCaptureSessionPresetMedium NS_AVAILABLE(10_7, 4_0) __TVOS_PROHIBITED __WATCHOS_PROHIBITED;
AVF_EXPORT AVCaptureSessionPreset const AVCaptureSessionPresetLow NS_AVAILABLE(10_7, 4_0) __TVOS_PROHIBITED __WATCHOS_PROHIBITED;
AVF_EXPORT AVCaptureSessionPreset const AVCaptureSessionPreset320x240 NS_AVAILABLE_MAC(10_7) __TVOS_PROHIBITED __WATCHOS_PROHIBITED;
AVF_EXPORT AVCaptureSessionPreset const AVCaptureSessionPreset352x288 NS_AVAILABLE(10_7, 5_0) __TVOS_PROHIBITED __WATCHOS_PROHIBITED;
AVF_EXPORT AVCaptureSessionPreset const AVCaptureSessionPreset640x480 NS_AVAILABLE(10_7, 4_0) __TVOS_PROHIBITED __WATCHOS_PROHIBITED;
AVF_EXPORT AVCaptureSessionPreset const AVCaptureSessionPreset960x540 NS_AVAILABLE_MAC(10_7) __TVOS_PROHIBITED __WATCHOS_PROHIBITED;
AVF_EXPORT AVCaptureSessionPreset const AVCaptureSessionPreset1280x720 NS_AVAILABLE(10_7, 4_0) __TVOS_PROHIBITED __WATCHOS_PROHIBITED;
AVF_EXPORT AVCaptureSessionPreset const AVCaptureSessionPreset1920x1080 NS_AVAILABLE_IOS(5_0) __TVOS_PROHIBITED __WATCHOS_PROHIBITED;
AVF_EXPORT AVCaptureSessionPreset const AVCaptureSessionPreset3840x2160 NS_AVAILABLE_IOS(9_0) __TVOS_PROHIBITED __WATCHOS_PROHIBITED;
AVF_EXPORT AVCaptureSessionPreset const AVCaptureSessionPresetiFrame960x540 NS_AVAILABLE(10_9, 5_0) __TVOS_PROHIBITED __WATCHOS_PROHIBITED;
AVF_EXPORT AVCaptureSessionPreset const AVCaptureSessionPresetiFrame1280x720 NS_AVAILABLE(10_9, 5_0) __TVOS_PROHIBITED __WATCHOS_PROHIBITED;
AVF_EXPORT AVCaptureSessionPreset const AVCaptureSessionPresetInputPriority NS_AVAILABLE_IOS(7_0) __TVOS_PROHIBITED __WATCHOS_PROHIBITED;

可以使用sessionPreset属性为输出AVCaptureOutput自定义质量级别、比特率或其他设置。大多数常见的捕获配置都可以通过会话预置获得;然而,一些特殊的选项(比如高帧率)需要直接在AVCaptureDevice实例上设置捕获格式。

dispatch_async(serialQueue, ^{
    
    [captureSession beginConfiguration];
    
    if ([captureSession canSetSessionPreset:AVCaptureSessionPreset1920x1080]){
        captureSession.sessionPreset = AVCaptureSessionPreset1920x1080;
    }
    else if ([self.session canSetSessionPreset:AVCaptureSessionPreset1280x720]){
        captureSession.sessionPreset = AVCaptureSessionPreset1280x720;
    }
    else if ([self.session canSetSessionPreset:AVCaptureSessionPreset640x480]){
        captureSession.sessionPreset = AVCaptureSessionPreset640x480;
    }
    else{
        captureSession.sessionPreset = AVCaptureSessionPresetLow;
    }

    [captureSession commitConfiguration];
});

5、管理连接

方法 描述
- (void)addConnection:(AVCaptureConnection *)connection 向会话添加给定的捕获连接。如果-canAddConnection:返回YES,则可以使用此方法向会话添加AVCaptureConnection实例。当使用addInput:addOutput:时,所有兼容的输入和输出之间会自动形成连接。手动添加连接仅在添加没有连接的输入或输出时才需要。
- (BOOL)canAddConnection:(AVCaptureConnection *)connection 返回一个布尔值,该值指示给定连接是否可以添加到AVCaptureSession实例。
- (void)addInputWithNoConnections:(AVCaptureInput *)input 在没有形成任何连接的情况下向会话添加捕获输入。可以在会话运行时调用此方法。通常应该使用addInput:向会话添加输入。如果需要细粒度控制哪些输入连接到哪些输出,可以使用此方法。
- (void)addOutputWithNoConnections:(AVCaptureOutput *)output 在没有形成任何连接的情况下向会话添加捕获输出。可以在会话运行时调用此方法。通常,您应该使用addOutput:向会话添加输出。如果需要细粒度控制哪些输入连接到哪些输出,可以使用此方法。
- (void)removeConnection:(AVCaptureConnection *)connection 从会话中删除捕获连接。

6、共享应用程序的音频会话

属性 属性类型 描述
usesApplicationAudioSession BOOL 指示捕获会话是否使用应用程序的共享音频会话。如果此属性的值为NO,则AVCaptureSession会话使用私有的AVAudioSession实例进行音频录制,如果应用程序使用其自己的音频会话进行回放,可能会导致中断。对于iOS 7.0或更新版本的应用程序,这个属性默认为YES,允许同时播放和录制。
automaticallyConfiguresApplicationAudioSession BOOL 指示捕获会话是否自动更改应用程序的共享音频会话的设置。只有当usesApplicationAudioSession属性的值为YES时,此属性才生效,该属性的值默认为YES。导致捕获会话自动配置应用程序的共享AVAudioSession实例以获得最佳记录。例如,如果捕捉会话使用设备的后置摄像头,音频会话的麦克风和极性模式将被设置为从该方向最佳记录声音。注意,在捕获完成后,音频会话的原始状态不会恢复。如果将此属性的值设置为NO,应用程序将负责选择适当的音频会话设置。如果音频会话的设置与捕获会话不兼容,录制可能会失败。

7、同步多个输入和输出

//用于输出同步的时钟对象。
@property(nonatomic, readonly) CMClockRef masterClock;

返回的CMClockRef对象是只读的,并为捕获输出中的所有示例缓冲区提供了一个时间基础。这可以与AVCaptureInputPort对象中的时钟一起使用,以同步捕获输出和外部数据源(如运动示例)。
例如,要将输出时间戳同步到输入设备提供的原始时间戳,可以在captureOutput中执行以下操作:

AVCaptureInputPort *port = [[connection inputPorts] objectAtIndex:0];
CMClockRef originalClock = [port clock];

CMTime syncedPTS = CMSampleBufferGetPresentationTime( sampleBuffer );
CMTime originalPTS = CMSyncConvertTime( syncedPTS, [captureSession masterClock], originalClock );

8、管理颜色空间

@property(nonatomic) BOOL automaticallyConfiguresCaptureDeviceForWideColor;

一个布尔值,指定会话是否应该在可用的地方自动使用宽域颜色。所有设备和格式都支持sRGB颜色空间中的捕获。一些设备和格式也可以捕获P3颜色空间,其中包含更广泛的颜色范围。宽域捕获仅适用于某些捕获工作流,因此该属性控制这些工作流的自动配置。

当此属性为YES(默认值)时,会话配置适合于广域捕获:

  • 如果使用AVCaptureSessionPresetInputPriority之外的会话预置,会话会自动将设备AVCaptureDeviceactiveFormat属性设置为支持广域捕获的,并将设备AVCaptureDeviceactiveColorSpace属性设置为广域颜色空间。
  • 如果手动选择捕获格式(从而将会话设置为输入优先级),则会话仅当选择的格式支持广域捕获时,才会自动将设备AVCaptureDeviceactiveColorSpace属性设置为宽域颜色空间。

注意:当此属性为YES,且会话配置不适合于广域捕获时,除AVCaptureSessionPresetInputPriority之外的会话预置可以选择不支持广域捕获的捕获格式。

如果要直接更改捕获设备AVCaptureDeviceactiveColorSpace属性的值,请将此属性设置为NO(不管您是使用会话预设配置设备,还是直接设置捕获格式)。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容