Skip to content Skip to sidebar Skip to footer

Camera Preview Performance Issue On Some Devices

I am creating a camera application using android camera api by this example: https://examples.javacodegeeks.com/android/core/hardware/camera-hardware/android-camera-example/ I mad

Solution 1:

I had the same problem using surface view .use the below preview class.its working for me for all the device screen.

public class SquareCameraPreview extends SurfaceView {

publicstaticfinalStringTAG= SquareCameraPreview.class.getSimpleName();
privatestaticfinalintINVALID_POINTER_ID= -1;

privatestaticfinalintZOOM_OUT=0;
privatestaticfinalintZOOM_IN=1;
privatestaticfinalintZOOM_DELTA=1;

privatestaticfinalintFOCUS_SQR_SIZE=100;
privatestaticfinalintFOCUS_MAX_BOUND=1000;
privatestaticfinalintFOCUS_MIN_BOUND= -FOCUS_MAX_BOUND;

privatestaticfinaldoubleASPECT_RATIO=3.0 / 4.0;
private Camera mCamera;

privatefloat mLastTouchX;
privatefloat mLastTouchY;

// For scalingprivateint mMaxZoom;
privateboolean mIsZoomSupported;
privateintmActivePointerId= INVALID_POINTER_ID;
privateintmScaleFactor=1;
private ScaleGestureDetector mScaleDetector;

// For focusprivateboolean mIsFocus;
privateboolean mIsFocusReady;
private Camera.Area mFocusArea;
private ArrayList<Camera.Area> mFocusAreas;

publicSquareCameraPreview(Context context) {
    super(context);
    init(context);
}

publicSquareCameraPreview(Context context, AttributeSet attrs) {
    super(context, attrs);
    init(context);
}

publicSquareCameraPreview(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init(context);
}

privatevoidinit(Context context) {
    mScaleDetector = newScaleGestureDetector(context, newScaleListener());
    mFocusArea = newCamera.Area(newRect(), 1000);
    mFocusAreas = newArrayList<Camera.Area>();
    mFocusAreas.add(mFocusArea);
}

/**
 * Measure the view and its content to determine the measured width and the
 * measured height
 */@OverrideprotectedvoidonMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    intheight= MeasureSpec.getSize(heightMeasureSpec);
    intwidth= MeasureSpec.getSize(widthMeasureSpec);

    finalbooleanisPortrait=
            getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;

    if (isPortrait) {
        if (width > height * ASPECT_RATIO) {
            width = (int) (height * ASPECT_RATIO + 0.5);
        } else {
            height = (int) (width / ASPECT_RATIO + 0.5);
        }
    } else {
        if (height > width * ASPECT_RATIO) {
            height = (int) (width * ASPECT_RATIO + 0.5);
        } else {
            width = (int) (height / ASPECT_RATIO + 0.5);
        }
    }

    setMeasuredDimension(width, height);
}

publicintgetViewWidth() {
    return getWidth();
}

publicintgetViewHeight() {
    return getHeight();
}

publicvoidsetCamera(Camera camera) {
    mCamera = camera;

    if (camera != null) {
        Camera.Parametersparams= camera.getParameters();
        mIsZoomSupported = params.isZoomSupported();
        if (mIsZoomSupported) {
            mMaxZoom = params.getMaxZoom();
        }
    }
}

@OverridepublicbooleanonTouchEvent(MotionEvent event) {
    mScaleDetector.onTouchEvent(event);

    finalintaction= event.getAction();
    switch (action & MotionEvent.ACTION_MASK) {
        case MotionEvent.ACTION_DOWN: {
            mIsFocus = true;

            mLastTouchX = event.getX();
            mLastTouchY = event.getY();

            mActivePointerId = event.getPointerId(0);
            break;
        }
        case MotionEvent.ACTION_UP: {
            if (mIsFocus && mIsFocusReady) {
                handleFocus(mCamera.getParameters());
            }
            mActivePointerId = INVALID_POINTER_ID;
            break;
        }
        case MotionEvent.ACTION_POINTER_DOWN: {
            mCamera.cancelAutoFocus();
            mIsFocus = false;
            break;
        }
        case MotionEvent.ACTION_CANCEL: {
            mActivePointerId = INVALID_POINTER_ID;
            break;
        }
    }

    returntrue;
}

