1.认识 AVCapture 系列


AVCapture 系列是 AVFoundation 框架为我们提供的用于管理输入设备、采集、输出、预览等一系列接口,其工作原理如下:

\1. AVCaptureDevice: 信号采集硬件设备(摄像头、麦克风、屏幕等)AVCaptureDevice 代表硬件设备,并且为 AVCaptureSession 提供 input,要想使用 AVCaptureDevice,应该先将设备支持的 device 枚举出来, 根据摄像头的位置( 前置或者后置摄像头 )获取需要用的那个摄像头, 再使用;如果想要对 AVCaptureDevice 对象的一些属性进行设置,应该先调用 lockForConfiguration: 方法, 设置结束后,调用 unlockForConfiguration 方法;

[self.device lockForConfiguration:&error];

// 设置 ***

[self.device unlockForConfiguration];

2. AVCaptureInput: 输入数据管理


AVCaptureInput 继承自 NSObject,是向 AVCaptureSession 提供输入数据的对象的抽象超类;要将 AVCaptureInput 对象与会话 AVCaptureSession 关联,需要 AVCaptureSession实例调用 -addInput: 方法。由于 AVCaptureInput 是个抽象类,无法直接使用,所以我们一般使用它的子类类管理输入数据。我们常用的 AVCaptureInput 的子类有三个:

AVCaptureDeviceInput:用于从 AVCaptureDevice 对象捕获数据;AVCaptureScreenInput:从 macOS 屏幕上录制的一种捕获输入;AVCaptureMetadataInput:它为 AVCaptureSession 提供 AVMetadataItems。

3. AVCaptureOutput:输出数据管理


AVCaptureOutput 继承自 NSObject,是输出数据管理,该对象将会被添加到会话AVCaptureSession中,用于接收会话AVCaptureSession各类输出数据; AVCaptureOutput提供了一个抽象接口,用于将捕获输出数据(如文件和视频预览)连接到捕获会话AVCaptureSession的实例,捕获输出可以有多个由AVCaptureConnection对象表示的连接,一个连接对应于它从捕获输入(AVCaptureInput的实例)接收的每个媒体流,捕获输出在首次创建时没有任何连接,当向捕获会话添加输出时,将创建连接,将该会话的输入的媒体数据映射到其输出,调用AVCaptureSession的-addOutput:方法将AVCaptureOutput与AVCaptureSession关联。AVCaptureOutput 是个抽象类,我们必须使用它的子类,常用的 AVCaptureOutput的子类如下所示:

AVCaptureAudioDataOutput:一种捕获输出,用于记录音频,并在录制音频时提供对音频样本缓冲区的访问;AVCaptureAudioPreviewOutput :一种捕获输出,与一个核心音频输出设备相关联、可用于播放由捕获会话捕获的音频;AVCaptureDepthDataOutput :在兼容的摄像机设备上记录场景深度信息的捕获输出;AVCaptureMetadataOutput :用于处理捕获会话 AVCaptureSession 产生的定时元数据的捕获输出;AVCaptureStillImageOutput:在macOS中捕捉静止照片的捕获输出。该类在 iOS 10.0 中被弃用,并且不支持新的相机捕获功能,例如原始图像输出和实时照片,在 iOS 10.0 或更高版本中,使用 AVCapturePhotoOutput 类代替;AVCapturePhotoOutput :静态照片、动态照片和其他摄影工作流的捕获输出;AVCaptureVideoDataOutput :记录视频并提供对视频帧进行处理的捕获输出;AVCaptureFileOutput:用于捕获输出的抽象超类,可将捕获数据记录到文件中;AVCaptureMovieFileOutput :继承自 AVCaptureFileOutput,将视频和音频记录到 QuickTime 电影文件的捕获输出;AVCaptureAudioFileOutput :继承自 AVCaptureFileOutput,记录音频并将录制的音频保存到文件的捕获输出。

4. AVCaptureSession:


用来管理采集数据和输出数据,它负责协调从哪里采集数据,输出到哪里,它是整个Capture的核心,类似于RunLoop,它不断的从输入源获取数据,然后分发给各个输出源AVCaptureSession 继承自NSObject,是AVFoundation的核心类,用于管理捕获对象AVCaptureInput的视频和音频的输入,协调捕获的输出AVCaptureOutput

5. AVCaptureConnection:


用于 AVCaptureSession 来建立和维护 AVCaptureInput 和 AVCaptureOutput 之间的连接AVCaptureConnection 是 Session 和 Output 中间的控制节点,每个 Output 与 Session 建立连接后,都会分配一个默认的 AVCpatureConnection。

6. AVCapturePreviewLayer:


预览层,AVCaptureSession 的一个属性,继承自 CALayer,提供摄像头的预览功能,照片以及视频就是通过把 AVCapturePreviewLayer 添加到 UIView 的 layer 上来显示

