3

I'm facing an issue with Camera.setParameters, below is what I noticed,

On Nexus the SurfaceView(w, h) is 1080-1776 and the optimal size is W:1600-H:1200, it's working fine when I set the parameters

                        --------Nexus--------
SurfaceView(w, h) 1080-1776
Available cam sizes
size 1920-1080
size 1600-1200
size 1280-960
size 1280-768
size 1280-720
size 1024-768
size 800-600
size 800-480
size 720-480
size 640-480
size 352-288
size 320-240
size 176-144
optimalSize 1600-1200

==================================================================================================

The below is on Samsung, and it's crashing here, I already tried switching the W with H in the Camera.setParameters and it crahsed as well, I tried evey single size available and all of them crahsed

                    --------Samsung Back camera--------
SurfaceView(w, h)  1080-1920
Available cam sizes
size 1920-1080
size 1440-1080
size 1280-720
size 1056-864
size 960-720
size 720-480
size 640-480
size 320-240
size 176-144
optimalSize 1920-1080

And here the confusing part,

When I try the Camera.open(1) instead of Camera.open(0), the fron-facing camera, it works!!

                 --------Samsung front-facing camera--------
SurfaceView(w, h) 1080-1920
Available cam sizes
size 1920-1080
size 1440-1080
size 1280-720
size 1056-864
size 960-720
size 720-480
size 640-480
size 320-240
size 176-144
optimalSize 1920-1080

And the code I'm using is below, can some please tell me what's going on

class Preview extends ViewGroup implements SurfaceHolder.Callback {
    private final String TAG = "Preview";

    SurfaceView mSurfaceView;
    SurfaceHolder mHolder;
    Camera.Size mPreviewSize;
    List<Camera.Size> mSupportedPreviewSizes;
    Camera mCamera;
    Context mContext;
    int screenWidth;
    int screenHeight;
    Preview(Context context, SurfaceView sv, int width, int height) {
        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();
            // 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 Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
        final double ASPECT_TOLERANCE = 0.1;
        double targetRatio = (double) w / h;
        if (sizes == null) return null;

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

        int targetHeight = h;
        for (Camera.Size size : sizes) {
            Log.d("CamSettings", "size "+ size.width +"-"+ size.height);
        }
        // Try to find an size match aspect ratio and size
        for (Camera.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 (Camera.Size size : sizes) {
                if (Math.abs(size.height - targetHeight) < minDiff) {
                    optimalSize = size;
                    minDiff = Math.abs(size.height - targetHeight);
                }
            }
        }
        Log.d("CamSettings", "optimalSize "+ optimalSize.width +"-"+ optimalSize.height);

        return optimalSize;
    }

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

            mCamera.setDisplayOrientation(90);
            Camera.Parameters parameters = mCamera.getParameters();

            Log.d("CamSettings", "SurfaceView " + w + "-" + h);
              Camera.Size sc = getOptimalPreviewSize(parameters.getSupportedPreviewSizes(), w, h); 

            parameters.setPreviewSize(sc.width, sc.height);
            parameters.setPictureSize(sc.width, sc.height);


//            Camera.Size captureSize = determineBestPictureSize(parameters);


            requestLayout();
            mCamera.setParameters(parameters);
            mCamera.startPreview();
        }
    }

And the crash is this

E/AndroidRuntime: FATAL EXCEPTION: main
 Process: com.example.camtest1, PID: 21832
 java.lang.RuntimeException: setParameters failed
     at android.hardware.Camera.native_setParameters(Native Method)
     at android.hardware.Camera.setParameters(Camera.java:1701)
     at com.example.camtest1.Preview.surfaceChanged(Preview.java:174)
     at android.view.SurfaceView.updateWindow(SurfaceView.java:611)
     at android.view.SurfaceView.access$000(SurfaceView.java:94)
     at android.view.SurfaceView$3.onPreDraw(SurfaceView.java:183)
     at android.view.ViewTreeObserver.dispatchOnPreDraw(ViewTreeObserver.java:895)
     at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2222)
     at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1267)
     at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6638)
     at android.view.Choreographer$CallbackRecord.run(Choreographer.java:813)
     at android.view.Choreographer.doCallbacks(Choreographer.java:613)
     at android.view.Choreographer.doFrame(Choreographer.java:583)
     at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:799)
     at android.os.Handler.handleCallback(Handler.java:733)
     at android.os.Handler.dispatchMessage(Handler.java:95)
     at android.os.Looper.loop(Looper.java:146)
     at android.app.ActivityThread.main(ActivityThread.java:5635)
     at java.lang.reflect.Method.invokeNative(Native Method)
     at java.lang.reflect.Method.invoke(Method.java:515)
     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1291)
     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1107)
     at dalvik.system.NativeStart.main(Native Method)

---Update--- I just tried disable this

parameters.setPictureSize(sc.width, sc.height) 

and it's not crashing anymore, still trying to see if that is going to affect the aspect ratio

Let'sRefactor
  • 3,303
  • 4
  • 27
  • 43

3 Answers3

2

And here the confusing part,

When I try the Camera.open(1) instead of Camera.open(0), the fron-facing camera, it works!!

Here is your answer right here.
When you are using Camera.open() it got an overloading method that except camera id Camera.open(int cameraId). For each camera id it got it's own set of supported sized, which is only logical as the front and the back camera got different resolutions. This is why your code is working with Camera.open(0) and not with Camera.open(1)

Use those methods to find the right settings for you after obtaining reference to camera.

    camera.getParameters().getSupportedVideoSizes();
    camera.getParameters().getSupportedPictureSizes();
    camera.getParameters().getSupportedPreviewSizes()
Ilya Gazman
  • 31,250
  • 24
  • 137
  • 216
0

Disabling the solved my issue.

parameters.setPictureSize(sc.width, sc.height) 

It looks like that the sizes I got was for the preview, I wonder how to get/set the size of the picture!

0

You can also get supported picture sizes like you do on preview sizes.

getSupportedPictureSizes() method will return a list of Camera.Size's that is supported by the device's camera. And you can pass this list to the getOptimalPreviewSize. If you want preview and photo to have the same view angle, you can give parameters to getOptimalPreviewSize as getSupportedPictureSizes, yourPreviewWidth, yourPreviewHeight. So it will return a consistent picture size to your preview.

Anil
  • 543
  • 3
  • 16