真实的将帧从ARSession上传到firebase存储器

aiazj4mn  于 2023-03-03  发布在  其他
关注(0)|答案(1)|浏览(149)

我正在尝试将帧从ARSession实时流传输到Firebase Storage,在帧被发送到Firebase之前,会对帧进行一些预处理,app的流程如下。
变量frameCount用于命名数据库中的图像文件。我希望图像按照捕获时的顺序命名。文件上传成功,问题是:
1.它不是实时的,因为upload()异步运行并需要一些时间
1.图片没有按顺序上传。我希望它们按捕获时的顺序上传。异步部分做了一些与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,将数据写入文件,并以顺序方式上传。下一帧的管道应该堆叠在前一帧的执行之上,并等待它成功上传。

m3eecexj

m3eecexj1#

如果没有别的,你需要确保在你的闭包中没有引用一个正在变化的属性。所以,举个例子,你需要引用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)
    }
}

也有一些方法可以使这个任务按顺序运行(按顺序,一次一个),但是这会使它运行得更慢。我敢打赌,您已经跟不上您的“实时”目标了,而使这个异步任务按顺序运行可能只会使情况变得更糟。

相关问题