美文网首页音视频iOS开发技术iOS-进阶学习
iOS AVCaptureSession学习笔记(一)

iOS AVCaptureSession学习笔记(一)

作者: brownfeng | 来源:发表于2017-02-11 15:45 被阅读9477次

基本使用流程

AVCaptureSession是AVFoundation的核心类,用于捕捉视频和音频,协调视频和音频的输入和输出流.下面是简书上找的围绕AVCaptureSession的图

AVCapureSession.jpg

围绕AVCaptureSession的核心类的简介

AVCaptureSession是AVFoundation的核心类,用于捕捉视频和音频,协调视频和音频的输入和输出流.

对session的常见操作:

1. 创建AVCaptureSession

设置SessionPreset,用于设置output输出流的bitrate或者说画面质量

// 1 创建session
AVCaptureSession *session = [AVCaptureSession new];
//设置session显示分辨率
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
    [session setSessionPreset:AVCaptureSessionPreset640x480];
else
    [session setSessionPreset:AVCaptureSessionPresetPhoto];

2. 给Session添加input输入

一般是Video或者Audio数据,也可以两者都添加,即AVCaptureSession的输入源AVCaptureDeviceInput.

// 2 获取摄像头device,并且默认使用的后置摄像头,并且将摄像头加入到captureSession中
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
AVCaptureDeviceInput *deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];

isUsingFrontFacingCamera = NO;
if ([session canAddInput:deviceInput]){
    [session addInput:deviceInput];
}

3. 给session添加output输出

添加AVCaptureOutput,即AVCaptureSession的输出源.一般输出源分成:音视频源,图片源,文件源等.

  • 音视频输出AVCaptureAudioDataOutput,AVCaptureVideoDataOutput.
  • 静态图片输出AVCaptureStillImageOutput(iOS10中被AVCapturePhotoOutput取代了)
  • AVCaptureMovieFileOutput表示文件源.

通常如果需要音视频帧,需要在将output加入到session之前,设置videoSetting或者audioSetting,主要是音视频的格式或者回调的delegate以及dispatch queue.

// 4 创建拍照使用的AVCaptureStillImageOutput,并且注册observer观察capturingStillImage,并将output加入到session. 使用observer的作用监控"capturingStillImage",如果为YES,那么表示开始截取视频帧.在回调方法中显示闪屏效果
stillImageOutput = [AVCaptureStillImageOutput new];
[stillImageOutput addObserver:self forKeyPath:@"capturingStillImage" options:NSKeyValueObservingOptionNew context:(__bridge void * _Nullable)(AVCaptureStillImageIsCapturingStillImageContext)];
if ([session canAddOutput:stillImageOutput]){
    [session addOutput:stillImageOutput];
}

// 5 创建预览output,设置预览videosetting,然后设置预览delegate使用的回调线程,将该预览output加入到session
videoDataOutput = [AVCaptureVideoDataOutput new];

// we want BGRA, both CoreGraphics and OpenGL work well with 'BGRA'
NSDictionary *rgbOutputSettings = [NSDictionary dictionaryWithObject:
                                   [NSNumber numberWithInt:kCMPixelFormat_32BGRA] forKey:(id)kCVPixelBufferPixelFormatTypeKey];
[videoDataOutput setVideoSettings:rgbOutputSettings];
[videoDataOutput setAlwaysDiscardsLateVideoFrames:YES]; // discard if the data output queue is blocked (as we process the still image)

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

if ([session canAddOutput:videoDataOutput]){
    [session addOutput:videoDataOutput];
}

4. AVCaptureConnection设置input,output连接的重要属性

在给AVCaptureSession添加input和output以后,就可以通过audio或者video的output生成AVCaptureConnection.通过connection设置output的视频或者音频的重要属性,比如ouput video的方向videoOrientation(这里注意videoOrientation并非DeviceOrientation,默认情况下录制的视频是90度转角的,这个是相机传感器导致的,请google)

[[videoDataOutput connectionWithMediaType:AVMediaTypeVideo] setEnabled:NO];
AVCaptureConnection *videoCon = [videoDataOutput connectionWithMediaType:AVMediaTypeVideo];

// 原来的刷脸没有这句话.因此录制出来的视频是有90度转角的, 这是默认情况
if ([videoCon isVideoOrientationSupported]) {
//        videoCon.videoOrientation = AVCaptureVideoOrientationPortrait;
    // 下面这句是默认系统video orientation情况!!!!,如果要outputsample图片输出的方向是正的那么需要将这里设置称为portrait
    //videoCon.videoOrientation = AVCaptureVideoOrientationLandscapeLeft;
}

5. 视频预览层AVCaptureVideoPreviewLayer

