媒体捕捉 - AVCaptureSession

本文介绍如何使用AVFoundation框架进行摄像头的开发,包括设置捕捉会话、配置摄像头和麦克风输入、配置静态图片和视频输出等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

捕捉功能综述

捕捉会话

AVFoundation捕捉栈的核心类是AVCaptureSession。一个捕捉会话相当于一个虚拟的“插线板”,用于连接输入和输出的资源。捕捉会话管理从物理设备得到的数据流,比如摄像头和麦克风设备,输出到一个或多个目的地。可以动态配置输入输出的线路,让开发者能够在会话进行中按照需要重新配置捕捉环境,比如音频输入源在手机麦克风和耳机等其他设备间的切换。

捕捉会话还可以额外配置一个会话预设值(session preset),用来控制捕捉数据格式和质量。会话预设值默认为AVCaptureSessionHigh,它适用于大多数情况,不过框架仍然提供了多个预设值对输出进行控制,以满足应用程序的特殊需求。

捕捉设备

AVCaptureDevice为诸如摄像头或麦克风等物理设备定义了一个接口。大多数情况下,这些设备都内设于Mac、iPhone、iPad中,不过也可能是外部数码相机或便携摄像机。AVCaptureDevice针对物理硬件设备定义了大量的控制方法,比如摄像头聚焦,曝光,白平衡,和闪光灯等。

AVCaptureDevice定义了大量类方法用于访问系统的捕捉设备,最常用的一个方法是defaultDeviceWithMediaType:,他会根据给定的媒体类型返回一个系统指定的默认设备。例如:

AVCaptureDevice * device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

实例中我们请求一个默认的视频设备,在包含前置摄像头和后置摄像头的iOS系统下,这个方法会返回后置摄像头,因为它是系统默认摄像头。在带有摄像头的Mac机器上,会返回内置的FaceTime摄像头。

捕捉设备输入

在使用捕捉设备进行处理前,首先需要将它添加为捕捉会话的输入。不能直接添加到AVCaptureSession中,但是可以通过将它封装在一个AVCaptureDeviceInput实例中添加。这个对象在设备输出数据和捕捉会话间扮演着接线板的作用。使用deviceInputWithDevice:error:方法创建AVCaptureDeviceInput,如下所示:

NSError * error = nil;
AVCaptureDeviceInput * videoInput = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];

捕捉的输出

AVFoundation定义了AVCaptureOutput的许多扩展类。AVCaptureOutput是一个抽象基类,用于为获得的数据寻找输出目的地。框架定义了一些这个抽象类的高级扩展类,比如AVCaptureStillImageOutputAVCaptureMovieFileOutput,使用它们很容易实现捕捉静态图片和视频的功能。还可以在这里找到底层的扩展,比如AVCaptureAudioDataOutputAVCaptureVideoDataOutput,使用它们可以直接访问硬件捕捉到的数字样本数据。使用这些底层输出类需要对捕捉设备的数据渲染有更好的理解,不过这些类可以提供更强大的功能,比如对音频和视频流进行实时处理。

捕捉连接

在上面的插图中有一个类没有明确的名字,而是由一个连接不同组件的黑色箭头所表示,这就是AVCaptureConnect类。捕捉会话首先需要确定由给定捕捉设备输入渲染的媒体类型,并自动建立其到能接收改媒体类型的捕捉输出端的连接。比如AVCaptureMovieFileOutput可以接收音频和视频数据,所以会话会确定哪些输入产生视频,哪些产生音频,并正确地建立改连接。对这些连接的访问可以让开发者对信号流进行底层的控制,比如禁用某些特定的连接,或在音频连接中访问单独的音频轨道。

捕捉预览

如果不能在影像捕捉中看到正在捕捉的场景,那么应用就不会好用。幸运的是框架定义了一个AVCaptureVideoPreviewLayer类来满足该需求。预览层是一个Core Animation的CALayer子类,对捕捉视频数据进行实时预览。这个类所扮演的角色类似于AVPlayerLayer,不过还是针对摄像头捕捉的需求进行了定制。像AVPlayerLayer一样,AVCaptureVideoPreviewLayer也支持视频重力的概念,可以控制视频内容渲染的缩放和拉伸效果。

新建一个THCameraController类负责处理摄像头多媒体信息采集处理

配置媒体采集会话AVCaptureSession

- (BOOL)setupSession:(NSError **)error {

    self.captureSession = [[AVCaptureSession alloc] init];                  // 1
    self.captureSession.sessionPreset = AVCaptureSessionPresetHigh;

    // Set up default camera device
    AVCaptureDevice *videoDevice =                                          // 2
        [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

    AVCaptureDeviceInput *videoInput =                                      // 3
        [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:error];
    if (videoInput) {
        if ([self.captureSession canAddInput:videoInput]) {                 // 4
            [self.captureSession addInput:videoInput];
            self.activeVideoInput = videoInput;
        }
    } else {
        return NO;
    }

    // Setup default microphone
    AVCaptureDevice *audioDevice =                                          // 5
        [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];

    AVCaptureDeviceInput *audioInput =                                      // 6
        [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:error];
    if (audioInput) {
        if ([self.captureSession canAddInput:audioInput]) {                 // 7
            [self.captureSession addInput:audioInput];
        }
    } else {
        return NO;
    }

    // Setup the still image output
    self.imageOutput = [[AVCaptureStillImageOutput alloc] init];            // 8
    self.imageOutput.outputSettings = @{AVVideoCodecKey : AVVideoCodecJPEG};

    if ([self.captureSession canAddOutput:self.imageOutput]) {
        [self.captureSession addOutput:self.imageOutput];
    }

    // Setup movie file output
    self.movieOutput = [[AVCaptureMovieFileOutput alloc] init];             // 9

    if ([self.captureSession canAddOutput:self.movieOutput]) {
        [self.captureSession addOutput:self.movieOutput];
    }

    return YES;
}

在子线程里开启捕捉会话

- (void)startSession {
    if (![self.captureSession isRunning]) {                                 // 1
        dispatch_async([self globalQueue], ^{
            [self.captureSession startRunning];
        });
    }
}

- (void)stopSession {
    if ([self.captureSession isRunning]) {                                  // 2
        dispatch_async([self globalQueue], ^{
            [self.captureSession stopRunning];
        });
    }
}

- (dispatch_queue_t)globalQueue {
    return dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
}

在外面的显示界面启动会话,并指定预览layer,从这里开始视频数据流就开始在应用中流转了。

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:YES];

    AVCaptureVideoPreviewLayer *previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.cameraController.captureSession];
    previewLayer.frame = self.view.bounds;
    previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    [self.view.layer insertSublayer:previewLayer atIndex:0];
}

- (void)viewDidLoad {
    [super viewDidLoad];

    self.cameraController = [[THCameraController alloc] init];
    NSError *error;
    if ([self.cameraController setupSession:&error]) {
        [self.cameraController startSession];
    }else {
        NSLog(@"errpr:%@", [error localizedDescription]);
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值