您当前的位置:首页 > 计算机 > 编程开发 > 安卓(android)开发

setPreviewCallbackWithBuffer的出帧效率会变低

时间:02-09来源:作者:点击数:

下面代码实现一个无预览的视频采集,并且每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手机测试时又没这个问题,是否是因为手米手机速度快,格式转换快,所以没耽误帧率?

方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门