第47月第4天 arkit录制
1.
获取当前渲染的图像帧数据
要想保存视频,最重要一点就是得到当前渲染好的帧数据。得到帧数据后,下面的工作交给AVFoundation就可以轻松搞定了。
那么,如何得到当前画面的帧数据呢?
可以看到渲染的视图ARSCNView最终是继承自UIView,从UIView截取画面是很容易的。但是这样得到的画面,分辨率和当前视图的frame是一致的,如果要保存高分辨率就得缩放,这样肯定会模糊。所以这个方法最先排除。
再来看看ARSCNView这个类,它的直接父类是SCNView。前面提到SceneKit是苹果自带的游戏框架,这个框架里面或许有API能直接获取。查找了相关资料,确实发现SCNRenderer有个snapshotAtTime:withSize:antialiasingMode:方法可以截取UIImage,而SCNRenderer所需要的场景scene属性可以从ARSCNView中直接获取。既然可以得到UIImage,就可以转换为CVPixelBufferRel扔给AVFoundation框架处理。
https://blog.csdn.net/weixin_34267123/article/details/89565403
https://github.com/AFathi/ARVideoKit/
if let view = view as? ARSCNView { guard let mtlDevice = MTLCreateSystemDefaultDevice() else { logAR.message("ERROR:- This device does not support Metal") return } renderEngine = SCNRenderer(device: mtlDevice, options: nil) renderEngine.scene = view.scene gpuLoop = CADisplayLink(target: WeakProxy(target: self), selector: #selector(renderFrame)) gpuLoop.preferredFramesPerSecond = fps.rawValue gpuLoop.add(to: .main, forMode: .common) status = .readyToRecord } if view is ARSCNView { guard let size = bufferSize else { return nil } //UIScreen.main.bounds.size var renderedFrame: UIImage? pixelsQueue.sync { renderedFrame = renderEngine.snapshot(atTime: self.time, with: size, antialiasingMode: .none) } if let _ = renderedFrame { } else { renderedFrame = renderEngine.snapshot(atTime: time, with: size, antialiasingMode: .none) } guard let buffer = renderedFrame!.buffer else { return nil } return buffer }