Using android camera2 API to display camera feed

I am trying to create a very simple application that displays a camera image on a display. I am using the camera2 API because I am new to this so I try to use the latest technology.

I get to the point where I call createCaptureSession()

but then onConfigureFailed()

gets called and I don't know what the problem is or how to find it.

Here is my source:

SurfaceView mSurfaceView;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    Log.d(TAG, "onCreate() start");

    setContentView(R.layout.activity_main);

    mSurfaceView = (SurfaceView) findViewById(R.id.surfaceView);

}

protected void onResume() {
    super.onResume();

    Log.d(TAG, "onResume() start");

    initCamera();
}

private void initCamera() {
    Log.d(TAG, "initCamera() start");
    CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
    Log.d(TAG, "acquired cameraManager: " + cameraManager);

    String[] cameraIdList;
    try {
        cameraIdList = cameraManager.getCameraIdList();
    } catch (CameraAccessException e) {
        Log.e(TAG, "couldn't get camera list", e);
        return;
    }
    Log.d(TAG, "acquired cameraIdList: length: " + cameraIdList.length);

    if (cameraIdList.length == 0) {
        Log.w(TAG, "couldn't detect a camera");
        return;
    }

    String camera0Id = cameraIdList[0];

    Log.d(TAG, "chosen camera: " + camera0Id);

    try {
        cameraManager.openCamera(camera0Id, deviceCallback, null);
    } catch (CameraAccessException e) {
        Log.e(TAG, "couldn't open camera", e);
    }
    Log.d(TAG, "called cameraManager.openCamera()");
}

CameraDevice.StateCallback deviceCallback = new CameraDevice.StateCallback() {

    @Override
    public void onOpened(CameraDevice camera) {
        Log.d(TAG, "deviceCallback.onOpened() start");

        Surface surface = mSurfaceView.getHolder().getSurface();
        Log.d(TAG, "surface: " + surface);

        List<Surface> surfaceList = Collections.singletonList(surface);

        try {
            camera.createCaptureSession(surfaceList, sessionCallback, null);
        } catch (CameraAccessException e) {
            Log.e(TAG, "couldn't create capture session for camera: " + camera.getId(), e);
            return;
        }

    }

    @Override
    public void onDisconnected(CameraDevice camera) {
        Log.d(TAG, "deviceCallback.onDisconnected() start");
    }

    @Override
    public void onError(CameraDevice camera, int error) {
        Log.d(TAG, "deviceCallback.onError() start");
    }

};

CameraCaptureSession.StateCallback sessionCallback = new CameraCaptureSession.StateCallback() {
    @Override
    public void onConfigured(CameraCaptureSession session) {
        Log.i(TAG, "capture session configured: " + session);
    }

    @Override
    public void onConfigureFailed(CameraCaptureSession session) {
        Log.e(TAG, "capture session configure failed: " + session);
    }
};

      

And the result:

...īš• onCreate() start
...īš• onResume() start
...īš• initCamera() start
...īš• acquired cameraManager: android.hardware.camera2.CameraManager@5d68786
...īš• acquired cameraIdList: length: 2
...īš• chosen camera: 0
...īš• called cameraManager.openCamera()
...īš• deviceCallback.onOpened() start
...īš• surface: Surface(name=null)/@0x52c91e3
...īš• capture session configure failed: android.hardware.camera2.impl.CameraCaptureSessionImpl@1a8c7a99

      

My AndroidManifest.xml has the following:

<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera2" />

      

+3


source to share


3 answers


you have to set the preview size



mSurfaceView.getHolder().setFixedSize(previewSize.getWidth(), previewSize.getHeight());

      

+3


source


Set custom camera code:

import java.io.IOException;
import java.util.List;

import android.annotation.SuppressLint;
import android.content.Context;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.Size;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;

@SuppressWarnings("deprecation")
public class Preview extends ViewGroup implements SurfaceHolder.Callback {
    private final String TAG = "Preview";

    SurfaceView mSurfaceView;
    SurfaceHolder mHolder;
    Size mPreviewSize;
    List<Size> mSupportedPreviewSizes;
    Camera mCamera;