privatevoidhandleZoom(Camera.Parameters params) {
    intzoom= params.getZoom();
    if (mScaleFactor == ZOOM_IN) {
        if (zoom < mMaxZoom) zoom += ZOOM_DELTA;
    } elseif (mScaleFactor == ZOOM_OUT) {
        if (zoom > 0) zoom -= ZOOM_DELTA;
    }
    params.setZoom(zoom);
    mCamera.setParameters(params);
}

privatevoidhandleFocus(Camera.Parameters params) {
    floatx= mLastTouchX;
    floaty= mLastTouchY;

    if (!setFocusBound(x, y)) return;

    List<String> supportedFocusModes = params.getSupportedFocusModes();
    if (supportedFocusModes != null
            && supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
        Log.d(TAG, mFocusAreas.size() + "");
        params.setFocusAreas(mFocusAreas);
        params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
        mCamera.setParameters(params);
        mCamera.autoFocus(newCamera.AutoFocusCallback() {
            @OverridepublicvoidonAutoFocus(boolean success, Camera camera) {
                // Callback when the auto focus completes
            }
        });
    }
}

publicvoidsetIsFocusReady(finalboolean isFocusReady) {
    mIsFocusReady = isFocusReady;
}

privatebooleansetFocusBound(float x, float y) {
    intleft= (int) (x - FOCUS_SQR_SIZE / 2);
    intright= (int) (x + FOCUS_SQR_SIZE / 2);
    inttop= (int) (y - FOCUS_SQR_SIZE / 2);
    intbottom= (int) (y + FOCUS_SQR_SIZE / 2);

    if (FOCUS_MIN_BOUND > left || left > FOCUS_MAX_BOUND) returnfalse;
    if (FOCUS_MIN_BOUND > right || right > FOCUS_MAX_BOUND) returnfalse;
    if (FOCUS_MIN_BOUND > top || top > FOCUS_MAX_BOUND) returnfalse;
    if (FOCUS_MIN_BOUND > bottom || bottom > FOCUS_MAX_BOUND) returnfalse;

    mFocusArea.rect.set(left, top, right, bottom);

    returntrue;
}

privateclassScaleListenerextendsScaleGestureDetector.SimpleOnScaleGestureListener {

    @OverridepublicbooleanonScale(ScaleGestureDetector detector) {
        mScaleFactor = (int) detector.getScaleFactor();
        handleZoom(mCamera.getParameters());
        returntrue;
    }
}

}

public class CameraFragment extends Fragment implements SurfaceHolder.Callback, Camera.PictureCallback {

publicstaticint HIGH_RESOLUTION_WIDTH=1000;
publicstaticint HIGH_RESOLUTION_HIGHT=1500;
publicstatic String clorie_count;
privatelongstartTime=0L;

publicstaticfinalStringTAG= CameraFragment.class.getSimpleName();
publicstaticfinalStringCAMERA_ID_KEY="camera_id";
publicstaticfinalStringCAMERA_FLASH_KEY="flash_mode";
publicstaticfinalStringIMAGE_INFO="image_info";

privatestaticfinalintPICTURE_SIZE_MAX_WIDTH=1280;
privatestaticfinalintPREVIEW_SIZE_MAX_WIDTH=640;

privateint mCameraID;
private String mFlashMode;
private Camera mCamera;
private SquareCameraPreview mPreviewView;
private SurfaceHolder mSurfaceHolder;

privatebooleanmIsSafeToTakePhoto=false;

private ImageParameters mImageParameters;

private CameraOrientationListener mOrientationListener;
@OverridepublicvoidonAttach(Activity activity) {
    super.onAttach(activity);
    context = activity;
    mOrientationListener = newCameraOrientationListener(context);
}

View view;
Dialog listDialog;

@SuppressLint("NewApi")@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {

    view = inflater.inflate(R.layout.camera_fragment, container, false);

    if (savedInstanceState == null) {
            mCameraID = getBackCameraID();
            mFlashMode = CameraSettingPreferences.getCameraFlashMode(getActivity());
            mImageParameters = newImageParameters();
        } else {
            mCameraID = savedInstanceState.getInt(CAMERA_ID_KEY);
            mFlashMode = savedInstanceState.getString(CAMERA_FLASH_KEY);
            mImageParameters = savedInstanceState.getParcelable(IMAGE_INFO);
        }
   mPreviewView = (SquareCameraPreview) view.findViewById(R.id.camerapreview);
         mPreviewView.getHolder().addCallback(CameraFragment.this);
         mImageParameters.mIsPortrait =getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;

         capture_icon.setOnClickListener(newOnClickListener() {

        @OverridepublicvoidonClick(View v) {
            // TODO Auto-generated method stub
            takePicture();
        }
    });
return view;
}
         privatevoidtakePicture() {

            if (mIsSafeToTakePhoto) {
                setSafeToTakePhoto(false);

                mOrientationListener.rememberOrientation();

                // Shutter callback occurs after the image is captured. This can// be used to trigger a sound to let the user know that image is taken
                Camera.ShutterCallbackshutterCallback=null;

                // Raw callback occurs when the raw image data is available
                Camera.PictureCallbackraw=null;

                // postView callback occurs when a scaled, fully processed// postView image is available.
                Camera.PictureCallbackpostView=null;

                // jpeg callback occurs when the compressed image is available
                mCamera.takePicture(shutterCallback, raw, postView, this);
            }
        }        