开始视频采集1、创建并初始化输入AVCaptureInput: AVCaptureDeviceInput 和输出AVCaptureOutput: AVCaptureVideoDataOutput;2、创建并初始化 AVCaptureSession,把 AVCaptureInput 和 AVCaptureOutput 添加到 AVCaptureSession 中;3、调用 AVCaptureSession 的 startRunning 开启采集初始化输入通过 AVCaptureDevice 的 devicesWithMediaType: 方法获取摄像头,iPhone 都是有前后摄像头的,这里获取到的是一个设备的数组,要从数组里面拿到我们想要的前摄像头或后摄像头,然后将 AVCaptureDevice 转化为 AVCaptureDeviceInput,添加到 AVCaptureSession中

/************************** 设置输入设备 *************************/

// --- 获取所有摄像头 ---

NSArray *cameras = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];

// --- 获取当前方向摄像头 ---

NSArray *captureDeviceArray = [cameras filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"position == %d", _capturerParam.devicePosition]];

if (captureDeviceArray.count == 0) {

return nil;

}

// --- 转化为输入设备 ---

AVCaptureDevice *camera = captureDeviceArray.firstObject;

self.captureDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:camera

error:&error];

设置视频采集参数

@implementation VideoCapturerParam

- (instancetype)init {

self = [super init];

if (self) {

_devicePosition = AVCaptureDevicePositionFront; // 摄像头位置,默认为前置摄像头

_sessionPreset = AVCaptureSessionPreset1280x720; // 视频分辨率 默认 AVCaptureSessionPreset1280x720

_frameRate = 15; // 帧 单位为 帧/秒,默认为15帧/秒

_videoOrientation = AVCaptureVideoOrientationPortrait; // 摄像头方向 默认为当前手机屏幕方向

switch ([UIDevice currentDevice].orientation) {

case UIDeviceOrientationPortrait:

case UIDeviceOrientationPortraitUpsideDown:

_videoOrientation = AVCaptureVideoOrientationPortrait;

break;

case UIDeviceOrientationLandscapeRight:

_videoOrientation = AVCaptureVideoOrientationLandscapeRight;

break;

case UIDeviceOrientationLandscapeLeft:

_videoOrientation = AVCaptureVideoOrientationLandscapeLeft;

break;

default:

break;

}

}

return self;

}

初始化输出初始化视频输出 AVCaptureVideoDataOutput,并设置视频数据格式,设置采集数据回调线程,这里视频输出格式选的是 kCVPixelFormatType_420YpCbCr8BiPlanarFullRange,YUV 数据格式

/************************** 设置输出设备 *************************/

// --- 设置视频输出 ---

self.captureVideoDataOutput = [[AVCaptureVideoDataOutput alloc] init];

NSDictionary *videoSetting = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange], kCVPixelBufferPixelFormatTypeKey, nil]; // kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange 表示输出的视频格式为NV12

[self.captureVideoDataOutput setVideoSettings:videoSetting];

// --- 设置输出串行队列和数据回调 ---

dispatch_queue_t outputQueue = dispatch_queue_create("VideoCaptureOutputQueue", DISPATCH_QUEUE_SERIAL);

// --- 设置代理 ---

[self.captureVideoDataOutput setSampleBufferDelegate:self queue:outputQueue];

// --- 丢弃延迟的帧 ---

self.captureVideoDataOutput.alwaysDiscardsLateVideoFrames = YES;

初始化 AVCaptureSession 并设置输入输出1、初始化 AVCaptureSession,把上面的输入和输出加进来,在添加输入和输出到 AVCaptureSession 先查询一下 AVCaptureSession 是否支持添加该输入或输出端口;2、设置视频分辨率及图像质量(AVCaptureSessionPreset),设置之前同样需要先查询一下 AVCaptureSession 是否支持这个分辨率;3、如果在已经开启采集的情况下需要修改分辨率或输入输出,需要用 beginConfiguration 和commitConfiguration 把修改的代码包围起来。在调用 beginConfiguration 后,可以配置分辨率、输入输出等,直到调用 commitConfiguration 了才会被应用;4、AVCaptureSession 管理了采集过程中的状态,当开始采集、停止采集、出现错误等都会发起通知,我们可以监听通知来获取 AVCaptureSession 的状态,也可以调用其属性来获取当前 AVCaptureSession 的状态, AVCaptureSession 相关的通知都是在主线程的。

前置摄像头采集到的画面是翻转的,若要解决画面翻转问题,需要设置 AVCaptureConnection 的 videoMirrored 为 YES。

/************************** 初始化会话 *************************/

self.captureSession = [[AVCaptureSession alloc] init];

self.captureSession.usesApplicationAudioSession = NO;

