Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Camera: app passed NULL surface

I've found several questions on this but no answers so here's hoping someone might have some insight. When I try to swap the camera I call the swapCamera function below. However the camera preview just freezes (the app is not frozen though just the live camera preview).

When I open the app for the first time everything works just fine. However I noticed something interesting. When I log out the memoryaddress of the _surfaceHolder object (i.e. my SurfaceHolder object) it gives me one value, but whenever I query that value after the app has finished launching and everything, that memory address has changed.

Further still, the error it gives me when I swapCamera is very confusing. I logged out _surfaceHolder before I passed it to the camera in _camera.setPreviewDisplay(_surfaceHolder); and it is NOT null before it's passed in.

Any help is greatly appreciated.

I've noticed some interesting behaviour

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback
{
    private SurfaceHolder _surfaceHolder;
    private Camera _camera;
    boolean _isBackFacing;

    public CameraPreview(Context context, Camera camera) {
        super(context);
        _camera = camera;
        _isBackFacing = true;

        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        _surfaceHolder = getHolder();
        _surfaceHolder.addCallback(this);
    }

    void refreshCamera()
    {
        try {
            _camera.setPreviewDisplay(_surfaceHolder);
            _camera.startPreview();
        } catch (IOException e) {
            Log.d("iCamera", "Error setting camera preview: " + e.getMessage());
        }
    }

    public void surfaceCreated(SurfaceHolder holder)
    {
//        The Surface has been created, now tell the camera where to draw the preview.
        refreshCamera();
    }

    public void surfaceDestroyed(SurfaceHolder holder)
    {
        // empty. Take care of releasing the Camera preview in your activity.
        _surfaceHolder.removeCallback(this);
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h)
    {
         // If your preview can change or rotate, take care of those events here.
        // Make sure to stop the preview before resizing or reformatting it.

        if (_surfaceHolder.getSurface() == null){
            // preview surface does not exist
            return;
        }

        try {
            _camera.stopPreview();
        } catch (Exception e) {
            // ignore: tried to stop a non-existent preview
        }

        // set preview size and make any resize, rotate or
        // reformatting changes her
        _camera.setDisplayOrientation(90);

        // _startPoint preview with new settings
        refreshCamera();
    }

    public void swapCamera()
    {
        Camera cam = null;
        int cameraCount = Camera.getNumberOfCameras();
        Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
        _camera.stopPreview();
        _camera.release();
        for (int i = 0; i < cameraCount; i++)
        {
            Camera.getCameraInfo(i,cameraInfo);
            if(cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT && _isBackFacing == true)
            {
                try
                {
                    _camera = Camera.open(i);

                }catch (RuntimeException e)
                {
                    Log.e("Error","Camera failed to open: " + e.getLocalizedMessage());
                }
            }

            if(cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK && _isBackFacing == false)
            {
                try
                {
                    _camera = Camera.open(i);
                }catch (RuntimeException e)
                {
                    Log.e("Error","Camera failed to open: " + e.getLocalizedMessage());
                }
            }
        }

        _isBackFacing = !_isBackFacing;
        refreshCamera();
    }
}
like image 501
Aggressor Avatar asked May 19 '15 21:05

Aggressor


1 Answers

So after much debugging and digging what I found to be the culprit was the onResume function.

In it, I was 'refreshing' the camera variable in case it got lost between context switching.

public void onResume()
{
    super.onResume();
    _cameraPreview = new CameraPreview(getActivity());
}

This was causing my surfaceHolder to be created anew. I'm not exactly sure why it would cause a null, but I think because I created a new instance of a SurfaceHolder, the internal Android code was keeping a reference to the old (now null) SurfaceHolder. By removing my 'refresh' (i.e. reinstantiating) call from onResume the problem was fixed.

The error is misleading I think because its saying a null surface was passed but thats because I think its keeping a reference to a null surfaceHolder even if you created a new one and passed that in (it seems to use the OLD now null one anyways). So if you get this error, check that you aren't re-creating the surfaceHolder and passing it in.

like image 77
Aggressor Avatar answered Nov 01 '22 12:11

Aggressor