Search code examples
javaandroidcamerasurfaceviewsurfaceholder

Getting image data continuously from camera, SurfaceView or SurfaceHolder


So I have this camera preview set up with Camera, SurfaceView and SurfaceHolder. I have also an ImageView where I will be putting a modified version of the camera image and I want this to update lets say once every second.

All code is ready and already working when I load images from "res" but I have a really hard time reading the image data from the camera.

I've tried following already:

  1. Creating an intent for MediaStore.ACTION_IMAGE_CAPTURE and starting an onActivityResult getting a small thumbnail (enough for me actually) from (Bitmap)data.getExtras().get("data")

    The problem is that this opens the camera App and you need to "manually" take a picture.

  2. Creating a Camera.PreviewCallback, taking the YuvImage, and converting it to an image using YuvImage.compressToJpeg(...).

    The problem here is that I can't get it to start no matter when or where i put the Camera.setPreviewCallbackWithBuffer(PreviewCallback).

  3. Try to take the data directly from PreviewHolder by locking in to the canvas using lockCanvas() and trying to convert it to a bitmap

    Obviously Doesn't work.

Edit: What is the best way to make this work? I mean QR-Code readers must read the image data out of the camera continuously, how do they work?


Solution

  • I went for option number 2 and finally made it work.

    used this callback, forgot the @Override before

    private Camera.PreviewCallback  previewCallback= new Camera.PreviewCallback()
    {   
        @Override
        public void onPreviewFrame(byte[] data,Camera cam)
        {
                Camera.Size previewSize = cam.getParameters().getPreviewSize();
                YuvImage yuvImage = new YuvImage(data, ImageFormat.NV21,previewSize.width,previewSize.height, null);
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                yuvImage.compressToJpeg(new Rect(0,0,previewSize.width,previewSize.height),80,baos);
                byte[] jdata = baos.toByteArray();
                Bitmap bitmap = BitmapFactory.decodeByteArray(jdata,0,jdata.length);    
        }
    };
    

    And initiating it using setPreviewCallback rather than setPreviewCallbackWithBuffer

    SurfaceHolder.Callback surfaceCallback=new SurfaceHolder.Callback() 
    {   
        public void surfaceCreated(SurfaceHolder holder) {
    
            camera.setPreviewCallback(previewCallback);
        }
    }