Camera2介绍
Camera2 API是Android系统中用于访问相机功能的一套API。它提供了更强大和灵活的相机控制能力,相比之前的Camera API,Camera2 API支持更多的功能和更高的性能。
使用Camera2 API,开发者可以实现更多的相机功能,如手动对焦、手动曝光、原生RAW图像捕获等。同时,Camera2 API也提供了更好的性能和更低的延迟,使得相机应用在性能要求较高的场景下能够更好地发挥作用。
在Android系统中,相机功能的实现离不开Camera2 API的支持,因此对于需要使用相机功能的应用开发者来说,熟悉并掌握Camera2 API是非常重要的。
Camera2主要包括以下几个重要组件:
- CameraManager:相机管理器,用于检测和连接可用的相机设备。
- CameraDevice:相机设备,代表一个物理相机设备,可以打开、配置和关闭相机设备。
- CameraCaptureSession:相机捕获会话,用于发送捕获请求和接收捕获结果,可以预览、拍照、录像等。
- CameraCharacteristics:相机特性,提供了相机设备的静态信息,如支持的参数、分辨率、对焦模式等。
使用Camera2,开发者可以更灵活地控制相机的功能和参数,实现更丰富的相机应用程序。
Camera2使用
- 检查相机权限:确保在AndroidManifest.xml文件中添加了相机权限
<uses-permission android:name="android.permission.CAMERA" />
- 1.
- 设置相机预览
- 创建一个TextureView用于显示相机预览画面。
- 使用CameraManager获取相机设备的ID,并打开相机。
- 创建CameraCaptureSession用于预览。
- 拍照
- 创建一个按钮用于触发拍照操作。
- 当用户点击按钮时,使用CameraCaptureSession进行拍照操作。
- 保存拍摄的照片到指定的文件路径。
- 处理相机权限和生命周期
- 在onResume方法中检查相机权限,并打开相机。
- 在onPause方法中关闭相机,释放相关资源。
示例代码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextureView
android:id="@+id/textureView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"/>
<Button
android:onClick="takePicture"
android:id="@+id/btnCapture"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:text="拍照"/>
</LinearLayout>
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
public class CameraActivity extends AppCompatActivity {
private static final int REQUEST_CAMERA_PERMISSION = 200;
private static final int REQUEST_WRITE_EXTERNAL_STORAGE_PERMISSION = 201;
private CameraManager cameraManager;
private String cameraId;
private CameraDevice cameraDevice;
private CameraCaptureSession cameraCaptureSession;
private CaptureRequest.Builder captureRequestBuilder;
private ImageReader imageReader;
private TextureView textureView;
private final TextureView.SurfaceTextureListener surfaceTextureListener = new TextureView.SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
openCamera();
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
return false;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
}
};
private final CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(@NonNull CameraDevice camera) {
cameraDevice = camera;
createCameraPreview();
}
@Override
public void onDisconnected(@NonNull CameraDevice camera) {
cameraDevice.close();
}
@Override
public void onError(@NonNull CameraDevice camera, int error) {
cameraDevice.close();
cameraDevice = null;
}
};
private final CameraCaptureSession.StateCallback captureSessionStateCallback = new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(@NonNull CameraCaptureSession session) {
cameraCaptureSession = session;
try {
captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void onConfigureFailed(@NonNull CameraCaptureSession session) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera);
textureView = findViewById(R.id.textureView);
textureView.setSurfaceTextureListener(surfaceTextureListener);
}
@Override
protected void onResume() {
super.onResume();
if (textureView.isAvailable()) {
openCamera();
} else {
textureView.setSurfaceTextureListener(surfaceTextureListener);
}
}
@Override
protected void onPause() {
closeCamera();
super.onPause();
}
private void openCamera() {
cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
cameraId = cameraManager.getCameraIdList()[0];
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION);
return;
}
cameraManager.openCamera(cameraId, stateCallback, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void createCameraPreview() {
SurfaceTexture texture = textureView.getSurfaceTexture();
texture.setDefaultBufferSize(textureView.getWidth(), textureView.getHeight());
Surface surface = new Surface(texture);
try {
captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
captureRequestBuilder.addTarget(surface);
cameraDevice.createCaptureSession(Collections.singletonList(surface), captureSessionStateCallback, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void closeCamera() {
if (cameraCaptureSession != null) {
cameraCaptureSession.close();
cameraCaptureSession = null;
}
if (cameraDevice != null) {
cameraDevice.close();
cameraDevice = null;
}
}
public void takePicture() {
if (cameraDevice == null) {
return;
}
CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraDevice.getId());
Size[] jpegSizes = null;
if (characteristics != null) {
jpegSizes = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).getOutputSizes(ImageFormat.JPEG);
}
int width = 640;
int height = 480;
if (jpegSizes != null && jpegSizes.length > 0) {
width = jpegSizes[0].getWidth();
height = jpegSizes[0].getHeight();
}
ImageReader reader = ImageReader.newInstance(width, height, ImageFormat.JPEG, 1);
List<Surface> outputSurfaces = new ArrayList<>(2);
outputSurfaces.add(reader.getSurface());
outputSurfaces.add(new Surface(textureView.getSurfaceTexture()));
CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureBuilder.addTarget(reader.getSurface());
captureBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
int rotation = getWindowManager().getDefaultDisplay().getRotation();
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
File file = new File(getExternalFilesDir(null), "pic.jpg");
ImageReader.OnImageAvailableListener readerListener = new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader reader) {
Image image = null;
try {
image = reader.acquireLatestImage();
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.capacity()];
buffer.get(bytes);
save(bytes);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (image != null) {
image.close();
}
}
}
private void save(byte[] bytes) throws IOException {
OutputStream output = null;
try {
output = new FileOutputStream(file);
output.write(bytes);
} finally {
if (output != null) {
output.close();
}
}
}
};
reader.setOnImageAvailableListener(readerListener, null);
final CameraCaptureSession.CaptureCallback captureListener = new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
Toast.makeText(CameraActivity.this, "Saved:" + file, Toast.LENGTH_SHORT).show();
createCameraPreview();
}
};
cameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(@NonNull CameraCaptureSession session) {
try {
session.capture(captureBuilder.build(), captureListener, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void onConfigureFailed(@NonNull CameraCaptureSession session) {
}
}, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
- 84.
- 85.
- 86.
- 87.
- 88.
- 89.
- 90.
- 91.
- 92.
- 93.
- 94.
- 95.
- 96.
- 97.
- 98.
- 99.
- 100.
- 101.
- 102.
- 103.
- 104.
- 105.
- 106.
- 107.
- 108.
- 109.
- 110.
- 111.
- 112.
- 113.
- 114.
- 115.
- 116.
- 117.
- 118.
- 119.
- 120.
- 121.
- 122.
- 123.
- 124.
- 125.
- 126.
- 127.
- 128.
- 129.
- 130.
- 131.
- 132.
- 133.
- 134.
- 135.
- 136.
- 137.
- 138.
- 139.
- 140.
- 141.
- 142.
- 143.
- 144.
- 145.
- 146.
- 147.
- 148.
- 149.
- 150.
- 151.
- 152.
- 153.
- 154.
- 155.
- 156.
- 157.
- 158.
- 159.
- 160.
- 161.
- 162.
- 163.
- 164.
- 165.
- 166.
- 167.
- 168.
- 169.
- 170.
- 171.
- 172.
- 173.
- 174.
- 175.
- 176.
- 177.
- 178.
- 179.
- 180.
- 181.
- 182.
- 183.
- 184.
- 185.
- 186.
- 187.
- 188.
- 189.
- 190.
- 191.
- 192.
- 193.
- 194.
- 195.
- 196.
- 197.
- 198.
- 199.
- 200.
- 201.
- 202.
- 203.
- 204.
- 205.
- 206.
- 207.
- 208.
- 209.
- 210.
- 211.
- 212.
- 213.
- 214.
- 215.
- 216.
- 217.
- 218.
- 219.
- 220.
- 221.
- 222.
- 223.
- 224.
- 225.
- 226.
- 227.
- 228.
在这个示例中,我们首先需要获取相机权限和存储权限,然后通过CameraManager打开相机,创建预览界面,并实现拍照功能。在拍照时,我们需要设置图片的大小、旋转角度等参数,并保存拍摄的照片。
Camera2优缺点
优点
- 「全面的控制」:Camera2 API提供了更多的相机控制,包括手动对焦、曝光、白平衡等功能,使得开发者可以更精细地控制相机的行为。
- 「性能优化」:Camera2 API在性能上进行了优化,能够更好地利用多核处理器和硬件加速功能,提高相机应用的运行效率。
- 「支持原生RAW格式」:Camera2 API支持原生的RAW图像捕获,使得摄影爱好者和专业摄影师可以更好地处理和编辑照片。
缺点
- 「复杂性」:相比于之前的Camera API,Camera2 API的使用复杂度更高,需要开发者具备更多的相机知识和经验。
- 「兼容性问题」:部分老旧的设备可能不支持Camera2 API,这会导致应用在这些设备上无法正常运行。
- 「学习曲线」:对于新手开发者来说,学习并掌握Camera2 API可能需要花费更多的时间和精力。