feat: Add FPS Counter to Android (enableFpsGraph
) (#2460)
* feat: Add FPS Counter to Android (`enableFpsGraph`) * feat: Add FPS View * Update FpsCounterView.kt * Implement actual graph * fix layout * Update FpsGraphView.kt * Update CameraPage.tsx
This commit is contained in:
parent
8c5b60355f
commit
9089014ed8
@ -81,22 +81,28 @@ class CameraView(context: Context) :
|
|||||||
previewView.resizeMode = value
|
previewView.resizeMode = value
|
||||||
field = value
|
field = value
|
||||||
}
|
}
|
||||||
|
var enableFpsGraph: Boolean = false
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
updateFpsGraph()
|
||||||
|
}
|
||||||
|
|
||||||
// code scanner
|
// code scanner
|
||||||
var codeScannerOptions: CodeScannerOptions? = null
|
var codeScannerOptions: CodeScannerOptions? = null
|
||||||
|
|
||||||
// private properties
|
// private properties
|
||||||
private var isMounted = false
|
private var isMounted = false
|
||||||
|
private val coroutineScope = CoroutineScope(CameraQueues.cameraQueue.coroutineDispatcher)
|
||||||
internal val cameraManager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
|
internal val cameraManager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
|
||||||
|
|
||||||
// session
|
// session
|
||||||
internal val cameraSession: CameraSession
|
internal val cameraSession: CameraSession
|
||||||
private val previewView: PreviewView
|
private val previewView: PreviewView
|
||||||
private var currentConfigureCall: Long = System.currentTimeMillis()
|
private var currentConfigureCall: Long = System.currentTimeMillis()
|
||||||
|
|
||||||
internal var frameProcessor: FrameProcessor? = null
|
internal var frameProcessor: FrameProcessor? = null
|
||||||
|
|
||||||
private val coroutineScope = CoroutineScope(CameraQueues.cameraQueue.coroutineDispatcher)
|
// other
|
||||||
|
private var fpsGraph: FpsGraphView? = null
|
||||||
|
|
||||||
init {
|
init {
|
||||||
this.installHierarchyFitter()
|
this.installHierarchyFitter()
|
||||||
@ -225,8 +231,22 @@ class CameraView(context: Context) :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun updateFpsGraph() {
|
||||||
|
if (enableFpsGraph) {
|
||||||
|
if (fpsGraph != null) return
|
||||||
|
fpsGraph = FpsGraphView(context)
|
||||||
|
addView(fpsGraph)
|
||||||
|
} else {
|
||||||
|
if (fpsGraph == null) return
|
||||||
|
removeView(fpsGraph)
|
||||||
|
fpsGraph = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onFrame(frame: Frame) {
|
override fun onFrame(frame: Frame) {
|
||||||
frameProcessor?.call(frame)
|
frameProcessor?.call(frame)
|
||||||
|
|
||||||
|
fpsGraph?.onTick()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onError(error: Throwable) {
|
override fun onError(error: Throwable) {
|
||||||
|
@ -79,6 +79,11 @@ class CameraViewManager : ViewGroupManager<CameraView>() {
|
|||||||
view.enableZoomGesture = enableZoomGesture
|
view.enableZoomGesture = enableZoomGesture
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ReactProp(name = "enableFpsGraph")
|
||||||
|
fun setEnableFpsGraph(view: CameraView, enableFpsGraph: Boolean) {
|
||||||
|
view.enableFpsGraph = enableFpsGraph
|
||||||
|
}
|
||||||
|
|
||||||
@ReactProp(name = "videoStabilizationMode")
|
@ReactProp(name = "videoStabilizationMode")
|
||||||
fun setVideoStabilizationMode(view: CameraView, videoStabilizationMode: String?) {
|
fun setVideoStabilizationMode(view: CameraView, videoStabilizationMode: String?) {
|
||||||
val newMode = VideoStabilizationMode.fromUnionValue(videoStabilizationMode)
|
val newMode = VideoStabilizationMode.fromUnionValue(videoStabilizationMode)
|
||||||
|
@ -0,0 +1,116 @@
|
|||||||
|
package com.mrousavy.camera
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.Canvas
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.graphics.Paint
|
||||||
|
import android.view.Gravity
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.FrameLayout
|
||||||
|
import android.widget.TextView
|
||||||
|
import kotlin.math.max
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
@SuppressLint("SetTextI18n")
|
||||||
|
class FpsGraphView(context: Context) : FrameLayout(context) {
|
||||||
|
private val textView = TextView(context)
|
||||||
|
private val graph = Graph(context)
|
||||||
|
|
||||||
|
init {
|
||||||
|
textView.textSize = 18f
|
||||||
|
textView.setTextColor(Color.WHITE)
|
||||||
|
textView.text = "0 FPS"
|
||||||
|
|
||||||
|
graph.callback = object : Graph.Callback {
|
||||||
|
override fun onAverageFpsChanged(averageFps: Int) {
|
||||||
|
textView.text = "$averageFps FPS"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val layoutParams = LayoutParams(300, 150)
|
||||||
|
layoutParams.setMargins(15, 150, 0, 0)
|
||||||
|
layoutParams.gravity = Gravity.TOP or Gravity.LEFT
|
||||||
|
addView(graph, layoutParams)
|
||||||
|
addView(textView, layoutParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onTick() {
|
||||||
|
graph.onTick()
|
||||||
|
}
|
||||||
|
|
||||||
|
class Graph(context: Context) :
|
||||||
|
View(context),
|
||||||
|
Runnable {
|
||||||
|
private val maxBars = 30
|
||||||
|
private val ticks = arrayListOf<Double>()
|
||||||
|
private val bars = arrayListOf<Int>()
|
||||||
|
private val paint = Paint().apply {
|
||||||
|
color = Color.RED
|
||||||
|
strokeWidth = 5f
|
||||||
|
style = Paint.Style.FILL
|
||||||
|
}
|
||||||
|
var callback: Callback? = null
|
||||||
|
|
||||||
|
init {
|
||||||
|
post(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun run() {
|
||||||
|
val averageFps = getAverageFps(ticks)
|
||||||
|
ticks.clear()
|
||||||
|
|
||||||
|
bars.add(averageFps)
|
||||||
|
if (bars.size > maxBars) {
|
||||||
|
bars.removeAt(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
invalidate()
|
||||||
|
postDelayed(this, 1000)
|
||||||
|
|
||||||
|
callback?.onAverageFpsChanged(averageFps)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getAverageFps(ticks: List<Double>): Int {
|
||||||
|
if (ticks.isEmpty()) return 0
|
||||||
|
if (ticks.size < 2) return 1
|
||||||
|
|
||||||
|
val totalDuration = ticks.last() - ticks.first()
|
||||||
|
val averageFrameDuration = totalDuration / (ticks.size - 1).toDouble()
|
||||||
|
|
||||||
|
val double = 1000.0 / averageFrameDuration
|
||||||
|
return double.roundToInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onTick() {
|
||||||
|
val currentTick = System.currentTimeMillis()
|
||||||
|
ticks.add(currentTick.toDouble())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDraw(canvas: Canvas) {
|
||||||
|
super.onDraw(canvas)
|
||||||
|
|
||||||
|
if (bars.size < 2) return
|
||||||
|
|
||||||
|
val maxFps = max(bars.max().toFloat(), 60f)
|
||||||
|
val blockWidth = width.toFloat() / maxBars
|
||||||
|
for (i in 0..maxBars) {
|
||||||
|
val fps = bars.getOrNull(i)
|
||||||
|
if (fps != null) {
|
||||||
|
val blockHeight = (fps / maxFps) * height
|
||||||
|
canvas.drawRect(
|
||||||
|
i * blockWidth,
|
||||||
|
height - blockHeight,
|
||||||
|
(i + 1) * blockWidth,
|
||||||
|
height.toFloat(),
|
||||||
|
paint
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Callback {
|
||||||
|
fun onAverageFpsChanged(averageFps: Int)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user