// --- 添加输入设备到会话 ---

if ([self.captureSession canAddInput:self.captureDeviceInput]) {

[self.captureSession addInput:self.captureDeviceInput];

}

else {

NSLog(@"VideoCapture:: Add captureVideoDataInput Faild!");

return nil;

}

// --- 添加输出设备到会话 ---

if ([self.captureSession canAddOutput:self.captureVideoDataOutput]) {

[self.captureSession addOutput:self.captureVideoDataOutput];

}

else {

NSLog(@"VideoCapture:: Add captureVideoDataOutput Faild!");

return nil;

}

// --- 设置分辨率 ---

if ([self.captureSession canSetSessionPreset:self.capturerParam.sessionPreset]) {

self.captureSession.sessionPreset = self.capturerParam.sessionPreset;

}

/************************** 初始化连接 *************************/

self.captureConnection = [self.captureVideoDataOutput connectionWithMediaType:AVMediaTypeVideo];

// --- 设置摄像头镜像,不设置的话前置摄像头采集出来的图像是反转的 ---

if (self.capturerParam.devicePosition == AVCaptureDevicePositionFront && self.captureConnection.supportsVideoMirroring) { // supportsVideoMirroring 视频是否支持镜像

self.captureConnection.videoMirrored = YES;

}

self.captureConnection.videoOrientation = self.capturerParam.videoOrientation;

self.videoPreviewLayer = [AVCaptureVideoPreviewLayer layerWithSession:self.captureSession];

self.videoPreviewLayer.connection.videoOrientation = self.capturerParam.videoOrientation;

self.videoPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;

采集视频 / 回调

/**

* 开始采集

*/

- (NSError *)startCpture {

if (self.isCapturing) {

return [NSError errorWithDomain:@"VideoCapture:: startCapture faild: is capturing" code:1 userInfo:nil];

}

// --- 摄像头权限判断 ---

AVAuthorizationStatus videoAuthStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];

if (videoAuthStatus != AVAuthorizationStatusAuthorized) {

return [NSError errorWithDomain:@"VideoCapture:: Camera Authorizate faild!" code:1 userInfo:nil];

}

[self.captureSession startRunning];

self.isCapturing = YES;

kLOGt(@"开始采集视频");

return nil;

}

/**

* 停止采集

*/

- (NSError *)stopCapture {

if (!self.isCapturing) {

return [NSError errorWithDomain:@"VideoCapture:: stop capture faild! is not capturing!" code:1 userInfo:nil];

}

[self.captureSession stopRunning];

self.isCapturing = NO;

kLOGt(@"停止采集视频");

return nil;

}

#pragma mark ————— AVCaptureVideoDataOutputSampleBufferDelegate —————

/**

* 摄像头采集数据回调

@prama output 输出设备

@prama sampleBuffer 帧缓存数据,描述当前帧信息

@prama connection 连接

*/

- (void)captureOutput:(AVCaptureOutput *)output didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {

if ([self.delagate respondsToSelector:@selector(videoCaptureOutputDataCallback:)]) {

[self.delagate videoCaptureOutputDataCallback:sampleBuffer];

}

}

7.调用 / 获取数据


调用很简单,初始化视频采集参数 VideoCapturerParam 和 视频采集器 VideoVapturer , 设置预览图层 videoPreviewLayer , 调用 startCpture 就可以开始采集了,然后实现数据采集回调的代理方法 videoCaptureOutputDataCallback 获取数据

// --- 初始化视频采集参数 ---

VideoCapturerParam *param = [[VideoCapturerParam alloc] init];

// --- 初始化视频采集器 ---

self.videoCapture = [[VideoVapturer alloc] initWithCaptureParam:param error:nil];

self.videoCapture.delagate = self;

// --- 开始采集 ---

[self.videoCapture startCpture];

// --- 初始化预览View ---

self.recordLayer = self.videoCapture.videoPreviewLayer;

self.recordLayer.frame = CGRectMake(0, 0, CGRectGetWidth(self.view.bounds), CGRectGetHeight(self.view.bounds));

[self.view.layer addSublayer:self.recordLayer];

#pragma mark ————— VideoCapturerDelegate ————— 视频采集回调

- (void)videoCaptureOutputDataCallback:(CMSampleBufferRef)sampleBuffer {

NSLog(@"%@ sampleBuffer : %@ ", kLOGt(@"视频采集回调"), sampleBuffer);

}

至此,我们就完成了视频的采集,在采集前和过程中,我们可能会对采集参数、摄像头方向、帧率等进行修改。

原文https://zhuanlan.zhihu.com/p/485646912

★文末名片可以免费领取音视频开发学习资料,内容包括(FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)以及音视频学习路线图等等。

见下方!↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

