当前位置: 首页 > 编程日记 > 正文

iOS视频流采集概述(AVCaptureSession)

需求:需要采集到视频帧数据从而可以进行一系列处理(如: 裁剪,旋转,美颜,特效....). 所以,必须采集到视频帧数据.


阅读前提:

  • 使用AVFoundation框架
  • 采集音视频帧数据

GitHub地址(附代码) : iOS视频流采集概述

简书地址 : iOS视频流采集概述

博客地址 : iOS视频流采集概述

掘金地址 : iOS视频流采集概述


注意:本文仅仅是原理性讲解,而实际相机的设置也是比较复杂,具体相机参数的设置请参考另一篇 - iOS相机设置实战


Overview

AVCaptureSession:使用相机或麦克风实时采集音视频数据流.

  • AVCaptureSession : 管理输入输出音视频流

  • AVCaptureDevice : 相机硬件的接口,用于控制硬件特性,诸如镜头的位置(前后摄像头)、曝光、闪光灯等。

  • AVCaptureInput : 配置输入设备,提供来自设备的数据

  • AVCaptureOutput : 管理输出的结果(音视频数据流)

  • AVCaptureConnection: 表示输入与输出的连接

  • AVCaptureVideoPreviewLayer: 显示当前相机正在采集的状况

一个session可以配置多个输入输出

下图展示了向session中添加输入输出后的连接情况

授权

首先需要在Info.plist文件中添加键Privacy - Camera Usage Description以请求相机权限.

注意: 如果不添加,程序crash,如果用户不给权限,则会显示全黑的相机画面.

1. 使用Capture Session管理数据流

AVCaptureSession *session = [[AVCaptureSession alloc] init];
// Add inputs and outputs.
[session startRunning];复制代码

1.1. 使用preset配置分辨率,帧率

  • canSetSessionPreset:检查是否支持指定分辨率
  • setActiveVideoMinFrameDuration: 设置帧率最小值
  • setActiveVideoMaxFrameDuration: 设置帧率最大值

CMTimeMake: 分子为1,即每秒钟来多少帧.

  • 在低帧率下(帧率<=30)可以用如下方式设置
- (void)setCameraResolutionByPresetWithHeight:(int)height session:(AVCaptureSession *)session {[session beginConfiguration];session.sessionPreset = preset;[session commitConfiguration];
}- (void)setCameraForLFRWithFrameRate:(int)frameRate {// Only for frame rate <= 30AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];[captureDevice lockForConfiguration:NULL];[captureDevice setActiveVideoMinFrameDuration:CMTimeMake(1, frameRate)];[captureDevice setActiveVideoMaxFrameDuration:CMTimeMake(1, frameRate)];[captureDevice unlockForConfiguration];
}
复制代码
  • 高帧率下设置分辨率(帧率>30)

如果需要对某一分辨率支持高帧率的设置,如50帧,60帧,120帧...,原先setActiveVideoMinFrameDurationsetActiveVideoMaxFrameDuration是无法做到的,Apple规定我们需要使用新的方法设置帧率setActiveVideoMinFrameDurationsetActiveVideoMaxFrameDuration,并且该方法必须配合新的设置分辨率activeFormat的方法一起使用.

新的设置分辨率的方法activeFormatsessionPreset是互斥的,如果使用了一个, 另一个会失效,建议直接使用高帧率的设置方法,废弃低帧率下设置方法,避免产生兼容问题。

Apple在更新方法后将原先分离的分辨率与帧率的设置方法合二为一,原先是单独设置相机分辨率与帧率,而现在则需要一起设置,即每个分辨率有其对应支持的帧率范围,每个帧率也有其支持的分辨率,需要我们遍历来查询,所以原先统一的单独的设置分辨率与帧率的方法在高帧率模式下相当于弃用,可以根据项目需求选择,如果确定项目不会支持高帧率(fps>30),可以使用以前的方法,简单且有效.

注意: 使用activeFormat方法后,之前使用sessionPreset方法设置的分辨率将自动变为AVCaptureSessionPresetInputPriority,所以如果项目之前有用canSetSessionPreset比较的if语句也都将失效,建议如果项目必须支持高帧率则彻底启用sessionPreset方法.

具体设置方法参考另一篇文章:iOS相机设置实战

注意: 在将session配置为使用用于高分辨率静态拍摄的活动格式并将以下一个或多个操作应用于AVCaptureVideoDataOutput时,系统可能无法满足目标帧速率:缩放,方向更改,格式转换。