在input,output等重要信息都添加到session以后,可以用session创建AVCaptureVideoPreviewLayer,这是摄像头的视频预览层.

previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:session];
[previewLayer setBackgroundColor:[[UIColor blackColor] CGColor]];
[previewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];// 犹豫使用的aspectPerserve
CALayer *rootLayer = [previewView layer];
[rootLayer setMasksToBounds:YES];
[previewLayer setFrame:[rootLayer bounds]];
[rootLayer addSublayer:previewLayer];

6. 启动session

// 7 启动session,output开始接受samplebuffer回调
[session startRunning];

Apple Demo SquareCam的session的完整的初始化

具体解释见注释

/**
 *  相机初始化方法
 */
- (void)setupAVCapture
{
    NSError *error = nil;
    
    // 1 创建session
    AVCaptureSession *session = [AVCaptureSession new];
    // 2 设置session显示分辨率
    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
        [session setSessionPreset:AVCaptureSessionPreset640x480];
    else
        [session setSessionPreset:AVCaptureSessionPresetPhoto];
    
    // 3 获取摄像头device,并且默认使用的后置摄像头,并且将摄像头加入到captureSession中
    AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    AVCaptureDeviceInput *deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];
    
    isUsingFrontFacingCamera = NO;
    if ( [session canAddInput:deviceInput] )
        [session addInput:deviceInput];
    
    // 4 创建拍照使用的AVCaptureStillImageOutput,并且注册observer观察capturingStillImage,并将output加入到session. 使用observer的作用监控"capturingStillImage",如果为YES,那么表示开始截取视频帧.在回调方法中显示闪屏效果
    stillImageOutput = [AVCaptureStillImageOutput new];
    [stillImageOutput addObserver:self forKeyPath:@"capturingStillImage" options:NSKeyValueObservingOptionNew context:(__bridge void * _Nullable)(AVCaptureStillImageIsCapturingStillImageContext)];
    if ( [session canAddOutput:stillImageOutput] )
        [session addOutput:stillImageOutput];
    
    // 5 创建预览output,设置预览videosetting,然后设置预览delegate使用的回调线程,将该预览output加入到session
    videoDataOutput = [AVCaptureVideoDataOutput new];
    
    // we want BGRA, both CoreGraphics and OpenGL work well with 'BGRA'
    NSDictionary *rgbOutputSettings = [NSDictionary dictionaryWithObject:
                                       [NSNumber numberWithInt:kCMPixelFormat_32BGRA] forKey:(id)kCVPixelBufferPixelFormatTypeKey];
    [videoDataOutput setVideoSettings:rgbOutputSettings];
    [videoDataOutput setAlwaysDiscardsLateVideoFrames:YES]; // discard if the data output queue is blocked (as we process the still image)
    
    // 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];
    
    if ( [session canAddOutput:videoDataOutput] )
        [session addOutput:videoDataOutput];
    
    
    [[videoDataOutput connectionWithMediaType:AVMediaTypeVideo] setEnabled:NO];
    AVCaptureConnection *videoCon = [videoDataOutput connectionWithMediaType:AVMediaTypeVideo];
    
    // 原来的刷脸没有这句话.因此录制出来的视频是有90度转角的, 这是默认情况
    if ([videoCon isVideoOrientationSupported]) {
//        videoCon.videoOrientation = AVCaptureVideoOrientationPortrait;
        
        // 下面这句是默认系统video orientation情况!!!!,如果要outputsample图片输出的方向是正的那么需要将这里设置称为portrait
        //videoCon.videoOrientation = AVCaptureVideoOrientationLandscapeLeft;
    }
    effectiveScale = 1.0;
    // 6 获取相机的实时预览layer,并且设置layer的拉升属性AVLayerVideoGravityResizeAspect,设置previewLayer的bounds,并加入到view中
    previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:session];
    [previewLayer setBackgroundColor:[[UIColor blackColor] CGColor]];
    [previewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];// 犹豫使用的aspectPerserve
    CALayer *rootLayer = [previewView layer];
    [rootLayer setMasksToBounds:YES];
    [previewLayer setFrame:[rootLayer bounds]];
    [rootLayer addSublayer:previewLayer];
    
    // 7 启动session,output开始接受samplebuffer回调
    [session startRunning];

bail:
    if (error) {
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:[NSString stringWithFormat:@"Failed with error %d", (int)[error code]]
                                                            message:[error localizedDescription]
                                                           delegate:nil 
                                                  cancelButtonTitle:@"Dismiss" 
                                                  otherButtonTitles:nil];
        [alertView show];
        [self teardownAVCapture];
    }
}

请参考apple 的官方demo: SquareCam

相关文章

