Camera2:SurfaceTexture 缓冲区大小被覆盖
Camera2: SurfaceTexture buffer size is being overridden
我正在使用 Camera2 API 编写一个应用程序,它应该显示来自相机的预览并拍照。目前我的代码工作如下:
- Camera Fragment实例化时,等待
TextureView.SurfaceTextureListener.onSurfaceTextureAvailable
被调用
- 在 ViewModel 中,从 CameraCharacteristics 获取可用且合适的图片和预览尺寸,并使用 LiveData 将找到的预览尺寸发送到 Fragment
- Fragment 观察预览大小 LiveData 并调用
setDefaultBufferSize
为其 TextureView
的 SurfaceTexture
使用新大小
- 设置新尺寸后,创建捕获会话,并设置重复预览请求,因此
TextureView
开始显示来自相机的图像
- 为避免干扰其他相机应用程序的工作,在 Fragment 的
onPause
之后清除所有相机相关的东西,并在 onResume
之后再次执行步骤 1-4
Surface
实例在 Fragment 和相机逻辑之间共享 类:共享变量在 TextureView.SurfaceTextureListener.onSurfaceTextureAvailable
中用它初始化,并在调用 TextureView.SurfaceTextureListener.onSurfaceTextureDestroyed
时设置为 null
这适用于具有现代 Android 版本的流行品牌的某些设备,但该应用程序应该适用于具有 Android 6[=59= 的特定 通用中国平板电脑] ("CameraManager: Using legacy camera HAL
"),我遇到了一个问题。
- 实例化相机并开始预览时,我看到预览尺寸为 640x480(因此图像被拉伸),但是传递给
setDefaultBufferSize
的尺寸为 1280x720
- Logcat 也充满了连续
Surface::setBuffersUserDimensions(this=0x7f55fb5200,w=640,h=480)
条消息
- 我在 SO 上发现,在一些 Android 5 的三星设备上,某些分辨率可能不适用于 Camera2,但在这里 当我关闭应用程序并再次打开它时, 预览分辨率根据需要为1280x720
- 所以我的猜测是,我可能会在第一个相机片段设置时过早地调用
setDefaultBufferSize
,并且只有在应用程序最小化后重新创建视图时,所需的分辨率才会“拾取”
- 我还尝试在传递给
TextureView.post
的 lambda 中调用 setDefaultBufferSize
,它解决了问题,除了我应该请求用户权限的情况 在 Camera Fragment 上(即当用户第一次打开相机时),因此 Fragment 会暂停几次以显示权限弹出窗口。但是,如果没有 TextureView.post
setDefaultBufferSize
也会在主线程中调用,所以我猜 TextureView.post
造成的延迟是这里的游戏规则改变者
- 我还在
setDefaultBufferSize
文档中看到:新的默认缓冲区大小将在图像制作者下次请求缓冲区填充时生效。对于 Canvas,这将是下一次调用 Surface.lockCanvas。对于 OpenGL ES,应该销毁 EGLSurface(通过 eglDestroySurface),使其成为非当前(通过 eglMakeCurrent),然后重新创建(通过 eglCreateWindowSurface)以确保新的默认大小生效。 在我看来可能是这样的
通过覆盖 SurfaceTextureListener
的 onSurfaceTextureSizeChanged
并使用所需的预览大小调用 surfaceTexture.setDefaultBufferSize
解决了这个问题。当默认缓冲区大小被不正确的大小覆盖时(在初始化期间),调用此方法,我再次覆盖它。
我正在使用 Camera2 API 编写一个应用程序,它应该显示来自相机的预览并拍照。目前我的代码工作如下:
- Camera Fragment实例化时,等待
TextureView.SurfaceTextureListener.onSurfaceTextureAvailable
被调用 - 在 ViewModel 中,从 CameraCharacteristics 获取可用且合适的图片和预览尺寸,并使用 LiveData 将找到的预览尺寸发送到 Fragment
- Fragment 观察预览大小 LiveData 并调用
setDefaultBufferSize
为其TextureView
的SurfaceTexture
使用新大小
- 设置新尺寸后,创建捕获会话,并设置重复预览请求,因此
TextureView
开始显示来自相机的图像 - 为避免干扰其他相机应用程序的工作,在 Fragment 的
onPause
之后清除所有相机相关的东西,并在onResume
之后再次执行步骤 1-4
Surface
实例在 Fragment 和相机逻辑之间共享 类:共享变量在TextureView.SurfaceTextureListener.onSurfaceTextureAvailable
中用它初始化,并在调用TextureView.SurfaceTextureListener.onSurfaceTextureDestroyed
时设置为 null
这适用于具有现代 Android 版本的流行品牌的某些设备,但该应用程序应该适用于具有 Android 6[=59= 的特定 通用中国平板电脑] ("CameraManager: Using legacy camera HAL
"),我遇到了一个问题。
- 实例化相机并开始预览时,我看到预览尺寸为 640x480(因此图像被拉伸),但是传递给
setDefaultBufferSize
的尺寸为 1280x720 - Logcat 也充满了连续
Surface::setBuffersUserDimensions(this=0x7f55fb5200,w=640,h=480)
条消息 - 我在 SO 上发现,在一些 Android 5 的三星设备上,某些分辨率可能不适用于 Camera2,但在这里 当我关闭应用程序并再次打开它时, 预览分辨率根据需要为1280x720
- 所以我的猜测是,我可能会在第一个相机片段设置时过早地调用
setDefaultBufferSize
,并且只有在应用程序最小化后重新创建视图时,所需的分辨率才会“拾取” - 我还尝试在传递给
TextureView.post
的 lambda 中调用setDefaultBufferSize
,它解决了问题,除了我应该请求用户权限的情况 在 Camera Fragment 上(即当用户第一次打开相机时),因此 Fragment 会暂停几次以显示权限弹出窗口。但是,如果没有TextureView.post
setDefaultBufferSize
也会在主线程中调用,所以我猜TextureView.post
造成的延迟是这里的游戏规则改变者 - 我还在
setDefaultBufferSize
文档中看到:新的默认缓冲区大小将在图像制作者下次请求缓冲区填充时生效。对于 Canvas,这将是下一次调用 Surface.lockCanvas。对于 OpenGL ES,应该销毁 EGLSurface(通过 eglDestroySurface),使其成为非当前(通过 eglMakeCurrent),然后重新创建(通过 eglCreateWindowSurface)以确保新的默认大小生效。 在我看来可能是这样的
通过覆盖 SurfaceTextureListener
的 onSurfaceTextureSizeChanged
并使用所需的预览大小调用 surfaceTexture.setDefaultBufferSize
解决了这个问题。当默认缓冲区大小被不正确的大小覆盖时(在初始化期间),调用此方法,我再次覆盖它。