Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android: Camera, onSurfaceTextureUpdated, Bitmap.getPixels - framerate drops from 30 to 3

I have quite a horrible performance when trying to get the pixels of the Camera preview.

The image format is around 600x900. The preview rate is quite stable 30fps on my HTC one.

As soon as I try to get the pixels of the image the framerate drops to below 5!

public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
    Bitmap bmp = mTextureView.getBitmap();
    int width = bmp.getWidth();
    int height = bmp.getHeight();
    int[] pixels = new int[bmp.getHeight() * bmp.getWidth()];
    bmp.getPixels(pixels, 0, width, 0, 0, width, height);
}

The performance is so slow, it's not really bearable.

Now my only 'easy' solution is to skip frames to at least keep some visual performance. But I'd actually like to have that code perform faster.

I would appreciate any ideas and suggestions, maybe someone solved this already ?

UPDATE

getbitmap: 188.341ms
array: 122ms 
getPixels: 12.330ms
recycle: 152ms

It takes 190 milliseconds just to get the bitmap !! That's the problem

like image 556
John Avatar asked Oct 20 '22 12:10

John


1 Answers

I digged into this for several hours.

So short answer: I found no way to avoid getBitmap() and increase performance. The function is known to be slow, I found many similar questions and no results.

However I found another solution which is about 3 times faster and solves the problem for me. I keep using the TextureView approach, I use it because it gives more freedom on how to display the Camera preview (for example I can display the camera live preview in a small window of my own aspect ratio without distortion)

But to work with the image data I do not use onSurefaceTextureUpdated() anymore.

I registered a callback of the cameraPreviewFrame which gives me the pixel data I need. So no getBitmap anymore, and a lot more speed.

Fast, new code:

myCamera.setPreviewCallback(preview);

Camera.PreviewCallback preview = new Camera.PreviewCallback()
{
    public void onPreviewFrame(byte[] data, Camera camera)
    {
        Camera.Parameters parameters = camera.getParameters();
        Camera.Size size = parameters.getPreviewSize();
        Image img = new Image(size.width, size.height, "Y800");
    }
};

Slow:

private int[] surface_pixels=null;
private int surface_width=0;
private int surface_height=0;
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture)
{
    int width,height;

    Bitmap bmp= mTextureView.getBitmap();
    height=barcodeBmp.getHeight();
    width=barcodeBmp.getWidth();
    if (surface_pixels == null)
    {
        surface_pixels = new int[height * width];
    } else
    {
        if ((width != surface_width) || (height != surface_height))
        {
            surface_pixels = null;
            surface_pixels = new int[height * width];
        }
    }
    if ((width != surface_width) || (height != surface_height))
    {
        surface_height = barcodeBmp.getHeight();
        surface_width = barcodeBmp.getWidth();
    }

    bmp.getPixels(surface_pixels, 0, width, 0, 0, width, height);
    bmp.recycle();

    Image img = new Image(width, height, "RGB4");
 }

I hope this helps some people with the same problem.

If someone should find a way to create a bitmap in a fast manner within onSurfaceTextureUpdated please respond with a code sample.

like image 65
John Avatar answered Oct 23 '22 03:10

John