如何以最有效的方式创建多个 camera2 预览?
Posted
技术标签:
【中文标题】如何以最有效的方式创建多个 camera2 预览?【英文标题】:How to create multiple camera2 previews in most efficient way? 【发布时间】:2020-04-18 20:25:36 【问题描述】:我正在尝试在我的活动中创建 4 个我的相机预览流。我创建了一个 TextureView,它注册到 feed 的 camera2 API,然后我在 SurfaceView 上设置了一个监听器,以便监听 feed 的变化并相应地更新其他 3 个预览(ImageViews)。您可以在下面的代码中看到:
private final TextureView.SurfaceTextureListener mSurfaceTextureListener
= new TextureView.SurfaceTextureListener()
@Override
public void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height)
cameraHandler.openCamera(width, height);
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height)
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture texture)
return true;
@Override
public void onSurfaceTextureUpdated(SurfaceTexture texture)
for (ImageView mSecondaryPreview : mSecondaryPreviews)
Bitmap frame = Bitmap.createBitmap(mTextureView.getWidth(), mTextureView.getHeight(), Bitmap.Config.ARGB_8888);
mTextureView.getBitmap(frame);
mSecondaryPreview.setImageBitmap(frame);
;
如您所见,这必须从 TextureView 中读取每一帧,提取位图,然后设置其他 3 个 ImageView 流的位图。我最初尝试在 UI 线程上执行此操作,这非常慢,然后尝试将其提交给帧速率更好的后台处理程序,但由于负载导致应用程序崩溃的许多问题。
谢谢
编辑
所以为了裁剪预览的底部0.4375,我把ttmp改成了
float[] ttmp =
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.4375f,
0.0f, 0.4375f,
1.0f, 1.0f,
1.0f, 0.4375f,
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.4375f,
0.0f, 0.4375f,
1.0f, 1.0f,
1.0f, 0.4375f,
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.4375f,
0.0f, 0.4375f,
1.0f, 1.0f,
1.0f, 0.4375f,
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.4375f,
0.0f, 0.4375f,
1.0f, 1.0f,
1.0f, 0.4375f
;
但这并没有按预期裁剪
【问题讨论】:
您的用例是什么?您需要 3 个作为ImageViews
,还是将 4 个副本包含在一个 GLSurfaceView
中?
是的,4 个 GLSurfaceView 副本可以正常工作,我试图了解如何实现这一点,但我迷路了
您能否提供一些指导,让我了解如何获得 4 个 GLSurfaceView 副本
我没有时间给出完整的答案,但如果您可以在 GLSurfaceView
(see here for a rough example) 中进行预览,那么再制作 3 个副本只需再添加 6 个即可多边形(vtmp
,ttmp
)。就效率而言,OpenGL 绝对是您的最佳选择。
嗨,我已经在GLSurfaceView
上使用带有vtmp = 1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f
和ttmp = 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f
的前置摄像头进行预览。我现在如何添加更多多边形?如果您能提供帮助,还有一个单独的问题,预览从左到右倒置,您知道要更改哪些数字以解决此问题/我找不到任何文档。非常感谢
【参考方案1】:
因此,如果您可以让GLSurfaceView
像在this question 中一样使用相机预览,那么您只需添加 6 个多边形即可再制作 3 个副本。让我解释一下它们是如何布局的。 vtmp
和 ttmp
分别以GL_TRIANGLE_STRIP
的形式描述了两个三角形的矢量坐标和纹理坐标:
float[] vtmp =
1.0f, 1.0f, //Top right of screen
1.0f, -1.0f, //Bottom right of screen
-1.0f, 1.0f, //Top left of screen
-1.0f, -1.0f //Bottom left of screen
;
float[] ttmp =
1.0f, 1.0f, //Top right of camera surface
0.0f, 1.0f, //Top left of camera surface
1.0f, 0.0f, //Bottom right of camera surface
0.0f, 0.0f //Bottom left of camera surface
;
第 1 步:让我们将原始类型更改为 GL_TRIANGLES
,因为使用 GL_TRIANGLE_STRIP
会很困难:
//This also includes a fix for the left/right inversion:
float[] vtmp =
//Triangle 1:
-1.0f, -1.0f,
-1.0f, 1.0f,
1.0f, 1.0f,
//Triangle 2:
1.0f, -1.0f,
-1.0f, 1.0f,
1.0f, 1.0f
;
float[] ttmp =
//Triangle 1:
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
//Triangle 2:
0.0f, 0.0f,
1.0f, 1.0f,
1.0f, 0.0f
;
pVertex = ByteBuffer.allocateDirect(12*4).order(ByteOrder.nativeOrder()).asFloatBuffer();
(...)
pTexCoord = ByteBuffer.allocateDirect(12*4).order(ByteOrder.nativeOrder()).asFloatBuffer();
(...)
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6); //Careful: Multiple changes on this line
(...)
如果步骤 1 顺利,那么让我们在步骤 2 中添加额外的三角形:
float[] vtmp =
//Triangle 1:
-1.0f, 0.0f,
-1.0f, 1.0f,
0.0f, 0.0f,
//Triangle 2:
0.0f, 0.0f,
-1.0f, 1.0f,
0.0f, 1.0f,
//Triangle 3:
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 0.0f,
//Triangle 4:
1.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f,
//Triangle 5:
0.0f, -1.0f,
0.0f, 0.0f,
1.0f, -1.0f,
//Triangle 6:
1.0f, -1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
//Triangle 7:
-1.0f, -1.0f,
-1.0f, 0.0f,
0.0f, -1.0f,
//Triangle 8:
0.0f, -1.0f,
-1.0f, 0.0f,
0.0f, 0.0f
;
float[] ttmp =
//This is the same as in Step 1, but duplicated 4 times over:
//Triangle 1:
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
//Triangle 2:
0.0f, 0.0f,
1.0f, 1.0f,
1.0f, 0.0f,
//Triangle 3:
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
//Triangle 4:
0.0f, 0.0f,
1.0f, 1.0f,
1.0f, 0.0f,
//Triangle 5:
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
//Triangle 6:
0.0f, 0.0f,
1.0f, 1.0f,
1.0f, 0.0f,
//Triangle 7:
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
//Triangle 8:
0.0f, 0.0f,
1.0f, 1.0f,
1.0f, 0.0f
;
pVertex = ByteBuffer.allocateDirect(48*4).order(ByteOrder.nativeOrder()).asFloatBuffer();
(...)
pTexCoord = ByteBuffer.allocateDirect(48*4).order(ByteOrder.nativeOrder()).asFloatBuffer();
(...)
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 24);
(...)
【讨论】:
非常感谢,您的回答对我理解它的工作原理有很大帮助,我会试一试并回复您 所以我一直在努力解决,基本上演示使用GL_TRIANGLE_STRIP
而不是GL_TRIANGLE_LIST
。我能够使用 vtmp = -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f
和 ttmp = 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f
解决 xy 反转,但我无法在步骤 1 中将其转换为使用 GL_TRIANGLES
。再次感谢您的所有帮助
GL_TRIANGLE_LIST
是一个错字,我的意思是GL_TRIANGLE_STRIP
。那么出了什么问题呢?
如果我将代码更改为第 1 步,我会从左下角、左上角、右上角的三角形中获得预览,该三角形被分成 3 个三角形,显示预览的不同部分。我试图将它与openglbook.com/images/4262_02_06.png 进行比较,它似乎是正确的,所以我真的不确定它为什么这样做:/。在添加额外多边形之前,我是否需要在第一步中更改字节缓冲区分配,我已经这样做了,但可能是第 2 步?
很抱歉打扰您,我还有最后一个问题。感谢您的帮助,我现在已经完全按照我喜欢的方式设置了预览,作为正方形,但是相机是 1920x1080,在以前的方法中,我可以简单地为视图添加一个边距,但你知道我之前如何裁剪纹理它是这样写的,所以它是一个未压扁的方形输出?非常感谢以上是关于如何以最有效的方式创建多个 camera2 预览?的主要内容,如果未能解决你的问题,请参考以下文章
Java一次替换字符串中的多个不同子字符串(或以最有效的方式)
如何以最有效的方式将运动员的名字分配给新列“名字”? [复制]
如何在 Camera2 API Android 5.0 中获取单个预览帧?