    public Preview(Context context, SurfaceView sv) {
        super(context);

        mSurfaceView = sv;
        // addView(mSurfaceView);

        mHolder = mSurfaceView.getHolder();
        mHolder.addCallback(this);
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    public void setCamera(Camera camera) {
        mCamera = camera;
        if (mCamera != null) {
            mSupportedPreviewSizes = mCamera.getParameters()
                    .getSupportedPreviewSizes();
            requestLayout();

            mCamera.setDisplayOrientation(90);
            setCamFocusMode();

            // // get Camera parameters
            // Camera.Parameters params = mCamera.getParameters();
            //
            // List<String> focusModes = params.getSupportedFocusModes();
            // if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
            // // set the focus mode
            // params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
            // // set Camera parameters
            // mCamera.setParameters(params);
            //
            // }
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // We purposely disregard child measurements because act as a
        // wrapper to a SurfaceView that centers the camera preview instead
        // of stretching it.
        final int width = resolveSize(getSuggestedMinimumWidth(),
                widthMeasureSpec);
        final int height = resolveSize(getSuggestedMinimumHeight(),
                heightMeasureSpec);
        setMeasuredDimension(width, height);

        if (mSupportedPreviewSizes != null) {
            mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width,
                    height);
        }
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        if (changed && getChildCount() > 0) {
            final View child = getChildAt(0);

            final int width = r - l;
            final int height = b - t;

            int previewWidth = width;
            int previewHeight = height;
            if (mPreviewSize != null) {
                previewWidth = mPreviewSize.width;
                previewHeight = mPreviewSize.height;
            }

            // Center the child SurfaceView within the parent.
            if (width * previewHeight > height * previewWidth) {
                final int scaledChildWidth = previewWidth * height
                        / previewHeight;
                child.layout((width - scaledChildWidth) / 2, 0,
                        (width + scaledChildWidth) / 2, height);
            } else {
                final int scaledChildHeight = previewHeight * width
                        / previewWidth;
                child.layout(0, (height - scaledChildHeight) / 2, width,
                        (height + scaledChildHeight) / 2);
            }
        }
    }

    public void surfaceCreated(SurfaceHolder holder) {
        // The Surface has been created, acquire the camera and tell it where
        // to draw.
        try {
            if (mCamera != null) {
                mCamera.setPreviewDisplay(holder);
            }
        } catch (IOException exception) {
            Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
        }
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        // Surface will be destroyed when we return, so stop the preview.
        if (mCamera != null) {
            mCamera.stopPreview();
        }
    }

    private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
        final double ASPECT_TOLERANCE = 0.1;
        double targetRatio = (double) w / h;
        if (sizes == null)
            return null;

        Size optimalSize = null;
        double minDiff = Double.MAX_VALUE;

        int targetHeight = h;

        // Try to find an size match aspect ratio and size
        for (Size size : sizes) {
            double ratio = (double) size.width / size.height;
            if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
                continue;
            if (Math.abs(size.height - targetHeight) < minDiff) {
                optimalSize = size;
                minDiff = Math.abs(size.height - targetHeight);
            }
        }

        // Cannot find the one match the aspect ratio, ignore the requirement
        if (optimalSize == null) {
            minDiff = Double.MAX_VALUE;
            for (Size size : sizes) {
                if (Math.abs(size.height - targetHeight) < minDiff) {
                    optimalSize = size;
                    minDiff = Math.abs(size.height - targetHeight);
                }
            }
        }
        return optimalSize;
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        if (mCamera != null) {

            Camera.Parameters parameters = mCamera.getParameters();
            List<Camera.Size> previewSizes = parameters
                    .getSupportedPreviewSizes();

            // You need to choose the most appropriate previewSize for your app
            Camera.Size previewSize;
            try {
                previewSize = previewSizes.get(1);
                parameters.setPreviewSize(previewSize.width, previewSize.height);
                mCamera.setParameters(parameters);
                mCamera.startPreview();
            } catch (Exception e) {
                previewSize = previewSizes.get(0);
                parameters.setPreviewSize(previewSize.width, previewSize.height);
                mCamera.setParameters(parameters);
                mCamera.startPreview();
            }
        }
    }

    @SuppressLint("InlinedApi")
    private void setCamFocusMode() {

        if (null == mCamera) {
            return;
        }
        /* Set Auto focus */
        Parameters parameters = mCamera.getParameters();
        List<String> focusModes = parameters.getSupportedFocusModes();
        if (focusModes
                .contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
            parameters
                    .setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
        } else if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
            parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
        }
        mCamera.setParameters(parameters);
    }

    // Check Flash in Camera or not
    public boolean hasFlash() {
        if (mCamera == null) {
            return false;
        }

        Camera.Parameters parameters = mCamera.getParameters();
        if (parameters.getFlashMode() == null) {
            return false;
        }

        List<String> supportedFlashModes = parameters.getSupportedFlashModes();
        if (supportedFlashModes == null
                || supportedFlashModes.isEmpty()
                || supportedFlashModes.size() == 1
                && supportedFlashModes.get(0).equals(
                        Camera.Parameters.FLASH_MODE_OFF)) {
            return false;
        }
        return true;
    }

    public boolean setFlash(int flashMode) {
        if (mCamera == null) {
            return false;
        }

        Camera.Parameters parameters = mCamera.getParameters();
        if (parameters.getFlashMode() == null) {
            return false;
        }

        List<String> supportedFlashModes = parameters.getSupportedFlashModes();
        if (flashMode == 1 && supportedFlashModes.get(2).equals(
                        Camera.Parameters.FLASH_MODE_AUTO)) {
            parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
        } else if (flashMode == 2 && supportedFlashModes.get(1).equals(
                        Camera.Parameters.FLASH_MODE_ON)) {
            parameters.setFlashMode(Camera.Parameters.FLASH_MODE_ON);
        } else if (flashMode == 3 && supportedFlashModes.get(0).equals(
                        Camera.Parameters.FLASH_MODE_OFF)) {
            parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
        }
        mCamera.setParameters(parameters);
        return true;
    }
}

      



You can set the size of the camera preview in the surfaceChanged () method.

This code works for me as well on Android 5.0.1 and 5.1.1.

+2


source


Since the claimant said that he tested the Galaxy S4, it may be due to the fact that some Samsung Lollipop phones did not implement the Camera2 API. DPReview

+1


source







All Articles