gpt4 book ai didi

objective-c - Cocoa - 相机开始录制时检测事件

转载 作者:行者123 更新时间:2023-12-03 16:50:33 27 4
gpt4 key购买 nike

在我的 OSX 应用程序中,我使用下面的代码来显示相机的预览。

  [[self session] beginConfiguration];

NSError *error = nil;
AVCaptureDeviceInput *newVideoDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:&error];

if (captureDevice != nil) {
[[self session] removeInput: [self videoDeviceInput]];
if([[self session] canAddInput: newVideoDeviceInput]) {
[[self session] addInput:newVideoDeviceInput];
[self setVideoDeviceInput:newVideoDeviceInput];
} else {
DLog(@"WTF?");
}
}

[[self session] commitConfiguration];

但是,我需要检测相机预览可用的确切时间。

换句话说,我正在尝试检测与 OSX 下的 Facetime 相同的时刻,一旦相机提供预览,动画就会开始。

实现这一目标的最佳方法是什么?

最佳答案

我知道这个问题确实很老,但当我寻找同样的问题时,我也偶然发现了它,并且我找到了答案,所以这里是。

对于初学者来说,AVFoundation 级别太高,您需要下降到较低级别 CoreMediaIO。关于此的文档并不多,但基本上您需要执行几个查询。

为此,我们将使用调用组合。首先,CMIOObjectGetPropertyDataSize 让我们获取接下来要查询的数据的大小,然后在调用 CMIOObjectGetPropertyData 时可以使用该大小。要设置获取属性数据大小调用,我们需要从顶部开始,使用以下属性地址:

var opa = CMIOObjectPropertyAddress(
mSelector: CMIOObjectPropertySelector(kCMIOHardwarePropertyDevices),
mScope: CMIOObjectPropertyScope(kCMIOObjectPropertyScopeGlobal),
mElement: CMIOObjectPropertyElement(kCMIOObjectPropertyElementMaster)
)

接下来,我们将设置一些变量来保存我们需要的数据:

var (dataSize, dataUsed) = (UInt32(0), UInt32(0))
var result = CMIOObjectGetPropertyDataSize(CMIOObjectID(kCMIOObjectSystemObject), &opa, 0, nil, &dataSize)
var devices: UnsafeMutableRawPointer? = nil

从现在开始,我们需要等待,直到我们得到一些数据,所以让我们忙循环:

repeat {
if devices != nil {
free(devices)
devices = nil
}
devices = malloc(Int(dataSize))
result = CMIOObjectGetPropertyData(CMIOObjectID(kCMIOObjectSystemObject), &opa, 0, nil, dataSize, &dataUsed, devices);
} while result == OSStatus(kCMIOHardwareBadPropertySizeError)

一旦我们在执行中超过了这一点,devices 将指向潜在的许多设备。我们需要循环遍历它们,有点像这样:

if let devices = devices {
for offset in stride(from: 0, to: dataSize, by: MemoryLayout<CMIOObjectID>.size) {
let current = devices.advanced(by: Int(offset)).assumingMemoryBound(to: CMIOObjectID.self)
// current.pointee is your object ID you will want to keep track of somehow
}
}

最后,清理设备

free(devices)

此时,您将需要使用上面保存的对象 ID 来进行另一个查询。我们需要一个新的特性地址:

var CMIOObjectPropertyAddress(
mSelector: CMIOObjectPropertySelector(kCMIODevicePropertyDeviceIsRunningSomewhere),
mScope: CMIOObjectPropertyScope(kCMIOObjectPropertyScopeWildcard),
mElement: CMIOObjectPropertyElement(kCMIOObjectPropertyElementWildcard)
)

这告诉 CoreMediaIO 我们想知道设备当前是否正在某处运行(阅读:在任何应用程序中),并通配其余字段。接下来我们进入查询的重点,下面的camera对应于您之前保存的ID:

var (dataSize, dataUsed) = (UInt32(0), UInt32(0))
var result = CMIOObjectGetPropertyDataSize(camera, &opa, 0, nil, &dataSize)
if result == OSStatus(kCMIOHardwareNoError) {
if let data = malloc(Int(dataSize)) {
result = CMIOObjectGetPropertyData(camera, &opa, 0, nil, dataSize, &dataUsed, data)
let on = data.assumingMemoryBound(to: UInt8.self)
// on.pointee != 0 means that it's in use somewhere, 0 means not in use anywhere
}
}

通过上述代码示例,您应该足以测试相机是否正在使用。您只需要获得一次设备(答案的第一部分);但是,您必须随时检查它是否正在使用中,以获取此信息。作为额外练习,请考虑使用 CMIOObjectAddPropertyListenerBlock,以便在我们上面使用的正在使用的属性地址的事件更改时收到通知。

虽然这个答案对于OP来说已经晚了近3年,但我希望它对 future 的人有所帮助。这里的示例是使用 Swift 3.0 给出的。

关于objective-c - Cocoa - 相机开始录制时检测事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23973669/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com