0

I am trying to create 4 streams of my camera preview on my activity. I created a TextureView which is registered to the camera2 API for the feed and then I set up a listener on the SurfaceView in order to listen to changes for the feed and update the other 3 previews (ImageViews) accordingly. You can see in my code below:

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

As you can see this has to read from the TextureView for every frame, extract the bitmap and then set the bitmap of the other 3 ImageView streams. I tried to do this on the UI thread initially which is very slow and then tried to submit it to the background handler which was better frame rate but caused a lot of issues with the app crashing due to the load.

Thanks

EDIT

So in order to crop the bottom 0.4375 of the preview, I changed ttmp to

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

but this did not crop as expected

kabeersvohra
  • 1,049
  • 1
  • 14
  • 31
  • What is your use case? Do you need 3 to be `ImageViews`, or will 4 copies inside one `GLSurfaceView` work? – greeble31 Dec 30 '19 at 02:07
  • Yes, 4 copies of the GLSurfaceView would work fine, I tried to understand how to implement this but I was lost – kabeersvohra Dec 30 '19 at 02:12
  • Could you possible provide some guidance on what I have to do to get 4 copies of the GLSurfaceView – kabeersvohra Dec 30 '19 at 02:17
  • I don't have time for a complete answer, but if you can get the preview working in a `GLSurfaceView` ([see here for a rough example](https://stackoverflow.com/questions/36703984/rotating-android-camera-preview-by-90-degrees-on-glsurfaceview-using-opengl-2-0)) then making 3 more copies is simply a matter of adding 6 more polygons (`vtmp`, `ttmp`). OpenGL is definitely your best choice, in terms of efficiency. – greeble31 Dec 30 '19 at 03:01
  • Hi, so I have got the preview working on a `GLSurfaceView` using the front facing camera with `vtmp = { 1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f }` and `ttmp = { 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f }`. How would I now add more polygons? Also a separate question if you would be able to help, the preview is inverted left to right, do you know which numbers to change in order to fix this/I can't find any documentation for this. Thanks a lot – kabeersvohra Dec 30 '19 at 14:09
  • You did that quick, I'm impressed – greeble31 Dec 30 '19 at 14:57
  • hahaha cheers :) – kabeersvohra Dec 30 '19 at 15:00
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/205094/discussion-between-kabeersvohra-and-greeble31). – kabeersvohra Dec 30 '19 at 17:09

1 Answers1

1

So if you can get GLSurfaceView working with the camera preview as in this question then you can make 3 more copies simply by adding 6 more polygons. Let me explain how they are layed out. vtmp and ttmp describe the vector coordinates and texture coordinates, respectively, of two triangles, in a GL_TRIANGLE_STRIP form:

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

Step 1: Let's change the primitive type to a GL_TRIANGLES, because this is going to be difficult with a 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
(...)

If Step 1 went well, then let's add the extra triangles in Step 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);
(...)
greeble31
  • 4,894
  • 2
  • 16
  • 30
  • Thank you very much, your answer helps me a lot in understanding how this works, I will give it a go and get back to you – kabeersvohra Dec 30 '19 at 15:01
  • So I have been trying to work it out, basically the demo used `GL_TRIANGLE_STRIP` rather than `GL_TRIANGLE_LIST`. I was able to resolve the xy inversion using `vtmp = {-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f}` and `ttmp = {0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f}` but I am unable to translate this to using `GL_TRIANGLES` in step 1. Thank you again for all your help – kabeersvohra Dec 30 '19 at 16:37
  • `GL_TRIANGLE_LIST` was a typo, I meant `GL_TRIANGLE_STRIP`. So what's going wrong? – greeble31 Dec 30 '19 at 16:58
  • If I change my code to step 1, I get a preview in a triangle from bottom left, top left, top right which is split into 3 triangles showing different parts of the preview. I was trying to compare it to https://openglbook.com/images/4262_02_06.png and it seems correct so I am really not sure why it is doing that :/. Is it the case that I need to change the byte buffer allocations in the first step before adding the extra polygons, I have done this but maybe its for step 2? – kabeersvohra Dec 30 '19 at 17:05
  • Sorry to keep disturbing you, I have one last question. Thanks to your help I have now set up the previews exactly how I like them, as squares, however the camera is 1920x1080, in the previous method I could simply add a margin to the view but do you know how I could crop the texture before it is written so that it is an unsquashed square output? thanks a lot – kabeersvohra Dec 30 '19 at 19:10
  • @kabeersvohra You want to solve this using the texture coordinates. Instead of "covering" the triangle starting at a Y (v) of 0.0f to a Y (v) of 1.0f, you want to do it from like 0.2f to 0.8f. That cuts off the top/bottom 0.2f of the camera texture. Which is probably too much; you'll have to figure out how to correct the aspect ratio on your own. Does that make sense? – greeble31 Dec 30 '19 at 19:25
  • So I did this (edited the question) but it does not work as I expected, do you know what I did wrong here? – kabeersvohra Dec 30 '19 at 19:47
  • worked it out, turns out the coordinates are `y,x` rather than `x,y` :) – kabeersvohra Dec 30 '19 at 19:53