        privatevoidsetSafeToTakePhoto(finalboolean isSafeToTakePhoto) {
        mIsSafeToTakePhoto = isSafeToTakePhoto;
    }

    privatevoidsetCameraFocusReady(finalboolean isFocusReady) {
        if (this.mPreviewView != null) {
            mPreviewView.setIsFocusReady(isFocusReady);
        }
    }
    /**
     * Determine the current display orientation and rotate the camera preview
     * accordingly
     */privatevoiddetermineDisplayOrientation() {
        CameraInfocameraInfo=newCameraInfo();
        Camera.getCameraInfo(mCameraID, cameraInfo);

        // Clockwise rotation needed to align the window display to the natural positionintrotation= getActivity().getWindowManager().getDefaultDisplay().getRotation();
        intdegrees=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 displayOrientation;

        // CameraInfo.Orientation is the angle relative to the natural position of the device// in clockwise rotation (angle that is rotated clockwise from the natural position)if (cameraInfo.facing == CameraInfo.CAMERA_FACING_FRONT) {
            // Orientation is angle of rotation when facing the camera for// the camera image to match the natural orientation of the device
            displayOrientation = (cameraInfo.orientation + degrees) % 360;
            displayOrientation = (360 - displayOrientation) % 360;
        } else {
            displayOrientation = (cameraInfo.orientation - degrees + 360) % 360;
        }

        mImageParameters.mDisplayOrientation = displayOrientation;
        mImageParameters.mLayoutOrientation = degrees;