1.2. 更改相机设置

如果你需要在开启相机后进一步调节相机参数,在beginConfigurationcommitConfiguration中写入更改的代码.调用beginConfiguration后可以添加移除输入输出,更改分辨率,配置个别的输入输出属性,直到调用commitConfiguration所有的更改才会生效.

[session beginConfiguration];
// Remove an existing capture device.
// Add a new capture device.
// Reset the preset.
[session commitConfiguration];复制代码

1.3. 监听Session状态

可以使用通知监听相机当前状态,如开始,停止,意外中断等等...

  • 监听掉帧
- (void)captureOutput:(AVCaptureOutput *)output didDropSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
复制代码
  • 处理相机运行中突然出错
[kTVUNotification addObserver:self selector:@selector(handleCameraRuntimeError)name:AVCaptureSessionRuntimeErrorNotificationobject:nil];
[kTVUNotification addObserver:self selector:@selector(handleCameraInterruptionEndedError)name:AVCaptureSessionInterruptionEndedNotificationobject:nil];
[kTVUNotification addObserver:self selector:@selector(handleCameraWasInterruptedError)name:AVCaptureSessionWasInterruptedNotificationobject:nil];
复制代码

2. AVCaptureDevice表示输入设备

2.1. 定义

AVCaptureDevice对象是关于相机硬件的接口,用于控制硬件特性,诸如镜头的位置、曝光、闪光灯等。

2.2. 获取设备

使用AVCaptureDevice的devicesdevicesWithMediaType:方法可以找到我们需要的设备, 可用设备列表可能会发生变化, 如它们被别的应用使用,或一个新的输入设备接入(如耳机),通过注册AVCaptureDeviceWasConnectedNotification,AVCaptureDeviceWasDisconnectedNotification可以在设备变化时得到通知.

2.3. 设备特性

可以通过代码获取当前输入设备的位置(前后置摄像头)以及其他硬件相关信息.

NSArray *devices = [AVCaptureDevice devices];for (AVCaptureDevice *device in devices) {NSLog(@"Device name: %@", [device localizedName]);if ([device hasMediaType:AVMediaTypeVideo]) {if ([device position] == AVCaptureDevicePositionBack) {NSLog(@"Device position : back");}else {NSLog(@"Device position : front");}}
}
复制代码

2.4. 相机功能设置

不同设备具有不同的功能,如果需要可以开启对应的功能

NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
NSMutableArray *torchDevices = [[NSMutableArray alloc] init];for (AVCaptureDevice *device in devices) {[if ([device hasTorch] &&[device supportsAVCaptureSessionPreset:AVCaptureSessionPreset640x480]) {[torchDevices addObject:device];}
}
复制代码

注意:在设置相机属性前,总是先通过API查询当前设备是否支持该功能,再进行相应处理

  • 聚焦模式-Focus Modes
    • AVCaptureFocusModeLocked: 设置一个固定的聚焦点
    • AVCaptureFocusModeAutoFocus: 首次自动对焦然后锁定一个聚焦点
    • AVCaptureFocusModeContinuousAutoFocus: 指当场景改变,相机会自动重新对焦到画面的中心点
isFocusModeSupported: 查询设备是否支持.
adjustingFocus: 判断一个设备是否正在改变对焦点
复制代码

使用focusPointOfInterestSupported测试设备是否支持设置对焦点,如果支持,使用focusPointOfInterest设置聚焦点,{0,0}代表画面左上角坐标,{1,1}代表右下角坐标.

if ([currentDevice isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus]) {CGPoint autofocusPoint = CGPointMake(0.5f, 0.5f);[currentDevice setFocusPointOfInterest:autofocusPoint];[currentDevice setFocusMode:AVCaptureFocusModeContinuousAutoFocus];
}复制代码
  • 曝光模式-Exposure Modes
    • AVCaptureExposureModeContinuousAutoExposure: 自动调节曝光模式
    • AVCaptureExposureModeLocked: 固定的曝光模式
isExposureModeSupported:是否支持某个曝光模式
adjustingExposure:判断一个设备是否正在改变曝光值
复制代码
if ([currentDevice isExposureModeSupported:AVCaptureExposureModeContinuousAutoExposure]) {CGPoint exposurePoint = CGPointMake(0.5f, 0.5f);[currentDevice setExposurePointOfInterest:exposurePoint];[currentDevice setExposureMode:AVCaptureExposureModeContinuousAutoExposure];
}复制代码
  • 闪光灯模式-Flash Modes
    • AVCaptureFlashModeOff: 永不开启
    • AVCaptureFlashModeOn: 总是开启
    • AVCaptureFlashModeAuto: 自动开启,根据光线判断
hasFlash:是否有闪光灯
isFlashModeSupported:是否支持闪光灯模式
复制代码
  • 手电筒模式-Torch Mode
    • AVCaptureTorchModeOff
    • AVCaptureTorchModeOn
    • AVCaptureTorchModeAuto
hasTorch: 是否有手电筒
isTorchModeSupported: 是否支持手电筒模式
复制代码

手电筒只有在相机开启时才能打开

  • 视频稳定性-Video Stabilization
    • videoStabilizationEnabled
    • enablesVideoStabilizationWhenAvailable

该功能默认是关闭的,画面稳定功能依赖于设备特定的硬件,并且不是所有格式的元数据与分辨率都支持此功能.

开启该功能可能造成画面延迟

  • 白平衡-White Balance
    • AVCaptureWhiteBalanceModeLocked
    • AVCaptureWhiteBalanceModeContinuousAutoWhiteBalance
isWhiteBalanceModeSupported: 是否支持白平衡模式
adjustingWhiteBalance: 是否正在调整白平衡
复制代码

相机为了适应不同类型的光照条件需要补偿。这意味着在冷光线的条件下,传感器应该增强红色部分,而在暖光线下增强蓝色部分。在 iPhone 相机中,设备会自动决定合适的补光,但有时也会被场景的颜色所混淆失效。幸运地是,iOS 8 可以里手动控制白平衡。

自动模式工作方式和对焦、曝光的方式一样,但是没有“感兴趣的点”,整张图像都会被纳入考虑范围。在手动模式,我们可以通过开尔文所表示的温度来调节色温和色彩。典型的色温值在 2000-3000K (类似蜡烛或灯泡的暖光源) 到 8000K (纯净的蓝色天空) 之间。色彩范围从最小的 -150 (偏绿) 到 150 (偏品红)。

  • 设置设备方向
    • AVCaptureConnectionsupportsVideoOrientation:
AVCaptureConnection *captureConnection = <#A capture connection#>;
if ([captureConnection isVideoOrientationSupported])
{AVCaptureVideoOrientation orientation = AVCaptureVideoOrientationLandscapeLeft;[captureConnection setVideoOrientation:orientation];
}
复制代码
  • 配置设备

使用锁配置相机属性,lockForConfiguration:,为了避免在你修改它时其他应用程序可能对它做更改.

if ([device isFocusModeSupported:AVCaptureFocusModeLocked]) {NSError *error = nil;if ([device lockForConfiguration:&error]) {device.focusMode = AVCaptureFocusModeLocked;[device unlockForConfiguration];}else {// Respond to the failure as appropriate.
复制代码
  • 切换设备
AVCaptureSession *session = <#A capture session#>;
[session beginConfiguration];[session removeInput:frontFacingCameraDeviceInput];
[session addInput:backFacingCameraDeviceInput];[session commitConfiguration];
复制代码

3. 配置Capture Inputs添加到Session中

一个AVCaptureInput代表一种或多种媒体数据,比如,输入设备可以同时提供视频和音频数据.每种媒体流代表一个AVCaptureInputPort对象.使用AVCaptureConnection可以将AVCaptureInputPort与AVCaptureOutput连接起来.

NSError *error;
AVCaptureDeviceInput *input =[AVCaptureDeviceInput deviceInputWithDevice:device error:&error];
if (!input) {// Handle the error appropriately.
}AVCaptureSession *captureSession = <#Get a capture session#>;
AVCaptureDeviceInput *captureDeviceInput = <#Get a capture device input#>;
if ([captureSession canAddInput:captureDeviceInput]) {[captureSession addInput:captureDeviceInput];
}
else {// Handle the failure.
}复制代码

4. 使用Capture Outputs从Session中获取输出流

AVCaptureOutput: 从session中获取输出流.

  • AVCaptureMovieFileOutput: 将数据写入文件
  • AVCaptureVideoDataOutput: 将视频数据以回调形式输出视频帧
  • AVCaptureAudioDataOutput: 将音频数据以回调形式输出音频帧
  • AVCaptureStillImageOutput: 捕捉静态图片
addOutput: 添加输出
canAddOutput: 是否能添加AVCaptureSession *captureSession = <#Get a capture session#>;
AVCaptureMovieFileOutput *movieOutput = <#Create and configure a movie output#>;
if ([captureSession canAddOutput:movieOutput]) {[captureSession addOutput:movieOutput];
}
else {// Handle the failure.
}复制代码

4.1. AVCaptureMovieFileOutput

4.1.1. 写入文件

AVCaptureMovieFileOutput: 使用此类作为输出.可以配置录制最长时间,文件大小以及禁止在磁盘空间不足时继续录制等等.

AVCaptureMovieFileOutput *aMovieFileOutput = [[AVCaptureMovieFileOutput alloc] init];
CMTime maxDuration = <#Create a CMTime to represent the maximum duration#>;
aMovieFileOutput.maxRecordedDuration = maxDuration;
aMovieFileOutput.minFreeDiskSpaceLimit = <#An appropriate minimum given the quality of the movie format and the duration#>;
复制代码
4.1.2. 开始录制

你需要提供一个文件保存地址的URL以及代理去监听状态,这个代理是AVCaptureFileOutputRecordingDelegate, 必须实现captureOutput:didFinishRecordingToOutputFileAtURL:fromConnections:error:代理方法

URL不能是已经存在的文件,因为无法重写.

AVCaptureMovieFileOutput *aMovieFileOutput = <#Get a movie file output#>;
NSURL *fileURL = <#A file URL that identifies the output location#>;
[aMovieFileOutput startRecordingToOutputFileURL:fileURL recordingDelegate:<#The delegate#>];
复制代码
4.1.3. 确保文件写入成功

通过代理方法可以检查是否写入成功

需要检查AVErrorRecordingSuccessfullyFinishedKey的值,因为可能写入没有错误,但由于磁盘内存不足导致最终写入失败.

写入失败的原因

  • 磁盘内存不足(AVErrorDiskFull)
  • 录制设备失去连接(AVErrorDeviceWasDisconnected)
  • session意外中断(AVErrorSessionWasInterrupted)
- (void)captureOutput:(AVCaptureFileOutput *)captureOutputdidFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURLfromConnections:(NSArray *)connectionserror:(NSError *)error {BOOL recordedSuccessfully = YES;if ([error code] != noErr) {// A problem occurred: Find out if the recording was successful.id value = [[error userInfo] objectForKey:AVErrorRecordingSuccessfullyFinishedKey];if (value) {recordedSuccessfully = [value boolValue];}}// Continue as appropriate...
复制代码
4.1.4. 添加Metadata到文件

可以在任意时间设置输出文件的metadata信息,即使正在录制.

AVCaptureMovieFileOutput *aMovieFileOutput = <#Get a movie file output#>;
NSArray *existingMetadataArray = aMovieFileOutput.metadata;
NSMutableArray *newMetadataArray = nil;
if (existingMetadataArray) {newMetadataArray = [existingMetadataArray mutableCopy];
}
else {newMetadataArray = [[NSMutableArray alloc] init];
}AVMutableMetadataItem *item = [[AVMutableMetadataItem alloc] init];
item.keySpace = AVMetadataKeySpaceCommon;
item.key = AVMetadataCommonKeyLocation;CLLocation *location - <#The location to set#>;
item.value = [NSString stringWithFormat:@"%+08.4lf%+09.4lf/"location.coordinate.latitude, location.coordinate.longitude];[newMetadataArray addObject:item];aMovieFileOutput.metadata = newMetadataArray;复制代码

4.2 AVCaptureVideoDataOutput

4.2.1. 获取视频帧数据

AVCaptureVideoDataOutput对象可以通过代理(setSampleBufferDelegate:queue:)获取实时的视频帧数据.同时需要指定一个接受视频帧的串行队列.

必须使用串行队列,因为要保证视频帧是按顺序传输给代理方法

captureOutput:didOutputSampleBuffer:fromConnection:代理方法中接受视频帧,每个视频帧被存放在CMSampleBufferRef引用对象中, 默认这些buffers以相机最有效的格式发出,我们也可以通过videoSettings指定输出相机的格式.需要将要指定的格式设置为kCVPixelBufferPixelFormatTypeKey的value,使用availableVideoCodecTypes可以查询当前支持的相机格式.

AVCaptureVideoDataOutput *videoDataOutput = [AVCaptureVideoDataOutput new];
NSDictionary *newSettings =@{ (NSString *)kCVPixelBufferPixelFormatTypeKey : @(kCVPixelFormatType_32BGRA) };
videoDataOutput.videoSettings = newSettings;// discard if the data output queue is blocked (as we process the still image
[videoDataOutput setAlwaysDiscardsLateVideoFrames:YES];)// 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];AVCaptureSession *captureSession = <#The Capture Session#>;if ( [captureSession canAddOutput:videoDataOutput] )[captureSession addOutput:videoDataOutput];复制代码
4.3. AVCaptureStillImageOutput

如果要使用附带metadata元数据的静止图像,需要使用AVCaptureStillImageOutput.

  • 像素与编码格式

使用availableImageDataCVPixelFormatTypes, availableImageDataCodecTypes获取当前支持的格式,以便于查询是否支持你想要设置的格式.

AVCaptureStillImageOutput *stillImageOutput = [[AVCaptureStillImageOutput alloc] init];
NSDictionary *outputSettings = @{ AVVideoCodecKey : AVVideoCodecJPEG};
[stillImageOutput setOutputSettings:outputSettings];
复制代码
  • 采集图像

向output发送一条captureStillImageAsynchronouslyFromConnection:completionHandler:消息以采集一张图像.

AVCaptureConnection *videoConnection = nil;
for (AVCaptureConnection *connection in stillImageOutput.connections) {for (AVCaptureInputPort *port in [connection inputPorts]) {if ([[port mediaType] isEqual:AVMediaTypeVideo] ) {videoConnection = connection;break;}}if (videoConnection) { break; }
}[stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler:^(CMSampleBufferRef imageSampleBuffer, NSError *error) {CFDictionaryRef exifAttachments =CMGetAttachment(imageSampleBuffer, kCGImagePropertyExifDictionary, NULL);if (exifAttachments) {// Do something with the attachments.}// Continue as appropriate.}];复制代码

5. 展示预览图

如果相机的session已经开始工作,我们可以为用户创建一个预览图展示当前相机采集的状况(即就像系统相机拍摄视频时的预览界面)

5.1. Video Preview

  • AVCaptureVideoPreviewLayer: 展示相机预览情况,CALayer的子类.
  • 使用AVCaptureVideoDataOutput可以将像素层呈现给用户

a video preview layer保持对它关联session的强引用,为了确保在图层尝试显示视频时不会被释放

AVCaptureSession *captureSession = <#Get a capture session#>;
CALayer *viewLayer = <#Get a layer from the view in which you want to present the preview#>;AVCaptureVideoPreviewLayer *captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:captureSession];
[viewLayer addSublayer:captureVideoPreviewLayer];
复制代码

preview layer是CALayer的子类,因此它具有CALayer的行为,你可以对这一图层执行转换,旋转等操作.

5.1.1. 视频重力感应模式
  • AVLayerVideoGravityResizeAspect: 保持分辨率的原始尺寸,即横纵比,未填充的屏幕区域会有黑条
  • AVLayerVideoGravityResizeAspectFill: 保持横纵比,铺满屏幕时可以牺牲部分像素
  • AVLayerVideoGravityResize: 拉伸视频以充满屏幕,图像会失真
5.1.2. 点击聚焦

实现带有预览层的对焦时,必须考虑预览层的预览方向和重力以及镜像预览的可能性.

5.2. 显示Audio Levels

注意:一般采集音频不使用AVCaptureSession, 而是用更底层的AudioQueue, AudioUnit, 如需帮助请参考另一篇文章: 音频采集

使用AVCaptureAudioChannel对象监视捕获连接中音频通道的平均功率和峰值功率级别.音频级不支持KVO,因此必须经常轮询更新级别,以便更新用户界面(例如,每秒10次)。

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. 总结

下面将介绍如何采集视频帧并将其转换为UIImage对象.

6.1. 流程

  • 创建AVCaptureSession对象管理输入输出流
  • 创建AVCaptureDevice对象管理当前硬件支持的所有设备,可以遍历找到我们需要的设备
  • 创建AVCaptureDeviceInput对象表示具体的的输入端的硬件设备
  • 创建AVCaptureVideoDataOutput对象管理输出视频帧
  • 实现AVCaptureVideoDataOutput代理方法以产生视频帧
  • 将视频帧从CMSampleBuffer格式转为UIImage格式

下面是简单流程实现

  • 创建并配置session对象
AVCaptureSession *session = [[AVCaptureSession alloc] init];
session.sessionPreset = AVCaptureSessionPresetMedium;复制代码
  • 创建并配置设备的输入端
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对象(如视频帧的格式, 帧率),以产生未压缩的原始数据.

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);复制代码
  • 实现代理方法
- (void)captureOutput:(AVCaptureOutput *)captureOutputdidOutputSampleBuffer:(CMSampleBufferRef)sampleBufferfromConnection:(AVCaptureConnection *)connection {UIImage *image = imageFromSampleBuffer(sampleBuffer);// Add your code here that uses the image.
}
复制代码
  • 开始/停止录制

配置完capture session之后,确保应用程序拥有权限.

NSString *mediaType = AVMediaTypeVideo;[AVCaptureDevice requestAccessForMediaType:mediaType completionHandler:^(BOOL granted) {if (granted){//Granted access to mediaType[self setDeviceAuthorized:YES];}else{//Not granted access to mediaTypedispatch_async(dispatch_get_main_queue(), ^{[[[UIAlertView alloc] initWithTitle:@"AVCam!"message:@"AVCam doesn't have permission to use Camera, please change privacy settings"delegate:selfcancelButtonTitle:@"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.

assetWriterInput.expectsMediaDataInRealTime=YES;
复制代码

转载于:https://juejin.im/post/5cb1f987f265da039d3274c3

相关文章:

300秒搞定第一超算1万年的计算量,量子霸权时代已来?

&#xff08;由AI科技大本营付费下载自视觉中国&#xff09;作者 | 马超责编 | 郭芮来源 | CSDN 博客近日&#xff0c;美国航天局&#xff08;NASA&#xff09;发布了一篇名为《Quantum Supremacy Using a Programmable Superconducting Processor》的报道&#xff0c;称谷歌的…

2014-3-6 星期四 [第一天执行分析]

昨日进度&#xff1a; [毛思想]&#xff1a;看测控技术量待定 --> [良]超额完成&#xff0c;昨天基本上把测控看了一大半啦 [汇编]&#xff1a;认真听课&#xff0c;边听边消化自学 --> [中]基本满足&#xff0c;还需要抽时间总结&#xff0c;特别是前面寻址的各种情况…

行列式介绍及Eigen/OpenCV/C++的三种实现

行列式&#xff0c;记作det(A)&#xff0c;是一个将方阵A映射到实数的函数。行列式等于矩阵特征值的乘积。行列式的绝对值可以用来衡量矩阵参与矩阵乘法后空间扩大或者缩小了多少。如果行列式是0&#xff0c;那么空间至少沿着某一维完全收缩了&#xff0c;使其失去了所有的体积…

基于Go的语义解析开源库FMR,“屠榜”模型外的NLP利器

&#xff08;由AI科技大本营付费下载自视觉中国&#xff09;作者 | 刘占亮 一览群智技术副总裁编辑 | Jane出品 | AI科技大本营&#xff08;ID&#xff1a;rgznai100&#xff09;如何合理地表示语言的内在意义&#xff1f;这是自然语言处理业界中长久以来悬而未决的一个命题。在…

【高级数据类型2】- 10. 接口

2019独角兽企业重金招聘Python工程师标准>>> Go语言-接口 在Go语言中&#xff0c;一个接口类型总是代表着某一种类型&#xff08;即所有实现它的类型&#xff09;的行为。一个接口类型的声明通常会包含关键字type、类型名称、关键字interface以及由花括号包裹的若干…

Linux软件包命令

2019独角兽企业重金招聘Python工程师标准>>> dpkg命令&#xff1a; dpkg -i **/**.deb 安装软件 dpkg -x **.deb 解开.deb文件 dpkg -r /-p 删除并清配置 更详细的 用dpkg --help 查询 如下&#xff1a; dpkg -i|--install <.deb 文件的文件名> ... | -R|--re…

Caffe中计算图像均值的实现(cifar10)

在深度学习中&#xff0c;在进行test时经常会减去train数据集的图像均值&#xff0c;这样做的好处是&#xff1a;属于数据预处理中的数据归一化&#xff0c;降低数据间相似性&#xff0c;可以将数值调整到一个合理的范围。以下code是用于计算cifar10中训练集的图像均值&#xf…

阿里云弹性公网IP(EIP)的使用限制

阿里云弹性公网IP&#xff08;EIP&#xff09;是一种可以独立购买和持有的公网IP地址资源&#xff0c;弹性公网IP具有独立购买持有、弹性绑定和配置灵活等优势&#xff0c;但实际使用中弹性公网IP也是有很多限制的&#xff0c;阿里云惠网分享弹性公网IP&#xff08;EIP&#xf…

400名微软员工主动曝光薪资:28万元到228万元不等!

作者 | Dave Gershgorn译者 | 弯月&#xff0c;编辑 | 郭芮来源 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09;【导读】近日&#xff0c;近400名微软员工分享了他们的薪酬&#xff08;从4万美元到32万美元不等&#xff0c;约为28万人民币到228万人民币&#xff09;&am…

Extjs:添加查看全部按钮

var grid new Ext.grid.GridPanel({renderTo:tsllb,title:产品成本列表,selModel:csm,height:350,columns:[csm,{header: "编码", dataIndex: "bm", sortable: true,hidden:true},{header: "产品", dataIndex: "cp", sortable: true},…

练手扎实基本功必备:非结构文本特征提取方法

作者 | Dipanjan (DJ) Sarkar编译 | ronghuaiyang来源 | AI公园&#xff08;ID:AI_Paradise&#xff09;【导读】本文介绍了一些传统但是被验证是非常有用的&#xff0c;现在都还在用的策略&#xff0c;用来对非结构化的文本数据提取特征。介绍在本文中&#xff0c;我们将研究如…

范数介绍及C++/OpenCV/Eigen的三种实现

有时我们需要衡量一个向量的大小。在机器学习中&#xff0c;我们经常使用被称为范数(norm)的函数衡量向量大小。形式上&#xff0c;Lp范数定义如下&#xff1a;范数(包括Lp范数)是将向量映射到非负值的函数。直观上来说&#xff0c;向量x的范数衡量从原点到点x的距离。更严格地…

js添加网页水印和three.js场景中加水印

我们在日常网页开发的时候&#xff0c;可能想给自己的网页或者canvas里面添加水印&#xff0c;增添个人标记&#xff0c;我这里分为普通静态html页面和threejs中3d场景里面添加水印功能。一 静态html页面添加水印你只需要在你的页面添加一个图片遮罩&#xff0c;通过绝对定位和…

JAVA学习笔记(6)

关于多线程的优先级&#xff0c;这个程序里面&#xff0c;现在计算机比较好&#xff0c;int存储不下了&#xff0c;我跑了好几次都是负分&#xff0c;特把int改成long。但是之后跑出来的结果&#xff0c;两个数字都差不多&#xff0c;不知道是什么问题&#xff1f;等待答案中。…

C++/C++11中std::deque的使用

std::deque是双端队列&#xff0c;可以高效的在头尾两端插入和删除元素&#xff0c;在std::deque两端插入和删除并不会使其它元素的指针或引用失效。在接口上和std::vector相似。与sdk::vector相反&#xff0c;std::deque中的元素并非连续存储&#xff1a;典型的实现是使用一个…

贾扬清:我对人工智能方向的一点浅见

阿里妹导读&#xff1a;作为 AI 大神&#xff0c;贾扬清让人印象深刻的可能是他写的AI框架Caffe &#xff0c;那已经是六年前的事了。经过多年的沉淀&#xff0c;成为“阿里新人”的他&#xff0c;对人工智能又有何看法&#xff1f;最近&#xff0c;贾扬清在阿里内部分享了他的…

吴甘沙:天外飞“厕”、红绿灯消失,未来无人驾驶将被重新定义

整理 | 夕颜出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;2019 年9 月 5 日至 7 日&#xff0c;由新一代人工智能产业技术创新战略联盟&#xff08;AITISA&#xff09;指导&#xff0c;鹏城实验室、北京智源人工智能研究院支持&#xff0c;专业中文 IT 技术社区 CS…

Linux内核--网络栈实现分析(二)--数据包的传递过程--转

转载地址http://blog.csdn.net/yming0221/article/details/7492423 作者&#xff1a;闫明 本文分析基于Linux Kernel 1.2.13 注&#xff1a;标题中的”&#xff08;上&#xff09;“&#xff0c;”&#xff08;下&#xff09;“表示分析过程基于数据包的传递方向&#xff1a;”…

C++/C++11中std::stack的使用

栈stack 是一个容器适配器(container adaptor)类型&#xff0c;被特别设计用来运行于LIFO(Last-in First-out&#xff0c;后进先出)场景&#xff0c;在该场景中&#xff0c;只能从容器末尾添加和删除元素&#xff0c;其定义在stack头文件中。stack默认基于std::deque实现&#…

团队前四次作业——个人总结

团队前四次作业——个人总结 描述 团队名称待就业六人组相关团队第四次作业答辩——反思与总结做了哪些事&#xff1f;工作量、完成度 作业负责工作量完成度团队队员展示创意合照后期1h95%项目选题报告编写创新和收益部分2h85%项目原型设计原型设计6h95%需求规格说明书功能需求…

吴甘沙:天外飞“厕”、红绿灯消失,未来无人驾驶将被重新定义 | AI ProCon 2019

2019 年9 月 5 日至 7 日&#xff0c;由新一代人工智能产业技术创新战略联盟&#xff08;AITISA&#xff09;指导&#xff0c;鹏城实验室、北京智源人工智能研究院支持&#xff0c;专业中文 IT 技术社区 CSDN 主办的 2019 中国 AI 开发者大会&#xff08;AI ProCon 2019&#x…

MySQL基础day03_数据的导入、导出-MySQL 5.6

MySQL基础day03_数据的导入、导出-MySQL 5.6注&#xff1a;把数据按照一定格式存放到文件里才能进行数据的导入。1&#xff0c;数据导入的条件把文件里的内容保存到数据的表里&#xff1b;把数据按照一定格式存放文件里&#xff1b;注&#xff1a;默认情况下&#xff0c;只有管…

“含光”剑出,谁与争锋?阿里重磅发布首颗AI芯片含光800

作者 | 夕颜、胡巍巍 编辑 | 唐小引 出品 | AI 科技大本营&#xff08;ID:rgznai100&#xff09; 9 月末的杭州气温适宜&#xff0c;宜出游&#xff0c;宜在湖边餐厅浅酌一杯清茶消闲。但在钱塘江水支流河畔的云栖小镇&#xff0c;却完全一副与闲适氛围不相称的热闹景象。 …

c++面试题中经常被面试官面试的小问题总结(一)(本篇偏向基础知识)

原文作者&#xff1a;aircraft 原文链接&#xff1a;https://www.cnblogs.com/DOMLX/p/10711810.html 1.类中的函数定义后加了一个const代表什么&#xff1f; 代表它将具备以下三个性质&#xff1a;1.const对象只能调用const成员函数。2.const对象的值不能被修改&#xff0c;在…

矩阵特征分解介绍及雅克比(Jacobi)方法实现特征值和特征向量的求解(C++/OpenCV/Eigen)

对角矩阵(diagonal matrix)&#xff1a;只在主对角线上含有非零元素&#xff0c;其它位置都是零&#xff0c;对角线上的元素可以为0或其它值。形式上&#xff0c;矩阵D是对角矩阵&#xff0c;当且仅当对于所有的i≠j, Di,j 0. 单位矩阵就是对角矩阵&#xff0c;对角元素全部是1…

Entity Framework CodeFirst数据迁移

原文:Entity Framework CodeFirst数据迁移前言 紧接着前面一篇博文Entity Framework CodeFirst尝试。 我们知道无论是“Database First”还是“Model First”当模型发生改变了都可以通过Visual Studio设计视图进行更新&#xff0c;那么对于Code First如何更新已有的模型呢&…

限时早鸟票 | 2019 中国大数据技术大会(BDTC)超豪华盛宴抢先看!

2019 年12月5-7 日&#xff0c;由中国计算机学会主办&#xff0c;CCF 大数据专家委员会承办&#xff0c;CSDN、中科天玑数据科技股份有限公司协办的 2019 中国大数据技术大会&#xff0c;将于北京长城饭店隆重举行。届时&#xff0c;超过百位技术专家及行业领袖将齐聚于此&…

Google AI 系统 DeepMind无法通过 高中数学

Google 旗下 DeepMind 团队让 AI 系统接受一项高中程度的数学测试&#xff0c;结果在 40 道题目中只答对了 14 题&#xff0c;甚至连「1111111」也算错了。说来难以置信&#xff0c;Google AI 系统能打败人类世界棋王&#xff0c;却无法通过高中程度的数学考试。上周&#xff0…

C++11中std::tuple的使用

std::tuple是类似pair的模板。每个pair的成员类型都不相同&#xff0c;但每个pair都恰好有两个成员。不同std::tuple类型的成员类型也不相同&#xff0c;但一个std::tuple可以有任意数量的成员。每个确定的std::tuple类型的成员数目是固定的&#xff0c;但一个std::tuple类型的…

PHP Countable接口

实现该接口可以使用count()方法来获取集合的总数转载于:https://www.cnblogs.com/xiaodo0/p/3611307.html