网友评论

  • 沃小沃:请问 用 replaykit 录屏怎么设置分辨率
    21028c2ec73c:您好,可以加下我的QQ吗?我们需要一些上架:3366817827
    brownfeng:@沃小沃 没有用过这个库哦
  • 帆123:楼主有碰到过在没有调用AVCaptureSession 没有调用stop的情况下,却stop了吗?
    brownfeng:@帆0229 好像是observer 相关的错误. 你检查一下
    帆123:@brownfeng 没有进入后台,每次中断的时候会出现一条 30:AudioSessionSetActive_Priv is passing a serverPID of 0 to CheckRPCError! 想不通为什么
    brownfeng:是不是进入后台时候被中断了
  • feng_dev:求如何根据本地url压缩视频的方法,类似微信,压缩完体积2M以内,清晰度较好。
    brownfeng:@爱音乐的李小峰 https://www.zhihu.com/question/20692215 姚冬大大的回复里面有demo.. 很多iOS H264的编解码的例子. 看你的需求.肯定是将一个本地音视频文件转化成其他的格式的文件(包括音视频处理等等), 其实有更加高级的api可以选择. 你可以看一下一本AVFoundation的书. 最后几章应该有你要的结果 --- http://item.jd.com/1714483284.html
    feng_dev:@brownfeng 大神能否再详细说下,或者有推荐博客链接嘛?感激不尽~~:pray::pray::pray:
    brownfeng:@爱音乐的李小峰 H264 压缩效果可以. 本地文件的化, 硬件编解码应该可以搞定
  • 西叶lv:- (void)lightSensitive {

    // 1.获取硬件设备
    AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

    // 2.创建输入流
    AVCaptureDeviceInput *input = [[AVCaptureDeviceInput alloc]initWithDevice:device error:nil];

    // 3.创建设备输出流
    AVCaptureVideoDataOutput *output = [[AVCaptureVideoDataOutput alloc] init];
    [output setSampleBufferDelegate:self queue:dispatch_get_main_queue()];


    // AVCaptureSession属性
    AVCaptureSession *session = [[AVCaptureSession alloc]init];
    // 设置为高质量采集率
    [session setSessionPreset:AVCaptureSessionPresetHigh];
    // 添加会话输入和输出
    if ([session canAddInput:input]) {
    [session addInput:input];
    }
    if ([session canAddOutput:output]) {
    [session addOutput:output];
    }

    // 9.启动会话
    [session startRunning];

    }
    我这样写,AVCaptureSession对象被提前释放了,[session startRunning];无效,只能把AVCaptureSession对象定义成属性,才行.为啥AVCaptureSession对象会被提前释放呢??求解答
    brownfeng:@郝嘉律 session 是局部变量.老老实实的强引用吧
    西叶lv:@brownfeng 我调用startRunning方法也是在方法里阿,在局部变量的作用蜮里。
    brownfeng:你这个captureSession是一个方法里面的局部变量... 怎么不会被释放呢....
  • 王者归来之英雄有梦:大神知道为什么设置了闪光灯,拍照的时候却不闪一下(PS:代码里没用到AVCaptureSession和AVCaptureVideoPreviewLayer)?是不是这个的原因?还有上面代码中previewView是什么东东?在哪里创建的?
    brownfeng:闪光灯设置我在项目中没有用到哦. previewView 是你在界面上要实时预览摄像头内容创建的一个UIView, 将CaptureSession的AVCaptureVideoPreviewLayer获取以后添加到你要预览的preView(预览控件)的layer上就行啦. 参考苹果官方demo - SquareCam
  • 乔治贝利:AVCapturePhotoOutput有没有完整的使用模版
    brownfeng:@乔治贝利 没时间呢. 兄弟. 建议自己google一下
    乔治贝利:是的,现在都有10系统了。大神能帮我看个代码吗
    brownfeng:暂时用stillImageOutput 这个把. AVCapturePhotoOutput这个iOS 10以上才有的api
  • 899e2d74bdeb:请问我知道哦可以通过 self.mCaptureSession.sessionPreset 这个改变图像的分辨率,但是如果我想改成自己的自定易的分辨率大小可以?
    brownfeng:@请你喝茶 可以控制啊. output都添加进去.直接输出.具体是扫码还是录制在delegate 回调里面控制就行
    请你喝茶:请问下怎么切换不同的output呢,比如说一个按钮点击是扫码功能,另一个按钮点击是视频录制功能,怎么进行这两个output的切换呢
    brownfeng:@哎疯 好像不行,要使用apple定义的AVCaptureSessionPresetXXX类型的NSString。如果有这方面需要。自己后面拿到图片数据帧自己处理就行

本文标题:iOS AVCaptureSession学习笔记(一)

本文链接:https://www.haomeiwen.com/subject/ganiittx.html