概述
http://wiki.heyitao.com/program/android/training/camera-cameradirect
这个课时将会讨论如何通过系统的 APIs 来直接控制摄像头。
和使用相机程序拍照和录制视频比起来,直接控制摄像头要比较麻烦一点点。如果您想开发一个专业的相机程序或者完全自定义拍照的界面,这个课时将告诉你如何去做。
你也可以参考开发指南里的摄像头章节学习更多的知识。
打开摄像头
在控制摄像头之前,需要先获取到 Camera 对象。和Android自带的相机程序一样,推荐在另外一个线程中打开摄像头。 打开摄像头可能需要消耗一些时间,放到非UI线程中就不会出现ANR了。一般可以在 onResume() 函数中启动打开摄像头的线程。
如果摄像头正在被其他程序使用,那么调用 Camera.open() 会抛出一个异常,所以要用 try 来处理这个异常。
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 开始,框架支持多个摄像头了。如果使用旧的API, 不设置任何参数调用函数 open() 将会打开第一个背面的摄像头。
创建 Camera Preview
拍照程序通常在用户按下快门之前显示一个预览窗口。要实现这个预览窗口需要使用 SurfaceView 对象。
Preview Class
要显示一个预览图像就需要一个预览的类。该类需要实现 android.view.SurfaceHolder.Callback 接口,该接口用来把摄像头获取的数据传递给预览窗口显示。
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);
}
...
}
在显示预览图像之前,需要把这个预览类设置到 Camera 对象中,下面会介绍如何设置。
设置预览类开始显示预览窗口
摄像头对象和预览类必须按照特定的顺序来创建,要首先创建摄像头对象。下面的代码片段中,初始化摄像头的工作封装起来了,用户每次修改了摄像头的设置,然后调用setCamera()函数时都会调用函数 Camera.startPreview() 。每次在预览类的 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();
}
设置预览窗口的方向
大多数的相机程序都使用横向拍照,这也是摄像头传感器的自然方向。但是这并不影响您在竖屏的时候拍照,设备的方向信息会存储到图片的EXIF信息中。可以通过函数 setCameraDisplayOrientation() 来改变预览的显示方向而不影响图片的保存数据。然而,在API level 14之前的版本中,在修改预览方向之前需要先停止预览窗口然后重新启动预览。
拍摄照片
在预览启动以后就可以通过函数 Camera.takePicture() 来拍摄照片了。可以创建 Camera.PictureCallback 和 Camera.ShutterCallback 对象作为参数来调用函数 Camera.takePicture()。
如果您想连续不断的拍照,可以创建一个实现 Camera.PreviewCallback 接口的类并且实现 onPreviewFrame() 函数。 For something in between, you can capture only selected preview frames, or set up a delayed action to call takePicture().
重启预览窗口
在拍摄一张照片后,需要重启预览来能继续拍摄下一张。下面的示例在处理快门事件的时候重启了预览。
@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();
}
停止预览并且释放资源
何时停止预览并释放摄像头呢? 当预览surface被销毁的时候去释放资源是个不错的地方,下面是在 Preview 类中的一个示例代码:
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;
}
}
Earlier in the lesson, this procedure was also part of the setCamera() method, so initializing a camera always begins with stopping the preview.
最后
以上就是眼睛大水池为你收集整理的Android培训之直接控制摄像头的全部内容,希望文章能够帮你解决Android培训之直接控制摄像头所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复