如何以最有效的方式创建多个 camera2 预览?

How to create multiple camera2 previews in most efficient way?

我正在尝试在 activity 上创建 4 个相机预览流。我创建了一个注册到 camera2 API 的 TextureView 用于提要,然后我在 SurfaceView 上设置了一个侦听器以收听提要的更改并相应地更新其他 3 个预览(ImageView)。您可以在下面的代码中看到:

    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
    };

但这并没有像预期的那样裁剪

因此,如果您可以 GLSurfaceView 那样使用相机预览,那么您只需再添加 6 个多边形就可以再制作 3 个副本。让我解释一下它们是如何布局的。 vtmpttmp分别描述两个三角形的向量坐标和纹理坐标,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);
(...)