我正在尝试将帧从 ARSession 实时流式传输到 Firebase 存储。在将帧发送到 firebase 之前,会对帧进行一些预处理。应用程序的流程如下。
frameCount
变量用于命名数据库中的图像文件。我希望图像在拍摄时按顺序命名。文件正在上传成功,问题是:
count
变量无关的事情。经过几个小时的调试,我发现对于不同的帧多次使用相同的count
值。上传无处不在。 frameCount
达到 100,但上传滞后于 5-10。然后,当我停止会话时,上传部分继续但顺序随机。例如,它会上传文件 98.jpg,下一个文件是 5.jpg var frameCount = 0
func session(_ session: ARSession, didUpdate frame: ARFrame) {
frameCount += 1
DispatchQueue.async{
process(frame: frame, count: frameCount)
}
}
func process(frame: ARFrame, count: Int){
// all the processing happens here to get jpg data of the image
var imgData = ...
var fileURL = writeToFile(imageData: imgData, count: count)
upload(fileURL: fileURL, count: count)
}
func writeToFile(imageData: Data, count: Int)-> URL{
jpgFileURL = try getDirectory().appendingPathComponent("\(count).jpg")
try jpgData.write(to: jpgFileURL!)
return jpgFileURL
}
func upload(fileURL: URL, count: Int){
let imageFileRef = storageRef.child("\(count).jpg")
imageFileRef.putFile(from: fileURL) // this part runs asynchronously
}
我已经尝试了 DispatchQueues、await/async 关键字、TaskGroups 等的多种变体,但似乎没有任何效果。在核心,我只想增加
frameCount
,将数据写入文件,然后按顺序上传。下一帧的管道应该叠加在前一帧的执行之上,并等待它成功上传。
如果不出意外,您要确保不要在闭包中引用可变属性。因此,例如,您想要引用
frameCount
的副本。要复制它,请使用“捕获列表”。所以而不是……
dispatchQueue.async {
process(frame: frame, count: frameCount)
}
而是使用……
dispatchQueue.async { [frameCount] in
process(frame: frame, count: frameCount)
}
这仍然不会按顺序上传它们,但它会确保它们至少具有
frameCount
的当前唯一值,因此被正确命名。
现在,我不知道你正在处理多少帧,但这很容易遭受“线程爆炸”,一旦积压超过 64 帧,它可能会表现得很奇怪。您可能希望将其限制为某个合理的数字。你可以用
OperationQueue
做到这一点:
var frameCount = 0
let operationQueue: OperationQueue = {
let queue = OperationQueue()
queue.name = "frame.queue"
queue.maxConcurrentOperationCount = 6
return queue
}()
func session(_ session: ARSession, didUpdate frame: ARFrame) {
frameCount += 1
operationQueue.addOperation { [frameCount] in
process(frame: frame, count: frameCount)
}
}
或者 Swift 并发:
var frameCount = 0
func session(_ session: ARSession, didUpdate frame: ARFrame) {
frameCount += 1
Task.detached { [frameCount] in
process(frame: frame, count: frameCount)
}
}
也有办法让它按顺序运行(按顺序,一次一个),但这会使它运行得更慢。我打赌你已经跟不上你的“实时”目标,让这个异步任务串行运行可能只会让情况变得更糟。