iOS音视频开发——视频采集相关推荐

  1. 音视频开发-视频基础

    1 视频产生 视频本质就是一组连续播放的图像,所以研究视频离不开对于图像的研究.而图像又是由众多的色彩构成,这里就会涉及到图像的最小单元一个像素点的构成,像素点一般是由RGB三种颜色组成. 1.1 R ...

  2. 音视频开发: ffmpeg采集桌面屏幕、摄像头保存为视频

    一.环境介绍 ffmpge版本: 4.2.2 系统环境: win10 64位 下载地址: https://download.csdn.net/download/xiaolong1126626497/1 ...

  3. 音视频开发 视频编解码理论知识

    像素 像素是图像的基本单元,一个个像素就组成了图像.你可以认为像素就是图像中的一个点.在下面这张图中,你可以看到一个个方块,这些方块就是像素. 分辨率 图像(或视频)的分辨率是指图像的大小或尺寸.我们 ...

  4. FFMPEG音频视频开发: 视频转码、合并、修改分辨率、比特率

    一.环境介绍 操作系统介绍:win10 64位 FFMPEG版本: 4.4.2 QT版本: 5.12.6 二.FFMPEG下载 ubuntu系统下编译安装ffmpeg:  https://blog.c ...

  5. 直播软件搭建音视频开发中的视频采集

    直播软件搭建音视频开发中的视频采集 前言 在直播和短视频行业日益火热的发展形势下,音视频开发(采集.编解码.传输.播放.美颜)等技术也随之成为开发者们关注的重点,本系列文章就音视频开发过程中所运用到的 ...

  6. 网页测试本地服务器_音视频开发搭建一个直播服务器

    现在抖音.快手等直播实在是太火了,因此对音视频的开发非常感兴趣.查阅了相关资料,使用Nginx搭建一个简单的直播跟点播流媒体服务器,能够实时推流到服务器,同时在网页端播放直播的视频. 先上效果 使用O ...

  7. 从开发小白到入职抖音音视频开发岗位技术总结

    1.职业发展的迷茫 前几天发了一篇关于音视频开发学习录总结,文章链接:https://blog.csdn.net/Linuxhus/article/details/112705431 收到一些网友的来 ...

  8. iOS音视频开发七:视频采集

    将通过拆解采集 → 编码 → 封装 → 解封装 → 解码 → 渲染流程并实现 Demo 来向大家介绍如何在 iOS/Android 平台上手音视频开发. 这里是第七篇:iOS 视频采集 Demo.这个 ...

  9. iOS音视频开发八:视频编码,H.264 和 H.265 都支持

    我们将通过拆解采集 → 编码 → 封装 → 解封装 → 解码 → 渲染流程并实现 Demo 来向大家介绍如何在 iOS/Android 平台上手音视频开发. 这里是第八篇:iOS 视频编码 Demo. ...

最新文章

  1. usaco contact
  2. JavaScript判断浏览器类型及版本
  3. 学会使用Spring注解
  4. QQ 邮箱的换肤 bug
  5. C语言变参函数的实现,C语言的那些小秘密之变参函数的实现
  6. 一个极好的ALV例子
  7. java 选中当前,Java开发网 - 请问如何获得SWT中List widget当前选中的项目
  8. 小程序tabbar这套方案全搞定!
  9. win7变成linux桌面背景,教大家把Ubuntu界面改造成Windows7系统
  10. AudioDestinationNode
  11. 39、【华为HCIE-Storage】--对象存储原理
  12. Exchange邮箱数据库事务日志引起磁盘暴涨
  13. pandas——解决excel科学计数法问题
  14. aamp;m大学计算机科学,斑马博士捷报|德克萨斯AM大学 (TAMU) MSc Computer Science录取!...
  15. 众多IT精英齐聚首尔,竟是因为这项技术……
  16. 为什么女程序员很孤独?
  17. 深度操作系统deepin下载与安装教程-系统安装
  18. ASM PCRP21-100-1-SSI-KAB5M
  19. 一文熟悉 Go 的循环结构 —— for 循环
  20. 网络故障的技术一些东东

热门文章

  1. 在阿里云上部署nodejs服务 + https
  2. 安装php环境显示端口被占用,【亲测】启动PHPstudy提醒80、3306端口被占用的2种解决办法_全百科网...
  3. 菜单设置:点击第一级菜单,第二级菜单在下方出现,并且下方的一级菜单自动下移
  4. 扬帆志远—tiktok跨境电商运营流程
  5. dz调用图片PHP写法,100分discuz列表页调用帖子图片
  6. S32K14x芯片bootloader独立flash驱动功能
  7. 平面设计实验三 手机海报与选区操作
  8. 华为手机备忘录怎么加视频?超多功能的智能备忘录
  9. 10大H5前端框架,让你开发不愁
  10. epubjs阅读器引擎介绍(一)