`[AVCaptureSession canAddOutput:output]`间歇性地返回NO.我能找出原因吗?

Dre*_*rew 13 objective-c ios avcapturesession avcapturemoviefileoutput

我使用canAddOutput:,以确定是否我可以添加AVCaptureMovieFileOutput到一个AVCaptureSession和我发现,canAddOutput:有时没有返回,且多为返回YES.有没有办法找出NO被归还的原因?或者一种消除导致NO返回的情况的方法?或者我能做的其他任何事情都会阻止用户看到间歇性故障?

进一步说明:这种情况大约在30次通话中发生一次.由于我的应用程序尚未启动,因此仅在一台设备上进行了测试:运行7.1.2的iPhone 5

l0g*_*g3r 13

这里引用文献(讨论canAddOutput:)

You cannot add an output that reads from a track of an asset other than the asset used to initialize the receiver.

解释将帮助您(请检查您的代码是否与本指南匹配,如果您做得很好,它不应该触发错误,因为基本上canAddOuput:检查兼容性).

AVCaptureSession
用于组织设备输入和输出之间的连接,类似于DShow过滤器的连接.如果可以连接输入和输出,则在启动后,数据将从输入读取到输出.几个要点:
a)AVCaptureDevice,设备的定义,两个摄像头设备.
b)AVCaptureInput
c)AVCaptureOutput
输入和输出不是一对一的,例如视频+音频输入时的视频输出.切换相机前后:

AVCaptureSession * session = <# A capture session #>; 
[session beginConfiguration]; 
[session removeInput: frontFacingCameraDeviceInput]; 
[session addInput: backFacingCameraDeviceInput]; 
[session commitConfiguration];
Run Code Online (Sandbox Code Playgroud)

添加捕获INPUT:
要将捕获设备添加到捕获会话,请使用AVCaptureDeviceInput的实例(抽象AVCaptureInput类的具体子类).捕获设备输入管理设备的端口.

NSError * error = nil; 
AVCaptureDeviceInput * input = 
[AVCaptureDeviceInput deviceInputWithDevice: device error: & error]; 
if (input) { 
   // Handle the error appropriately. 
}
Run Code Online (Sandbox Code Playgroud)

添加输出,输出分类:

要从捕获会话获取输出,请添加一个或多个输出.输出是AVCaptureOutput的具体子类的实例;
您使用:
AVCaptureMovieFileOutput输出到电影文件
AVCaptureVideoDataOutput如果您想要处理正在捕获的视频中的帧
AVCaptureAudioDataOutput如果您想处理正在捕获的音频数据
AVCaptureStillImageOutput如果您想捕获带有元数据的静态图像您可以将输出添加到捕获使用addOutput的会话:
您可以使用检查捕获输出是否与现有会话兼容canAddOutput:.
您可以在会话运行时根据需要添加和删除输出.

AVCaptureSession * captureSession = <# Get a capture session #>; 
AVCaptureMovieFileOutput * movieInput = <# Create and configure a movie output #>; 
if ([captureSession canAddOutput: movieInput]) { 
   [captureSession addOutput: movieInput]; 
} 
else {
   // Handle the failure. 
}
Run Code Online (Sandbox Code Playgroud)

保存视频文件,添加视频文件输出:

使用AVCaptureMovieFileOutput对象将影片数据保存到文件.(AVCaptureMovieFileOutput是AVCaptureFileOutput的具体子类,它定义了许多基本行为.)您可以配置电影文件输出的各个方面,例如录制的最长持续时间或最大文件大小.如果剩余的磁盘空间少于一定数量,您也可以禁止录制.

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 #>;
Run Code Online (Sandbox Code Playgroud)

处理预览视频帧数据,每个帧取景器数据可用于后续的高级处理,例如人脸检测等.
AVCaptureVideoDataOutput对象使用委托来销售视频帧.您可以使用设置委托
setSampleBufferDelegate: queue:.
除了委托之外,还指定了一个调用它们委派方法的串行队列.您必须使用串行队列来确保以正确的顺序将帧传递给委托.
您不应该传递返回的队列,dispatch_get_current_queue因为无法保证当前队列在哪个线程上运行.您可以使用队列来修改交付和处理视频帧的优先级.对于帧的数据处理,必须对大小(图像大小)和处理时间限制进行​​限制,如果处理时间过长,底层传感器将不会向layouter发送数据和回调.

您应该将会话输出设置为应用程序的最低实际分辨率.
将输出设置为高于必要的分辨率会浪费处理周期并且不必要地消耗功率.您必须确保captureOutput:didOutputSampleBuffer:fromConnection:的实现能够在分配给帧的时间内处理样本缓冲区.如果它花费的时间太长,并且您保持视频帧,AVFoundation将停止提供帧,不仅是您的代表,还有其他输出,如预览图层.

处理捕获过程:

AVCaptureStillImageOutput * stillImageOutput = [[AVCaptureStillImageOutput alloc] 
init]; 
NSDictionary * outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys: AVVideoCodecJPEG, 
AVVideoCodecKey, nil]; 
[StillImageOutput setOutputSettings: outputSettings];
Run Code Online (Sandbox Code Playgroud)

能够支持不同格式还支持直接生成jpg流.如果要捕获JPEG图像,通常不应指定自己的压缩格式.相反,您应该让静止图像输出为您进行压缩,因为它的压缩是硬件加速的.如果需要图像的数据表示,则可以使用jpegStillImageNSDataRepresentation:获取NSData对象,而无需重新压缩数据,即使您修改了图像的元数据.

相机预览显示:

您可以使用AVCaptureVideoPreviewLayer对象为用户提供正在录制内容的预览.AVCaptureVideoPreviewLayer是CALayer的子类(参见Core Animation Programming Guide.您不需要任何输出来显示预览.

AVCaptureSession * captureSession = <# Get a capture session #>; 
CALayer * viewLayer = <# Get a layer from the view in which you want to present the 
The preview #>; 
AVCaptureVideoPreviewLayer * captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer 
alloc] initWithSession: captureSession]; 
[viewLayer addSublayer: captureVideoPreviewLayer];
Run Code Online (Sandbox Code Playgroud)

通常,预览图层的行为与渲染树中的任何其他CALayer对象相同(请参阅核心动画编程指南).您可以像对待任何图层一样缩放图像并执行变换,旋转等操作.一个区别是您可能需要设置图层的方向属性以指定它应如何旋转来自相机的图像.此外,在iPhone 4上,预览图层支持镜像(这是预览前置摄像头时的默认设置).