4

I'm having a little trouble of getting an image/drawable or a bitmap from a SurfaceView that works as a camera preivew.

    final CameraSurfaceView cameraSurfaceView = new CameraSurfaceView(this);
    LinearLayout ll = (LinearLayout)findViewById(R.id.linearLayout1);
    ll.addView(cameraSurfaceView); // THIS WORKS

    ImageView ivCam = (ImageView) findViewById(R.id.ivCam);
    ivCam.setImageBitmap(cameraSurfaceView.getDrawingCache()); // THIS DOESN'T :(

Any suggestions? Thanks!

EDIT:

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        final CameraSurfaceView cameraSurfaceView = new CameraSurfaceView(this);
        LinearLayout ll = (LinearLayout)findViewById(R.id.LLS);
        ll.addView(cameraSurfaceView); // THIS WORKS


    }

///////////////////////////////////////////////////////////////////////////////////////////////   

    public class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback
    {
            private SurfaceHolder holder;
            private Camera camera;

            public CameraSurfaceView(Context context) 
            {
                    super(context);

                    //Initiate the Surface Holder properly
                    this.holder = this.getHolder();
                    this.holder.addCallback(this);
                    this.holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
            }

            @Override
            public void surfaceCreated(SurfaceHolder holder) 
            {
                    try
                    {
                            this.camera = Camera.open();
                            this.camera.setPreviewDisplay(this.holder);

                            this.camera.setPreviewCallback(new PreviewCallback() {

                              public void onPreviewFrame(byte[] _data, Camera _camera) {

                                Camera.Parameters params = _camera.getParameters();
                                   int w = params.getPreviewSize().width;
                                   int h = params.getPreviewSize().height;
                                   int format = params.getPreviewFormat();
                                   YuvImage image = new YuvImage(_data, format, w, h, null);

                                   ByteArrayOutputStream out = new ByteArrayOutputStream();
                                   Rect area = new Rect(0, 0, w, h);
                                   image.compressToJpeg(area, 50, out);
                                   Bitmap bm = BitmapFactory.decodeByteArray(out.toByteArray(), 0, out.size());

                                   ImageView ivCam = (ImageView) findViewById(R.id.imageView1);
                                   ivCam.setImageBitmap(bm);  /// NULL POINT EX HERE!
                              }
                            });

                    }
                    catch(IOException ioe)
                    {
                            ioe.printStackTrace(System.out);
                    }
            }


            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) 
            {
                this.camera.startPreview();
            }    

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) 
            {
                this.camera.stopPreview();
                this.camera.release();
                this.camera = null;
            }


            public Camera getCamera()
            {
                    return this.camera;
            }


    }
Roger
  • 6,443
  • 20
  • 61
  • 88

1 Answers1

5

It's far more complicated than that. The background of the SurfaceView is not the camera preview. You have to have a class that implements Camera.PreviewCalback. Once you have that, you can get a byte array containing the image that the preview sends. On some phones, you can set the preview to be a JPEG in which case you can decode it straight with BitmapFactory. On other phones that don't support that feature, you'll get by default a YUV 4:2:0 image that you have to convert into a JPEG image.

On Android 2.2+, you can convert the YUV image to a JPEG like so:

   int w = params.getPreviewSize().width;
   int h = params.getPreviewSize().height;
   int format = params.getPreviewFormat();
   YuvImage image = new YuvImage(data, format, w, h, null);

   ByteArrayOutputStream out = new ByteArrayOutputStream();
   Rect area = new Rect(0, 0, w, h);
   image.compressToJpeg(area, 50, out);
   Bitmap bm = BitmapFactory.decodeByteArray(out.toByteArray(), 0, out.size());
   ivCam.setImageBitmap(bm);

If you're targeting older models, you have to use a conversion algorithm like the one here.

http://blog.tomgibara.com/post/132956174/yuv420-to-rgb565-conversion-in-android

A SO source:

Getting frames from Video Image in Android

EDIT: If all you want is to show the camera view, then you just add the SurfaceView that your camera is using to a layout that is already displayed like you did in your question. It's already displaying it.

Community
  • 1
  • 1
DeeV
  • 35,865
  • 9
  • 108
  • 95
  • Great, thanks! I've added "implements PreviewCallback" to my activity and your code into its "public void onPreviewFrame(byte[] data, Camera camera) {" ... but how do I initialize the camera from the activity? Simply "Camera camera = Camera.open(); camera.startPreview();" gives Fail to connect to camera service. :/ – Roger Oct 17 '11 at 14:11
  • You said you have the camera implementation already working. Keep that. You need that. Add `camera.setPreviewCallback` with your preview object. – DeeV Oct 17 '11 at 14:15
  • oh, just where should i put it camera.setPreviewCallback ? – Roger Oct 17 '11 at 14:37
  • You can call it any time that has access to the camera object. I generally have it in my custom `SurfaceView` class under a method called `public void savePreviewCallback(Camera.PreviewCallback callback)` which allows me to pass in whatever callback handler I want. It also keeps the camera object within the view for code isolation. – DeeV Oct 17 '11 at 14:55
  • Thanks, please see the edit above, it gives a Null Point Exception with the BitMap. – Roger Oct 17 '11 at 15:01
  • Are you sure it's on the bitmap or the `ImageView`? I'm thinking `ivCam` doesn't have a reference because it can't find the view. – DeeV Oct 17 '11 at 15:16
  • Oho, yeap, it on ivCam! Hmm... but I do have the R.id.imageView1 allright in the XML file. Maybe its just that it belongs to the initial activity, not the CameraSurfaceView I'm trying to call it from. – Roger Oct 17 '11 at 15:21
  • I can not log into chats from where I am. Against policy. The reason your ImageView isn't finding a reference is because `findViewById()` is acting on the `SurfaceView` which doesn't have the `ImageView` contained inside it. You either need to pass in the reference yourself from the `Activity` or retrieve the Bitmap from the `SurfaceView` class. Which you choose and how you do it is entirely up to your implementation. – DeeV Oct 17 '11 at 15:33
  • WORKS! :) Declared ivCam as static. :) – Roger Oct 17 '11 at 15:34
  • @DeeV can you please help with this : https://stackoverflow.com/questions/61728321/how-to-change-preview-of-camera-at-runtime – Cosmic Dev May 12 '20 at 13:00