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!