Android相机开发指南:直接控制相机硬件
在Android应用开发中,相机功能是非常重要且常用的模块。本文将深入讲解如何通过Android框架API直接控制相机硬件,实现自定义相机功能。
相机控制基础
直接控制相机相比调用系统相机应用要复杂得多,但能提供更灵活的定制能力。我们需要掌握以下几个核心概念:
- 相机实例管理:获取和释放Camera对象
- 预览界面:显示相机实时画面
- 参数配置:调整相机各项设置
- 拍照流程:实现拍照功能
- 资源释放:合理管理相机资源
获取相机实例
获取Camera实例是控制相机的第一步。最佳实践是在Activity的onCreate()
方法中开启单独线程操作相机,避免阻塞UI线程。
private boolean safeCameraOpen(int id) {
boolean isOpened = false;
try {
releaseCameraAndPreview();
mCamera = Camera.open(id); // 获取指定摄像头实例
isOpened = (mCamera != null);
} catch (Exception e) {
Log.e(TAG, "相机打开失败");
e.printStackTrace();
}
return isOpened;
}
注意:
- 从API 9开始支持多摄像头,不传参数默认使用后置摄像头
- 必须处理异常情况,防止其他应用占用相机时崩溃
创建预览界面
相机预览需要使用SurfaceView来显示实时画面。我们需要创建一个实现SurfaceHolder.Callback
接口的Preview类:
class Preview extends ViewGroup implements SurfaceHolder.Callback {
SurfaceView mSurfaceView;
SurfaceHolder mHolder;
Preview(Context context) {
super(context);
mSurfaceView = new SurfaceView(context);
addView(mSurfaceView);
// 设置SurfaceHolder回调
mHolder = mSurfaceView.getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
...
}
预览流程控制
相机实例与预览界面需要按特定顺序初始化:
- 先创建Camera实例
- 将Camera实例与Preview关联
- 启动预览
public void setCamera(Camera camera) {
if (mCamera == camera) return;
stopPreviewAndFreeCamera(); // 先停止现有预览
mCamera = camera;
if (mCamera != null) {
// 获取支持的预览尺寸
List<Size> sizes = mCamera.getParameters().getSupportedPreviewSizes();
mSupportedPreviewSizes = sizes;
requestLayout();
try {
mCamera.setPreviewDisplay(mHolder); // 设置预览显示
} catch (IOException e) {
e.printStackTrace();
}
mCamera.startPreview(); // 必须启动预览才能拍照
}
}
相机参数配置
我们可以通过Camera.Parameters调整相机设置:
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
requestLayout();
mCamera.setParameters(parameters); // 应用参数设置
mCamera.startPreview(); // 重启预览使设置生效
}
常见可配置参数包括:
- 预览尺寸
- 图片尺寸
- 对焦模式
- 闪光灯模式
- 白平衡
- 曝光补偿等
方向处理
相机预览默认使用横屏方向,这是传感器自然方向。我们可以通过setDisplayOrientation()
调整预览方向而不影响拍照:
public static void setCameraDisplayOrientation(Activity activity,
int cameraId, Camera camera) {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(cameraId, info);
int rotation = activity.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;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // 补偿镜像
} else {
result = (info.orientation - degrees + 360) % 360;
}
camera.setDisplayOrientation(result);
}
拍照实现
启动预览后,可以通过takePicture()
方法拍照:
mCamera.takePicture(shutterCallback, rawCallback, jpegCallback);
三个回调参数分别处理:
- ShutterCallback:快门声音触发时调用
- PictureCallback:原始图像数据可用时调用
- PictureCallback:JPEG图像数据可用时调用
拍照完成后必须重启预览才能继续拍照:
@Override
public void onClick(View v) {
switch(mPreviewState) {
case STATE_FROZEN:
mCamera.startPreview();
mPreviewState = STATE_PREVIEW;
break;
default:
mCamera.takePicture(null, rawCallback, null);
mPreviewState = STATE_BUSY;
}
}
资源释放
相机是共享资源,必须及时释放:
private void stopPreviewAndFreeCamera() {
if (mCamera != null) {
mCamera.stopPreview(); // 停止预览
mCamera.release(); // 释放相机资源
mCamera = null;
}
}
最佳实践是在Activity的onPause()
中释放相机,在onResume()
中重新获取。
总结
直接控制相机硬件需要处理较多细节,但提供了最大的灵活性。关键点包括:
- 合理管理相机实例生命周期
- 正确实现预览界面
- 妥善处理各种回调
- 及时释放资源
掌握这些技术后,开发者可以创建功能强大、界面独特的相机应用,满足各种专业拍摄需求。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考