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"