I'm developing ARKit app along with Vision
/AVKit
frameworks. I'm using MLModel
for classification of my hand gestures. My app recognizes Victory
, Okey
and ¡No pasarán!
hand gestures for controlling a video.
The app works fine but view's content is rendered at 120 fps. I do not need such a frame rate. It's too much for my app and it's a heavy burden for CPU. I tried to reduce a frame rate to 30 fps using SceneKit's instance property:
var preferredFramesPerSecond: Int { get set }
but my frame rate is still the same – 120 fps.
Here's how I made it:
import UIKit
import AVKit
import SceneKit
import ARKit
import Vision
class ViewController: UIViewController, ARSCNViewDelegate {
@IBOutlet var sceneView: ARSCNView!
var avPlayerView = AVPlayerViewController()
private let player = AVQueuePlayer()
let clips = ["AA", "BB", "CC"]
private var token: NSKeyValueObservation?
var number: Int = 0
var once: Bool = true
let dispatchQueueML = DispatchQueue(label: "net.aaa.iii")
var visionRequests = [VNRequest]()
override func viewDidLoad() {
super.viewDidLoad()
sceneView.delegate = self
sceneView.showsStatistics = true
sceneView.preferredFramesPerSecond = 30 // HERE IT GOES
sceneView.rendersContinuously = true
let scene = SCNScene()
sceneView.scene = scene
sceneView.scene.background.contents = UIColor.black.withAlphaComponent(0)
guard let selectedModel = try? VNCoreMLModel(for: handsModel().model) else {
fatalError("Couldn't load a model.")
}
let classificationRequest = VNCoreMLRequest(model: selectedModel,
completionHandler: classificationCompleteHandler)
classificationRequest.imageCropAndScaleOption = VNImageCropAndScaleOption.centerCrop
visionRequests = [classificationRequest]
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.addAllVideosToPlayer()
present(avPlayerView, animated: true,
completion: { self.player.play() })
let configuration = ARWorldTrackingConfiguration()
configuration.isAutoFocusEnabled = false
sceneView.session.run(configuration)
}
func addAllVideosToPlayer() {
avPlayerView.player = player
// .........................
}
func toggleNextVideo() {
// ..............
}
func togglePreviousVideo() {
// ..............
}
// ..............................
// ..............................
DispatchQueue.main.async {
if (topPredictionScore != nil && topPredictionScore! > 0.01) {
if (topPredictionName == "FistGesture") && (self.once == false) {
self.once = true
}
if (topPredictionName == "OkeyGesture") && (self.once == true) {
self.toggleNextVideo()
self.once = false
}
}
}
}
Here's what Apple says about it:
SceneKit chooses an actual frame rate that is as close as possible to your preferred frame rate based on the capabilities of the screen the view is displayed on. The actual frame rate is usually a factor of the maximum refresh rate of the screen to provide a consistent frame rate.
For example, if the maximum refresh rate of the screen is
60
fps, that is also the highest frame rate the view sets as the actual frame rate. However, if you ask for a lower frame rate, SceneKit might choose30
,20
,15
or some other factor to be the actual frame rate. For this reason, you want to choose a frame rate that your app can consistently maintain. The default value is60
fps.
How to lower a View's frame rate to 30 fps?