Camera2 API是Android系统中用于访问相机功能的一套API。它提供了更强大和灵活的相机控制能力,相比之前的Camera API,Camera2 API支持更多的功能和更高的性能。
使用Camera2 API,开发者可以实现更多的相机功能,如手动对焦、手动曝光、原生RAW图像捕获等。同时,Camera2 API也提供了更好的性能和更低的延迟,使得相机应用在性能要求较高的场景下能够更好地发挥作用。
在Android系统中,相机功能的实现离不开Camera2 API的支持,因此对于需要使用相机功能的应用开发者来说,熟悉并掌握Camera2 API是非常重要的。
Camera2主要包括以下几个重要组件:
CameraManager:相机管理器,用于检测和连接可用的相机设备。
CameraDevice:相机设备,代表一个物理相机设备,可以打开、配置和关闭相机设备。
CameraCaptureSession:相机捕获会话,用于发送捕获请求和接收捕获结果,可以预览、拍照、录像等。
CameraCharacteristics:相机特性,提供了相机设备的静态信息,如支持的参数、分辨率、对焦模式等。
使用Camera2,开发者可以更灵活地控制相机的功能和参数,实现更丰富的相机应用程序。
检查相机权限:确保在AndroidManifest.xml文件中添加了相机权限
<uses-permission android:name="android.permission.CAMERA"/>
设置相机预览
创建一个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>
publicclass CameraActivity extends AppCompatActivity { private static finalintREQUEST_CAMERA_PERMISSION=200;private static finalintREQUEST_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(){@Overridepublicvoid onSurfaceTextureAvailable(SurfaceTexture surface,intwidth,intheight){ openCamera();}@Overridepublicvoid onSurfaceTextureSizeChanged(SurfaceTexture surface,intwidth,intheight){ }@OverridepublicbooleanonSurfaceTextureDestroyed(SurfaceTexture surface){returnfalse;}@Overridepublicvoid onSurfaceTextureUpdated(SurfaceTexture surface){ } };private final CameraDevice.StateCallback stateCallback=new CameraDevice.StateCallback(){@Overridepublicvoid onOpened(@NonNullCameraDevice camera){ cameraDevice=camera;createCameraPreview();}@Overridepublicvoid onDisconnected(@NonNullCameraDevice camera){ cameraDevice.close();}@Overridepublicvoid onError(@NonNullCameraDevice camera,interror){ cameraDevice.close();cameraDevice=null;} };private final CameraCaptureSession.StateCallback captureSessionStateCallback=new CameraCaptureSession.StateCallback(){@Overridepublicvoid onConfigured(@NonNullCameraCaptureSessionsession){ 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();} }@Overridepublicvoid onConfigureFailed(@NonNullCameraCaptureSessionsession){ } };@Overrideprotected void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState);setContentView(R.layout.activity_camera);textureView=findViewById(R.id.textureView);textureView.setSurfaceTextureListener(surfaceTextureListener);}@Overrideprotected void onResume(){ super.onResume();if(textureView.isAvailable()){ openCamera();}else{ textureView.setSurfaceTextureListener(surfaceTextureListener);} }@Overrideprotected 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;} }publicvoid 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);}intwidth=640;intheight=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);introtation=getWindowManager().getDefaultDisplay().getRotation();captureBuilder.set(CaptureRequest.JPEG_ORIENTATION,ORIENTATIONS.get(rotation));Filefile=newFile(getExternalFilesDir(null),"pic.jpg");ImageReader.OnImageAvailableListener readerListener=new ImageReader.OnImageAvailableListener(){@Overridepublicvoid 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 voidsave(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(){@Overridepublicvoid onCaptureCompleted(@NonNullCameraCaptureSessionsession,@NonNullCaptureRequest request,@NonNullTotalCaptureResult result){ super.onCaptureCompleted(session,request,result);Toast.makeText(CameraActivity.this,"Saved:"+file,Toast.LENGTH_SHORT).show();createCameraPreview();} };cameraDevice.createCaptureSession(outputSurfaces,new CameraCaptureSession.StateCallback(){@Overridepublicvoid onConfigured(@NonNullCameraCaptureSessionsession){ try {session.capture(captureBuilder.build(),captureListener,null);} catch(CameraAccessException e){ e.printStackTrace();} }@Overridepublicvoid onConfigureFailed(@NonNullCameraCaptureSessionsession){ } },null);} catch(CameraAccessException e){ e.printStackTrace();} } }
在这个示例中,我们首先需要获取相机权限和存储权限,然后通过CameraManager打开相机,创建预览界面,并实现拍照功能。在拍照时,我们需要设置图片的大小、旋转角度等参数,并保存拍摄的照片。
优点
「全面的控制」:Camera2 API提供了更多的相机控制,包括手动对焦、曝光、白平衡等功能,使得开发者可以更精细地控制相机的行为。
「性能优化」:Camera2 API在性能上进行了优化,能够更好地利用多核处理器和硬件加速功能,提高相机应用的运行效率。
「支持原生RAW格式」:Camera2 API支持原生的RAW图像捕获,使得摄影爱好者和专业摄影师可以更好地处理和编辑照片。
缺点
「复杂性」:相比于之前的Camera API,Camera2 API的使用复杂度更高,需要开发者具备更多的相机知识和经验。
「兼容性问题」:部分老旧的设备可能不支持Camera2 API,这会导致应用在这些设备上无法正常运行。
「学习曲线」:对于新手开发者来说,学习并掌握Camera2 API可能需要花费更多的时间和精力。