        mCamera.setDisplayOrientation(mImageParameters.mDisplayOrientation);
    }
    privatevoidsetupCamera() {
        // Never keep a global parameters
        Camera.Parametersparameters= mCamera.getParameters();

        SizebestPreviewSize= determineBestPreviewSize(parameters);
        SizebestPictureSize= determineBestPictureSize(parameters);

        parameters.setPreviewSize(bestPreviewSize.width, bestPreviewSize.height);
        parameters.setPictureSize(bestPictureSize.width, bestPictureSize.height);


        // Set continuous picture focus, if it's supportedif (parameters.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
            parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
        }

        finalViewchangeCameraFlashModeBtn= getView().findViewById(R.id.flash);
        List<String> flashModes = parameters.getSupportedFlashModes();
        if (flashModes != null && flashModes.contains(mFlashMode)) {
            parameters.setFlashMode(mFlashMode);
            changeCameraFlashModeBtn.setVisibility(View.VISIBLE);
        } else {
            changeCameraFlashModeBtn.setVisibility(View.INVISIBLE);
        }

        // Lock in the changes
        mCamera.setParameters(parameters);
    }
    private Size determineBestPreviewSize(Camera.Parameters parameters) {
        return determineBestSize(parameters.getSupportedPreviewSizes(), PREVIEW_SIZE_MAX_WIDTH);
    }

    private Size determineBestPictureSize(Camera.Parameters parameters) {
        return determineBestSize(parameters.getSupportedPictureSizes(), PICTURE_SIZE_MAX_WIDTH);
    }

    private Size determineBestSize(List<Size> sizes, int widthThreshold) {
        SizebestSize=null;
        Size size;
        intnumOfSizes= sizes.size();
        for (inti=0; i < numOfSizes; i++) {
            size = sizes.get(i);
            booleanisDesireRatio= (size.width / 4) == (size.height / 3);
            booleanisBetterSize= (bestSize == null) || size.width > bestSize.width;

            if (isDesireRatio && isBetterSize) {
                bestSize = size;
            }
        }

        if (bestSize == null) {
            Log.d(TAG, "cannot find the best camera size");
            return sizes.get(sizes.size() - 1);
        }

        return bestSize;
    }

     /**
     * Start the camera preview
     */privatevoidstartCameraPreview() {
        determineDisplayOrientation();
        setupCamera();

        try {
            mCamera.setPreviewDisplay(mSurfaceHolder);
            mCamera.startPreview();

            setSafeToTakePhoto(true);
            setCameraFocusReady(true);
        } catch (IOException e) {
            Log.d(TAG, "Can't start camera preview due to IOException " + e);
            e.printStackTrace();
        }
    }

    privatevoidgetCamera(int cameraID) {
        try {
            mCamera = Camera.open(cameraID);
            mPreviewView.setCamera(mCamera);
        } catch (Exception e) {
            Log.d(TAG, "Can't open camera with id " + cameraID);
            e.printStackTrace();
        }
    }

    @OverridepublicvoidonPictureTaken(byte[] arg0, Camera arg1) {
        // TODO Auto-generated method stub



        HERE YOU GET THE PHOTO BYTE[] arg0

        CONVERT IT TO BITMAP OR STROE INTO A FILE


    }

    @OverridepublicvoidsurfaceChanged(SurfaceHolder arg0, int arg1, int arg2,
            int arg3) {
        // TODO Auto-generated method stub

    }

    @OverridepublicvoidsurfaceCreated(SurfaceHolder holder) {
        // TODO Auto-generated method stub
         mSurfaceHolder = holder;

            getCamera(mCameraID);
            startCameraPreview();
    }

    @OverridepublicvoidsurfaceDestroyed(SurfaceHolder arg0) {
        // TODO Auto-generated method stub

    } 



        privatestaticclassCameraOrientationListenerextendsOrientationEventListener {

            privateint mCurrentNormalizedOrientation;
            privateint mRememberedNormalOrientation;

            publicCameraOrientationListener(Context context) {
                super(context, SensorManager.SENSOR_DELAY_NORMAL);
            }

            @OverridepublicvoidonOrientationChanged(int orientation) {
                if (orientation != ORIENTATION_UNKNOWN) {
                    mCurrentNormalizedOrientation = normalize(orientation);
                }
            }

            /**
             * @param degrees Amount of clockwise rotation from the device's natural position
             * @return Normalized degrees to just 0, 90, 180, 270
             */privateintnormalize(int degrees) {
                if (degrees > 315 || degrees <= 45) {
                    return0;
                }

                if (degrees > 45 && degrees <= 135) {
                    return90;
                }

                if (degrees > 135 && degrees <= 225) {
                    return180;
                }

                if (degrees > 225 && degrees <= 315) {
                    return270;
                }

                thrownewRuntimeException("The physics as we know them are no more. Watch out for anomalies.");
            }

            publicvoidrememberOrientation() {
                mRememberedNormalOrientation = mCurrentNormalizedOrientation;
            }

            publicintgetRememberedNormalOrientation() {
                rememberOrientation();
                return mRememberedNormalOrientation;
            }
        }
        /*@Override
        public void onResume() {
            super.onResume();

            if (mCamera == null) {
                restartPreview();
            }
        }*/@OverridepublicvoidonStop() {
            mOrientationListener.disable();

            // stop the previewif (mCamera != null) {
                stopCameraPreview();
                mCamera.release();
                mCamera = null;
            }
            if (getKillStatus()) {
                android.os.Process.killProcess(android.os.Process.myPid());
            }
           // CameraSettingPreferences.saveCameraFlashMode(getActivity(), mFlashMode);super.onStop();
        }
        @OverridepublicvoidonResume() {
            super.onResume();
            /*if (camera != null) {
                camera.stopPreview();
                preview.setupCamera(null,isResolutionHigh);
                camera.release();
                camera = null;
            }

            int numCams = Camera.getNumberOfCameras();
            if (numCams > 0) {
                try {
                    camera = Camera.open(0);
                    camera.startPreview();
                    preview.setupCamera(camera,isResolutionHigh);

                } catch (RuntimeException ex) {
                    // Toast.makeText(ctx, getString(R.string.camera_not_found),
                    // Toast.LENGTH_LONG).show();
                }
            }*/if (mCamera == null) {
                restartPreview();
            }

        }
        privatevoidrestartPreview() {
            if (mCamera != null) {
                stopCameraPreview();
                mCamera.release();
                mCamera = null;
            }

            getCamera(mCameraID);
            startCameraPreview();
        }
        /**
         * Stop the camera preview
         */privatevoidstopCameraPreview() {
            setSafeToTakePhoto(false);
            setCameraFocusReady(false);

            // Nulls out callbacks, stops face detection
            mCamera.stopPreview();
            mPreviewView.setCamera(null);
        }
        privateintgetBackCameraID() {
            return CameraInfo.CAMERA_FACING_BACK;
        }

}        

