How to get rid of camera freezes (SurfaceView)?

Viewed 920

I'm trying to create custom camera using Camera API. I have already looked through a lot of similar questions, but anyway can't get rid from freezes in my Camera Preview. Sometimes preview freezes when activity started, despite of using another thread. But when I try to switch to face camera, preview image Freezes every time. In log i Got only something like this:

I/Choreographer: Skipped 41 frames!  The application may be doing too much work on its main thread.

My SurfaceView is placed in Fragment in ViewPager activity if it's matter.

My Custom Camera class methods:

Set Display Orientation:

void setCameraDisplayOrientation(int cameraId) {
        int rotation = getActivity().getWindowManager().getDefaultDisplay().getRotation();
        int degrees = 0;
        switch (rotation) {
            case Surface.ROTATION_0:
                degrees = 0;
                break;
            case Surface.ROTATION_90:
                degrees = 90;
                break;
            case Surface.ROTATION_180:
                degrees = 180;
                break;
            case Surface.ROTATION_270:
                degrees = 270;
                break;
        }

        int result = 0;

        Camera.CameraInfo info = new Camera.CameraInfo();
        Camera.getCameraInfo(cameraId, info);

        if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
            result = ((360 - degrees) + info.orientation);
        } else

            if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
                result = ((360 - degrees) - info.orientation);
                result += 360;
            }
        result = result % 360;
        camera.setDisplayOrientation(result);
    }

Holder Callback class:

class HolderCallback implements SurfaceHolder.Callback {

        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            try {
                camera.setPreviewDisplay(holder);
                camera.startPreview();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }


        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width,
                                   int height) {
            // TODO Auto-generated method stub
            if (mIsPreviewing) {
                camera.stopPreview();
                mIsPreviewing = false;
            }

            if (camera != null) {
                Camera.Parameters parameters = camera.getParameters();
                Camera.Size bestSize = getBestPreviewSize(width, height, parameters);

                if (bestSize != null) {
                    parameters.setPreviewSize(bestSize.width, bestSize.height);
                    camera.setParameters(parameters);

                    Toast.makeText(
                            getActivity().getApplicationContext(),
                            "Оптимальный размер: " + String.valueOf(bestSize.width)
                                    + " : " + String.valueOf(bestSize.height),
                            Toast.LENGTH_LONG).show();
                }
                try {
                    camera.setPreviewDisplay(holder);
                    camera.startPreview();
                    mIsPreviewing = true;

//                    camera.autoFocus(autoFocusCallback);
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }

        private Camera.Size getBestPreviewSize(int width, int height,
                                               Camera.Parameters parameters) {
            Camera.Size bestSize = null;
            List<Camera.Size> sizeList = parameters.getSupportedPreviewSizes();

            bestSize = sizeList.get(0);

            for (int i = 1; i < sizeList.size(); i++) {
                if ((sizeList.get(i).width * sizeList.get(i).height) > (bestSize.width * bestSize.height)) {
                    bestSize = sizeList.get(i);
                }
            }
            return bestSize;
        }


        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {

        }

    }

Camera Handler Thread:

private CameraHandlerThread mThread = null;
    private static class CameraHandlerThread extends HandlerThread {
        Handler mHandler = null;

        CameraHandlerThread() {
            super("CameraHandlerThread");
            start();
            mHandler = new Handler(getLooper());
        }

        synchronized void notifyCameraOpened() {
            notify();
        }

        void openCamera() {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    camera = Camera.open(CAMERA_ID);
                    //set camera to continually auto-focus
                    Camera.Parameters params = camera.getParameters();
//*EDIT*//params.setFocusMode("continuous-picture");
//It is better to use defined constraints as opposed to String, thanks to AbdelHady
//                    params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
//                    camera.setParameters(params);
                    //STEP #1: Get rotation degrees
                    Camera.CameraInfo info = new Camera.CameraInfo();
                    Camera.getCameraInfo(Camera.CameraInfo.CAMERA_FACING_BACK, info);

                    int degrees = 0;
                    switch (rotation) {
                        case Surface.ROTATION_0: degrees = 0; break; //Natural orientation
                        case Surface.ROTATION_90: degrees = 90; break; //Landscape left
                        case Surface.ROTATION_180: degrees = 180; break;//Upside down
                        case Surface.ROTATION_270: degrees = 270; break;//Landscape right
                    }
                    int rotate = (info.orientation - degrees + 360) % 360;

//STEP #2: Set the 'rotation' parameter
                    params.setRotation(rotate);
                    camera.setParameters(params);
                    notifyCameraOpened();
                    camera.startPreview();

                }
            });
            try {
                wait();
            }
            catch (InterruptedException e) {
                Log.d(TAG, "openCamera: Cannot open Camera");
            }
        }
    }

Opening camera:

private void newOpenCamera() {
    mThread = new CameraHandlerThread();
    synchronized (mThread) {
        mThread.openCamera();
    }
}

Fragment methods:

 @Override
    public void onResume() {
        super.onResume();
        newOpenCamera();
        setCameraDisplayOrientation(CAMERA_ID);
    }

    @Override
    public void onPause() {
        super.onPause();
        if (camera != null)
            camera.release();
        camera = null;
    }

@Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        sv = (SurfaceView) getActivity().findViewById(R.id.surfaceView);

        makePhotoBtn = (ImageView) getActivity().findViewById(R.id.makephotoBtn);
        switchCameraBtn = (ImageView) getActivity().findViewById(R.id.switchCameraBtn);
        holder = sv.getHolder();
        holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

        holderCallback = new HolderCallback();
        holder.addCallback(holderCallback);
        rotation = getActivity().getWindowManager().getDefaultDisplay().getRotation();


        makePhotoBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                camera.takePicture(null, null, new Camera.PictureCallback() {
                    @Override
                    public void onPictureTaken(byte[] data, Camera camera) {
                        try {
                            new SaveBitmap().execute(toObjects(data));
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                });
            }
        });


        switchCameraBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                swapCamera();
            }
        });
    }

And Swap Camera Method:

 private void swapCamera() {

        if (camera != null) {
            camera.stopPreview();
            camera.setPreviewCallback(null);
            camera.release();
            camera = null;
            holder.removeCallback(holderCallback);
            holder = null;
            sv = null;
            sv = (SurfaceView) getActivity().findViewById(R.id.surfaceView);
        }

        //swap the id of the camera to be used
        if (CAMERA_ID == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            CAMERA_ID = 0;
        } else  {
            CAMERA_ID = 1;
        }

        newOpenCamera();


    }

What can I do to get rid of freezes in this case? Appreciate any help!

0 Answers
Related