我尝试使用Camera API创建自定义相机。我已经查看了很多类似的问题,但无论如何都不能在我的相机预览中摆脱冻结。有时候预览会在活动开始时冻结,尽管使用了其他线程。但是当我尝试切换到面部相机时,预览图像每次冻结。在日志中我只有这样的东西:
I/Choreographer: Skipped 41 frames! The application may be doing too much work on its main thread.
如果重要的话,我的SurfaceView将被置于ViewPager活动的Fragment中。
我的自定义相机类方法:
设置显示方向:
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 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) {
}
}
相机处理程序线程:
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");
}
}
}
打开相机:
private void newOpenCamera() {
mThread = new CameraHandlerThread();
synchronized (mThread) {
mThread.openCamera();
}
}
片段方法:
@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();
}
});
}
交换相机方法:
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();
}
在这种情况下,我该怎样做才能摆脱冻结?感谢任何帮助!