AND YOUR XML FILE

<com.demo.camera.SquareCameraPreviewandroid:id="@+id/camerapreview"android:layout_width="match_parent"android:layout_height="wrap_content"
        />

ImageParameter Class

public class ImageParameters implements Parcelable {

    public boolean mIsPortrait;

    public int mDisplayOrientation;
    public int mLayoutOrientation;

    public int mCoverHeight, mCoverWidth;
    public int mPreviewHeight, mPreviewWidth;

    public ImageParameters(Parcel in) {
        mIsPortrait = (in.readByte() == 1);

        mDisplayOrientation = in.readInt();
        mLayoutOrientation = in.readInt();

        mCoverHeight = in.readInt();
        mCoverWidth = in.readInt();
        mPreviewHeight = in.readInt();
        mPreviewWidth = in.readInt();
    }

    public ImageParameters() {}

    public int calculateCoverWidthHeight() {
       return Math.abs(mPreviewHeight - mPreviewWidth) / 2;
    }

    public int getAnimationParameter() {
        return mIsPortrait ? mCoverHeight : mCoverWidth;
    }

    public boolean isPortrait() {
        return mIsPortrait;
    }

    public ImageParameters createCopy() {
        ImageParameters imageParameters = new ImageParameters();

        imageParameters.mIsPortrait = mIsPortrait;
        imageParameters.mDisplayOrientation = mDisplayOrientation;
        imageParameters.mLayoutOrientation = mLayoutOrientation;

        imageParameters.mCoverHeight = mCoverHeight;
        imageParameters.mCoverWidth = mCoverWidth;
        imageParameters.mPreviewHeight = mPreviewHeight;
        imageParameters.mPreviewWidth = mPreviewWidth;

        return imageParameters;
    }

    public String getStringValues() {
        return "is Portrait: " + mIsPortrait + "," +
                "\ncover height: " + mCoverHeight + " width: " + mCoverWidth
                + "\npreview height: " + mPreviewHeight + " width: " + mPreviewWidth;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeByte((byte) (mIsPortrait ? 1 : 0));

        dest.writeInt(mDisplayOrientation);
        dest.writeInt(mLayoutOrientation);

        dest.writeInt(mCoverHeight);
        dest.writeInt(mCoverWidth);
        dest.writeInt(mPreviewHeight);
        dest.writeInt(mPreviewWidth);
    }

    public static final Creator<ImageParameters> CREATOR = new Parcelable.Creator<ImageParameters>() {
        @Override
        public ImageParameters createFromParcel(Parcel source) {
            return new ImageParameters(source);
        }

        @Override
        public ImageParameters[] newArray(int size) {
            return new ImageParameters[size];
        }
    };
}

Another class you need camera setting preference

public class CameraSettingPreferences {

    private static final String FLASH_MODE = "squarecamera__flash_mode";

    private static SharedPreferences getCameraSettingPreferences(@NonNull final Context context) {
        return context.getSharedPreferences("com.desmond.squarecamera", Context.MODE_PRIVATE);
    }

    protected static void saveCameraFlashMode(@NonNull final Context context, @NonNull final String cameraFlashMode) {
        final SharedPreferences preferences = getCameraSettingPreferences(context);

        if (preferences != null) {
            final SharedPreferences.Editor editor = preferences.edit();
            editor.putString(FLASH_MODE, cameraFlashMode);
            editor.apply();
        }
    }

    public static String getCameraFlashMode(@NonNull final Context context) {
        final SharedPreferences preferences = getCameraSettingPreferences(context);

        if (preferences != null) {
            return preferences.getString(FLASH_MODE, Camera.Parameters.FLASH_MODE_AUTO);
        }

        return Camera.Parameters.FLASH_MODE_AUTO;
    }
}

Let me know if you have any doubts.

Post a Comment for "Camera Preview Performance Issue On Some Devices"