在这一节课,我们会讨论如何通过使用framework的APIs来直接控制相机的硬件。直接控制设备的相机,相比起拍照与录像来说,要复杂一些。然而,如果你想要创建一个专业的特殊的相机程序,这节课会演示这部分内容。
获取到 Camera
对象是直接控制Camera的第一步。正如Android自带的相机程序一样,推荐访问Camera的方式是在onCreate方法里面另起一个Thread来打开Camera。这个方法可以避免因为打开工作比较费时而引起ANR。在一个更加基础的实现方法里面,打开Camera的动作被延迟到onResume()方法里面去执行,这样使得代码能够更好的重用,并且保持控制流程不会复杂化。[原文是:In a more basic implementation, opening the camera can be deferred to the onResume()
method to facilitate code reuse and keep the flow of control simple.]
在camera正在被另外一个程序使用的时候去执行 Camera.open()
会抛出一个exception,所以需要捕获起来。
private boolean safeCameraOpen(int id) { boolean qOpened = false; try { releaseCameraAndPreview(); mCamera = Camera.open(id); qOpened = (mCamera != null); } catch (Exception e) { Log.e(getString(R.string.app_name), "failed to open Camera"); e.printStackTrace(); } return qOpened; } private void releaseCameraAndPreview() { mPreview.setCamera(null); if (mCamera != null) { mCamera.release(); mCamera = null; } }自从API level 9开始,camera的framework可以支持多个cameras。如果你使用
open()
,你会获取到最后的一个camera。
SurfaceView
来展现录制的画面。
android.view.SurfaceHolder.Callback
接口,这个接口用来传递从camera硬件获取的数据到程序。
class Preview extends ViewGroup implements SurfaceHolder.Callback { SurfaceView mSurfaceView; SurfaceHolder mHolder; Preview(Context context) { super(context); mSurfaceView = new SurfaceView(context); addView(mSurfaceView); // Install a SurfaceHolder.Callback so we get notified when the // underlying surface is created and destroyed. mHolder = mSurfaceView.getHolder(); mHolder.addCallback(this); mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } ... }这个Preview类必须在查看图片之前传递给
Camera
对象。正如下面描述的:
Camera.startPreview()
。Preview对象必须在
surfaceChanged()
的回调方法里面去做重新创建的动作。
public void setCamera(Camera camera) { if (mCamera == camera) { return; } stopPreviewAndFreeCamera(); mCamera = camera; if (mCamera != null) { List<Size> localSizes = mCamera.getParameters().getSupportedPreviewSizes(); mSupportedPreviewSizes = localSizes; requestLayout(); try { mCamera.setPreviewDisplay(mHolder); } catch (IOException e) { e.printStackTrace(); } /* Important: Call startPreview() to start updating the preview surface. Preview must be started before you can take a picture. */ mCamera.startPreview(); } }
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { // Now that the size is known, set up the camera parameters and begin // the preview. Camera.Parameters parameters = mCamera.getParameters(); parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height); requestLayout(); mCamera.setParameters(parameters); /* Important: Call startPreview() to start updating the preview surface. Preview must be started before you can take a picture. */ mCamera.startPreview(); }
setCameraDisplayOrientation()
方法可以使得你改变预览的方向,并且不会影响到图片被记录的效果。然而,在Android API level 14之前,你必须在改变方向之前,先停止你的预览,然后才能去重启它。
只要预览开始之后,可以使用 Camera.takePicture()
方法来拍下一张图片。你可以创建Camera.PictureCallback
与 Camera.ShutterCallback
对象并传递他们到Camera.takePicture()
中。
如果你想要做连拍的动作,你可以创建一个Camera.PreviewCallback
并实现onPreviewFrame()
.你还可以选择几个预览帧来进行拍照,或是建立一个延迟拍照的动作。
@Override public void onClick(View v) { switch(mPreviewState) { case K_STATE_FROZEN: mCamera.startPreview(); mPreviewState = K_STATE_PREVIEW; break; default: mCamera.takePicture( null, rawCallback, null); mPreviewState = K_STATE_BUSY; } // switch shutterBtnConfig(); }
当你的程序在使用Camera之后,有必要做清理的动作。特别是,你必须释放 Camera
对象,不然会引起其他app crash。
那么何时应该停止预览并释放相机呢? 在预览的surface被摧毁之后,可以做停止预览与释放相机的动作。如下所示:
public void surfaceDestroyed(SurfaceHolder holder) { // Surface will be destroyed when we return, so stop the preview. if (mCamera != null) { /* Call stopPreview() to stop updating the preview surface. */ mCamera.stopPreview(); } } /** * When this function returns, mCamera will be null. */ private void stopPreviewAndFreeCamera() { if (mCamera != null) { /* Call stopPreview() to stop updating the preview surface. */ mCamera.stopPreview(); /* Important: Call release() to release the camera for use by other applications. Applications should release the camera immediately in onPause() (and re-open() it in onResume()). */ mCamera.release(); mCamera = null; } }在这节课的前面,这一些系列的动作也是
setCamera()
方法的一部分,因此初始化一个camera的动作,总是从停止预览开始的。
学习自:http://developer.android.com/training/camera/cameradirect.html,欢迎交流!
转载请注明出自:http://blog.csdn.net/kesenhoo,谢谢!