下面代码实现一个无预览的视频采集,并且每10秒统计一下帧率:
class MainActivity : AppCompatActivity() {
private lateinit var camera: Camera
private val surfaceTexture = SurfaceTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES)
private val width = 1920
private val height = 1080
private var fps = 0
private var start = 0L
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
println("width = $width height = $height")
camera = Camera.open()
camera.parameters = camera.parameters.apply {
previewFormat = ImageFormat.NV21
setPreviewSize(width, height)
}
camera.setPreviewTexture(surfaceTexture)
camera.setPreviewCallback { data, camera ->
fps++
val current = System.currentTimeMillis()
if (start == 0L) {
start = current
}
if (current - start >= 10000) {
println("帧速:${fps}帧/10秒")
fps = 0
start = current
}
}
camera.startPreview()
}
override fun onDestroy() {
super.onDestroy()
camera.setPreviewCallback(null)
camera.stopPreview()
camera.release()
}
}
在小米11 pro运行效果如下:
width = 1920 height = 1080
帧速:301帧/10秒
帧速:300帧/10秒
帧速:300帧/10秒
帧速:300帧/10秒
帧速:301帧/10秒
帧速:300帧/10秒
帧速:300帧/10秒
平均帧速为30帧/秒。听闻使用缓冲区可以提高效率,于是我们把视频采集改为使用缓冲的方式,如下:
class MainActivity : AppCompatActivity() {
private lateinit var camera: Camera
private val surfaceTexture = SurfaceTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES)
private val width = 1920
private val height = 1080
private val callbackBuffer = ByteArray((width * height * 3) shr 1)
private var fps = 0
private var start = 0L
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
println("width = $width height = $height")
camera = Camera.open()
camera.parameters = camera.parameters.apply {
previewFormat = ImageFormat.NV21
setPreviewSize(width, height)
}
camera.setPreviewTexture(surfaceTexture)
camera.addCallbackBuffer(callbackBuffer)
camera.setPreviewCallbackWithBuffer { data, camera ->
fps++
val current = System.currentTimeMillis()
if (start == 0L) {
start = current
}
if (current - start >= 10000) {
println("帧速:${fps}帧/10秒")
fps = 0
start = current
}
camera.addCallbackBuffer(callbackBuffer)
}
camera.startPreview()
}
override fun onDestroy() {
super.onDestroy()
camera.setPreviewCallback(null)
camera.stopPreview()
camera.release()
}
}
在小米11 pro运行结果如下:
width = 1920 height = 1080
帧速:276帧/10秒
帧速:293帧/10秒
帧速:298帧/10秒
帧速:299帧/10秒
帧速:295帧/10秒
帧速:297帧/10秒
可以看到,使用了缓冲之后,帧率下降了,效率并没有提高,只能说更省内存了。在公司的手机上测试效果相差更明显,如没使用缓冲的测试情况:
width = 1920 height = 1080
帧速:189帧/10秒
帧速:249帧/10秒
帧速:247帧/10秒
帧速:250帧/10秒
帧速:173帧/10秒
帧速:162帧/10秒
帧速:147帧/10秒
帧速:173帧/10秒
使用了缓冲后的测试情况:
width = 1920 height = 1080
帧速:133帧/10秒
帧速:181帧/10秒
帧速:133帧/10秒
帧速:129帧/10秒
帧速:141帧/10秒
帧速:139帧/10秒
帧速:133帧/10秒
帧速:135帧/10秒
可以看到,使用了缓冲后帧速明显下降。如果使用YV12格式,
基于这个测试结果,在我们公司的项目开发上我就没有使用缓冲区了,因为我们开发的项目是运行在一个特别的Android设备上,这个Android设备一启动就只运行我们的一个应用,没有其它应用,所以多消耗点内存也没事,反正内存是够用的。
对于格式的选择上也有讲究的,比如在公司的手机上,使用NV21格式,宽640,高480,使用缓冲区,测试结果如下:
width = 640 height = 480
帧速:192帧/10秒
帧速:240帧/10秒
帧速:236帧/10秒
帧速:239帧/10秒
帧速:238帧/10秒
帧速:238帧/10秒
帧率还行,然后我们只改一个格式,把NV21改成YV12,测试结果如下:
width = 640 height = 480
帧速:181帧/10秒
帧速:182帧/10秒
帧速:179帧/10秒
帧速:177帧/10秒
可以看到,就改了一个格式,帧率下降明显,是否可以认为这台设备的摄像头采集就是用NV21采集的,当我们使用YV12格式时,框架需要进行NV21 到 YV12格式的转换操作,所以导致帧率下降?当我使用小米11 pro手机测试时又没这个问题,是否是因为手米手机速度快,格式转换快,所以没耽误帧率?