![]() |
飘逸的山羊 · 国学典籍举要(280 部)· 5 月前 · |
![]() |
考研的大脸猫 · 【极客体验】极米 Z3 ...· 5 月前 · |
![]() |
独立的鸵鸟 · 广州人也有自己的“鹤岗”,15万可入手两室两厅!· 5 月前 · |
![]() |
时尚的匕首 · WX-0593 combined with ...· 7 月前 · |
![]() |
风流倜傥的黄豆 · Agilent 的敏捷开发转型之旅 | ...· 7 月前 · |
相机 图像分辨率 像素分辨率 session |
https://xiaodongxie1024.github.io/2019/04/15/20190413_iOS_VideoCaptureExplain/ |
![]() |
旅行中的闹钟
6 月前 |
AVCaptureSession:使用相机或麦克风实时采集音视频数据流.
AVCaptureConnection: 表示输入与输出的连接
AVCaptureVideoPreviewLayer: 显示当前相机正在采集的状况
一个session可以配置多个输入输出
下图展示了向session中添加输入输出后的连接情况
首先需要在Info.plist文件中添加键
Privacy - Camera Usage Description
以请求相机权限.
注意: 如果不添加,程序crash,如果用户不给权限,则会显示全黑的相机画面.
1 |
AVCaptureSession *session = [[AVCaptureSession alloc] init]; |
CMTimeMake: 分子为1,即每秒钟来多少帧.
在低帧率下(帧率<=30)可以用如下方式设置
1 |
- (void)setCameraResolutionByPresetWithHeight:(int)height session:(AVCaptureSession *)session { |
高帧率下设置分辨率(帧率>30)
如果需要对某一分辨率支持高帧率的设置,如50帧,60帧,120帧…,原先
setActiveVideoMinFrameDuration
与
setActiveVideoMaxFrameDuration
是无法做到的,Apple规定我们需要使用新的方法设置帧率
setActiveVideoMinFrameDuration
与
setActiveVideoMaxFrameDuration
,并且该方法必须配合新的设置分辨率
activeFormat
的方法一起使用.
新的设置分辨率的方法
activeFormat
与
sessionPreset
是互斥的,如果使用了一个, 另一个会失效,建议直接使用高帧率的设置方法,废弃低帧率下设置方法,避免产生兼容问题。
Apple在更新方法后将原先分离的分辨率与帧率的设置方法合二为一,原先是单独设置相机分辨率与帧率,而现在则需要一起设置,即每个分辨率有其对应支持的帧率范围,每个帧率也有其支持的分辨率,需要我们遍历来查询,所以原先统一的单独的设置分辨率与帧率的方法在高帧率模式下相当于弃用,可以根据项目需求选择,如果确定项目不会支持高帧率(fps>30),可以使用以前的方法,简单且有效.
注意: 使用
activeFormat
方法后,之前使用
sessionPreset
方法设置的分辨率将自动变为
AVCaptureSessionPresetInputPriority
,所以如果项目之前有用
canSetSessionPreset
比较的if语句也都将失效,建议如果项目必须支持高帧率则彻底启用
sessionPreset
方法.
注意: 在将session配置为使用用于高分辨率静态拍摄的活动格式并将以下一个或多个操作应用于AVCaptureVideoDataOutput时,系统可能无法满足目标帧速率:缩放,方向更改,格式转换。
1 |
[session beginConfiguration]; |
1 |
- (void)captureOutput:(AVCaptureOutput *)output didDropSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection |
1 |
[kTVUNotification addObserver:self selector:@selector(handleCameraRuntimeError) |
AVCaptureDevice对象是关于相机硬件的接口,用于控制硬件特性,诸如镜头的位置、曝光、闪光灯等。
可以通过代码获取当前输入设备的位置(前后置摄像头)以及其他硬件相关信息.
1 |
NSArray *devices = [AVCaptureDevice devices]; |
1 |
NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; |
注意:在设置相机属性前,总是先通过API查询当前设备是否支持该功能,再进行相应处理
1 |
isFocusModeSupported: 查询设备是否支持. |
使用
focusPointOfInterestSupported
测试设备是否支持设置对焦点,如果支持,使用
focusPointOfInterest
设置聚焦点,{0,0}代表画面左上角坐标,{1,1}代表右下角坐标.
1 |
if ([currentDevice isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus]) { |
1 |
isExposureModeSupported:是否支持某个曝光模式 |
1 |
if ([currentDevice isExposureModeSupported:AVCaptureExposureModeContinuousAutoExposure]) { |
1 |
hasFlash:是否有闪光灯 |
1 |
hasTorch: 是否有手电筒 |
手电筒只有在相机开启时才能打开
该功能默认是关闭的,画面稳定功能依赖于设备特定的硬件,并且不是所有格式的元数据与分辨率都支持此功能.
开启该功能可能造成画面延迟
1 |
isWhiteBalanceModeSupported: 是否支持白平衡模式 |
相机为了适应不同类型的光照条件需要补偿。这意味着在冷光线的条件下,传感器应该增强红色部分,而在暖光线下增强蓝色部分。在 iPhone 相机中,设备会自动决定合适的补光,但有时也会被场景的颜色所混淆失效。幸运地是,iOS 8 可以里手动控制白平衡。
自动模式工作方式和对焦、曝光的方式一样,但是没有“感兴趣的点”,整张图像都会被纳入考虑范围。在手动模式,我们可以通过开尔文所表示的温度来调节色温和色彩。典型的色温值在 2000-3000K (类似蜡烛或灯泡的暖光源) 到 8000K (纯净的蓝色天空) 之间。色彩范围从最小的 -150 (偏绿) 到 150 (偏品红)。
1 |
AVCaptureConnection *captureConnection = <#A capture connection#>; |
使用锁配置相机属性,
lockForConfiguration:
,为了避免在你修改它时其他应用程序可能对它做更改.
1 |
if ([device isFocusModeSupported:AVCaptureFocusModeLocked]) { |
1 |
AVCaptureSession *session = <#A capture session#>; |
1 |
NSError *error; |
AVCaptureOutput: 从session中获取输出流.
1 |
addOutput: 添加输出 |
AVCaptureMovieFileOutput: 使用此类作为输出.可以配置录制最长时间,文件大小以及禁止在磁盘空间不足时继续录制等等.
1 |
AVCaptureMovieFileOutput *aMovieFileOutput = [[AVCaptureMovieFileOutput alloc] init]; |
URL不能是已经存在的文件,因为无法重写.
1 |
AVCaptureMovieFileOutput *aMovieFileOutput = <#Get a movie file output#>; |
需要检查
AVErrorRecordingSuccessfullyFinishedKey
的值,因为可能写入没有错误,但由于磁盘内存不足导致最终写入失败.
写入失败的原因
1 |
- (void)captureOutput:(AVCaptureFileOutput *)captureOutput |
可以在任意时间设置输出文件的metadata信息,即使正在录制.
1 |
AVCaptureMovieFileOutput *aMovieFileOutput = <#Get a movie file output#>; |
AVCaptureVideoDataOutput对象可以通过代理(
setSampleBufferDelegate:queue:
)获取实时的视频帧数据.同时需要指定一个接受视频帧的串行队列.
必须使用串行队列,因为要保证视频帧是按顺序传输给代理方法
在
captureOutput:didOutputSampleBuffer:fromConnection:
代理方法中接受视频帧,每个视频帧被存放在CMSampleBufferRef引用对象中, 默认这些buffers以相机最有效的格式发出,我们也可以通过
videoSettings
指定输出相机的格式.需要将要指定的格式设置为
kCVPixelBufferPixelFormatTypeKey
的value,使用
availableVideoCodecTypes
可以查询当前支持的相机格式.
1 |
AVCaptureVideoDataOutput *videoDataOutput = [AVCaptureVideoDataOutput new]; |
如果要使用附带metadata元数据的静止图像,需要使用
AVCaptureStillImageOutput
.
使用
availableImageDataCVPixelFormatTypes, availableImageDataCodecTypes
获取当前支持的格式,以便于查询是否支持你想要设置的格式.
1 |
AVCaptureStillImageOutput *stillImageOutput = [[AVCaptureStillImageOutput alloc] init]; |
向output发送一条
captureStillImageAsynchronouslyFromConnection:completionHandler:
消息以采集一张图像.
1 |
AVCaptureConnection *videoConnection = nil; |
如果相机的session已经开始工作,我们可以为用户创建一个预览图展示当前相机采集的状况(即就像系统相机拍摄视频时的预览界面)
AVCaptureVideoDataOutput
可以将像素层呈现给用户
a video preview layer保持对它关联session的强引用,为了确保在图层尝试显示视频时不会被释放
1 |
AVCaptureSession *captureSession = <#Get a capture session#>; |
preview layer是CALayer的子类,因此它具有CALayer的行为,你可以对这一图层执行转换,旋转等操作.
实现带有预览层的对焦时,必须考虑预览层的预览方向和重力以及镜像预览的可能性.
注意:一般采集音频不使用AVCaptureSession, 而是用更底层的AudioQueue, AudioUnit, 如需帮助请参考另一篇文章: 音频采集
使用AVCaptureAudioChannel对象监视捕获连接中音频通道的平均功率和峰值功率级别.音频级不支持KVO,因此必须经常轮询更新级别,以便更新用户界面(例如,每秒10次)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14 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. 总结
6.1. 流程
- 创建AVCaptureSession对象管理输入输出流
- 创建AVCaptureDevice对象管理当前硬件支持的所有设备,可以遍历找到我们需要的设备
- 创建AVCaptureDeviceInput对象表示具体的的输入端的硬件设备
- 创建AVCaptureVideoDataOutput对象管理输出视频帧
- 实现AVCaptureVideoDataOutput代理方法以产生视频帧
- 将视频帧从CMSampleBuffer格式转为UIImage格式
下面是简单流程实现
创建并配置session对象
1
2 AVCaptureSession *session = [[AVCaptureSession alloc] init];
session.sessionPreset = AVCaptureSessionPresetMedium;创建并配置设备的输入端
1
2
3
4
5
6
7
8
9
10 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对象(如视频帧的格式, 帧率),以产生未压缩的原始数据.
1
2
3
4
5
6
7
8
9 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);
- 实现代理方法
1
2
3
4
5
6
7 - (void)captureOutput:(AVCaptureOutput *)captureOutput
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
fromConnection:(AVCaptureConnection *)connection {
UIImage *image = imageFromSampleBuffer(sampleBuffer);
// Add your code here that uses the image.
}- 开始/停止录制
配置完capture session之后,确保应用程序拥有权限.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 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.
1 assetWriterInput.expectsMediaDataInRealTime=YES;
- 1. 需求:需要采集到视频帧数据从而可以进行一系列处理(如: 裁剪,旋转,美颜,特效….). 所以,必须采集到视频帧数据.
- 2. 阅读前提:
- 3. 注意:本文仅仅是原理性讲解,而实际相机的设置也是比较复杂,具体相机参数的设置请参考另一篇 - iOS相机设置实战
- 4. Overview
- 5. 授权
- 6. 1. 使用Capture Session管理数据流
- 7. 2. AVCaptureDevice表示输入设备
- 8. 3. 配置Capture Inputs添加到Session中
- 9. 4. 使用Capture Outputs从Session中获取输出流
- 10. 5. 展示预览图
- 11. 6. 总结
- 12. 7. 补充
![]() |
飘逸的山羊 · 国学典籍举要(280 部) 5 月前 |
![]() |
独立的鸵鸟 · 广州人也有自己的“鹤岗”,15万可入手两室两厅! 5 月前 |